OpenCV之Mat详解

首先要了解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优点

  1. OpenCV函数中输出图像的内存分配是自动完成的(如果不特别指定的话)。
  2. 使用OpenCV的C++接口时不需要考虑内存释放问题。
  3. 赋值运算符和拷贝构造函数( ctor )只拷贝信息头。
  4. 使用函数 clone() 或者 copyTo() 来拷贝一副图像的矩阵。

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

 

革命尚未成功,同志仍需努力。

你可能感兴趣的:(OpenCV)