opencv Mat数据的三种标准访问方式

  众所周知,Mat类型相比IPLImage有诸多优点,网上相关解释较多,此处不再赘述。本文总结了三种最常用的Mat类型数据访问方式,给出了标准写法,希望对大家有帮助。

  1. Mat 类型数据的访问

    这个问题网上有很多资源,但是不太统一,实际使用时会感到混乱。在本博客的代码都是在VS2010 + opencv2.4.10运行后通过的,尽量确保代码的简洁性和正确性。CSDN的魏大神列举了13种访问方式[1],确实很好很强大。但是实际中我们只要掌握三种方式就够了,关键是对这三种方式要熟练掌握。

  •    方式1: at<type>(i,j)访问

 

    这种方式在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 }                      

 

  •    方式2: ptr<type>(i) [j] 方式

 

  这种访问方式就是所谓的文艺青年了,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行就不会越界,但是注释掉了这一行我用这段代码干嘛呢?大神们可以给出我出错的原因,我搞不定,直接变身为普通青年就解决了。

  • 方式3:img.data + step[0]*i + step[1]*j 方式

 

  这就是所谓的暴力青年了,对于上面那个例子,暴力青年的写法如下:

 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

posted @ 2015-05-07 14:55 Zack888 阅读(...) 评论(...)  编辑 收藏