cv::Mat是OpenCV定义的用于表示任意维度的稠密数组,OpenCV使用它来存储和传递图像,理解它对我们操作图像是有帮助的,本文将介绍cv::Mat的初始化方式、内置方法等。
由于cv::Mat要用于存储图像,它里面的元素可以是“像素”,对于像素,OpenCV定义了专门的数据格式来描述它们。
“像素”的数据格式----命名规则:
基本数据类型 + 通道数
CV_{8U, 16S, 16U, 32S, 32F, 64F}C{1, 2, 3}
例如:CV_8UC3: 三通道、每个通道是unsigned char类型的数据
{8U, 16S, 16U, 32S, 32F, 64F}:
8U:unsigned char ; 16S: short int ; 16U: unsigned short int ; 32F: float ; 64F: double
{1,2,3}代表通道数,彩色图像每个像素需要存储B、G、R(蓝、绿、红)3个信息,需要3个位置, 每一个称为一个“颜色通道”
灰度图像无颜色,只有一个通道,故常为CV_8UC1
。
//使用示例:
//默认构造函数与值构造函数
cv::Mat img; //默认构造函数
//值构造函数1
cv::Mat img1(480, 640, CV_8UC3); //图像高(行)480-row,宽(列)640-col, 数据类型:CV_8UC3
//值构造函数2
//cv::Scalar(B, G, R)可以表示三通道颜色,这里所示为纯蓝色
cv::Mat img2(480, 640, CV_8UC3, cv::Scalar(255, 0, 0));
//值构造函数3
//效果与上面一样
cv::Size sz3(480, 640);
cv::Mat img3(sz3, CV_8UC3, cv::Scalar(255, 0, 0));
//拷贝构造函数1---都是以静态引用传递参数(const &)
cv::Mat img4(img3);
//拷贝构造函数2---只拷贝感兴趣的区域----由Rect对象定义
//rect左上角(100,100),宽高均为200,(x,y,width,height)
cv::Rect rect(100, 100, 200, 200);
cv::Mat img5(img3, rect);
//拷贝构造函数3--从指定行列构造
//从img3中拷贝0-239行以及0-319行到img6
cv::Range rows(0, 240);
cv::Range cols(0, 320);
cv::Mat img6(img3, rows, cols);
//静态构造函数
cv::Mat img7 = cv::Mat::zeros(480, 640, CV_8UC3); //480行640列,值全为零的数组。
cv::Mat img8 = cv::Mat::ones(480, 640, CV_64FC1); //全1矩阵
cv::Mat img9 = cv::Mat::eye(480, 640, CV_16SC2); //单位矩阵
固定向量类,形如Vec3b,参考我的博客,OpenCV基础类型3:
详解Vec固定向量
//使用示例
//直接访问---模板函数at<>()
//单通道, 尖括号里面的类型照着文章开头介绍的类型对应关系输入
cv::Mat img = cv::Mat::ones(240, 320, CV_32FC1);
float elem = img.at<float>(10, 10);
//多通道---Vec3b代表固定向量类
//利用固定向量类访问:https://blog.csdn.net/czsnooker/article/details/118314514?spm=1001.2014.3001.5501
//注意类型之间的对应,固定向量与Mat的代表字母有一点差异
//UC3 -> 3b
cv::Mat img1(480, 640, CV_8UC3, cv::Scalar(255,255,0));
cv::Vec3b elem = img1.at<cv::Vec3b>(10, 10);
elem_B = elem[0]; //蓝色通道数值---255
elem_G = elem[1]; //绿色通道数值---255
elem_R = elem[2]; //红色通道---0
//暂不介绍指针访问
//使用示例
//320×320, 3通道白色图像
cv::Mat img(320, 320, CV_8UC3, cv::Scalar(255,255,255));
//访问第1行元素
cv::Mat img_r_0 = img.row(0);
//访问第2列元素
cv::Mat img_c_2 = img.col(1);
//0-160行元素组成的数组
cv::Mat img_r_range = img.rowRange(0, 160);
//0-160列元素组成的数组
cv::Mat img_c_range = img.colRange(0, 160);
//注意:上述操作没有复制行和列,其实相当于只是引用了指定的行和列,我们可以对其进行读写。返回值仍然可以当作图像对待,它是原图像的一部分。
//使用示例:
//克隆矩阵
cv::Mat img(480, 640, CV_64FC3);
cv::Mat img1 = img.clone();
//设置元素值
img1.setTo(cv::Scalar(1.0, 2.0, 3.0));
//返回通道数目
size_t num_c = img1.channels();
//返回数组大小
cv::Size sz = img1.size();
//检验数组是否为空,为空返回true
bool e = img1.empty();
更多的内容请参见:
https://docs.opencv.org/4.5.2/d3/d63/classcv_1_1Mat.html#af2d2652e552d7de635988f18a84b53e5
有时候cv::Mat会被用作像3×3或4×4这样的小型矩阵,它可以像固定矩阵一样做矩阵的代数运算,有时候它也用作3×1的向量,这时候它可以有固定向量的功能。关于这一部分,可以参考我的博客----固定矩阵与固定向量类,那些操作基本上完全适配cv::Mat,因此不在此赘述。
固定向量类
固定矩阵类
在Python中,对于OpenCV而言,使用了Numpy来代替cv::Mat存储图像,相应的,对图像的操作转变为对Numpy数组的操作。