认识OpenCV之Mat类(二)

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博大精深,仍需上下求索!

猜你喜欢

转载自blog.csdn.net/JACK_YOUNG007/article/details/88912408
今日推荐