众所周知,Mat类型相比IPLImage有诸多优点,网上相关解释较多,此处不再赘述。本文总结了三种最常用的Mat类型数据访问方式,给出了标准写法,希望对大家有帮助。
这个问题网上有很多资源,但是不太统一,实际使用时会感到混乱。在本博客的代码都是在VS2010 + opencv2.4.10运行后通过的,尽量确保代码的简洁性和正确性。CSDN的魏大神列举了13种访问方式 [1] ,确实很好很强大。但是实际中我们只要掌握三种方式就够了,关键是对这三种方式要熟练掌握。
这种方式在Debug模式下的访问速度是最慢的,但是在Release模式下的访问速度也是相当快的,和其他两种方式相近。杨大神将几种常用访问方式比喻成普通青年、文艺青年、暴力青年 [2] ,十分恰当。方式1就是所谓的普通青年了。先上代码吧!
1 int ROWS = 100; // height 2 int COLS = 200; // width 3 Mat img1(ROWS , COLS , CV_32FC1); 4 5 for (int i=0; i<ROWS ; i++) 6 { 7 for (int j=0; j<COLS ; j++) 8 { 9 img1.at<float>(i,j) = 3.2f; 10 } 11 }
普通青年的代码看似十分Naive,但是他能够绝对确保安全,不会发生指针越位问题,稍后会给出一个例子。我们在实际中会碰到各种类型的图像,dupuleng 筒子贡献了对应表 [3] ,方便普通青年使用at操作。
Mat_<uchar>---------CV_8U
Mat<char>-----------CV_8S
Nat_<short>---------CV_16S
Mat_<ushort>--------CV_16U
Mat_<int>-----------CV_32S
Mat_<float>----------CV_32F
Mat_<double>--------CV_64F
再给出一个多通道图像的访问方式:
1 int ROWS = 100; // height 2 int COLS = 200; // width 3 Mat img1(ROWS , COLS , CV_8UC3); 4 5 for (int i=0; i<ROWS ; i++) 6 { 7 for (int j=0; j<COLS ; j++) 8 { 9 img1.at<vec3b>(i,j)[0]= 3.2f; // B 通道 10 img1.at<vec3b>(i,j)[1]= 3.2f; // G 通道 11 img1.at<vec3b>(i,j)[2]= 3.2f; // R 通道 12 } 13 }
这种访问 方式 就是所谓的文艺青年了,dupuleng 筒子认为这是加强版,我觉得这是十分高效的方法,所以就定义它为标准的ptr访问方式。
1 int ROWS = 100; // height 2 int COLS = 200; // width 3 Mat img1(ROWS , COLS , CV_32FC1); 4 5 for (int i=0; i<ROWS ; i++) 6 { 7 float* pData1=img5.ptr<float>(i); 8 for (int j=0; j<COLS ; j++) 9 { 10 pData1[j] = 3.2f; 11 } 12 }
方才说到普通青年有时候会比两外两种青年更靠谱,为了生成H通道和S通道像素值的二维直方图,各划分为20个bin,文艺青年的写法如下:
1 Mat channel_H(ROWS,COLS,CV_32FC1,Scalar(0.5)); 2 Mat channel_S(ROWS,COLS,CV_32FC1,Scalar(0.5)); 3 int hs_map[20][20] = {0}; 4 for (int i = 0; i < ROWS; i++) 5 { 6 float* Hdata = channel_H.ptr<float>(i); 7 float* Sdata = channel_S.ptr<float>(i); 8 for (int j = 0; j < COLS; j++) 9 { 10 int x = (int)floor(Hdata[j]* 20); //floor是向下取整 11 int y = (int)floor(Sdata[j]* 20); 12 if (x >= 20) 13 x = 19; 14 if (y >= 20) 15 y = 19; 16 hs_map[x][y]++; 17 } 18 }
经过多次调试,仍然发生指针越界,才领悟到文艺青年是不靠谱的,注释掉第16行就不会越界,但是注释掉了这一行我用这段代码干嘛呢?大神们可以给出我出错的原因,我搞不定,直接变身为普通青年就解决了。
这就是所谓的暴力青年了,对于上面那个例子,暴力青年的写法如下:
1 Mat channel_H(ROWS,COLS,CV_32FC1,Scalar(0.5)); 2 Mat channel_S(ROWS,COLS,CV_32FC1,Scalar(0.5)); 3 int hs_map[20][20] = {0}; 4 for (int i = 0; i < ROWS; i++) 5 { 6 float* Hdata = (float*)(channel_H.data + channel_H.step[0] * i); //可以观察到channel_S.dims不断增加,不知何故 7 float* Sdata = (float*)(channel_S.data + channel_S.step[0] * i); 8 for (int j = 0; j < COLS; j++) 9 { 10 int x = (int)floor(Hdata[channel_H.step[1]*j]* 20); 11 int y = (int)floor(Hdata[channel_S.step[1]*j]* 20); 12 if (x >= 20) 13 x = 19; 14 if (y >= 20) 15 y = 19; 16 hs_map[x][y]++; 17 } 18 }
当然暴力青年的做法在此处也是不可行的,我再次拥抱普通青年了。补充一下,由于是float类型的数据,故step[1] = 4, step[0] = 4* COLS;
[1] http://blog.csdn.net/xiaowei_cqu/article/details/19839019
[2] http://blog.csdn.net/yang_xian521/article/details/7161335
[3] http://www.cnblogs.com/dupuleng/articles/4072736.html