OPENCV——重点结构体Mat

一、Mat 是什么

Mat 是 OpenCV核心图像 / 矩阵容器 ,用来在内存中存放图片、视频帧、矩阵数据,替代老旧的 IplImage,自带自动内存管理,不会轻易内存泄漏。 简单理解:图片加载到内存后,全部像素数据都存在 Mat 里,所有图像处理函数(滤波、裁剪、缩放、识别)都必须接收 Mat 作为输入输出

Mat的输出一般包含图像的宽度、高度、通道数量、通道深度、字节类

Mat 内部两大组成部分

  1. 矩阵头(Header,轻量) 固定大小,存图像描述信息:
    • rows:图像高度(行数,H)
    • cols:图像宽度(列数,W)
    • channels:通道数(灰度图 1 通道,RGB 彩色 3 通道)
    • type:像素数据类型(CV_8UC3、CV_8UC1 等)
    • data:指针,指向真实像素缓冲区
    • refcount:引用计数器(内存自动回收核心)
  2. 像素数据缓冲区(Data,大块内存) 真正存每个像素数值,占用内存远大于头部,存放在堆内存。

二、Mat的深度和字节类型

上面是Opencv的字节类型和通道数的定义,在OPENCV中通常分为四个通道和8种数据类型。分别是单通道(灰度图 )、双通道(二值图像 )、三通道(RGB彩色图像 )、四通道( Alpha 的四通道图像)。

灰度图:

灰度图又称之为灰阶图,颜色介于白色和黑色之间按对数关系分为若干等级,这种图像称之为灰度。灰度分为256个阶

二值图像:

二值图像中的图像中每一个像素只有两个值分别是0和1,其中0表示黑色、1表示白色

三通道图像:

三通道(RGB)图像也就是我们所说的RGB图像,所以三通道图像可以用来彩色图像。

四通道图像:

四通道(ARGB)也就是在彩色图像中

1. 单通道分类:

CV_8UC1:指的是一个8位无符号整型单通道矩阵

CV_32SC1:指的是一个32位整型单通道矩阵

CV_32FC1:指的是一个32位浮点型单通道矩阵

CV_64FC1:指的是一个64位浮点型单通道矩阵

CV_16SC1:指的是一个16位整型单通道矩阵

2. 双通道分类:

CV_8UC2:指的是一个8位无符号整型双通道矩阵

CV_32SC2:指的是一个32位整型双通道矩阵

CV_32FC2:指的是一个32位浮点型双通道矩阵

CV_64FC2:指的是一个64位浮点型双通道矩阵

CV_16SC2:指的是一个16位整型双通道矩阵

3.三通道分类:

CV_8UC3:指的是一个8位无符号整型三通道矩阵

CV_32SC3:指的是一个32位整型三通道矩阵

CV_32FC3:指的是一个32位浮点型三通道矩阵

CV_64FC3:指的是一个64位浮点型三通道矩阵

CV_16SC3:指的是一个16位整型三通道矩阵

4.四通道分类:

CV_8UC4:指的是一个8位无符号整型四通道矩阵

CV_32SC4:指的是一个32位整型四通道矩阵

CV_32FC4:指的是一个32位浮点型四通道矩阵

CV_64FC4:指的是一个64位浮点型四通道矩阵

CV_16SC4:指的是一个16位整型四通道矩阵

通道(channels)是什么?

一张图片每个像素由几组数字组成,几组就是几通道。

1 通道(单通道 CV_8UC1)

灰度图:每个像素只有 1 个数值,代表亮度,范围 0~255

  • 0 = 纯黑
  • 255 = 纯白
  • 中间数字是深浅灰色 例:黑白摄像头、灰度掩码、二值图。

3 通道(三通道 CV_8UC3)

彩色 BGR 图(OpenCV 默认顺序 B/G/R,不是 RGB) 每个像素存 3 个数字,分别代表蓝、绿、红,混合出千万种颜色。 例:日常拍照、摄像头彩色画面。

4 通道(四通道 CV_8UC4)

BGR+Alpha 透明通道,第 4 个数字控制透明度。 例:PNG 透明图片,UI 贴图。

一句话总结

通道 = 每个像素存几组颜色 / 亮度数据。

多少位代表什么

代表单个数值占用多少二进制存储空间,决定数值能取多大范围。

1. 8 位(8 bit)

1 字节存储一个数字,二进制最多 8 个 0/1,最大值:\(2^8-1 = 255\) 取值范围:0 ~ 255 日常图片、摄像头画面全是 8 位,最常用。

2. 16 位(16 bit)

2 字节存储,最大值 \(2^{16}-1=65535\) 范围更大,用来存:相机 RAW 原始帧、红外、高精度灰度,普通肉眼图片不用。

3. 32 位浮点(32F)

4 字节,小数,能存小数点,用于算法计算(梯度、卷积、数学运算),不能直接存图片。

通俗理解

