一直覺得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