在 OpenCV 中,cv::Mat 是最核心的矩阵数据结构,用于存储图像、矩阵和多维数组数据。它的设计非常高效,具有自动内存管理功能,是计算机视觉处理的基础容器。
cv::Mat 的核心组成
每个 cv::Mat 对象包含两个主要部分:
-
矩阵头(Header)
- 包含元数据信息(尺寸、数据类型、通道数等)
- 大小固定(约几十字节)
-
矩阵数据(Data)
- 实际像素/矩阵值的连续内存块
- 可能很大(如 1920x1080 图像 ≈ 6MB)
关键属性(存储在 Header 中)
class CV_EXPORTS Mat {
public:
// 核心属性
int dims; // 维度(图像通常是2维)
int rows, cols; // 行数和列数(2D时)
uchar* data; // 指向实际数据的指针
size_t step[CV_MAX_DIM]; // 每个维度的步长(字节)
int flags; // 包含数据类型和通道信息
MatSize size; // 多维尺寸
// ...
};
数据类型和通道表示
数据类型和通道数通过 flags 字段编码:
-
数据类型(通过 depth() 获取):
CV_8U // 8位无符号整数 (0-255)
CV_32F // 32位浮点数
// 其他:CV_8S, CV_16U, CV_64F 等
-
通道数(通过 channels() 获取):
CV_8UC1 // 单通道(灰度图)
CV_8UC3 // 3通道(BGR彩色图)
CV_32FC4 // 4通道浮点数据(如RGBA)
内存管理机制
cv::Mat 使用引用计数实现高效内存管理:
Mat A = imread("image.jpg"); // 分配新内存,引用计数=1
Mat B = A; // 浅拷贝,共享数据,引用计数=2
Mat C = A.clone(); // 深拷贝,新内存分配,引用计数=1
- 当引用计数降为0时,自动释放内存
clone() 和 copyTo() 用于深拷贝
创建 Mat 对象的常见方式
// 1. 创建空矩阵
cv::Mat emptyMat;
// 2. 指定尺寸和类型
cv::Mat img(480, 640, CV_8UC3); // 480行, 640列, 3通道uchar
// 3. 初始化为特定值
cv::Mat whiteImg(300, 300, CV_8UC3, Scalar(255, 255, 255));
// 4. 从数组创建
float data[2][3] = {{1,2,3}, {4,5,6}};
cv::Mat mat2x3(2, 3, CV_32FC1, data);
// 5. 特殊矩阵
cv::Mat eye = Mat::eye(3, 3, CV_32F);
在信号中传递 cv::Mat 的注意事项
当在 Qt 信号中传递 cv::Mat 时:
emit frameCaptured(processedFrame);
-
浅拷贝风险:默认是浅拷贝(仅复制矩阵头),多个对象共享像素数据
-
解决方案:
// 方法1:显式深拷贝
emit frameCaptured(processedFrame.clone());
// 方法2:使用共享指针(推荐)
emit frameCaptured(std::make_shared<cv::Mat>(processedFrame));
-
跨线程安全:如果信号跨线程传递,需确保接收方能安全访问内存
实际图像存储示例
对于 640x480 的 BGR 彩色图像:
cv::Mat image(480, 640, CV_8UC3);
重要成员函数
函数 |
描述 |
mat.rows |
获取行数(高度) |
mat.cols |
获取列数(宽度) |
mat.channels() |
获取通道数 |
mat.total() |
总像素数(行×列) |
mat.isContinuous() |
检查内存是否连续 |
mat.clone() |
创建深拷贝 |
mat.convertTo() |
转换数据类型 |
mat.reshape() |
改变通道/维度 |
cv::Mat 的设计平衡了效率与易用性,是 OpenCV 高性能处理的基础。理解其内存模型对优化视觉算法至关重要。
|