从2001年以来,opencv的函数库一直是基于C接口构建的,因此在opencv1.0版本中,一般使用IplImage的C结构体在内存中存储图像,因此,我们在很多较经典的书籍或者开源项目中依然可见IplImage。但是用其存储图像的时候必须在退出前将图像内存手动release掉,即添加语句cvReleaseImage(&IplImage);,否则会造成内存泄漏。Mat类带来了自动的内存管理,同时它的操作也更加简单,比如用imshow显示图像,imread读取图像等等,跟Matlab有点接近。下面是将图像容器类mat转化成IplImage结构体的一种方法,最后别忘了cvReleaseImage(&pImg)。

Mat frame,frame1;
IplImage* pImg;
frame=capture.read();
frame1=frame.clone();
pImg=cvCreateImage(cvSize(frame.cols,frame.rows),,);
pImg->imageData=(char*)frame1.data;
...

Mat是一个类,它由两个数据部分组成:矩阵头和一个指向存储所有像素值的矩阵的指针。其中矩阵头包含了矩阵的尺寸、存储方法、储存地址等信息,由此可以看出矩阵头所占的内存很小,通常是一个常数值,而具体存储所有像素值的矩阵则非常大。因此,在程序中传递图像并创建副本时,大的开销是由矩阵造成的,而不是信息头。其实上面给的mat转IplImage结构体就是一个例子,显然复制图像会增加算法的复杂度,降低程序的性能。形象点说,在一个班级里,矩阵头就相当于存储了班级里有多少人、男女比多少、平均身高等信息,而矩阵就储存了班级中所有同学的所有基本信息,每一个同学就相当于是一个像素矩阵中的一个元素,那么根据不同的存储方法就得到了不同的元素表示方法,显然矩阵要比矩阵头复杂得多。

为了解决上述代码存在的问题。opencv使用了引用计数机制,其思路就是让每个Mat对象有自己的信息头,但是共享同一个矩阵。也就是让矩阵指针指向同一地址,共用一片内存来实现。复制图像的时候只是复制了矩阵头的信息和矩阵指针,并不是复制了整个矩阵。例如下面这段代码:

Mat A,C;//仅创建信息头部分
A= imread("1.jpg",CV_LOAD_IMAGE_COLOR);//这里为矩阵开辟内存
Mat B(A);//使用拷贝构造函数
C=A;

这段代码中,A、B和C都是Mat类型,它们都指向同一个也是唯一一个数据矩阵。虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其它对象。而通过clone()或者copyTo()来复制一个图像,就包括了矩阵本身,也因此,改变复制对象的内容并不会改变源矩阵,例如frame1显然是复制frame,因此对frame1的操作并不改变frame。

Mat的常见属性

属性 说明
data uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针。
dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3.
rows 矩阵的行数
cols 矩阵的列数
size 矩阵的大小,size(cols,rows)
channels() 矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由RGB三个通道组成
type() 表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)如:,CV_8UC3
depth() 矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_8UC3,一个3通道的16位的有符号整数。那么,depth则是CV_8UC
elemSize() 矩阵一个元素占用的字节数(不区分通道,即多个通道的总和)
elemSize1() 矩阵一个元素每个通道占用的字节数(区分通道,单个通道的值)
flags 一个int型数字,保存了许多有用的信息,flags说明

创建Mat的方式:

1、Mat M 
创建一个矩阵头,没有数据。 
2、Mat M(2,2,CV_8UC3,Scalar(0,0,1)); 
2*2大小的矩阵,每个元素为3通道8位无符号整数,如下:

0 0 1 0 0 1 
0 0 1 0 0 1 
3、Mat M(2,2,CV_8UC1,Scalar(10)); 
与上面类似: 
10 10 
10 10 
4、Mat M(2,2,CV_8UC1,Scalar::all(0));
5、以逗号分隔符初始化赋值:Mat M = (Mat_(3,3) << 1,2,3,4,5,6,7,8,9); 
6、为已经存在的IplImage指针创建信息头,例如:

IplImage* img=cvLoadImage("1.jpg",);
Mat mtx(img);//转换IplImage*为Mat

7、利用create()函数

Mat M;
M.create(,,CV_8UC());
cout<<"M="M<<endl;

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

8、Mat还有一些matlab式函数用来创建和初始化矩阵: 
Mat E = Mat::eye(4,4,CV_64F); //单位矩阵
Mat Z = Mat::zeros(4,4,CV_32F); //0矩阵
Mat O = Mat::ones(4,4,CV_8UC1); //1矩阵
9、为已经存在的对象创建新的信息头

Mat E=Mat::eye(,,CV_64F);
Mat Row=E.row().clone();
cout<<Row<<endl;

最新文章

  1. ubuntu下安装mysql, eclipse, tomcat
  2. editor does not contain a main type的解决方案
  3. 安装vim中文帮助vimcdoc
  4. &lt;span&gt;和&lt;a&gt;的margin上下和padding上下不起作用的原因和解决
  5. StringTokenizer类
  6. Nginx 的线程池与性能剖析
  7. java读写文件大全
  8. Spring Data JPA教程, 第三部分: Custom Queries with Query Methods(翻译)
  9. 【转】ASP.NET常用数据绑定控件优劣总结
  10. MYSQL 关闭服务的过程
  11. 解决虚拟内存不够导致Eclipse is not responding
  12. Docker中运行EOS FOR MAC
  13. How to update WPF browser application manifest and xbap file with ‘mage.exe’
  14. linux下 XGCOM串口助手的安装
  15. 【mysql】Innodb三大特性之double write
  16. oracle的cursor
  17. Kafka之sync、async以及oneway
  18. Javascript基础系列之(五)条件语句(逻辑操作符)
  19. [总结]可重用cell的定义方式
  20. 第二百一十四节,jQuery EasyUI,Calendar(日历)组件

热门文章

  1. 基于html5的多图片上传,预览
  2. [转帖]go 的goroutine 以及 channel 的简介.
  3. 使用 MQTTnet 快速实现 MQTT 通信
  4. MacOS &amp; dock 工具栏 &amp; 外接显示器 &amp; 主屏
  5. Spring Cloud与微服务构建:微服务简介
  6. wazuh官方安装指南(中文译版本)
  7. substring()方法到底做了什么?不同版本的JDK中是否有区别?为什么?
  8. 怎样将Android SDK源码 导入到Eclipse中?
  9. POI上传,导入excel文件到服务器1
  10. linux expect 的使用