首先要了解Mat的历史来源:
OpenCV基于 C 语言接口而建。为了在内存(memory)中存放图像,在OpenCV2.0版本之前采用名为 IplImage 的C语言结构体,时至今日这仍出现在大多数的旧版教程和教学材料。但这种方法必须接受C语言所有的不足,这其中最大的不足要数手动内存管理,其依据是用户要为开辟和销毁内存负责。虽然对于小型的程序来说手动管理内存不是问题,但一旦代码开始变得越来越庞大,你需要越来越多地纠缠于这个问题,而不是着力解决你的开发目标。
幸运的是,C++出现了,并且带来类的概念,这给用户带来另外一个选择:自动的内存管理(不严谨地说)。这是一个好消息,如果C++完全兼容C的话,这个变化不会带来兼容性问题。为此,OpenCV在2.0版本中引入了一个新的C++接口,利用自动内存管理给出了解决问题的新方法。使用这个方法,你不需要纠结在管理内存上,而且你的代码会变得简洁(少写多得)。但C++接口唯一的不足是当前许多嵌入式开发系统只支持C语言。所以,当目标不是这种开发平台时,没有必要使用旧方法(除非你是自找麻烦的受虐狂码农)。
Mat是opencv2.0推出的处理图像的新的数据结构,现在越来越有趋势取代之前的cvMat和lplImage,相比之下Mat最大的好处就是能够更加方便的进行内存管理,不再需要程序员手动管理内存的释放。opencv2.3中提到Mat是一个多维的密集数据数组,可以用来处理向量和矩阵、图像、直方图等等常见的多维数据。
总结一下Mat优点:
Mat矩阵头:
class CV_EXPORTS Mat
{
public:
/*..很多方法..*/
/*............*/
int flags;(Note :目前还不知道flags做什么用的)
int dims; /*数据的维数*/
int rows,cols; /*行和列的数量;数组超过2维时为(-1,-1)*/
uchar *data; /*指向数据*/
int * refcount; /*指针的引用计数器; 阵列指向用户分配的数据时,指针为 NULL
/* 其他成员 */
...
};
从以上结构体可以看出Mat也是一个矩阵头,默认不分配内存,只是指向一块内存(注意读写保护)。
初始化使用create函数或者Mat构造函数:
Mat(nrows, ncols, type, fillValue]);
M.create(nrows, ncols, type);
//例子
Mat M(7,7,CV_32FC2,Scalar(1,3)); /*创建复数矩阵1+3j*/
M.create(100, 60, CV_8UC(15)); /*创建15个通道的8bit的矩阵*/
/*创建100*100*100的8位数组*/
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar:all(0));
/*现成数组*/
double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}};
Mat M = Mat(3, 3, CV_64F, m).inv();
/*图像数据*/
Mat img(Size(320,240),CV_8UC3);
Mat img(height, width, CV_8UC3, pixels, step); /*const unsigned char* pixels,int width, int height, int step*/
/*使用现成图像初始化Mat*/
IplImage* img = cvLoadImage("greatwave.jpg", 1);
Mat mtx(img,0); // convert IplImage* -> Mat; /*不复制数据,只创建一个数据头*/
访问Mat的数据元素:
/*对某行进行访问*/
Mat M;
M.row(3) = M.row(3) + M.row(5) * 3; /*第5行扩大三倍加到第3行*/
/*对某列进行复制操作*/
Mat M1 = M.col(1);
M.col(7).copyTo(M1); /*第7列复制给第1列*/
/*对某个元素的访问*/
Mat M;
M.at(i,j); /*double*/
M.at(uchar)(i,j); /*CV_8UC1*/
Vec3i bgr1 = M.at(Vec3b)(i,j) /*CV_8UC3*/
Vec3s bgr2 = M.at(Vec3s)(i,j) /*CV_8SC3*/
Vec3w bgr3 = M.at(Vec3w)(i,j) /*CV_16UC3*/
/*遍历整个二维数组*/
double sum = 0.0f;
for(int row = 0; row < M.rows; row++)
{
const double * Mi = M.ptr(row);
for (int col = 0; col < M.cols; col++)
sum += std::max(Mi[j], 0.);
}
/*STL iterator*/
double sum=0;
MatConstIterator it = M.begin(), it_end = M.end();
for(; it != it_end; ++it)
sum += std::max(*it, 0.);
Mat可进行Matlab风格的矩阵操作,如初始化的时候可以用initializers,zeros(), ones(), eye(). 除以上内容之外,Mat还有有3个重要的方法:
Mat mat = imread(const String* filename); // 读取图像
imshow(const string frameName, InputArray mat); // 显示图像
imwrite (const string& filename, InputArray img); // 储存图像
补充:
加深Mat的学习:https://blog.csdn.net/yang_xian521/article/details/7107786
革命尚未成功,同志仍需努力。