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


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

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

  • 圖像的讀取

 

為了簡化問題,直接對灰度圖進行操作,灰度圖的獲取可以用Mat類里的imread函數(每每看到這個函數都很激動,又有了Matlab的感覺)。

//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轉化,這里就方便一點了哈!

原圖:

灰度讀取效果:

  • lookup table的產生

我們的目的是把讀取的圖像像素值進行量化,如果將0~255的像素量化成4級,就需將0~63的像素計算成0,64~127的像素計算成為64……

因為在C++編譯過程中,uchar/int的結果還是uchar,所以直接利用下面公式就可以得到

注意的是這里我用的是opencv.org上盜的圖,圖中的10可以用dividewidth替換,dividewidth的值需要根據量化的結果來確定,比如如果dividewidth=64;那么0~63的像素都會計算成0,64~127的像素都會計算成為64……以此類推,這樣就會被量化成4級。

但是值得注意的是,對於一張100*100的灰度圖就需要計算10000次,所以lookup table產生了。lookup table的思路是產生一個0~255的向量,沒個存放用上述公式計算的結果,然后遍歷的時候只需要查表就可以了,這樣對於一個100*100的灰度圖,本來需要計算10000次的,現在只需要計算256次。

產生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的方法。


免責聲明!

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



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