OpenCV学习之路(四) OpenCV 中的几种数据结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dashujua/article/details/82224322

通常我们在屏幕上看到的图像在转化到数字设备中时,记录的往往是图像中的每个点的数值(像素),即以像素点矩阵的形式进行存储。OpenCV 作为一个计算机视觉库,其主要的工作是处理和操作并进一步了解这些形式和信息,因此理解 OpenCV 是如何存储和处理图像是非常有必要的。

Mat 结构的使用

对于 OpenCV1.X 时代的基于 C 语言接口而建的图像存储格式 IplImage* ,一旦退出程序之前没有 release 掉的话,就会造成内存泄漏,并且用起来有些不方便,我们在调试的时候,往往要花费很多时间在手动释放内存的问题上,尤其出现在随着项目规模的增长逐渐增加的代码量时。

随着 C++ 面向对象的提出,带来了类的概念,使得我们可以编写析构函数让程序自动管理内存。我们不需要话费大量的时间来手动的管理内存,并且代码变得更加整洁且易读。但是某些嵌入式开发系统只支持 C 语言。OpenCV2.X 后,Mat 数据结构作为图像存储和处理的基本数据结构。其最基本的有点是:内存的获取及释放都将由系统自动完成。

Mat 类由两个部分组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。矩阵头的尺寸通常是常量,矩阵本身的尺寸会依图像的不同而不同。当我们在进行图像处理时,应尽量避免进行大尺寸图像的赋值。为了解决此问题,OpenCV 使用了引数机制。通过让矩阵指针指向同一地址来实现让每个 Mat 对象有自己的信息头,但共享同一个矩阵。复制构造函数和赋值运算符只复制信息头和矩阵指针,而不复制矩阵。如下代码:

Mat A,C;
A = imread("cat.jpg");
Mat B(A);
C = A;

这段代码中所有的 Mat 对象都指向同一个像素矩阵,不同的只是它们的信息头部分,通过任何一个对象所做的改变也会影响到其他的对象。当复制一个该Mat 对象的信息头时,矩阵的引用次数加一,当释放一个该Mat 对象的信息头时,矩阵的引用次数减一,当计数值为零时,矩阵会被清理。

我们也可以通过如下代码来创建只引用部分数据的信息头。

Mat D(A,Rect(10, 10, 100, 100)); //使用矩形界定
Mat E = A(Range::all(), Range(1,3)); //用行和列来界定

我们也可以通过使用 clone() 函数或 copyTo() 函数来复制矩阵本身(像素值矩阵本身),如下所示:

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

像素值的存储方法

存储像素值需要指定颜色空间和数据类型。其中,颜色空间是指针对一个给定的颜色,如何组合颜色元素对其编码。最简单的颜色空间是灰度级空间,只处理黑色和白色,对它们进行组合便可以产生不同程度的灰色。彩色方式的颜色空间包括 RGB、HSV、HLS等。其中RGB是最常见的,和人眼采用 相似的工作机制,基色是红、绿、蓝。HSV 和 HLS 则把颜色分解成色调、饱和度和亮度/明度。这是描述颜色更自然的方式,可以通过抛弃最后一个元素使算法对输入图像的光照条件不敏感。

当我们使用数据类型 char 来进行基元素的存储时,三个 char 型元素即可以表示 1600多万种的颜色(对应 RGB 空间),使用 float 或 double 能表示更精细的颜色,但存储量也会增减。

Mat 对象的几种创建方法

1.使用 Mat() 构造函数。代码如下:

Mat M(2, 2, CV_8UC3, Scalar(0,0,255));

参数分别表示 行数,列数,存储元素类型,元素值。

扫描二维码关注公众号,回复: 2973563 查看本文章

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

CV_[位数][带符号与否][类型前缀]C[通道数]

如 CV_8UC3,CV_32FC3

官网表示方法

Scalar 是 short 类型的向量,可用于表示颜色。

2.在C\C++中通过构造函数进行初始化。代码如下:

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

指定维数,然后传递一个指向某个数组的指针,该数组包含每个维度的尺寸,余下 的两个参数和1 中的一样。

3.为已经存在的 IplImage 指针创建信息头。代码如下:

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

4.Mat 类中的 Create() 函数来进行初始化。代码如下:

M.create(4, 4, CV_8UC(2));

注意:该方法不能为矩阵设置初始值,只是在改变尺寸时重新为矩阵数据开辟内存而已。

还有一些别的方法,可以查看官网的文档说明

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/dashujua/article/details/82224322