OpenCV从入门到放弃系列之——core模块.核心功能(一)
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模块.核心功能(一)的更多相关文章
- OpenCV从入门到放弃系列之——如何扫描图像、利用查找表和计时
目的 如何遍历图像中的每一个像素? OpenCV的矩阵值是如何存储的? 如何测试我们所实现算法的性能? 查找表是什么?为什么要用它? 测试用例 颜色空间缩减.具体做法就是:将现有颜色空间值除以某个输入 ...
- OpenCV从入门到放弃系列之——图像的基本操作
读取.修改.保存图像 图像读取函数imread(); 图像颜色空间的转换cvtColor(); 图像保存至硬盘imwrite(); /********************************* ...
- [大数据从入门到放弃系列教程]在IDEA的Java项目里,配置并加入Scala,写出并运行scala的hello world
[大数据从入门到放弃系列教程]在IDEA的Java项目里,配置并加入Scala,写出并运行scala的hello world 原文链接:http://www.cnblogs.com/blog5277/ ...
- [大数据从入门到放弃系列教程]第一个spark分析程序
[大数据从入门到放弃系列教程]第一个spark分析程序 原文链接:http://www.cnblogs.com/blog5277/p/8580007.html 原文作者:博客园--曲高终和寡 **** ...
- php从入门到放弃系列-01.php环境的搭建
php从入门到放弃系列-01.php环境的搭建 一.为什么要学习php 1.php语言适用于中小型网站的快速开发: 2.并且有非常成熟的开源框架,例如yii,thinkphp等: 3.几乎全部的CMS ...
- php从入门到放弃系列-04.php页面间值传递和保持
php从入门到放弃系列-04.php页面间值传递和保持 一.目录结构 二.两次页面间传递值 在两次页面之间传递少量数据,可以使用get提交,也可以使用post提交,二者的区别恕不赘述. 1.get提交 ...
- php从入门到放弃系列-03.php函数和面向对象
php从入门到放弃系列-03.php函数和面向对象 一.函数 php真正的威力源自它的函数,内置了1000个函数,可以参考PHP 参考手册. 自定义函数: function functionName( ...
- php从入门到放弃系列-02.php基础语法
php从入门到放弃系列-02.php基础语法 一.学习语法,从hello world开始 PHP(全称:PHP:Hypertext Preprocessor,即"PHP:超文本预处理器&qu ...
- K8S从入门到放弃系列-(16)Kubernetes集群Prometheus-operator监控部署
Prometheus Operator不同于Prometheus,Prometheus Operator是 CoreOS 开源的一套用于管理在 Kubernetes 集群上的 Prometheus 控 ...
随机推荐
- OpenERP 使用与开发笔记(一)
一直关注OpenERP,但一直未真正使用.最近一些数据想规范管理,免得使和EXCEL与WORD等到处找,所以想到OpenERP的自定义功能比较好,就再次找来相关资料重新拾掇起来.在这过程中,发现了许多 ...
- hduoj 1286 找新朋友
http://acm.hdu.edu.cn/showproblem.php?pid=1286 找新朋友 Time Limit: 2000/1000 MS (Java/Others) Memory Li ...
- android 中获取视频文件的缩略图(非原创)
在android中获取视频文件的缩略图有三种方法: 1.从媒体库中查询 2. android 2.2以后使用ThumbnailUtils类获取 3.调用jni文件,实现MediaMetadataRet ...
- mysql 表迁移
http://blog.csdn.net/evan_endian/article/details/8652528 mysql中把一个表的数据批量导入另一个表中 不管是在网站开发还是在应用程序开发 ...
- paper 114:Mahalanobis Distance(马氏距离)
(from:http://en.wikipedia.org/wiki/Mahalanobis_distance) Mahalanobis distance In statistics, Mahalan ...
- 夺命雷公狗-----React---28--小案例之react经典案例todos(全选和反选)完
这个功能实现的步骤如下所示: 最终实现全选和反选,代码如下所示: <!DOCTYPE html> <html lang="en"> <head> ...
- win下命令行替代品Cmder
Cmder简单使用小结 Cmder是一款Windows环境下非常简洁美观易用的cmd替代者,它支持了大部分的Linux命令. 从官网下载下来一个zip安装包,解压之后运行根目录的Cmder.exe即可 ...
- CSS颜色代码
颜色值 CSS 颜色使用组合了红绿蓝颜色值 (RGB) 的十六进制 (hex) 表示法进行定义.对光源进行设置的最低值可以是 0(十六进制 00).最高值是 255(十六进制 FF).从 0 到 25 ...
- 在Mac中保护私密文件,隐藏文件
在个人电脑中我们有些私密文件或者资料是不希望被人发现或者使用.保护私密文件的方式有很多,比如对文件进行加密,隐藏文件,修改文件后缀等.在Mac中我们也可以通过一些简单方式保护私密文件.这里我们简单介绍 ...
- thread.join 从异步执行变成同步
Java的线程模型为我们提供了更好的解决方案,这就是join方法.在前面已经讨论过,join的功能就是使用线程 从异步执行变成同步执行 当线程变成同步执行后,就和从普通的方法中得到返回数据没有什么区别 ...