参考: 1、https://docs.opencv.org/3.2.0/ 2、https://github.com/opencv/opencv/
对于OpenCV开发团队来说,不断改进库是很重要的。 我们不断思考如何减轻工作流程,同时保持图书馆的灵活性。 新的C ++接口是为我们提供这个目标的发展。 不过,向后兼容性仍然重要。 我们不想破坏为早期版本的OpenCV库编写的代码。 因此,我们确保我们添加一些处理这个的函数。 在下面你会学到:
与使用库的方式相比,OpenCV的版本2与第一版相比有什么变化如何将一些高斯噪声添加到图像什么是查找表,为什么使用它们?在做转换时,首先需要学习一些有关图像的新数据结构:Mat - 基本图像容器,它取代了旧的CvMat和IplImage。 切换到新的功能更容易。 你只需要记住一些新的东西。
OpenCV 2接收重组。 不再是所有的功能挤在一个单一的图书馆。 我们有很多模块,每个模块都包含与某些任务相关的数据结构和功能。 这样,如果只使用OpenCV的一个子集,则不需要运送大型库。 这意味着你也应该只包含你将使用的头文件。 例如:
#include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp>所有与OpenCV相关的东西都放到cv命名空间中,以避免与其他库数据结构和函数的名称冲突。 因此,无论是在OpenCV之后还是在包含之后,你都需要在cv ::关键字之前添加一个指令来使用这个:
using namespace cv; // The new C++ interface API is inside this namespace. Import it.因为这些函数已经在名字空间中了,所以他们不需要在他们的名字中包含cv前缀。 因此,所有新的C ++兼容函数都没有这个,它们遵循驼峰命名规则。 这意味着第一个字母很小(除非它是一个名字,像Canny),随后的单词以大写字母(如copyMakeBorder)开头。
现在,请记住,您需要将您使用的所有模块链接到您的应用程序,并且如果您使用DLL系统在Windows上,则需要再次将所有二进制文件添加到路径中。 有关更深入的信息,请参阅如何在Windows上阅读如何在“Microsoft Visual Studio”中使用OpenCV构建应用程序,对于Linux,在使用OpenCV和Eclipse(插件CDT)中解释了一个示例用法。
现在转换Mat对象,你可以使用IplImage或者CvMat操作符。 而在C界面中,您曾经使用过指针,现在不再是这种情况了。 在C ++接口中,我们大部分都是Mat对象。 这些对象可以通过简单的赋值自由转换为IplImage和CvMat。 例如:
Mat I; IplImage pI = I; CvMat mI = I;现在,如果你想要指针,转换只会更复杂一点。 编译器不能再自动确定你想要的,因为你需要明确指定你的目标。 这是调用IplImage和CvMat运算符,然后得到他们的指针。 为了得到指针,我们使用&sign:
Mat I; IplImage* pI = &I.operator IplImage(); CvMat* mI = &I.operator CvMat();C界面最大的抱怨之一就是它把所有的内存管理都留给了你。 你需要弄清楚什么时候释放你的未使用的对象是安全的,并确保在程序结束之前这样做,否则你可能会遇到麻烦的内存溢出。 要在OpenCV中解决这个问题,需要引入一种智能指针。 这会在不再使用的时候自动释放对象。 为了使用这个声明指针作为Ptr的专门化:
Ptr<IplImage> piI = &I.operator IplImage();从C数据结构转换到Mat是通过在其构造函数中传递这些结构来完成的。 例如:
Mat K(piL), L; L = Mat(pI);现在您已经完成了基本的一个例子,将C接口的用法与C ++的用法混合在一起。 您还可以在samples / cpp / tutorial_code / core / interoperability_with_OpenCV_1 / interoperability_with_OpenCV_1.cpp的OpenCV源代码库的示例目录中找到它。 为了进一步帮助查看差异,程序支持两种模式:一种混合的C和C ++和一种纯粹的C ++。 如果你定义了DEMO_MIXED_API_USE,你将最终使用第一个。 该程序将颜色平面分开,对其进行一些修改,最后将它们合并到一起。
#include <iostream> #include <opencv2/imgproc.hpp> #include "opencv2/imgcodecs.hpp" #include <opencv2/highgui.hpp> using namespace cv; // The new C++ interface API is inside this namespace. Import it. using namespace std; // comment out the define to use only the latest C++ API #define DEMO_MIXED_API_USE #ifdef DEMO_MIXED_API_USE # include <opencv2/highgui/highgui_c.h> # include <opencv2/imgcodecs/imgcodecs_c.h> #endif int main( int argc, char** argv ) { help(argv[0]); const char* imagename = argc > 1 ? argv[1] : "../data/lena.jpg"; #ifdef DEMO_MIXED_API_USE Ptr<IplImage> IplI(cvLoadImage(imagename)); // Ptr<T> is a safe ref-counting pointer class if(!IplI) { cerr << "Can not load image " << imagename << endl; return -1; } Mat I = cv::cvarrToMat(IplI); // Convert to the new style container. Only header created. Image not copied. #else Mat I = imread(imagename); // the newer cvLoadImage alternative, MATLAB-style function if( I.empty() ) // same as if( !I.data ) { cerr << "Can not load image " << imagename << endl; return -1; } #endif在这里你可以观察到,使用新的结构我们没有指针问题,尽管可以使用旧的函数,最后只是将结果转换为Mat对象。
// convert image to YUV color space. The output image will be created automatically. Mat I_YUV; cvtColor(I, I_YUV, COLOR_BGR2YCrCb); vector<Mat> planes; // Use the STL's vector structure to store multiple Mat objects split(I_YUV, planes); // split the image into separate color planes (Y U V)因为我们想要混淆图像亮度分量,我们首先从默认的BGR转换到YUV色彩空间,然后将结果分成不同的平面。 这里程序分裂:在第一个例子中,它使用OpenCV(C []运算符,迭代器,单独元素访问)中的三种主要图像扫描算法之一来处理每个平面。 在第二个变体中,我们给图像添加一些高斯噪声,然后根据一些公式将通道混合在一起。
扫描版本如下所示:
// Mat scanning // Method 1. process Y plane using an iterator MatIterator_<uchar> it = planes[0].begin<uchar>(), it_end = planes[0].end<uchar>(); for(; it != it_end; ++it) { double v = *it * 1.7 + rand()%21 - 10; *it = saturate_cast<uchar>(v*v/255); } for( int y = 0; y < I_YUV.rows; y++ ) { // Method 2. process the first chroma plane using pre-stored row pointer. uchar* Uptr = planes[1].ptr<uchar>(y); for( int x = 0; x < I_YUV.cols; x++ ) { Uptr[x] = saturate_cast<uchar>((Uptr[x]-128)/2 + 128); // Method 3. process the second chroma plane using individual element access uchar& Vxy = planes[2].at<uchar>(y, x); Vxy = saturate_cast<uchar>((Vxy-128)/2 + 128); } }在这里你可以观察到我们可以通过三种方式遍历一个图像的所有像素:一个迭代器,一个C指针和一个单独的元素访问风格。 您可以在如何使用OpenCV教程扫描图像,查找表和时间测量中阅读这些更深入的描述。 从旧的函数名称转换很容易。 只要删除cv前缀,并使用新的mat数据结构。 下面是使用加权加法函数的一个例子:
Mat noisyI(I.size(), CV_8U); // Create a matrix of the specified size and type // Fills the matrix with normally distributed random values (around number with deviation off). // There is also randu() for uniformly distributed random number generation randn(noisyI, Scalar::all(128), Scalar::all(20)); // blur the noisyI a bit, kernel size is 3x3 and both sigma's are set to 0.5 GaussianBlur(noisyI, noisyI, Size(3, 3), 0.5, 0.5); const double brightness_gain = 0; const double contrast_gain = 1.7; #ifdef DEMO_MIXED_API_USE // To pass the new matrices to the functions that only work with IplImage or CvMat do: // step 1) Convert the headers (tip: data will not be copied). // step 2) call the function (tip: to pass a pointer do not forget unary "&" to form pointers) IplImage cv_planes_0 = planes[0], cv_noise = noisyI; cvAddWeighted(&cv_planes_0, contrast_gain, &cv_noise, 1, -128 + brightness_gain, &cv_planes_0); #else addWeighted(planes[0], contrast_gain, noisyI, 1, -128 + brightness_gain, planes[0]); #endif const double color_scale = 0.5; // Mat::convertTo() replaces cvConvertScale. // One must explicitly specify the output matrix type (we keep it intact - planes[1].type()) planes[1].convertTo(planes[1], planes[1].type(), color_scale, 128*(1-color_scale)); // alternative form of cv::convertScale if we know the datatype at compile time ("uchar" here). // This expression will not create any temporary arrays ( so should be almost as fast as above) planes[2] = Mat_<uchar>(planes[2]*color_scale + 128*(1-color_scale)); // Mat::mul replaces cvMul(). Again, no temporary arrays are created in case of simple expressions. planes[0] = planes[0].mul(planes[0], 1./255);正如你所看到的,平面变量是Mat类型的。 但是,从Mat转换到IplImage很容易,只需一个简单的赋值操作就可以自动完成。
merge(planes, I_YUV); // now merge the results back cvtColor(I_YUV, I, COLOR_YCrCb2BGR); // and produce the output RGB image namedWindow("image with grain", WINDOW_AUTOSIZE); // use this to create images #ifdef DEMO_MIXED_API_USE // this is to demonstrate that I and IplI really share the data - the result of the above // processing is stored in I and thus in IplI too. cvShowImage("image with grain", IplI); #else imshow("image with grain", I); // the new MATLAB style function show #endif