OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
无匹配项
迁移指南

上一教程: 编写 OpenCV 文档
下一教程: 从其他 Doxygen 项目交叉引用 OpenCV

原作者Maksim Shabunin
兼容性OpenCV >= 3.0

更改概述

本文档面向希望将其代码迁移到 OpenCV 3.0 的软件开发人员。

与 2.4 版本相比,OpenCV 3.0 引入了许多新的算法和功能。一些模块已被重写,一些模块已被重组。尽管 2.4 版本中的大多数算法仍然存在,但接口可能有所不同。

本节描述了最显著的总体更改,所有详细信息和迁移操作示例都在文档的下一部分中。

Contrib 仓库

https://github.com/opencv/opencv_contrib

这是所有新的、实验性的和非免费算法的存放地。与主仓库相比,它没有得到支持团队的太多关注,但社区正在努力使其保持良好的状态。

要使用 *contrib* 仓库构建 OpenCV,请将以下选项添加到您的 cmake 命令中:

-DOPENCV_EXTRA_MODULES_PATH=<opencv_contrib 路径>/modules
头文件布局

在 2.4 版本中,所有头文件都位于相应的模块子文件夹中 (opencv2/<module>/<module>.hpp),在 3.0 版本中,存在包含大部分模块功能的顶级模块头文件:opencv2/<module>.hpp,并且所有 C 样式 API 定义已移动到单独的头文件中(例如 opencv2/core/core_c.h)。

算法接口

一般的算法使用方法已更改:现在必须在堆上创建它,并用智能指针 cv::Ptr 包装。2.4 版本允许堆栈和堆分配,直接或通过智能指针。

cv::Algorithm 类中删除了 *get* 和 *set* 方法以及 *CV_INIT_ALGORITHM* 宏。在 3.0 版本中,所有属性都已转换为成对的 *getProperty/setProperty* 纯虚方法。结果是不能通过名称创建和使用 cv::Algorithm 实例(使用泛型 *Algorithm::create(String)* 方法),应该显式调用相应的工厂方法。

更改的模块
  • *ml* 模块已被重写
  • *highgui* 模块已被拆分为几部分:*imgcodecs*、*videoio* 和 *highgui* 本身
  • *features2d* 模块已被重组(一些特征检测器已被移动到 *opencv_contrib/xfeatures2d* 模块)
  • *legacy*、*nonfree* 模块已被移除。一些算法已被移动到不同的位置,一些算法已被完全重写或移除
  • CUDA API 已更新(*gpu* 模块 -> 多个 *cuda* 模块,命名空间 *gpu* -> 命名空间 *cuda*)
  • OpenCL API 已更改(*ocl* 模块已被移除,单独的 *ocl::* 实现 -> 透明 API)
  • 其他一些方法和类已被重新定位

迁移提示

本节描述了带有示例的具体操作。

准备 2.4 版本

最新 2.4.11 OpenCV 版本中进行的一些更改允许您准备当前代码库进行迁移

  • cv::makePtr 函数现已可用
  • 已创建 *opencv2/<module>.hpp* 头文件

新的头文件布局

注意:OpenCV 3.0 中进行了旨在简化迁移的更改,因此以下说明不是必需的,但建议这样做。

  1. 替换旧模块头文件的包含
    // 旧头文件
    #include "opencv2/<module>/<module>.hpp"
    // 新头文件
    #include "opencv2/<module>.hpp"

使用算法的现代方法

  1. 必须使用 cv::makePtr 函数或相应的静态工厂方法(如果可用)来创建算法实例
    // 正确的方法
    Ptr<SomeAlgo> algo = makePtr<SomeAlgo>(...);
    Ptr<SomeAlgo> algo = SomeAlgo::create(...);
    其他方法已弃用
    // 错误的方法
    Ptr<SomeAlgo> algo = new SomeAlgo(...);
    SomeAlgo * algo = new SomeAlgo(...);
    SomeAlgo algo(...);
    Ptr<SomeAlgo> algo = Algorithm::create<SomeAlgo>("name");
  2. 应通过相应的虚方法 *getSomeProperty/setSomeProperty* 访问算法属性,已删除泛型 *get/set* 方法
    // 正确的方法
    double clipLimit = clahe->getClipLimit();
    clahe->setClipLimit(clipLimit);
    // 错误的方法
    double clipLimit = clahe->getDouble("clipLimit");
    clahe->set("clipLimit", clipLimit);
    clahe->setDouble("clipLimit", clipLimit);
  3. 删除 initModule_<moduleName>() 调用

