在学习笔记(1)中已经提到opencv2.x及3.x中用Mat代替了CvMat和IplImage,也就是说Mat既可以代替CvMat类型矩阵数据,也可以代替IplImage类型的图像数据,也就是说Mat统一了前两中数据结构。因此在OpenCv2中对矩阵数据和图像数据都可以进行显示。主要的三个函数如下
1、imread()
原型为C++: Mat imread(const string& filename, int flags=1 ),从文件中加载一副图像。filename是需要加载图像的文件名称。flags指定图像的颜色类型,包括枚举类型
CV_LOAD_IMAGE_ANYDEPTH:图像深度符合要求,按照16bit或者32bit读取
CV_LOAD_IMAGE_COLOR:转换成彩色显示
CV_LOAD_IMAGE_GRAYSCALE:转换成灰度图显示。
默认flags=1(属flags>0),也就是3通道彩色读取,通道顺序为B、G、R; flags=0读取为灰度图;flags<0时按照原图像格式读取(包含alpha通道)。
当图像读取错误,图像数据指针为空,即Mat::data==NULL。
tips: 图像保存同读取类似,原型为C++: bool imwrite(const string& filename, InputArray img,, const vector<int>& params=vector<int>()),第三个可选参数有需要的可以自己查阅。
2、namedWindow()
原型为C++: void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE ),用于创建一个显示图像窗口、设置有关窗口参数。winname是窗口的名称,flags是窗口的样式:
WINDOW_NORMAL 窗口可以通过鼠标拖拽调整
WINDOW_AUTOSIZE 默认方式,按照图像的size显示,不能再进行调整
WINDOW_OPENGL 设置窗口支持OpenGL。
创建窗口后,还可以:销毁指定的窗口 C++: void destroyWindow(const string& winname),参数同创建窗口;销毁所有图像窗口C++: void destroyAllWindows();移动指定窗口到屏幕指定坐标C++: void moveWindow(const string& winname, int x, int y)等。
3、imshow()
原型为C++: void imshow(const string& winname, InputArray mat),是将图像数据显示在指定窗口。imshow()可以和namedWindow()搭配使用,也可以单独使用。搭配使用时,可以设定窗口是口可以再进行大小调整。单独使用时,会直接创建名称为winname一个窗口并显示图像,也就是会先隐含的调用namedWindow(winname, WINDOW_AUTOSIZE)。
当图像深度不是8位时,会将各种深度映射到8位:如16-bit unsigned 或 32-bit integer的图像数据范围[0,255*256]映射到[0,255];32-bit floating-point的图像数据范围[0,1]同样映射到[0,255]。
4、示例
Mat image = imread("lena.bmp", 0);
if (!image.data){
cout << "fail to load image" << endl;
}
Mat temp = imread("pic3.bmp",0);
/* 对imageRoi的修改,会影响到Src, 原因是数据区共享 */
//Mat imageROI = image(Rect(50,80,temp.cols, temp.rows));
//Mat imageROI(image, Rect(50,80,temp.cols, temp.rows));//第二种方式
Mat imageROI = image(Range(50, 50 + temp.cols), Range(80, 80 + temp.rows)); // 第三种方式
imshow("temp", temp);
imshow("imageROI 1", imageROI);
imshow("src", image);
//image.copyTo(temp); // temp重新创建(大小不一样),重新指定mat头和数据 ;效果同 temp = image.clone();
temp.copyTo(imageROI);
temp.release(); //释放不影响已经显示的窗口
//imshow("temp2", temp); // 被释放,显示为空白。
imshow("imageROI 2", imageROI);
imshow("result", image);
waitKey(0);
结果如下。先用imread()读取lena的image图像,通过其数据指针判断是否读取成功,再读取一个temp小图。imageROI是引用lena的一个子图,起点为(50,80),大小为图像temp的size(行数rows和列数cols)。Range是一个类,用于指定图像的行范围和列范围。
由于imageROI是引用iamge,将temp深复制到imageROI会引起iamge的改变。temp先显示,再释放,不会影响原来窗口的显示结果。
图像的读取和显示比较简单,用一次就会了。推荐VS的一个插件Image Watch,在调试中可实时看到各种图像的显示结果,毕竟以后在大一点的程序中不会经常去通过显示图像来进行查看数据是否正常。( 工具-扩展和更新-联机 搜索之后安装即可)。调试中使用效果如下
附:子矩阵的获取
Mat A = Mat::eye(10, 10, CV_32S); // A是10行10列的矩阵
Mat B = A(Range::all(), Range(1, 3)); // B是A的第2、3列组成(列序号为1,2)
Mat C = B(Range(5, 9), Range::all()); // C ~ A(Range(5, 9), Range(1, 3))
// 上面是引用矩阵的超过2x2维的矩阵,当取连续多行或者连续多列时,使用下面的
Mat D = A.rowRange(1, 2); // C ~ A(Range(2,3), Range(0,9))
Mat E = A.colRange(4, 5); // C ~ A(Range(0,9), Range(5,6))
//单行,或者单列
Mat F = A.col(3); //C ~A(Range(0, 9), Range(3, 4)); //列类似