Mat - 基本图像容器

世间的图像是各种各样的,但是到了计算机的世界里所有的图像都简化为了数值矩以及矩阵信息。作为一个计算视觉库,OpenCV的主要目的就是处理和操作这些信息,来获取更高级的信息,也就是潜在的价值。因此,我们需要首先学习OpenCV是如何存储并操作图像的

Mat

2001年OpenCV刚刚出现的时候是基于C语言接口而建。 为了在内存(Memory)中存放图像, 当时采用的是名为IplImage(Intel Image Processing Library IPL)的C语言结构体,最大的问题就是需要手动的进行内存管理。在OpenCV2.0版本中出现了C++接口, 利用自动内存管理(说法不严谨)给出了解决问题的新方法。

Mat是一个类,包含两部分数据部分:

  • (1)矩阵头(包含矩阵尺寸、存储方法、存储地址等信息)

    其中矩阵头的尺寸是常数值,矩阵本身的尺寸根据图像的大小而定。

    当在程序中传递图像并创建拷贝时,大的开销是由矩阵造成的,而不是信息头,但是在OpenCV函数中矩阵的传递又是非常常见的。

  • (2)指针(指向存储所有像素值的矩阵)

为了解决矩阵开销问题,OpenCV采用了引用计数机制。其思路就是每个Mat对象都有自己的头信息, 但共享同一个矩阵,通过矩阵指针指向同一个地址而实现。而拷贝构造函数而只拷贝信息头和矩阵指针,不拷贝矩阵。

Mat A, C;                                  //只创建信息头部分
A = imread(argv[1], CV_LOAD_IMAGE_COLOR); //这里为矩阵开辟内存 Mat B(A); //使用拷贝构造函数 C = A; //赋值运算符

说明: A, B, C三个Mat对象都指向了同一个也是唯一一个数据矩阵。虽然他们的信息头不同, 但通过任何一个对象所做的改变都会影响其他对象。实际上,不同的对象只是访问相同数据矩阵的不同途径而已。

还可以创建只引用部分数据的信息头,比如创建一个感兴趣区域(ROI),你只需要创建包含边界信息的信息头:

Mat D(A, Rect(10, 10, 100, 100));          //使用一个矩阵
Mat E = A(Range:all(), Range(1, 3)); //使用行和列表示边界

如果矩阵属于多个Mat对象,那么当不再需要它时谁来负责清理?简单的回答是:最后一个使用它的对象。通过引用计数机制来实现。无论什么时候有人考虑了一个Mat对象的信息头,都会增加矩阵的引用次数;反之当一个头被释放之后,这个计数被减一;当计数为零的时候,矩阵会被清理。但某些时候我们仍然会想拷贝矩阵本身(不只是信息头和矩阵指针),这个时候可以使用clone()或者copyTo()函数。

Mat F = A.clone();
Mat G;
A.copyTo(G);

现在改变F或者G就不会影响Mat信息头所指向的矩阵。总结一下,你需要记住的是:

  • OpenCV函数中输出图像的内存分配是自动完成的(如果不特别指定的话)。

  • 使用OpenCV的C++接口时不需要考虑内存释放问题。

  • 赋值运算符和拷贝构造函数(constructor--ctor)只拷贝信息头。

  • 使用函数clone()或者copyTo()来拷贝一副图像的矩阵。

显示地创建一个Mat对象

  • Mat()构造函数
Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
cout << "M = " << endl << " " << M << endl;

对于二维多通道图像,首先要定义其尺寸,即行数和列数。

然后需要指定元素的数据类型以及每个矩阵点的通道数。

CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]

比如CV_8UC3表示使用8位的unsigned char型,每个像素由三个元素组成的三通道。预先定义的通道数可以多达四个。 Scalar是short型vector。指定这个可以使用指定的定制化值来初始化矩阵。当然,如果你需要更多维数,你可以使用宏并把通道数放在小括号中,如下所示

在C\C++中通过构造函数进行初始化

int sz[3] = {2, 2, 2};
Mat L(3, sz, CV_8UC1, Scalar::all(0));

上面的例子演示了如何创建一个超过两维的矩阵:指定维数,然后传递一个指向一个数组的指针,这个数组包含每个维度的尺寸;其余的相同

为已存在IplImage指针创建信息头:

IplImage* img = cvLoadImage("greatwave.jpg", 1);
Mat mtx(img); //convert IplImage* -> Mat
  • Create() function: 函数
M.create(4, 4, CV_8UC(2));
cout << "M = "<< endl << " " << M << endl << endl;

这个创建方法不能为矩阵设初值,它只是在改变尺寸时重新为矩阵数据开辟内存。

  • MATLAB形式的初始化: zeros(),eyes(),ones();
Mat E = Mat::eye(4, 4, CV_64F);
cout << "E = " << endl << " " << E << endl << endl; Mat O = Mat::ones(2, 2, CV_32F);
cout << "O = " << endl << " " << O << endl << endl; Mat Z = Mat::zeros(3,3, CV_8UC1);
cout << "Z = " << endl << " " << Z << endl << endl;
  • 对于小矩阵可以使用逗号分隔的方式初始化
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "C = " << endl << " " << C << endl << endl;
  • 使用clone()或copyTo()为一个存在的Mat对象创建一个新的信息头
Mat RowClone = C.row(1).clone();
cout << "RowClone = " << endl << " " << RowClone << endl << endl;

