OpenCV 4.x API与之前版本有何不同?

19

我注意到 OpenCV 4 已经发布,其中一个区别是 API 更改为符合 C++11 标准。

这意味着什么?

我应该如何更改我的代码以与这个版本兼容?


1
这是一个不错但可能比较宽泛的问题。关于C++方面我不太确定,但Python包装器中肯定有一些API变化。立刻想到的一件事是findContours回归到返回一对值(就像2.x版本中没有修改输入图像时那样),而不是3.x版本中的三个值。 - Dan Mašek
4个回答

12

我认为最大的不同之处在于,OpenCV 4.0使用更多的C++11特性。现在cv::String == std::string,而cv::Ptr是对std::shared_ptr的轻量级包装。

Opencv 4.0删除了文件夹include/opencv,只保留了include/opencv2。许多OpenCV 1.x的C API已被删除。受影响的模块包括objdetect、photo、video、videoio、imgcodecs、calib3d。不建议使用旧的宏定义或未命名的枚举,应改用命名枚举。

//! include/opencv2/imgcodes.hpp
namespace cv
{

//! @addtogroup imgcodecs
//! @{

//! Imread flags
enum ImreadModes {
       IMREAD_UNCHANGED            = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).
       IMREAD_GRAYSCALE            = 0,  //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
       IMREAD_COLOR                = 1,  //!< If set, always convert image to the 3 channel BGR color image.
       IMREAD_ANYDEPTH             = 2,  //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
       IMREAD_ANYCOLOR             = 4,  //!< If set, the image is read in any possible color format.
       IMREAD_LOAD_GDAL            = 8,  //!< If set, use the gdal driver for loading the image.
       IMREAD_REDUCED_GRAYSCALE_2  = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
       IMREAD_REDUCED_COLOR_2      = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
       IMREAD_REDUCED_GRAYSCALE_4  = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
       IMREAD_REDUCED_COLOR_4      = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
       IMREAD_REDUCED_GRAYSCALE_8  = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
       IMREAD_REDUCED_COLOR_8      = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
       IMREAD_IGNORE_ORIENTATION   = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
     };

    // ...
}

比如,在读取图片时,应该是这个样子:

cv::Mat img = cv::imread("test.png", cv::IMREAD_COLOR);

除了新功能之外,大多数C++ API保持不变。然而我发现最大的区别是cv2.findContours(在Python OpenCV中):

在OpenCV 3.4版本中:

findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> image, contours, hierarchy

在此输入图像描述

在OpenCV 4.0中:

findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy

使用2.x、3.x、4.x的另一种选择是:

在此输入图片描述

cnts, hiers = cv2.findContours(...)[-2:]

一些链接:

  1. OpenCV 发布页面
  2. OpenCV 更新日志
  3. OpenCV 简介
  4. OpenCV 文档
  5. 如何在不同的 OpenCV 版本中使用 `cv2.findContours`?
  6. Stackoverflow 上的 OpenCV 相关问题


一个有趣的问题:为什么他们没有使用类枚举而是用了枚举?我认为在C++11中,首选的是类枚举? - mans
2
也许他们只是使用历史写法?实际上,我认为 enum classenum struct 可能更好,因为它们是有作用域的。但由于代码库非常庞大,存在很多使用无作用域枚举的代码。如果将 enum 更改为 enum class,则使用 cv::IMREAD_COLOR 的现有代码将编译失败,除非修改为 cv::ImreadModes::IMREAD_COLOR。而且,在将 C++ OpenCV API 封装到 Python|Java|C# 中时,仍然存在许多与 enum 更改相关的错误。所以他们只是保持原样吗?我不太确定。 - Kinght 金
1
这里有一个关于Java绑定的enum struct问题在GitHub上的链接:https://github.com/opencv/opencv/pull/13471 - Kinght 金

8
根据OpenCV 4.0.0,除非您使用的某些C API已被删除,否则您不必对源代码进行任何重大修改(很可能根本不需要)。
正如已经说明的那样,

OpenCV现在是C++11库,需要符合C++11的编译器

要使用,需要clang版本3.3及更高版本,并添加标志-std=c++11。g++ 4.3及更高版本也是如此。
这允许它们使用std::string而不是cv::String和其他c++11功能。但不用担心,cv::String仍然可以使用,但现在是std::string的别名。智能指针等类似。

只是好奇,你有尝试将任何生产代码升级到4.x吗?这让我想在假期里构建新的依赖项和移植代码:D - Dan Mašek
1
实际上,我已经将一些C API模块重写为C++。这并不像看起来那么难 - 几乎所有的C函数(例如cvCvtColor)都有它们在C++中的等效函数cv::cvtColor(具有相同的功能)。此外,还支持从旧式C类型转换为C++类型,您可以在这里看到。希望你不会用这种方式度过假期 :D - kocica
@FilipKočica 顺便提一下,官方的OpenCV文档在这里:https://docs.opencv.org/。 - Catree

2

我认为最关键的影响是需要使用c++11编译器。

此外,它可能不会改变接口,但允许他们利用更新的语言更改,如智能指针等。


1
上述评论中提到的“根据OpenCV 4.0.0,您不必对源代码进行任何重大修改(很可能根本不需要),除非您正在使用已删除的某些C API。”似乎与事实相距甚远。
我和我的合作伙伴为一个合作者开发了一个软件包。我们使用了v3.4(C++140);该合作者安装了v4.5。现在我们发现我们的代码无法在他们的系统上编译,因为有许多符号名称更改了。例如:CV_THRESH_TOZERO,CV_GRAYTORGB。
我们知道如何解决这个问题(除了重写我们的软件),这涉及到一堆#ifdef。然而,这并不是“向后兼容”的通常意义。而且,这不应该是必要的:opencv的人员应该保留旧的定义以及新的定义。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接