转载

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

正文到此结束
Loading...