我们有多种方式来获取从现实世界中的数码影像:数码相机,扫描仪,计算机断层扫描或磁共振成像等。在任何情况下,我们看到的图像。 然而,当转换到我们的数字设备,我们记录图像是每一个点的数值。
例如,在上面的图片中,你可以看到镜护无非包含的所有像素点的数值矩阵。 现在,如何通过我们获取和存储的像素值的不同来适合最好我们需要,在一个电脑世界内的所有图像可能被减少的数值矩阵和一些其他信息的描述。OpenCV的是一个计算机视觉库其主要的重点是处理这些信息,找出进一步的处理和操作。 因此,你首先需要学习和使用OpenCV的存储和处理图像。
历史:
旧版本的opencv是用c的接口来实现,但是随着内容的添加,c接口带来的管理问题不断增加(特别的是内存管理问题),所以在opencv2.0之后的大量改用C++接口来编写。一般情况下C++是兼容c的,除非使用的环境是特定的嵌入式环境(嵌入式环境可能不支持C++),否则效率上是差不多的,并且带来更好的管理。
新版本opencv图像表示的类是MAT类(旧版本的是使用IplImage和cvMat)下面主要讲的就是MAT类(这个类很强大,自动分配空间,如果已经有空间的会用旧的空间,不够的会自动申请更多的,NB的类)
下面演示mat的读取图片的过程
MatA, C; // 仅仅创建图片头部
A=imread(argv[1],CV_LOAD_IMAGE_COLOR); //这里读取图片并且分配的空间
MatB(A); // 只是复制了结构(数据空间没复制)
C=A; //这里修改类头部
上面需要注意的是,上面的所有操作复制的仅仅是复制了个结构头部和数据指针,图片数据没有复制的哦。
旧版本还有一个设置ROI的功能(就是选择图片的那个矩形区域作为有效数据区域),新版本的设置方法如下:
1 2 |
Mat D (A, Rect(10, 10, 100, 100) ); // 使用矩形 Mat E =A(Range:all(), Range(1,3)); // 使用行和列来约束边界 |
如果你够比较厉害的话可能话会问:一个图片数据空间被多个MAT对象使用,那么这个图片数据空间最后是谁释放空间呢,这个是C++的巧妙的地方,最后实际是最后一次用这个数据之后会被释放。(用旧版本的结构这个效果要实现的话很多时候很痛苦。。。)
当然,如果你是想要复制图片数据的话就得用clone()和copyTo()的函数。
下面的都是连同图像结构头部和数据一起复制的方法:
MatF =A.clone();
MatG;
A.copyTo(G);
对了上面的复制可以只是复制某一行或者列:
Mat RowClone =C.row(1).clone();
cout<<"RowClone = "<<endl <<" "<<RowClone <<endl <<endl;
代码: MatM(2,2,CV_8UC3, Scalar(0,0,255));
cout<<"M = "<<endl <<" "<<M <<endl <<endl;
上面第一行标示的就是构建一个2*2的图片,保存格式是CV_8UC3,每个点的初始值是Scalar(0,0,255),CV_8UC3标示是3通道的8位无符号类型(就是说每个点有3个通道,每个通道是用一个8位的unsigned char来保存,当然3通道一般是还是BGR的顺序,当然可以是YUV,HSV等,至于为什么默认是BGR,而不是RGB,这个我就不明白了,反正这个顺序一直都是这样),Scalar(0,0,255)表示的是一个通用的色彩结构,表示的是对应通道上数值(这个结构默认第4个通道是0,因为一般我们的图像都是用3个通道,所以这个没管)。所以呢结构就是有2*2个0,0,255
同时,上面你发现了Mat结构已经重载了“<<”这个符号。
这个创建函数跟构建的基本一样,不说了。反正直接申请空间的就是上面两个方法了。
IplImage转MAT
旧版本的opencv用的是IplImage,要转Mat很简单:
牛B的打印功能(调试方便)
因为opencv2.x已经重载了<<符号,所以可以用他直接打印二维坐标,三维坐标,向量数组等。
二维坐标
Point2f P(5,1);
cout <<"Point (2D) = "<<P <<endl <<endl;
三维坐标
Point3f P3f(2,6,7);
cout<<"Point (3D) = "<<P3f <<endl <<endl;
通过Mat打印向量
vector<float>v;
v.push_back((float)CV_PI); v.push_back(2); v.push_back(3.01f);
cout<<"Vector of floats via Mat = "<<Mat(v) <<endl <<endl;
通过Mat打印坐标向量
vector<Point2f>vPoints(20);
for(size_t E =0;E <vPoints.size(); ++E)
vPoints[E]=Point2f((float)(E*5),(float)(E%7));
cout<<"A vector of 2D Points = "<<vPoints <<endl <<endl
看到上面应该觉得这个打印功能很NB了,至少我平时调试就容易很多,不然一起调试烦死你了。