机器学习模块

由于此模块已被重写,因此需要付出一些努力才能使您的软件适应它。所有算法都位于单独的 *ml* 命名空间中,以及它们的基类 *StatModel*。单独的 *SomeAlgoParams* 类已被一组相应的 *getProperty/setProperty* 方法取代。

下表说明了 2.4 和 3.0 机器学习类之间的对应关系。

2.4 3.0
CvStatModelcv::ml::StatModel
CvNormalBayesClassifiercv::ml::NormalBayesClassifier
CvKNearestcv::ml::KNearest
CvSVMcv::ml::SVM
CvDTreecv::ml::DTrees
CvBoostcv::ml::Boost
CvGBTrees未实现
CvRTreescv::ml::RTrees
CvERTrees未实现
EMcv::ml::EM
CvANN_MLPcv::ml::ANN_MLP
未实现 cv::ml::LogisticRegression
CvMLDatacv::ml::TrainData

虽然 3.0 中重写的 *ml* 算法允许您从 *xml/yml* 文件加载旧的训练模型,但预测过程可能会出现偏差。

来自 `points_classifier.cpp` 示例的以下代码片段说明了模型训练过程中的差异

using namespace cv;
// ======== 2.4 版本 ========
Mat trainSamples, trainClasses;
prepare_train_data(trainSamples, trainClasses);
CvBoost boost;
Mat var_types(1, trainSamples.cols + 1, CV_8UC1, Scalar(CV_VAR_ORDERED));
var_types.at(trainSamples.cols) = CV_VAR_CATEGORICAL;
CvBoostParams params(CvBoost::DISCRETE, // boost_type
100, // weak_count
0.95, // weight_trim_rate
2, // max_depth
false, //use_surrogates
0 // priors
);
boost.train(trainSamples, CV_ROW_SAMPLE, trainClasses, Mat(), Mat(), var_types, Mat(), params);
// ======== 3.0版本 ========
Ptr<Boost> boost = Boost::create();
boost->setBoostType(Boost::DISCRETE);
boost->setWeakCount(100);
boost->setWeightTrimRate(0.95);
boost->setMaxDepth(2);
boost->setUseSurrogates(false);
boost->setPriors(Mat());
boost->train(prepare_train_data()); // 'prepare_train_data' 返回 ml::TrainData 类实例
n维稠密数组类
**定义:** mat.hpp:829
int cols
**定义:** mat.hpp:2155
std::shared_ptr<_Tp> Ptr
**定义:** cvstd_wrapper.hpp:23
unsigned char uchar
**定义:** interface.h:51
#define CV_8UC1
**定义:** interface.h:88
**定义:** core.hpp:107

特征检测

一些算法 (FREAK, BRIEF, SIFT, SURF) 已移至 *opencv_contrib* 仓库的 *xfeatures2d* 模块,*xfeatures2d* 命名空间。它们的接口也已更改(继承自cv::Feature2D基类)。

*xfeatures2d* 模块类的列表

  • cv::xfeatures2d::BriefDescriptorExtractor - 用于计算BRIEF描述符的类 (2.4 版本位置: *features2d*)
  • cv::xfeatures2d::FREAK - 实现FREAK (快速视网膜关键点) 关键点描述符的类 (2.4 版本位置: *features2d*)
  • cv::xfeatures2d::StarDetector - 该类实现 Agrawal08 提出的关键点检测器,StarDetector 的同义词。(2.4 版本位置: *features2d*)
  • cv::xfeatures2d::SIFT - 使用尺度不变特征变换 (SIFT) 算法提取关键点和计算描述符的类 (2.4 版本位置: *nonfree*)
  • cv::xfeatures2d::SURF - 用于从图像中提取加速鲁棒特征的类 (2.4 版本位置: *nonfree*)

需要执行以下步骤

  1. 将 *opencv_contrib* 添加到编译过程中
  2. 包含opencv2/xfeatures2d.h头文件
  3. 使用命名空间xfeatures2d
  4. 如果需要,用detectcomputedetectAndCompute替换operator()调用

