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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM