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

相关文章
相关标签/搜索