现在有些类使用Feature2D基类提供的通用方法detectcomputedetectAndCompute,而不是自定义的operator()

以下代码片段说明了区别(来自video_homography.cpp示例)

using namespace cv;
// ====== 2.4 =======
#include "opencv2/features2d/features2d.hpp"
BriefDescriptorExtractor brief(32);
GridAdaptedFeatureDetector detector(new FastFeatureDetector(10, true), DESIRED_FTRS, 4, 4);
// ...
detector.detect(gray, query_kpts); // 查找兴趣点
brief.compute(gray, query_kpts, query_desc); // 在每个关键点位置计算简短描述符
// ====== 3.0 =======
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv::xfeatures2d;
Ptr<BriefDescriptorExtractor> brief = BriefDescriptorExtractor::create(32);
Ptr<FastFeatureDetector> detector = FastFeatureDetector::create(10, true);
// ...
detector->detect(gray, query_kpts); // 查找兴趣点
brief->compute(gray, query_kpts, query_desc); // 在每个关键点位置计算简短描述符
使用FAST方法进行特征检测的包装类。
**定义:** features2d.hpp:574
**定义:** xfeatures2d.hpp:67

OpenCL

所有专门的ocl实现都隐藏在通用的C++算法接口后面。现在可以在运行时动态选择函数执行路径:CPU或OpenCL;这种机制也称为“透明API”。

新的类cv::UMat旨在以方便的方式隐藏与OpenCL设备的数据交换。

以下示例说明了API修改(来自OpenCV网站

  • 支持OpenCL的OpenCV-2.x代码
    // 初始化
    VideoCapture vcap(...);
    ocl::OclCascadeClassifier fd("haar_ff.xml");
    ocl::oclMat frame, frameGray;
    Mat frameCpu;
    vector<Rect> faces;
    for(;;){
    // 处理循环
    vcap >> frameCpu;
    frame = frameCpu;
    ocl::cvtColor(frame, frameGray, BGR2GRAY);
    ocl::equalizeHist(frameGray, frameGray);
    fd.detectMultiScale(frameGray, faces, ...);
    // 绘制矩形…
    // 显示图像…
    }
    用于从视频文件、图像序列或摄像头捕获视频的类。
    **定义:** videoio.hpp:766
  • 支持OpenCL的OpenCV-3.x代码
    // 初始化
    VideoCapture vcap(...);
    CascadeClassifier fd("haar_ff.xml");
    UMat frame, frameGray; // 与普通CPU版本唯一的区别
    vector<Rect> faces;
    for(;;){
    // 处理循环
    vcap >> frame;
    cvtColor(frame, frameGray, BGR2GRAY);
    equalizeHist(frameGray, frameGray);
    fd.detectMultiScale(frameGray, faces, ...);
    // 绘制矩形…
    // 显示图像…
    }
    用于目标检测的级联分类器类。
    **定义:** objdetect.hpp:258
    **定义:** mat.hpp:2450

CUDA

CUDA模块已移至opencv_contrib仓库。

文档格式

文档已转换为Doxygen格式。您可以在OpenCV参考文档的“教程”部分找到更新的文档编写指南(OpenCV文档编写)。

支持两个版本

在某些情况下,可以同时支持两个版本的OpenCV。

源代码

要在您的应用程序源代码中检查库主版本,应使用以下方法

#if CV_MAJOR_VERSION == 2
// opencv 2 代码
#elif CV_MAJOR_VERSION == 3
// opencv 3 代码
#endif
注意
不要使用CV_VERSION_MAJOR,它在2.4和3.x分支中的含义不同!

构建系统

可以通过在构建系统中检查库版本来链接不同的模块或启用/禁用应用程序中的一些功能。为此可以使用标准的cmake或pkg-config变量。

  • cmake中的OpenCV_VERSION将包含完整版本号,例如“2.4.11”或“3.0.0”
  • cmake中的OpenCV_VERSION_MAJOR仅包含主版本号:2或3
  • pkg-config文件具有标准字段Version

示例

if(OpenCV_VERSION VERSION_LESS "3.0")
# 使用2.4模块
else()
# 使用3.x模块
endif()