一、Mat的前世今生

1、不得不说的OpenCV1.X时代

OpenCV1.X的函数库一直都是基于C接口构建的,其中一直作为图片存储结构的IplImage可以说是当时的大哥大

但是其有一个非常明显的缺点,那也是C语言中无法避免的问题—那就是内存需要手动释放。当工程越来越大时,我们就会逐渐纠结于内存管理的问题,这就有点舍本逐末了。

然而OpenCV1.X还是有非常明显的优势的,那也还是因为其是完全由C语言实现的库,完美支持大多数嵌入式开发系统,这是C++接口所不能做的。当然,随着时代的发展,嵌入式系统也都逐渐支持了C++,OpenCV1.X的这一优势正在逐渐减弱。

2、OpenCV2.X时代的主打—Mat类数据结构

Mat是一个类,由两个数据部分组成:矩阵头矩阵存储区(指针指向)

因为类的封装,类的实例化可以自动分配内存空间,而销毁时则会自动释放矩阵内存区。自动化的内存管理,让大型工程开发更加容易。

同时其中封装的矩阵的一些操作,使得这个类功能十分的强大。可以这么说,如果你不会用Mat,那么你还没有领略到OpenCV真正的美!!!

二、Mat详解之数据成员

1、数据成员

混合标志:int flags;

矩阵维数:intdims;

矩阵行列数:int rows, cols;

指向矩阵存储区的指针:uchar* data;

矩阵每一维步长:MStep step;

2、data详解

图像最小单元:像素

通道数表示像素表示的分量数

深度表示分量数据存储类型


三、Mat详解之构造与拷贝

1、构造

常用图像构造之一:Mat(int rows, int cols, int type);

rows为行数,cols为列数,type为图片类型(如CV_8UC1)

常用图像构造之二:Mat(Size size, int type);

size为图片尺寸, type为图片类型(如CV_8UC1)

常用图像构造之三:Mat(Size size, int type, void* data, size_t step=AUTO_STEP);

size为图片尺寸, type为图片类型,data为指向矩阵存储区的指针

2、拷贝

常用图像拷贝之一:Mat& operator = (const Mat& m);(软拷贝)

常用图像拷贝之二: Mat(const Mat& m);(软拷贝)

常用图像拷贝之三:void copyTo( OutputArray m ) const;(硬拷贝)

常用图像拷贝之四: Mat clone() const;(硬拷贝)

四、Mat详解之常用操作

1、数据查询

查询矩阵是否为空:bool empty() const;

查询矩阵类型:int type() const;(如CV_8UC1)

查询矩阵深度(像素数据类型):int depth() const;

查询矩阵通道数(像素分量数):int channels() const;

查询矩阵数据总量:size_t total() const;

2、赋值

常用图像赋值之一:Mat& operator = (const Scalar& s);

常用图像赋值之二:Mat& setTo(InputArray value, InputArray mask=noArray());

value为所赋的值,可以是数字或颜色类;mask为掩膜。

常用图像赋值之三: static MatExpr zeros(int rows, int cols, int type);(单通道置零)

常用图像赋值之四: static MatExpr ones(int rows, int cols, int type);(单通道置一)

常用图像赋值之五: static MatExpr eye(int rows, int cols, int type);(对角线置一)

3、行列操作

行操作之一:Mat row(int y) const;(返回第y行)

行操作之二:Mat rowRange(int startrow, int endrow) const;(返回数行)

列操作之一:Mat col(int x) const;(返回第x列)

列操作之二:Mat colRange(int startcol, int endcol) const;(返回数列)

4、矩阵计算

矩阵转置:MatExpr t() const;

矩阵求逆:MatExpr inv(int method=DECOMP_LU) const;

矩阵乘法:MatExpr mul(InputArray m, double scale=1) const;

五、Mat详解之访问像素

方法一:指针访问

         uchar*data = image.ptr<uchar>(i);

         uchar*data = image.data + i*image.cols;

         ……

方法二:迭代器iterator

方法三:动态地址计算

六、例程代码


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;

int main()
{
	//打印Mat主要数据成员信息,分析图片内存关系
	Mat src = Mat(300,300,CV_8UC3,Scalar(255,127,0));
	Mat roi = src(Rect(100,100,200,200));	//设置感兴趣区域

	cout << "flags of src: " << src.flags << "\tflags of roi: " << roi.flags << endl;
	cout << "size of src:" << src.rows << "," << src.cols << "\t" << src.size() << endl;
	cout << "size of roi:" << roi.rows << "," << roi.cols << "\t" << roi.size() << endl;
	cout << "type of src:" << src.type() << "\ttype of roi:" << roi.type() << endl;
	cout << "depth of src:" << src.depth() << "\tdepth of roi:" << roi.depth() << endl;
	cout << "channels of src:" << src.channels() << "\tchannels of roi:" << roi.channels() << endl;
	cout << "address of src: " << (int)src.data << "\t" << (int)src.datastart << "\t" << (int)src.dataend << "\t" << (int)src.datalimit << endl;
	cout << "address of roi: " << (int)roi.data << "\t" << (int)roi.datastart << "\t" << (int)roi.dataend << "\t" << (int)roi.datalimit << endl;
	cout << "address of (100,50) of src: " << (int)src.ptr(100,50) << "\taddress of (20,50) of roi: " << (int)roi.ptr(20,50) << endl << endl;

	imshow("src",src);
	imshow("roi",roi);
	src.release();
	waitKey(0);
	destroyAllWindows();

	//分析图片拷贝后内存关系
	src = Mat(200,200,CV_8UC3,Scalar(255,0,0));
	roi = src;
	Mat newImage1(src);
	Mat newImage2 = Mat(roi.size(),roi.type(),roi.data);
	Mat newImage3 = src.clone();
	Mat newImage4;
	src.copyTo(newImage4);
	
	cout << "address of src: " << (int)src.data << endl;
	cout << "address of roi: " << (int)roi.data << endl;
	cout << "address of newImage1: " << (int)newImage1.data << endl;
	cout << "address of newImage2: " << (int)newImage2.data << endl;
	cout << "address of newImage3: " << (int)newImage3.data << endl;
	cout << "address of newImage4: " << (int)newImage4.data << endl << endl;

	imshow("src",src);
	src.release();
	newImage3.release();
	newImage4.release();
	waitKey(0);
	
	//矩阵赋值
	src = Mat(3,3,CV_8UC1);
	src = Scalar(255);
	cout << "operator = :" << src << endl;
	src.setTo(Scalar(127));
	cout << "setTo:" << src << endl;
	src = Mat::zeros(src.size(),src.type());
	cout << "zeros:" << src << endl;
	src = Mat::ones(src.size(),src.type());
	cout << "ones:" << src << endl;
	src = Mat::eye(src.size(),src.type());
	cout << "eye:" << src << endl;
	
	//矩阵计算
	src = (Mat_<float>(3,3) << 1,0,-1,2,0,-2,3,0,-3);
	roi = (Mat_<float>(3,3) << 1,0,-1,2,0,-2,3,0,-3);
	cout << endl << "3*3:" << src << endl;
	cout << "t:" << src.t() << endl;
	cout << "inv:" << src.inv() << endl;
	cout << "mul:" << src.mul(roi) << endl;

	waitKey(0);
	return 0;
}