Mat中兩種像素遍歷方法比較

小白,入門中,不足其指正。剛剛接觸opencv,從一個Matlab風格的編程環境忽然跳轉到C++,實在有些不適。單就pixels scanning花了好長時間研究。opencv-tutorials給出了四種方法。這裏將比較其中最高效的方法與Mat類裏定義的at()的效率。html

本文以opencv-tutorials中給出的color reduction 爲例進行比較。編程

  • 圖像的讀取

 

爲了簡化問題,直接對灰度圖進行操做,灰度圖的獲取能夠用Mat類裏的imread函數(往往看到這個函數都很激動,又有了Matlab的感受)。ide

//read the image data
Mat GrayImage;
GrayImage = imread("test.jpg",0);
//show the image that read
namedWindow("OriginalGrayImage");
imshow("OriginalGrayImage",GrayImage);

其中imread的參數0表示的就是讀取灰度圖。相比於Matlab裏面還要用rgb22gray轉化,這裏就方便一點了哈!函數

原圖:this

灰度讀取效果:spa

  • lookup table的產生

咱們的目的是把讀取的圖像像素值進行量化,若是將0~255的像素量化成4級,就需將0~63的像素計算成0,64~127的像素計算成爲64……3d

由於在C++編譯過程當中,uchar/int的結果仍是uchar,因此直接利用下面公式就能夠獲得指針

注意的是這裏我用的是opencv.org上盜的圖,圖中的10能夠用dividewidth替換,dividewidth的值須要根據量化的結果來肯定,好比若是dividewidth=64;那麼0~63的像素都會計算成0,64~127的像素都會計算成爲64……以此類推,這樣就會被量化成4級。code

可是值得注意的是,對於一張100*100的灰度圖就須要計算10000次,因此lookup table產生了。lookup table的思路是產生一個0~255的向量,沒個存放用上述公式計算的結果,而後遍歷的時候只須要查表就能夠了,這樣對於一個100*100的灰度圖,原本須要計算10000次的,如今只須要計算256次。orm

產生lookup table的代碼段

uchar table[256];
int div = 64;
for(int i=0;i<256;i++)
    table[i] = (uchar)(div*(i/div));
  • 灰度量化-classic C style operator[]

Mat.ptr<type>(i)能夠得到第i行的指針,其中type表示的是Mat中存放的數據類型,通常的灰度圖爲uchar,rgb圖則是Vec3b。Mat.rows和Mat.cols中分別存放的是圖像的行數和列數。

具體代碼段以下

//get some informations from GrayImage
int nr = GrayImage.rows;
int nc = GrayImage.cols;

uchar* p;
for(int i=0;i<nr;i++)
{
  p = GrayImage.ptr<uchar>(i);
  for(int j=0;j<nc;j++)
  {
    p[j] = table[p[j]];
  }
}

運行結果:

  • 灰度量化-Mat.at<type>(i,j)

Mat類裏定義的at函數能夠直接訪問圖像中的像素。其中type參見上一條的解釋。(i,j)爲圖像中的座標。
 
具體代碼段以下:
for(int i=0;i<nr;i++)
    for(int j=0;j<nc;j++)
        GrayImage.at<uchar>(i,j) = table[GrayImage.at<uchar>(i,j)];

運行結果:

  • 如何得到運行時間

opencv中提供了兩個函數,getTickCount()和getTickFrequency();

Well OpenCV offers two simple functions to achieve this getTickCount() and getTickFrequency().

opencv.org盜來的代碼段:

double t = (double)getTickCount();
// do something ...
t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Times passed in seconds: " << t << endl;
  • 結果比較
運行環境:
OS: Windows 10-64bit
IDE: codeblocks 13.12 with g++
CPU: i3
內存: 4GB
 
運行結果:

classic C style operator[] 

0.00136458
Mat.at<type>(i,j) 0.00498963
從結果能夠看出,指針操做明顯更高效,這也就是爲何 opencv-tutorials中把它稱爲the effective way的緣由。可是,指針操做有危險性,因此不少人仍是緣由用Mat.at的方法。
相關文章
相關標籤/搜索