在之前的OpenCV学习笔记(一)用到的几种显示图像的方法中其中一种就是Mat。Mat结构在OpenCV 2.0后才得到广泛应用,相对于OpenCV1.0时代中的IplImage,它有个好处就是不用再手动释放图像内存。而用IplImage格式存储图像的时候就必须在推出前将图像内存release掉,即添加语句cvReleaseImage(&iplImg);,否则会造成内存泄漏。除了这个好处外,它的操作也更加简单,比如用imshow显示图像,imread读取图像等等,跟Matlab有点接近。

Mat是一个类,它由两个数据部分组成:矩阵头和一个指向存储所有像素值的矩阵的指针。其中矩阵头包含了矩阵的尺寸、存储方法、储存地址等信息,由此可以看出矩阵头所占的内存很小,而具体储存所有像素值的矩阵则非常大。举个例子,比如一个班级,矩阵头就相当于储存了班级里有多少人、男女比多少、平均身高、平均体重等信息,而矩阵就储存了班级中所有同学的所有基本信息,每一个同学就相当于是一个像素点,而每个像素点的颜色信息、深度信息等一串数据就相当于是每个同学的身高、体重、性别等一系列信息组成的一串数据。

那么问题来了,假如说我有一张图A,我想要把A图复制给B图,理论上我是不是应该重新开一片内存,用来储存B图的信息?但是仔细想一想,我A图和B图一毛一样,如果我再开一片内存存储B图,那岂不是和存储A图的内存重复啦?是不是会造成内存的浪费。所以OpenCV中的图像存储结构Mat就很好地解决了这个问题。它使用了引用计数机制,该机制的思路就是让每个Mat对象有自己的信息头,但是共享同一个矩阵。也就是让A图和B图的矩阵指针指向同一地址,共用一片内存。复制图像的时候只是复制了矩阵头的信息和矩阵指针,并不是复制了整个矩阵。

这么一来如果不是很熟悉的话使用起来就会有点别扭了。因为通过复制后得到的图像虽然名字不一样,一个叫A,一个叫B,信息头不同,但是通过任何一个对象所做的改变也会影响到其他对象。这跟人们平常想的很不一样。通俗地讲,我现在从图A那边copy出了B,那么假如我在B图上画一笔,那么我在A图上也会出现同样的一笔。如果这发生在现实生活中,有木有很神奇!具体看以下这段代码:

[cpp] view plaincopy
  1. #include<opencv2/opencv.hpp>
  2. using namespace cv;
  3. int main()
  4. {
  5. Mat A, C;
  6. A = imread("1.jpg",1);
  7. //两种copy方式
  8. Mat B(A);
  9. C = A;
  10. imshow("Picture B", B);
  11. imshow("Picture C", C);
  12. //图像模糊一下,总要增加点区别的咯,不然怎么看得出变化
  13. blur(C, C, Size(7, 7), Point(-1, -1));
  14. imshow("Picture A", A);
  15. imshow("Picture B second", B);
  16. waitKey(0);
  17. return 0;
  18. }</span>

运行后的结果如下:

看图的时候请别忘了看上面的窗口名,所以这个时候我们发现,这三张图A,B,C其实已经变成了同一张了,因为我们对C模糊处理后,发现A图和B图同样也变得模糊了。

比如说你想要在图像中的感兴趣区域的话就会变得很方便,比如说插入一句

[cpp] view plaincopy
  1. Mat D = A(Rect(10, 10, 200, 200));
  2. imshow("Picture D", D);</span>

那么显示出的D图像就是A图像的一部分,如果你把这句话插入到了模糊处理之后,那么D图像也是模糊的,如下:

那么有人会觉得这样子不好,有时候我只是想改动B图,A图想让它保留原来的样子,不想让它随着B图变化而变化。那么就需要使用到clone或者copyTo函数,如果使用了这两个函数,它就不再只是复制矩阵头了,它会复制整个矩阵本身,也就是重新开辟了一块内存在储存图像矩阵的所有信息。示例如下:

[cpp] view plaincopy
  1. Mat A;
  2. A = imread("1.jpg",1);
  3. Mat B = A.clone();
  4. blur(B, B, Size(10, 10), Point(-1, -1)); //模糊
  5. Mat C;
  6. A.copyTo(C);
  7. cvtColor(C, C, CV_BGR2GRAY); //灰度化
  8. imshow("Picture A", A);
  9. imshow("Picture B", B);
  10. imshow("Picture C", C);
  11. waitKey(0);</span>

