原以为IplImage结构体中widthStep元素的尺寸和width*nChannels一样,但大错特错! (要实现高速访问,必须对齐内存。)查看OpenCV2.1源代码,然后在src/cxcore/cxarray.cpp文件中找到cvInitImageHeader函数。 函数为宽度步长大小指定以下值:
3358 www.Sina.com/viewplaincopyprint? image-width step=((image-width * image-nchannels * ) image-depth-IPL_depth_sign )7)/8 (对齐-1) )
其中,IPL_DEPTH_SIGN的定义在cxtypes.h中,定义为#defineIPL_depth_sign0x80000000,align的大小为cv _ default _ image _
根据式(1)可知IPL_DEPTH_SIGN、align、depth的大小,分别手动计算以下图像的widthStep。
计算图像宽度的图像通道数的widthStep
331
23 1 4
5 3 16
5 1 8
7 3 24
7 1 8
4 3 12
4 1 4
为了进一步验证手算的正确性,我们编程实现输出widthStep的大小,程序如下:
运行结果为:12, 4, 16, 8, 24, 8, 与手动计算结果相同。
从网上查阅资料,OpenCV分配的内存按4字节对齐,这样我们对上述计算的结果可以有个合理的解释,如宽度为3、通道数为3的图像,每一行需要的 实际内存长度为3*3,为了内存对齐,OpenCV会在每行末尾自动补上3个字节的内存,内存初始化都为0,所以widthStep变为了12。
widthStep大小对IplImage极为重要,在cxarray.cpp中,我们可以找到如下代码行:
[cpp] view plain copy print ? 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的倍数?