位数越大,能表达的明暗 / 色彩层次越多,但占用内存翻倍。 8 位 1 张 1080P 图几 MB,16 位直接翻倍。

U / S / F:无符号、有符号、浮点 区别

1. U = unsigned 无符号整数(最常用,图片专用)

  • 只能存 **≥0 的正数 **
  • 8U:0 ~ 255
  • 16U:0 ~ 65535 图片亮度没有负数,所有原图都用 U 类型。

2. S = signed 有符号整数

可以存负数 + 正数 8S 范围:-128 ~ 127 用途:图像处理差值、差分图(比如前后帧相减会出现负数)。

3. F = float 浮点型(小数)

带小数点,例如 0.35、12.8、-2.1

  • 32F:32 位单精度浮点 用途:算法计算、归一化、梯度、深度学习矩阵,不能直接显示图片。

拆解规则:CV_位数 + U/S/F + C通道数

  1. CV_8UC1 8 位、无符号、1 通道 → 8 位灰度图
  2. CV_8UC3 8 位、无符号、3 通道 → 普通彩色 BGR 图
  3. CV_16UC1 16 位、无符号、单通道 → 相机 RAW 高精度灰度
  4. CV_32FC1 32 位浮点、单通道 → 算法浮点计算矩阵
  5. CV_8SC1 8 位有符号单通道 → 带负数的差分图像

三、Mat的创建和构造方法

Mat的创建一般分为五种方式:

3.1.Mat(int rows, int cols, int type);

重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是rows、cols以及存储类型type

rows **:**行数,也指的是图像的高度,height。

cols **:**列数,也指的是图像的宽度,width。

type **:**通道类型,具体的看上面的图

示例:Mat t1 = Mat(300,300,CV_8UC1),这指的是创建一个width:300,height:300,单通道的灰度图像.

3.2.Mat(Size size, int type);

重载的构造函数,这个构造函数在创建的时候,需要传入Size类和类型。

第一个传参:Size结构体,Size(width,height)

第二个传参:type通道类型,具体的看上面的图

示例:Mat t2 = Mat(Size(300,300),CV_8SC3),这指的是创建一个width:300,height:300,三通道的灰度图像

3.3.Mat(int rows, int cols, int type, const Scalar& s);

重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是rows、cols、存储类型type、还有Scalar颜色标量。

第一个传参: rows行数,也指的是图像的高度,height。

第二个传参: cols列数,也指的是图像的宽度,width。

第三个传参: type通道类型,具体的看上面的图

**第四个传参:**Scalar颜色标量,Scalar(v0,v1,v2,v3),v0,v1,v2,v3分别对应OPENCV颜色分量的四个值

示例: Mat mat = Mat(300,300,CV_8UC3,Scalar(255,255,255));表示的是创建一个cols:300,rows:300,三通道的灰度,颜色标量为白色的图像

3.4.Mat::zeros(rows,cols,type);

重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是rows、cols以及存储类型type。ZROS相当于创建一张黑色的图片,每个像素通道为0,并且Scalar(0,0,0)。

第一个传参: rows行数,也指的是图像的高度,height。

第二个传参: cols列数,也指的是图像的宽度,width。

第三个传参: type通道类型,具体的看上面的图

示例: Mat::zeros(300,300,CV_8SC3);,这指的是创建一个width:300,height:300,三通道的彩色图像,Scalar(0,0,0),相当于

Mat mat = Mat(300,300,CV_8SC3,Scalar(0,0,0));

3.5.Mat::ones(rows,cols,type);

重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是rows、cols以及存储类型type。ONES相当于每个像素第一个通道为1,后面两个通道为0。

第一个传参: rows行数,也指的是图像的高度,height。

第二个传参: cols列数,也指的是图像的宽度,width。

第三个传参: type通道类型,具体的看上面的图

示例: Mat::ones(300,300,CV_8SC3),这指的是创建一个width:300,height:300, 三通道的彩色图像,Scalar(1,0,0),

这等同于Mat mat = Mat(300,300,CV_8SC3,Scalar(1,0,0));

四、代码实现OPENCV创建Mat

完整代码

复制代码
// 引入OpenCV总头文件,包含核心数据结构、基础算法等绝大多数常用功能
#include <opencv2/opencv.hpp>
// 引入深度神经网络推理模块头文件,用于加载AI模型、执行前向推理
#include <opencv2/dnn.hpp>
// 引入图像编解码模块头文件,提供imread/imwrite等图片读写功能
#include <opencv2/imgcodecs.hpp>
// 引入图像处理模块头文件,提供滤波、几何变换、绘制等图像处理算法
#include <opencv2/imgproc.hpp>
// 引入C++标准输入输出库头文件,用于控制台打印、输入输出交互
#include <iostream>

// 声明使用cv命名空间,后续代码可直接写Mat、imwrite,无需加cv::前缀
using namespace cv; //Must Need Write cv
// 声明使用std标准命名空间,后续代码可直接写cout、string等,无需加std::前缀
using namespace std;