显示的结果为:

从结果中反映:A图并没有跟着B图变模糊,也没有跟着C图变成灰度图,所以说此时A、B、C三张图是独立存在的。

接下去学习的是显式创建Mat对象的七种方法:

方法一:使用Mat()构造函数

[cpp] view plaincopy
  1. Mat M(200, 200, CV_32FC3, Scalar(255, 0, 0));</span>

第一个参数是行数;第二是参数表示列数;第三个参数表示制定元素的数据类型以及通道数,定义为CV_[位数][带符号与否][类型前缀]C[通道数],所有的情况如下图所示:

第四个参数Scalar是个short型向量,可以用来初始化矩阵,也可以用来表示颜色信息。比如说我现在imshow一下输出的是一张200X200的蓝色图像。注:RGB在opencv中储存的顺序是BGR。

方法二:在C\C++中通过构造函数进行初始化。这种构造方法可以构造多维度的矩阵。

[cpp] view plaincopy
  1. int sz[3] = { 2, 2, 2 };
  2. Mat M(3, sz, CV_8UC3, Scalar::all(0));</span>

如上就构造了一个三维的矩阵。第一个参数表示维度数,第二个参数是一个指向数组的指针,该数组包含了每个维度的尺寸。第三个参数和第四个参数跟第一种方法一致。

方法三:为已存在的IplImage指针创建信息头。即实现从IplImage类型到Mat类型的转变。

值得注意的是:以前opencv2.X中IplImage转换到Mat的方法是

[cpp] view plaincopy
  1. IplImage* srcimg = cvLoadImage("1.jpg", 1);
  2. Mat M(srcimg);
  3. //方法二:Mat M = srcimg;</span>

但是这种方法在opencv3.X中就gg了,反正我这边是报错的,不知道大家在opencv3.0的环境中运行上述代码有没有报错,如果没有请告知,谢谢。那么在3.X中应该怎么实现从IplImage转换到Mat,请看下面的代码:

[cpp] view plaincopy
  1. IplImage* srcimg = cvLoadImage("1.jpg", 1);
  2. Mat M = cvarrToMat(srcimg);</span>

顺便说一下从Mat类型转换到IplImage类型的方法:

[cpp] view plaincopy
  1. Mat M = imread("1.jpg", 1);
  2. IplImage img = M; //opencv2.X,只copy了信息头
  3. IplImage *img = cvCloneImage(&(IplImage)M); //opencv3.X,真正的复制(包括所有数据)</span>

方法四:利用create函数

[cpp] view plaincopy
  1. Mat M;
  2. M.create(4, 4, CV_8UC(2));
  3. cout << "M=" << endl << " " << M << endl << endl;</span>

但是这种方法不能给矩阵赋初值,只有在改变尺寸时重新为矩阵数据开辟内存而已。

方法五:采用Matlab形式

[cpp] view plaincopy
  1. Mat A = Mat::eye(4, 4, CV_8UC1); //对角矩阵
  2. Mat B = Mat::ones(3, 3, CV_32FC3); //单位矩阵
  3. Mat C = Mat::zeros(3, 3, CV_64FC2); //零矩阵</span>

方法六:对小矩阵使用逗号分隔式初始化

[cpp] view plaincopy
  1. Mat A = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);</span>

参考文献:

1. 毛星云等著《OpenCV3编程入门》;

2. http://www.cnblogs.com/wangguchangqing/p/4016179.html

3. http://www.cnblogs.com/zcftech/archive/2013/04/10/3013027.html

4. http://www.cnblogs.com/edver/p/5187190.html

5. http://wenku.baidu.com/link?url=A4OyKRnJEMRKiWDZAvrCIT8FfVtRLqftsuM4WzOFxs-eC9txuzkwuxfQtZJvWX6Tn9EiUFOfAKTq5zxxjo2nmSTmj3P4rimmYbOONcWB-dO

版权声明:本文为博主原创文章,未经博主允许不得用于商业转载。 https://blog.csdn.net/wangxuwen2/article/details/51966031

