OpenCV學習筆記 Mat數據操做之普通青年、文藝青年、暴力青年

首先仍是要感謝簫鳴朋友在我《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最近的整數,仍是頗有用處的函數,推薦你們在須要的時候嘗試。

相關文章
相關標籤/搜索