上一个教程 : 为 OpenCV 编写文档
下一个教程 : 交叉引用其他 Doxygen 项目中的 OpenCV
原作者 | Maksim Shabunin |
---|---|
兼容性 | OpenCV >= 3.0 |
变更概述
本文档面向希望将其代码迁移到 OpenCV 3.0 的软件开发人员。
与 2.4 版相比,OpenCV 3.0 引入了许多新的算法和功能。一些模块被重写,一些模块被重组。虽然 2.4 中的大部分算法仍然存在,但接口可能有所不同。
本节将大致介绍最显著的变化,所有细节和过渡操作示例将在本文档的下一部分介绍。
贡献库
https://github.com/opencv/opencv_contrib
这里存放所有新算法、实验算法和非自由算法。与主资源库相比,支持团队对它的关注度并不高,但社区努力使其保持良好状态。
要使用贡献源构建 OpenCV,请在 cmake 命令中添加以下选项:
-DOPENCV_EXTRA_MODULES_PATH=<path-to-opencv_contrib>/modules
页眉布局
在 2.4 中,所有头文件都位于相应的模块子文件夹 (opencv2//.hpp),而在 3.0 中,顶层模块头文件包含了大部分模块功能:opencv2/.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 模块)
- 删除了遗留的非自由模块。一些算法被移到了不同的位置,一些算法被完全重写或移除
- 更新了 CUDA 应用程序接口(gpu 模块 -> 多个 cuda 模块,命名空间 gpu -> 命名空间 cuda)
- OpenCL API 已更改(ocl 模块已移除,单独的 ocl:: 实现 -> 透明 API)
- 重新定位了其他一些方法和类
过渡提示
本节将举例说明具体操作。
准备 2.4
在最新的 2.4.11 OpenCV 版本中进行的一些更改允许您为迁移当前代码库做好准备:
- cv::makePtr 函数现在可用
- 创建了 opencv2/.hpp 头文件
新的头文件布局
注意:OpenCV 3.0 中已经进行了旨在简化迁移的更改,因此以下说明并非必要,但建议使用。
- 替换旧模块头文件中的内容:
// 旧头文件
#include "opencv2/<module>/<module>.hpp" 新头文件
// 新头文件
#include "opencv2/<module>.hpp" 新头文件
使用算法的现代方法
- 算法实例必须使用 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");
- 算法属性应通过相应的虚拟方法 getSomeProperty/setSomeProperty 访问,通用 get/set 方法已被删除:
// 好方法
double clipLimit = clahe->getClipLimit();
clahe->setClipLimit(clipLimit);
// 坏方法
double clipLimit = clahe->getDouble("clipLimit");
clahe->set("clipLimit", clipLimit);
clahe->setDouble("clipLimit", clipLimit);
- 移除 initModule_() 调用
机器学习模块
由于该模块已被重写,因此需要花费一些精力来调整软件以适应它。所有算法都与其基类 StatModel 位于独立的 ml 命名空间中。独立的 SomeAlgoParams 类已被一组相应的 getProperty/setProperty 方法所取代。
下表说明了 2.4 和 3.0 机器学习类之间的对应关系。
2.4 | 3.0 |
---|---|
CvStatModel | cv::ml::StatModel |
CvNormalBayesClassifier | cv::ml::NormalBayesClassifier |
CvKNearest | cv::ml::KNearest |
CvSVM | cv::ml::SVM |
CvDTree | cv::ml::DTrees |
CvBoost | cv::ml::Boost |
CvGBTrees | Not implemented |
CvRTrees | cv::ml::RTrees |
CvERTrees | Not implemented |
EM | cv::ml::EM |
CvANN_MLP | cv::ml::ANN_MLP |
Not implemented | cv::ml::LogisticRegression |
CvMLData | cv::ml::TrainData |
尽管 3.0 中重写的 ml 算法允许从 xml/yml 文件加载旧的训练模型,但预测过程仍有可能出现偏差。
以下来自 points_classifier.cpp 示例的代码片段说明了模型训练过程中的差异:\
using namespace cv;
// ======== version 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<uchar>( 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 );
// ======== version 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' returns an instance of ml::TrainData class
特征检测
部分算法(FREAK、BRIEF、SIFT、SURF)已移至 opencv_contrib 资源库的 xfeatures2d 模块和 xfeatures2d 命名空间。它们的接口也已更改(继承自 cv::Feature2D
基类)。
xfeatures2d 模块类列表:
- cv::xfeatures2d::BriefDescriptorExtractor - 用于计算 BRIEF 描述符的类 (2.4 location: features2d)
- cv::xfeatures2d::FREAK - 实现 FREAK(快速视网膜关键点)关键点描述符的类(2.4 location: features2d)
- cv::xfeatures2d::StarDetector - 实现 CenSurE 检测器的类 (2.4 location: features2d)
- cv::xfeatures2d::SIFT - 使用尺度不变特征变换(SIFT)算法提取关键点和计算描述符的类(2.4 location: nonfree)
- cv::xfeatures2d::SURF - 从图像中提取加速鲁棒特征的类(2.4 位置:非免费)
需要以下步骤
- 在编译过程中添加 opencv_contrib
- 包含
opencv2/xfeatures2d.h
头文件 - 使用
xfeatures2d
命名空间 - 如果需要,用
detect
、compute
或detectAndCompute
替换operator()
调用
某些类现在使用 Feature2D 基类提供的一般方法 detect
、compute
或 detectAndCompute
,而不是自定义 operator()
以下代码片段说明了两者的区别(来自 video_homography.cpp 示例):
使用命名空间 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); //计算每个关键点位置的简要描述符
OpenCL
所有专门的 ocl
实现都隐藏在通用 C++ 算法接口之后。现在,函数执行路径可在运行时动态选择: 这种机制也被称为 “透明 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, ...);
// 绘制矩形 ...
// 显示图像 ...
}
- 支持 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, ...);
// 绘制矩形 ...
// 显示图像 ...
}
CUDA
CUDA 模块已移至 opencv_contrib 资源库。
- cuda - CUDA 加速计算机视觉
- cudaarithm - 矩阵运算
- cudabgsegm - 背景分割
- cudacodec - 视频编码/解码
- cudafeatures2d - 特征检测和描述
- cudafilters - 图像过滤
- cudaimgproc - 图像处理
- cudalegacy - 传统支持
- cudoptflow - 光学流
- cudastereo - 立体对应
- cudawarping - 图像扭曲
- cudv - 设备层
文档格式
文档已转换为 Doxygen 格式。您可以在 OpenCV 参考文档的教程部分找到更新的文档编写指南(Writing documentation for OpenCV)。
支持两个版本
在某些情况下,可以同时支持两个版本的 OpenCV。
源代码
要在应用程序源代码中检查库的主要版本,应使用以下方法:
#include "opencv2/core/version.hpp"。
#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()