OpenCV学习笔记(五):Mat结构相关推荐

  1. OpenCV学习笔记之Mat

    一. Mat介绍 在2001年刚刚出现的时候,OpenCV基于 C 语言接口而建.为了在内存(memory)中存放图像,当时采用名为 IplImage 的C语言结构体,时至今日这仍出现在大多数的旧版教 ...

  2. opencv学习笔记五--文件扫描+OCR文字识别

    opencv学习笔记五--文件扫描+OCR文字识别 文件扫描 定义函数 边缘检测 获取轮廓 变换 OCR文字识别 环境配置 代码 文件扫描 # 导入工具包 import numpy as np imp ...

  3. OpenCv学习笔记(二)--Mat矩阵(图像容器)的创建及CV_8UC1,CV_8UC2等参数详解

    (一)Mat矩阵(图像容器)创建时CV_8UC1,CV_8UC2等参数详解 1--Mat不但是一个非常有用的图像容器类,同时也是一个通用的矩阵类 2--创建一个Mat对象的方法很多,我们现在先看一下M ...

  4. opencv 学习笔记五 二维离散卷积

    卷积的用途: 卷积主要用于降噪处理,是降噪处理的一种方式: 二维离散卷积包含高斯滤波,平滑滤波,中值滤波,以及能保证图像边缘的双边滤波和导向滤波算法等: 一.了解噪声的来源以及噪声的分类: 图像中难免 ...

  5. OpenCV学习笔记五-图像混合

    将两张图片混合 P6 图像混合 #include<iostream> #include<opencv2/opencv.hpp>using namespace std; usin ...

  6. OpenCV学习笔记三-Mat数据结构

    主要记录Mat数据结构的一些操作 P3 Mat 数据结构的一些操作 #include<opencv2/opencv.hpp> #include<iostream>using n ...

  7. opencv学习笔记五十八:grabCut抠图

    基本步骤: 基于交互式界面由用户选择前景区域: 定义一个单通道的输出掩码,0为背景,1为前景,2为可能的背景,3为可能的前景: grabCut抠图:将输出结果与可能的前景作比较得到可能的前景: 定义三 ...

  8. OpenCV学习笔记五:直方图

    图像由不同颜色值的像素组成,像素值在图像中的分布情况是图像的一个重要特征. 一.计算图像的直方图 直方图是一个简单的表,它给出了图像中各个像素值的数目(归一化后则为相应的比例),在OpenCV中可以使 ...

  9. opencv学习笔记五十三:训练自己的级联分类器

    训练工作主要分为如下几步: 加载训练环境 制作训练数据集 获取样本路径列表 生成正样本描述文件(.vec) 训练人脸分类器 使用分类器进行人脸检测 加载训练环境  训练过程主要依靠OpenCV自带的两 ...

  10. opencv学习笔记五:cv2.warpAffine()函数详解

    cv2.warpAffine()函数主要是利用变换矩阵M对图像进行如旋转.仿射.平移等变换,只需要我们提供一个2*3的变换矩阵M,就可以对图像进行变换.它一般是和cv2.getRotationMatr ...

最新文章

  1. 中国地址住址五级以下
  2. 从零打造在线网盘系统之Hibernate框架起步
  3. Amcharts绑定新数据后不会刷新图表的解决办法
  4. Linux中表示“时间”的结构体和相关函数
  5. eBPF学习——抓取内核网络中的socket信息
  6. OpenGL与CUDA互操作方式总结
  7. Java.math包中常用的类
  8. 简单实现AJAX: ASP.NET2.0 中回调的实现及常见问题的解决
  9. boost::mpl模块实现pair_view相关的测试程序
  10. 世界最小晶体管问世 栅极长度仅一纳米
  11. 分享一个VisualStudio2010插件——Productivity Power Tools
  12. k-Means——经典聚类算法实验(Matlab实现)
  13. 一个不错的网络基础知识网站
  14. 对象-关系映射ORM(Object Relational Mapping)(转)
  15. java 测试磁盘io,详解三种Linux测试磁盘IO性能的方法总结,值得收藏
  16. ipv6地址_「案例」路由器怎么自动获取IPv6地址?
  17. 网络工程师干货:华为设备故障管理命令大全
  18. 百度地图、腾讯地图坐标转换
  19. 能模仿韩寒小四写作的神奇循环神经网络
  20. 考研数一英语二计算机,考研常识 | 我是考英语一还是英语二?数一二三都有什么区别...

热门文章

  1. boost::adaptors相关的测试程序
  2. boost::python模块使用通用函数或 ufunc 的示例
  3. boost::mp11::mp_unique_if相关用法的测试程序
  4. GDCM:MrProtocol的测试程序
  5. boost::core::is_same用法测试实例
  6. Boost:简单的双图bimap的测试程序
  7. Boost:can_queryr的使用测试程序
  8. ITK:创建3D体积
  9. VTK:RenderMan之PolyDataRIB
  10. VTK:Filtering之ContoursFromPolyData