// 程序主入口函数
int main()
{
    // 创建300行×300列的3通道8位无符号彩色图像,并用指定BGR颜色整体填充
    // 参数说明:Mat(行数, 列数, 像素格式, 初始填充值)
    // CV_8UC3:8位无符号整数、3通道彩色图像(BGR顺序)
    // Scalar(蓝, 绿, 红):OpenCV默认通道顺序为BGR,此处填充粉紫色
    Mat t0 = Mat(300,300,CV_8UC3,Scalar(218,112,214));
    // 将内存中的t0图像保存为当前目录下的t0.jpg文件
    imwrite("t0.jpg",t0);

    // 创建256行×256列的3通道8位无符号彩色图像,仅分配内存,像素值为内存随机值
    Mat t1 = Mat(256,256,CV_8UC3);
    // 对整张图像统一赋值为纯蓝色(B=255, G=0, R=0)
    t1 = Scalar(255,0,0);
    // 将t1图像保存为t1.jpg
    imwrite("t1.jpg",t1);

    // 创建全零矩阵(全黑图像),尺寸为宽300×高300,3通道8位彩色
    // 注意:Size(宽, 高) 参数顺序为先宽后高,与Mat构造函数先行后列顺序相反
    Mat t2 = Mat::zeros(Size(300,300),CV_8UC3);
    // 将全黑图像保存为t2.jpg
    imwrite("t2.jpg",t2);

    // 创建全1矩阵,尺寸为宽300×高300,3通道8位彩色
    // 8位图像中像素值1接近全黑,肉眼几乎无法区分;该方法多用于浮点矩阵运算
    Mat t3 = Mat::ones(Size(300,300),CV_8UC3);
    // 将全1图像保存为t3.jpg
    imwrite("t3.jpg",t3);

    // 仅分配300×300的3通道8位彩色图像内存,不初始化像素值
    // 像素内容为内存残留的随机数据,保存后为噪点乱码图像
    Mat t4 = Mat(Size(300,300), CV_8UC3);
    // 将未初始化的图像保存为t4.jpg
    imwrite("t4.jpg",t4);

    return 0;
}

命名空间

复制代码
using namespace cv;
using namespace std;
  • using namespace cv:OpenCV 所有类和函数都归属于cv命名空间,写了之后代码里可以直接写Matimwrite,不用每次都写全称cv::Matcv::imwrite
  • using namespace std:标准库命名空间,同理不用写std::cout

主函数:5 种图像创建方式详解

OpenCV 默认彩色图是 BGR 通道顺序 (不是常规的 RGB),Scalar(B, G, R) 对应蓝、绿、红三个通道,像素值范围 0~255。

4.1. 实现Mat构造,并保存到本地

复制代码
Mat t0 = Mat(300,300,CV_8UC3,Scalar(218,112,214));
imwrite("t0.jpg",t0);

这指的是创建一个width:300,height:300,三通道的灰度图像, 粉色的图像218

4.2. 利用**Mat(Size size, int type)**构造生成矩阵数据,并保存到本地

复制代码
Mat t1 = Mat(256,256,CV_8UC3);
t1 = Scalar(255,0,0);
imwrite("t1.jpg",t1);

这指的是创建一个width:256,height:256,三通道的图像。

然后再用t1 = Scalar(255,0,0);把矩阵变成蓝色

最后把矩阵保存到本地

4.3. 利用**Mat::zeros(rows,cols,type)**构造生成矩阵数据,并保存到本地

复制代码
Mat t2 = Mat::zeros(Size(300,300),CV_8UC3);
imwrite("t2.jpg",t2);

利用zeros去创建矩阵,ZROS相当于创建一张黑色的图片,每个像素通道为0,并且Scalar(0,0,0)。

然后把图片保存到本地

4.4. 利用**Mat::ones(rows,cols,type)**构造生成矩阵数据,并保存到本地

复制代码
Mat t3 = Mat::ones(Size(300,300),CV_8UC3);
imwrite("t3.jpg",t3);

利用ones去创建矩阵,ONES相当于每个像素第一个通道为1,后面两个通道为0,相当于Scalar(1,0,0))

然后把图片保存到本地

4.5.仅分配内存,不初始化

复制代码
Mat t4 = Mat(Size(300,300), CV_8UC3);
imwrite("t4.jpg",t4);
  • 只申请 300×300 的内存空间,不对像素做任何赋值;
  • 像素值是内存里残留的随机数据,保存出来的图片是噪点、花屏的乱码效果,没有实际意义,一般不这么写。

运行验证:交叉编译出可执行文件放到板子运行,执行后当前目录生成 5 张 jpg 图片,就代表 OpenCV 核心、imgcodecs、imgproc 模块都工作正常。如果上篇博客中的库没完全移植进板子里面,通过报错找到缺少的库并移植进去。