OpenCV裏IplImage的widthStep參數 和width參數

 一直以爲IplImage結構體中的widthStep元素大小等於width*nChannels,大錯特錯!(爲了快速訪問,要內存對齊啊)查看OpenCV2.1的源碼,在src/cxcore/cxarray.cpp文件中,找到cvInitImageHeader函數,函數中對widthStep大小賦值如下:

  1. image->widthStep = (((image->width * image->nChannels *(image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1));                                             

     其中IPL_DEPTH_SIGN的定義可以在cxtypes.h中找到,定義爲:#define IPL_DEPTH_SIGN 0x80000000, align的大小爲CV_DEFAULT_IMAGE_ROW_ALIGN,其大小在cxmisc.h中定義爲:#define  CV_DEFAULT_IMAGE_ROW_ALIGN 4,depth取8位深度。

     根據(1)式,已知IPL_DEPTH_SIGN、align、depth 的大小,分別手動計算如下圖像的widthStep:

        圖像寬度     圖像通道數              計算得到的widthStep

        3                    3                             12

        3                    1                             4

        5                    3                            16

        5                    1                             8

        7                    3                             24

        7                    1                             8

        4                    3                             12

        4                    1                             4

        爲了進一步驗證手算的正確性,我們編程實現輸出widthStep的大小,程序如下:


  1. IplImage *image_33 = cvCreateImage(cvSize(3, 3), 8, 3);  
  2.           IplImage *image_31 = cvCreateImage(cvSize(3, 3), 8, 1);  
  3.           IplImage *image_53 = cvCreateImage(cvSize(5, 3), 8, 3);  
  4.           IplImage *image_51= cvCreateImage(cvSize(5, 3), 8, 1);  
  5.           IplImage *image_73 = cvCreateImage(cvSize(7, 3), 8, 3);  
  6.           IplImage *image_71 = cvCreateImage(cvSize(7, 3), 8, 1);  
  7.   
  8.           printf("%d, %d, %d, %d, %d, %d", image_33->widthStep,image_31->widthStep,  
  9.      image_53->widthStep,image_51->widthStep,image_73->widthStep,image_71->widthStep);  

           運行結果爲:12, 4, 16, 8, 24, 8, 與手動計算結果相同。

          從網上查閱資料,OpenCV分配的內存按4字節對齊,這樣我們對上述計算的結果可以有個合理的解釋,如寬度爲3、通道數爲3的圖像,每一行需要的 實際內存長度爲3*3,爲了內存對齊,OpenCV會在每行末尾自動補上3個字節的內存,內存初始化都爲0,所以widthStep變爲了12。

widthStep大小對IplImage極爲重要,在cxarray.cpp中,我們可以找到如下代碼行:

  1. image->imageSize = image->widthStep * image->height;  
  2.   
  3. img->imageData = img->imageDataOrigin =(char*)cvAlloc( (size_t)img->imageSize );  

      可見widthStep直接影響到imageData的數據長度。在操作imageData時,我們要避開對OpenCV自動補齊的內存進行操作,如直方圖計算等。

寫到這裏,可能有人會問,我們平常都用widthStep = width * nChannels,怎麼就沒出錯?我之前也一直在疑惑,合理的解釋是,一般在實際應用中,圖像的寬度一般爲128, 256, 240, 320, 356,704等,剛好這些數字都能被4整除,widthStep剛好等於width * nChannels, 所以OpenCV並沒有爲這些圖像分配多的內存,因此我們在對imageData做順序操作也沒出錯。但是,請問誰能保證圖像的寬度一定會是4的倍數? 

發佈了50 篇原創文章 · 獲贊 86 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章