1.Mat是什么
Mat是一种图像容器,是二维向量,灰度图的Mat一般存放<uchar>类型,RGB彩色图像一般存放<Vec3b>类型。
单通道灰度图数据存放样式:

RGB三通道彩色图存放形式不同,每列并列存放通道数量的子列(注意通道数量反转为了BGR):

通常情况下Mat的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,在用指针访问时可以提供很大方便。可以用 isContinuous()函数来判断图像数组是否为连续的,语句为
if (img.isContinuous()){}
2.如何创建Mat对象
Mat到底有哪些参数呢,OpenCV官方文档对Mat的描述如下:
class
当我们用构造函数创建一个Mat对象的时候,可以指定图像的数据类型有CV_8UC1、CV_8UC3、CV_32FC1、CV_32FC3等多种形式,如定义
Mat img(480, 640, CV_16UC1);
就是创建一个640*480的16位深的单通道Mat对象。CV_8UC3自然就是最常见的8位3通道图(即255的RGB图像)。
当然最常用的是用opencv读入一张本地图像,此时自动就是一个Mat对象,但有时我们需要像python里的numpy那样方便地转换Mat对象的数据类型,numpy里可以这样操作
img
在C++的opencv里,就是这样转为16位的无符号整数三通道的:
using
Mat也可以通过深拷贝创建一个新地址的Mat,避免影响原始的Mat:
Mat copy;
image.copyTo(copy);
除此之外,python的numpy里经常采用如下的方式构建全1的矩阵:
import
那么c++里如何构建这样的Mat呢?
Mat
这样就创建了一个全为1的矩阵了(类似的可以zeros等等是一样的创建方法)。
有时我们对图像进行一些像素值的缩放,也就是对某个图像进行全部元素的加减乘除,python里自然非常方便,如所有元素除以100,那么image / 100.0即可。c++里使用convertTo非常容易实现这点(不必for循环了)。
如果我们要对矩阵A进行元素的加减乘除操作得到B,即B=a*A+b,则
A
举个例子,刚刚提到的全部元素除以100那就是
A.convertTo(B,CV_32F,0.01,0.00);
3.Mat对象如何访问元素
从Mat的类定义看,用data可以方便访问图像元素值。用Mat存储一幅图像时,若图像在内存中是连续存储的(即Mat对象的isContinuous == true),则可将图像的数据看成是一个一维数组,而其data(uchar*)成员就是指向图像数据的第一个字节的指针,因此可以用data指针访问图像数据,OpenCV中将data定义为uchar*类型。那么我们如何通过data指针去访问和修改图像的某一个像素值呢,对于数据为uchar类型的Mat对象,可以直接用data访问和修改,对于其他类型的Mat对象,将data强制转换成指向Mat对象对应数据类型的指针即可访问。
可以把Mat对象方便地转为一维指针数组,便于指针操作(指针访问数组进行操作速度更快):
unsigned short* Array = (unsigned short*)Data.data;
delete[] Array;
也可借用opencv里Mat类的智能指针,这样即可auto data = Data.ptr();
对这个数组进行了一系列图像处理操作后,如果要保存回Mat便于后续imshow和imwrite,保存方式可以这样:
Mat newData(480, 640, CV_16UC3, Array);
当然这样是灵活的提供了自己创的指针,用了后还需要delete,为了方便可以用Mat自带的智能指针进行操作。
这里举一个实例:如果我们只对像素值小于0.1的像素才执行膨胀操作(也就是为了填充0),python里搞一个mask就可以轻易实现
empty_pixels
在c++里则不然,用智能指针可以这样操作:(构建行智能指针数组)
Mat
这样使用智能指针也可以(这样可以操作每个元素了)
for (int k = 0; k < 480; k++)
{
for (int q = 0; q < 640; q++)
{
auto *ptr = depthArray.ptr<uint16_t>(k, q);
if (ptr[0] ==0)
{
ptr[0] = 10;
}
}
}
补充小tip:
记录一下常用的程序计时方法(和python里的time一样方便):
clock_t
这里记录一个好用的numpy的操作:numpy.where
np.where(condition, x, y)当满足condition时用x代替y,如
src
意思就是把小的像素值全都变为nan
另外,这里的condition也可以是布尔数组,每个条件都和x,y相对应(广播机制),x遇到False时由y给x对应位置的像素值。如
mask