i*step+j*channels+k 以及widthStep大小計算及原理

一直覺得IplImage結構體中的widthStep元素大小等於width*nChannels,大錯特錯!web

查看OpenCV2.1的源碼,在src/cxcore/cxarray.cpp文件中,找到cvInitImageHeader函數,函數中對widthStep大小賦值以下:編程

image->widthStep = (((image->width * image->nChannels *函數

(image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1));                                             (1)spa

其中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位深度。.net

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

圖像寬度     圖像通道數              計算獲得的widthStepblog

3                    3                             12內存

3                    1                             4get

5                    3                            16源碼

5                    1                             8

7                    3                             24

7                    1                             8

4                    3                             12

4                    1                             4

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

 IplImage *image_33 = cvCreateImage(cvSize(3, 3), 8, 3);
 IplImage *image_31 = cvCreateImage(cvSize(3, 3), 8, 1);
 IplImage *image_53 = cvCreateImage(cvSize(5, 3), 8, 3);
 IplImage *image_51= cvCreateImage(cvSize(5, 3), 8, 1);
 IplImage *image_73 = cvCreateImage(cvSize(7, 3), 8, 3);
 IplImage *image_71 = cvCreateImage(cvSize(7, 3), 8, 1);

 printf("%d, %d, %d, %d, %d, %d", image_33->widthStep,image_31->widthStep,
     image_53->widthStep,image_51->widthStep,image_73->widthStep,image_71->widthStep);

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

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

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

image->imageSize = image->widthStep * image->height;

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的倍數? 

純屬我的理解,若有錯誤,還請大蝦多多指出。

通過上面的分析,我已經徹底理解了widthStep的計算以及爲什麼data[i * step + j * channels + k]這麼計算了

本文轉自:http://blog.csdn.net/xidianzhimeng/article/details/16845097

相關文章
相關標籤/搜索