了解Opencv
Opencv是一个开源的计算机视觉编程程序库,可在windows,Linux,Mac,Android,iOS上面运行。目前Opencv已经到了第3版,增加了许多功能,API也全部迁移到了C++,当然也有Python版本。并且第三版还增加一个独立的最新算法库(contrib库),其中包含一些最新的算法,可能需要收费,但这些算法仍然在开发中,经常会被修改,没有特殊需求一般不需要使用。
Opencv包含多个模块,core模块包含核心功能,imgproc模块包含图像处理,highgui模块包含读写图像和视频的一些函数,在使用这些模块之前,需要包含头文件。
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
图像对象
在Opencv中,图像对象的数据是由Mat来表示的。对计算机来说,图像就是一个矩阵,因此Mat最主要的部分就是一个矩阵数据。除此之外,Mat还包括一些图像的属性,比如图像的长度、宽度、通道数等,我们可以用rows,cols,channels()来获取这些属性。
Mat image1(240, 320, CV_8U, 100);
cout << image1.cols << image1.rows << image1.channels();
除了图像的属性外,图像的像素也有它自己的格式。像素就是矩阵中的一个数据,这个数据的大小就表示了颜色的深浅。由于图像的通道包括单通道的和多通道的,所以像素也分为两种,单通道的就是一个数据就可以,多通道的需要多个数字组成一个像素。最常见的像素格式就是CV_8U,这表示这是单通道的像素格式,或者说为一个灰度图像,它的像素值为8个字节,用C++中unsigned char数据类型表示。另一个彩色图像的像素可以用CV_8UC3来表示,8U含义与单通道的一样,C3表示三个通道(channels),表示彩色像素类型,由三个数据RGB表示。若是灰度图像,则这三个RGB数据都相等。
opencv还能够进行图像的读取、展示、保存,读取图像使用imread()函数,保存图像使用imwrite(),展示图像使用imshow()。在读取时,还能够自行选择图像的读取格式,常用的有IMREAD_GRAYSCALE和IMREAD_COLOR,前一个表示灰度图像,后一个表示RGB图像。
Mat image = imread("demo.jpg",IMREAD_COLOR);
imshow("Image", image); // show the image
imwrite("test.jpg", image);
waitKey(0); // wait for a key pressed
waitKey(0)则表示在展示图像的时候,在等待规定时间内接受一个按键再进行下一步的操作,如果等待时间设为0,则表示一直等待下去。
Mat是Opencv经过高度优化的数据结构,它自带了内存管理,可以通过检测引用数来释放不需要的内存。同时它的赋值操作也分为浅赋值和深复制,浅赋值能够不必复制大量的数据,从而提高程序的性能,最好只在需要深复制时在进行深复制。
在赋值或者初始化时,使用的是浅赋值,这样变量的指针指向的是同一个数据。
cv::Mat image2(image1);
image3 = image2;
如上所示,image1,image2,image3指向的都是内存中同一块数据,所以只要修改其中一个任意一个变量,其他的都会改变。
而在进行深赋值时,需要使用函数copyTo(),或者clone(),这样复制出来的就是两个不同的内存数据块,这样就可以随意修改数据也不会影响其他的了。
其他对象
Point表示点类型,常用来表示坐标。Size表示尺寸,常用来表示图像的大小。Scalar表示色彩,用来表示图像的颜色。还有InputArray表示一个输入数组的代理,由于使用Mat可能会造成参数不兼容,所以Opencv中的函数使用的都是InputArray,同时还有OutputArray对象,表示输出数组的代理。
有时候还会遇到需要小矩阵的情况,这时候可以使用模板类Matx和它的子类。例如定义一个3*3的双精度型的浮点数矩阵可以使用Matx33d,定义一个3元素的向量可以使用Matx31d。这些矩阵还支持矩阵之间的操作,比如相乘相加等。
cv::Matx33d matrix(3.0, 2.0, 1.0,
2.0, 1.0, 3.0,
1.0, 2.0, 3.0);
cv::Matx31d vector(5.0, 1.0, 3.0);
cv::Matx31d result = matrix*vector;
获取ROI
ROI就是Region of Interest,表示感兴趣的区域。有时候我们只想获取一部分区域,那就需要用到ROI了。ROI实际上就是一个Mat对象,同时他和他的父图像指向的是同一个数据缓冲区,所以改变ROI也就能改变它的父图像了。
imageROI= image(cv::Rect(image.cols-logo.cols,image.rows-logo.rows,
logo.cols,logo.rows));
如上代码所演示,ROI可以直接使用Rect来定义,我们可以使用图像的大小和logo的大小来确定ROI的大小,接下来改变imageROI就会改变原始图像image。
另一种定义ROI的方式是使用Range结构,即从开始索引到结束索引的一片连续区域,但是行和列需要分别来定义。
imageROI = image(cv::Range(image.rows-logo.rows,image.rows),
cv::Range(image.cols-logo.cols,image.cols));
还能直接定义行和列组成的ROI,这样只能选择由特定区域的行或者列,但不是特别灵活。
imageROI = image.rowRange(start,end);
imageROI = image.colRange(start,end);
上面主要介绍了opencv的一些基础知识,不过想熟练使用,还得多加练习才是。
欢迎大家关注公众号“计算机视觉与机器学习”
计算机视觉和机器学习
网友评论