小白,入門中,不足其指正。剛剛接觸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)
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;
- 結果比較
| classic C style operator[] |
0.00136458 |
| Mat.at<type>(i,j) | 0.00498963 |
