Mat对象

         在了解基本图像容器之前,我们需要了解数字照点在计算机中的存储格式。我们有很多方法来获取现实世界中的图像,这些图像被数字化后才能存储到计算机。图像的存储格式十分严格,每一张图片,实际上就是一个二进制文件。我们可以用支持十六进制(二进制)的文本编辑器,打开一个图片文件。

 

用UltraEdit打开的图片文件

由上图可知,计算机中的图片,实际是二进制文件。我们平时打开一张图片,看到的图像,是看图软件根据二进制的值在计算机屏幕上,一个一个地将像素点打印出来的结果。理论上,我们可以直接修改二进制文件的值,来达到处理图片的目的。然而图像的文件存储格式,实在太严格了。所以,一般进行图像处理的时候,都是基于开源库OpenCV.

想要知道OpenCV是如何处理和操纵图片信息之前,我们不得不提及OpenCV内置的基本图像容器。所谓容器,就是能把图片在内存中的信息结构化,使图片的信息能被操作。

OpenCV的老版本是用C语言写的,之前的图像容器是IplImage,并且 是用结构体来定义的。很显然,C语言不支持自动内存管理,所以这种方式对于新手来说,可能会带来巨大的缺陷(处理一个大视频文件,没有及时释放内存)。在后续的版本中,OpenCV采用C++进行重构了,并把基本图像容器改为Mat。这样的好处就是,我们不用手动地管理内存了。虽然C++包括标准模板库STL都没有真正意义上的自动内存回收机制,但我们不用担心这么多,因为OpenCV恰到好处地在合适的地方进行了内存释放。


关于Mat

我们在使用OpenCV的时候,只需要知道Mat是一个类就行了。Mat由两部分构成:矩阵头(matrixheader)、指向矩阵的指针(pointer to the matrix)。

关于Mat我们还需要知道一点。有的时候要处理的图像文件特别大,如果我们定义了一个Mat的对象A和B,当我们把图像文件加载到A后,我们又想通过B来访问文件。这个时候,如果直接复制,肯定会造成很大的空间浪费。OpenCV在这一点上考虑得十分周到,它使用一种被称作引用计数系统(reference counting system)的机制来解决这种潜在的缺陷。

这种机制的核心思想,是让每一个Mat对象拥有一个header和一个指向图像数据的指针。当把A复制给B的时候,B拥有的仅仅是A的指针,而不存储图像数据的内容。


上面所有的对象A,B,C,最后都指向同一个图像数据文件,然而它们的文件头却不一样。修改其中的任何一个的信息,都会影响到其他对象。

实际上我们可以这样理解,OpenCV为每一个Mat对象提供了不同的访问潜在图像数据的方法,但是这些不同的Mat对象的header是不同的。我们甚至可以创建一个header,使得引用的数据仅仅是图像的一部分。例如高速公路上,抓拍到的照片,是一个图像文件,我们定义两个Mat对象,A和B.A引用整张图片,而B引用图中的车牌位置。这样的操作在OpenCV里很好实现。OpenCV内置了两种这样创建分部(subsection)的方法:通过定义矩形,通过指定行列。


用Mat存储图像

         下面,我们在OpenCV中读入一张图片,并用Mat来存储,然后把存储的矩阵写到文本文件中。


         接着,我们打开rst.txt,可以看到如下结果


Mat对象OpenCV中用于存储图像信息的核心内存对象,它不仅能够表示图像数据,还可以用于处理矩阵运算,广泛应用于计算机视觉和图像处理领域[^3]。Mat对象的设计支持高效的内存管理,通过引用计数和浅复制机制确保资源的有效利用,这意味着多个Mat对象可以共享同一块内存,只有当最后一个引用被销毁时,内存才会被释放[^4]。 ### Mat对象的创建方式 Mat对象可以通过多种方式构建,常见的构造方法包括指定行数、列数和数据类型等参数,例如: - `Mat(int rows, int cols, int type)`:创建一个指定尺寸和类型的二维矩阵。 - `Mat(Size size, int type)`:与前一种方式类似,但使用`Size`结构来定义矩阵的尺寸。 - `Mat(int rows, int cols, int type, const Scalar &s)`:创建并初始化为特定值的矩阵。 - `Mat(Size size, int type, const Scalar &s)`:与上一种方式类似,但使用`Size`结构定义尺寸。 - `Mat(int ndims, const int* sizes, int type)`:创建多维矩阵。 - `Mat(int ndims, const int* sizes, int type, const Scalar &s)`:创建并初始化为特定值的多维矩阵。 下面是一个简单的示例代码,展示如何创建空白的Mat对象: ```cpp #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { // 创建一个单通道的空白Mat对象,并设置为黑色 Mat t1 = Mat(256, 256, CV_8SC1); t1 = Scalar(0); imshow("t1", t1); // 创建一个多通道的空白Mat对象,并设置为绿色 Mat t2 = Mat(256, 256, CV_8SC3); t2 = Scalar(0, 255, 0); imshow("t2", t2); waitKey(0); destroyAllWindows(); return 0; } ``` ### Mat对象的常用方法 Mat对象提供了丰富的操作方法,包括但不限于: - `rows()` 和 `cols()`:分别返回Mat对象的行数和列数。 - `size()`:返回Mat对象的尺寸,即行数和列数的组合。 - `type()`:获取Mat对象的数据类型。 - `empty()`:检查Mat对象是否为空。 - `at<T>(int row, int col)`:访问指定位置的元素值,其中`T`是元素的数据类型。 - `ptr<T>(int row)`:获取指定行的指针,其中`T`是元素的数据类型。 - `clone()`:复制Mat对象并返回副本。 - `convertTo(Mat& dst, int type, double alpha=1, double beta=0)`:将Mat对象转换为指定类型,并可选地进行缩放和偏移。 - `reshape(int cn, int rows=0)`:改变Mat对象的通道数和行数。 - `channels()`:返回Mat对象的通道数。 - `depth()`:返回Mat对象的深度。 这些方法使得Mat对象不仅能够灵活地创建和操作图像数据,还能高效地进行各种图像处理任务。 ### 数据类型与通道类型 Mat对象支持多种数据类型和通道类型。数据类型决定了每个像素点的存储格式,常见的有8位无符号整型(`CV_8U`)、8位有符号整型(`CV_8S`)、16位无符号整型(`CV_16U`)、16位有符号整型(`CV_16S`)、32位整型(`CV_32S`)、32位浮点型(`CV_32F`)和64位双精度浮点型(`CV_64F`)。通道类型则决定了每个像素点包含的数据维度,例如单通道(`CV_8UC1`)、双通道(`CV_8UC2`)、三通道(`CV_8UC3`)和四通道(`CV_8UC4`)等。 ### 相关问题 1. 如何在OpenCV中使用Mat对象读取和显示图像? 2. Mat对象的引用计数机制是如何工作的? 3. 如何利用Mat对象进行图像的像素级操作? 4. Mat对象支持哪些类型的数学运算? 5. 在OpenCV中,如何使用Mat对象实现图像的缩放和旋转?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值