首先仍是要感謝簫鳴朋友在我《OpenCV學習筆記(四十)——再談OpenCV數據結構Mat詳解》的留言,告訴我M.at<float>(3, 3)在Debug模式下運行緩慢,推薦我使用M.ptr<float>(i)此類方法。這不由勾起了我測試一下的衝動。下面就爲你們奉上個人測試結果。數據結構
我這裏測試了三種操做Mat數據的辦法,套用流行詞,普通青年,文藝青年,爲啥第三種我不叫2b青年,你們慢慢日後看咯。函數
普通青年的操做的辦法一般是M.at<float>(i, j)學習
文藝青年通常會走路線M.ptr<float>( i )[ j ]測試
暴力青年一般直接強制使用我第40講提到的M.data這個指針spa
實驗代碼以下:.net
t = (double)getTickCount(); Mat img1(1000, 1000, CV_32F); for (int i=0; i<1000; i++) { for (int j=0; j<1000; j++) { img1.at<float>(i,j) = 3.2f; } } t = (double)getTickCount() - t; printf("in %gms\n", t*1000/getTickFrequency()); //*************************************************************** t = (double)getTickCount(); Mat img2(1000, 1000, CV_32F); for (int i=0; i<1000; i++) { for (int j=0; j<1000; j++) { img2.ptr<float>(i)[j] = 3.2f; } } t = (double)getTickCount() - t; printf("in %gms\n", t*1000/getTickFrequency()); //*************************************************************** t = (double)getTickCount(); Mat img3(1000, 1000, CV_32F); float* pData = (float*)img3.data; for (int i=0; i<1000; i++) { for (int j=0; j<1000; j++) { *(pData) = 3.2f; pData++; } } t = (double)getTickCount() - t; printf("in %gms\n", t*1000/getTickFrequency()); //*************************************************************** t = (double)getTickCount(); Mat img4(1000, 1000, CV_32F); for (int i=0; i<1000; i++) { for (int j=0; j<1000; j++) { ((float*)img3.data)[i*1000+j] = 3.2f; } } t = (double)getTickCount() - t; printf("in %gms\n", t*1000/getTickFrequency());
最後兩招能夠都當作是暴力青年的方法,由於反正都是指針的操做,侷限了各暴力青年手段就不顯得暴力了。指針
在Debug、Release模式下的測試結果分別爲:code
Debug | Release | |
普通青年 | 139.06ms | 2.51ms |
文藝青年 | 66.28ms | 2.50ms |
暴力青年1 | 4.95ms | 2.28ms |
暴力青年2 | 5.11ms | 1.37ms |
根據測試結果,我以爲簫銘說的是很可信的,普通青年的操做在Debug模式下果真緩慢,他推薦的文藝青年的路線確實有提升。值得注意的是原本後兩種辦法確實是一種比較2b青年的作法,由於at操做符或者ptr操做符,其實都是有內存檢查的,防止操做越界的,而直接使用data這個指針確實很危險。不過從速度上確實讓人眼前一亮,因此我不敢稱這樣的青年爲2b,尊稱爲暴力青年吧。blog
不過在Release版本下,幾種辦法的速度差異就不明顯啦,都是很普通的青年。因此若是你們最後發行程序的時候,能夠不在乎這幾種操做辦法的,推薦前兩種哦,都是很好的寫法,操做指針的事仍是留給大神們用吧。就到這裏吧~~內存
補充:簫銘又推薦了兩種文藝青年的處理方案,我也隨便測試了一下,先貼代碼,再貼測試結果:
/*********增強版********/ t = (double)getTickCount(); Mat img5(1000, 1000, CV_32F); float *pData1; for (int i=0; i<1000; i++) { pData1=img5.ptr<float>(i); for (int j=0; j<1000; j++) { pData1[j] = 3.2f; } } t = (double)getTickCount() - t; printf("in %gms\n", t*1000/getTickFrequency()); /*******終極版*****/ t = (double)getTickCount(); Mat img6(1000, 1000, CV_32F); float *pData2; Size size=img6.size(); if(img2.isContinuous()) { size.width = size.width*size.height; size.height = 1; } size.width*=img2.channels(); for(int i=0; i<size.height; i++) { pData2 = img6.ptr<float>(i); for(int j=0; j<size.width; j++) { pData2[j] = saturate_cast<float>(3.2f); } } t = (double)getTickCount() - t; printf("in %gms\n", t*1000/getTickFrequency());
測試結果:
Debug | Release | |
增強版文藝青年 | 5.74ms | 2.43ms |
終極版文藝青年 | 40.12ms | 2.34ms |
個人測試結果感受這兩種方案只是錦上添花的效果,也使你們的操做有了更多的選擇,但感受在速度上並無數量級的提高,再次感謝簫銘對我blog的支持。後來簫銘說saturate_cast才把速度降下來,我很贊成,就不貼上去測試結果了。但我查看資料瞭解了一下saturate_cast的做用。能夠當作是類型的強制轉換,好比對於saturate_cast<uchar>來講,就是把數據轉換成8bit的0~255區間,負值變成0,大於255的變成255。若是是浮點型的數據,變成round最近的整數,仍是頗有用處的函數,推薦你們在須要的時候嘗試。