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. PAT自测_打印沙漏、素数对猜想、数组元素循环右移、数字加倍重排、机器洗牌

    -自测1. 打印沙漏() 本题要求你写个程序把给定的符号打印成沙漏的形状.例如给定17个“*”,要求按下列格式打印 ***** *** * *** ***** 所谓“沙漏形状”,是指每行输出奇数个符号 ...

  2. REM 布局

    1.rem是什么? rem(font size of the root element)是指相对于根元素的字体大小的单位 2.为什么web app要使用rem? 实现强大的屏幕适配布局(淘宝,腾讯,网 ...

  3. Ubuntu 16.04 Steam

    Ubuntu 16.04安装Steam,直接去Steam官网下载客户端安装包即可.

  4. MapReduce 简介

    2. MapReduce 简介 MapReduce 实际上是分为两个过程 map 过程 : 数据的读取 reduce 过程 : 数据的计算 并行计算是一个非常复杂的过程, mapreduce是一个并行 ...

  5. Qt设计器中设置border-image注意问题

    Qt版本4.8.5,Windows7操作系统,在Qt设计师中通过样式表设计设置widget的border-image属性,debug版本编译会正常显示,但是release版本编译运行就不显示,把图片格 ...

  6. WebSphere MQ 安装

    WebSphereMQ可以在IBM官网下载,有试用版90天的.下载地址http://www.ibm.com/developerworks/cn/downloads/ws/wmq/index.html ...

  7. C语言三维数组分解

    很多人在学习C的时候,感觉三维数组很难想象,而且不理解深度是什么?做了一个图,帮大家分解一下                                                       ...

  8. 头疼:为什么chrome不能访问本地文件(带--disable-web-security --allow-file-access-from-files )

    如题,寻求帮助! chrome 带参数启动 --disable-web-security  --allow-file-access-from-files 照理应该可以加载本地文件,找遍google和英 ...

  9. 设置Beyond Compare 为 Git 默认的比较工具

    对于Beyond Compare4,Git版本号在2.2.0之后的,请在Git中依次输入以下命令: git config --global diff.tool bc3 git config --glo ...

  10. STM32的USART中断死循环,形成死机。

    作者:观海  QQ:531622 直接说重点:我用的是 STM32F103 芯片 USART2_IRQHandler 总是中断,程序死循环. 1.出现问题: 原程序的中断处理程序是: void USA ...