格式化打印

  • 调用函数randu()来对一个矩阵使用随机数填充,需要指定随机数的上界和下界:
Mat R = Mat(3, 2, CV_8UC3);
randu(R, Scalar::all(0), Scalar::all(255));
  • 默认打印方式
cout << "R (default) = " << endl << R << endl << endl;

OpenCV从入门到放弃系列之——core模块.核心功能(一)的更多相关文章

  1. OpenCV从入门到放弃系列之——如何扫描图像、利用查找表和计时

    目的 如何遍历图像中的每一个像素? OpenCV的矩阵值是如何存储的? 如何测试我们所实现算法的性能? 查找表是什么?为什么要用它? 测试用例 颜色空间缩减.具体做法就是:将现有颜色空间值除以某个输入 ...

  2. OpenCV从入门到放弃系列之——图像的基本操作

    读取.修改.保存图像 图像读取函数imread(); 图像颜色空间的转换cvtColor(); 图像保存至硬盘imwrite(); /********************************* ...

  3. [大数据从入门到放弃系列教程]在IDEA的Java项目里,配置并加入Scala,写出并运行scala的hello world

    [大数据从入门到放弃系列教程]在IDEA的Java项目里,配置并加入Scala,写出并运行scala的hello world 原文链接:http://www.cnblogs.com/blog5277/ ...

  4. [大数据从入门到放弃系列教程]第一个spark分析程序

    [大数据从入门到放弃系列教程]第一个spark分析程序 原文链接:http://www.cnblogs.com/blog5277/p/8580007.html 原文作者:博客园--曲高终和寡 **** ...

  5. php从入门到放弃系列-01.php环境的搭建

    php从入门到放弃系列-01.php环境的搭建 一.为什么要学习php 1.php语言适用于中小型网站的快速开发: 2.并且有非常成熟的开源框架,例如yii,thinkphp等: 3.几乎全部的CMS ...

  6. php从入门到放弃系列-04.php页面间值传递和保持

    php从入门到放弃系列-04.php页面间值传递和保持 一.目录结构 二.两次页面间传递值 在两次页面之间传递少量数据,可以使用get提交,也可以使用post提交,二者的区别恕不赘述. 1.get提交 ...

  7. php从入门到放弃系列-03.php函数和面向对象

    php从入门到放弃系列-03.php函数和面向对象 一.函数 php真正的威力源自它的函数,内置了1000个函数,可以参考PHP 参考手册. 自定义函数: function functionName( ...

  8. php从入门到放弃系列-02.php基础语法

    php从入门到放弃系列-02.php基础语法 一.学习语法,从hello world开始 PHP(全称:PHP:Hypertext Preprocessor,即"PHP:超文本预处理器&qu ...

  9. K8S从入门到放弃系列-(16)Kubernetes集群Prometheus-operator监控部署

    Prometheus Operator不同于Prometheus,Prometheus Operator是 CoreOS 开源的一套用于管理在 Kubernetes 集群上的 Prometheus 控 ...

随机推荐

  1. 使用Microsoft Fakes隔离测试代码

    在单元测试(Unit Test)中我们遇到的问题之一是:假如被测试组件(类或项目)为A,组件A依赖于组件B,那么在组件A的单元测试ATest中测试A时,也需要依赖于B,在B发生改动后,就可能影响到A的 ...

  2. Array.prototype.slice.call(arguments)

    Array.prototype.slice.call(arguments)能够将具有length属性的对象转化为数组, 可以理解为将arguments转化成一个数组对象,让它具有slice方法 如: ...

  3. 变量的解构赋值////////////z

    变量的解构赋值 数组的解构赋值 对象的解构赋值 字符串的解构赋值 数值和布尔值的解构赋值 函数参数的解构赋值 圆括号问题 用途 数组的解构赋值 基本用法 ES6允许按照一定模式,从数组和对象中提取值, ...

  4. PHP 返回JSON

    有个朋友说PHP不能返回JSON对象,作为.net的我认为应该是可以的,设置一下header 就行了. 果不然,google 一下,备忘如下: <?php $result = array('Na ...

  5. “error LNK2019: 无法解析的外部符号”之分析

    最近在用VS 2008开发,初学遇到不少问题,最头疼的问题之一就是:LNK2019. 百度一下讲的并不够全面,反正都没解决我的问题. error LNK2019问题在VC 6.0中是error LNK ...

  6. robots.txt文件没错,为何总提示封禁

    大家好,我的robots.txt文件没错,为何百度总提示封禁,哪位高人帮我看看原因,在此谢过. 我的站点www.haokda.com,robots.txt如下: ## robots.txt for P ...

  7. ftp常用命令

    ABOR 中断数据连接程序 ACCT <account> 系统特权帐号 ALLO <bytes> 为服务器上的文件存储器分配字节 APPE <filename> 添 ...

  8. Dynamics AX 2012 R2 安装Reporting Services 扩展

    今天Reinhard在VS中部署SSRS报表时,接到以下错误: 部署因错误而被取消.在报表服务器上,验证:-SQL Server Reporting Services 服务是否正在运行. 接着,Rei ...

  9. MessageClient

    using Manager.Common; using System; using System.Collections.Generic; using System.Diagnostics; usin ...

  10. html5 drag

    这里是学习html5的拖放功能.这个API主流浏览器基本支持.ie浏览器是有限支持,dataTransfer.setData/getData. 在html5里面,任何元素都是可以拖放的. 需要拖放的元 ...