1. Mat类简介
到 OpenCV2.X版本, OpenCV 开源库引入了面向对象编程思想,大量源代码用C++ 重写,Mat类(Matrix 缩写)是OpenCV 用于处理图像而引入的一个封装类。从功能上讲,Mat类在 IpIIamge 结构的基础上进一步增强,并且,由于引入C++ 高级编程特性,Mat类的扩展性大大提高,Mat 类的内容在后期的版本中不断丰富。查看Mat类的定义(OpenCV3.1\sources\modules\core\include\opencv2\core\mat.hpp
),会发现其设计实现十分全面而具体,基本覆盖计算机视觉对于图像处理的基本要求。
因此,在当前的 OpenCV 开发中,Mat 可以说是最常见的数据单元,深入了解Mat 类对于 OpenCV 深入开发有着重大意义。
2. Mat 类常用成员函数和成员变量
Mat 类十分庞大,其涉及的成员函数和变量难以一一细数。在这里,仅学习记录其最常见的部分,以便日常使用。
2.1 构造函数
2.1.1 默认构造函数
cv::Mat::Mat()
默认构造函数,生成一个矩阵并由 OpenCV 提供的函数(一般是 Mat::create() 和 cv::imread() )来分配储存空间。Mat类可以分为两个部分: 矩阵头和指向像素数据的矩阵指针。
矩阵头 包括数字图像的矩阵尺寸、存储方法、存储地址和引用次数等。矩阵头的大小是一个常数,不会随着像素的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,通常数量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV 使用了引用次数,当进行图像复制和传递时,不再复制整个Mat 数据,而只是复制矩阵头和指向像素矩阵的指针。例如:
cv::Mat a; //默认构造函数,创建矩阵头
a = cv::imread("test.jpg"); // 读入图像,矩阵指针指向该像素数据
cv::Mat b = a; //复制
上面的 a 和 b 有各自的矩阵头,但是其矩阵指针指向同一个矩阵,也就是其中任何一个改变了矩阵数据都会影响另一个。那么,多个 Mat 共用一个矩阵数据,最后谁来释放矩阵数据呢? 这就是引用计数的作用,当 Mat 对象被复制一次,就会将引用数据加 1,而每销毁一个 Mat 对象(共用同一个矩阵数据)时引用计数会被减1,当引用计数为 0 时,矩阵数据会被清理。
2.1.2 常用的构造函数
1. 常用构造函数(1)
cv::Mat::Mat(int rows, int cols, int type)
重载的构造函数,这也是常用构造函数之一,在创建对象同时,提供矩阵的大小(rows 行数; cols 列数),以及存储类型(CV_ [每一项的位数] [有符号或无符号] [类型前缀] C [通道数]),该类型表示矩阵中每一个元素在计算机内存的存储类型,如CV_8UC3具体含义“3通道8位无符号数”。使用举例:
Mat src(10,10, CV_32FC3);
# 表示 src 是一个 10*10 的矩阵,且矩阵元素以32位float型存储
2. 常用构造函数(2)
cv::Mat::Mat(Size size, int type)
# Size 类等效于一个成对数据, size::Size(cols, rows) 特别需要注意 cols 和 rows 的位置
示例:
Mat src1(3, 4, CV_32FC3);
Mat src2(Size(3, 4), CV_32FC3);
cout << "src1.rows=" << src1.rows << " src1.cols=" << src1.cols <<endl;
cout << "src2.rows=" << src2.rows << " src2.cols=" << src2.cols << endl;
cout << "src1.size="<<src1.size() << endl <<"src2.size=" << src2.size() <<endl;
# 输出结果;
src1.rows=3 src1.cols=4
src2.rows=4 src2.cols=3
src1.size=[4 x 3]
src2.size=[3 x 4]
Size 类的数据结构有点“反人类”,但这样做的好处是方便计算机内部的运算(比如OpenCV很多函数计算 Size 相关的数据也是按这个顺序来的),平时所说的分别率,也是Size的类型,比如屏幕的分别率 1440*900,其中 cols = 1440, rows = 900.
3. 常用构造函数(3)
cv::Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s)
该构造函数使用了 Scalar参数,作用是能够通过 Scalar 数据类来初始化元素值。例如,用来生成一张白色背景的图片:
Mat src(300, 400, CV_8UC3, Scalar(255,255,255));
imshow("test", src);
4. 常用构造函数(4)
cv::Mat::Mat(const Mat & m)
# 引用 m 矩阵,注意,这里是引用值
2.2 成员函数
2.2.1 at 函数
at 函数的功能是访问矩阵元素,根据不同的使用场景,有多个重载函数可供选择。
如,访问一个二维的矩阵,可用 at 函数原型为:
Mat src =imread("test.jpg");
int elem = src.at<int>(0,0);
# 访问 test.jpg 图像的 (0, 0) 元素
2.2.2 channels 函数
int cv::Mat::channels() const
# 返回图像的通道数
2.2.3 clone函数
Mat cv::Mat::clone() const
# 矩阵复制 这个函数很常用
试比较
Mat image1 = imread("test.png",IMREAD_COLOR);
Mat image2 = image1;
此时, image2 得到的是 image1 的一个引用,是一种基于浅拷贝策略的赋值,即 image2 实际上指向的是 image1 的内存单元。当 image1 提前被释放掉的时候,image2 访问无效。
如果想要复制 image1 的数据内容,而不仅仅是指向,那么就需要用 clone 函数,该函数实现的是“深拷贝”,能够把 Mat 的数据单元复制给其他对象,比如:
Mat image1 = imread("test.png",IMREAD_COLOR);
Mat image2 = image1.clone();
此时 image2 不在受限于 image1 的状态,可以自由操作。
2.2.4 convertTo 函数
void cv::Mat::convertTo(OutputArray m,int rtype,double alpha = 1,double beta = 0) const
转换矩阵存储类型,具体计算公式如下:
m(x,y)=saturate_cast<rType>(α(∗this)(x,y)+β)
# m 是输入矩阵, rtype 是目标类型, alpha是放缩系数, beta 是增减标量。
这个函数也至关重要,因为在数字图像处理中,矩阵是最基本的运算单位,而矩阵的数据类型转换全靠该函数来实现,比如说,从8位无符号数到32位浮点型的转换:
Mat image = imread("test.png",IMREAD_COLOR);
image.convertTo(CV_32FC3);
2.2.5 copyTo 函数
void cv::Mat::copyTo(OutputArray m) const
从 m 矩阵复制 data 数据单元,与 clone 函数的作用相似,使用形式不同:
Mat image1 = imread("test.png",IMREAD_COLOR);
Mat image2 = image1.clone();
Mat image3;
image1.copyTo(image3);
# 此时image2 和 image3 具有相同的数据内容,同时,不受限于 iamge1 的状态。
2.2.6 create 函数
void cv::Mat::create(int rows,int cols,int type)
# 分配矩阵的存储单位,一般和默认构造函数配合使用
2.2.7 depth 函数
int cv::Mat::depth() const
# 返回图像深度,即矩阵元素的存储方式
2.2.8 diag 函数
Mat cv::Mat::diag(int d = 0) const
# 提取矩阵对角线元素
2.2.9 mul 函数
MatExpr cv::Mat::mul(InputArray m,double scale = 1 ) const
# 矩阵的乘法
2.2.10 inv 函数
MatExpr cv::Mat::inv(int method = DECOMP_LU) const
# 求逆矩阵
2.2.11 t 函数
MatExpr cv::Mat::t() const
# 求转置矩阵
2.2.12 total 函数
size_t cv::Mat::total() const
# 返回矩阵的元素总个数, 如30*40的图像,存在 1200 个像素点
2.3 成员变量
int cv::Mat::cols; //返回矩阵的列数
int cv::Mat::rows // 返回矩阵行数
uchar* cv::Mat::data // 指向矩阵的数据单元的指针
int cv::Mat::dims // 返回矩阵维度,该维度≥2
MatSize cv::Mat::size // 返回矩阵大小
3. 后记
OpenCV博大精深,仍需上下求索!