大家好,又见面了,我是你们的朋友全栈君。
简言之:image->widthStep = (int(image->width * image->nChannels+3)/4)*4,既图像宽度*图像通道数,再向上取最近的4的倍数,因为每行是按4的倍数分配内存的
做直方图计算时要注意空的内存。
灰度图的width和widthstep不相等。前者是表示图像的每行像素数,后者指表示存储一行像素需要的字节数。
在OpenCV里边,widthStep必须是4的倍数,从而实现字节对齐,有利于提高运算速度。如果8U单通道图像宽度为3,那么widthStep是4,加一个字节补齐。这个图像的一行需要4个字节,只使用前3个,最后一个空着。也就是一个宽3高3的图像的imageData数据大小为4*3=12字节。
一直以为IplImage结构体中的widthStep元素大小等于width*nChannels,大错特错!
查看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));
其中IPL_DEPTH_SIGN的定义可以在cxtypes.h中找到,定义为:#define IPL_DEPTH_SIGN 0x80000000, align的大小为CV_DEFAULT_IMAGE_ROW_ALIGN,其大小在cxmisc.h中定义为:#define
根据(1)式,已知IPL_DEPTH_SIGN、align、depth 的大小,分别手动计算如下图像的widthStep:
图像宽度
3
3
5
5
7
7
4
4
为了进一步验证手算的正确性,我们编程实现输出widthStep的大小,程序如下:
运行结果为:12, 4, 16, 8, 24, 8, 与手动计算结果相同。
从网上查阅资料,OpenCV分配的内存按4字节对齐,这样我们对上述计算的结果可以有个合理的解释,如宽度为3、通道数为3的图像,每一行需要的 实际内存长度为3*3,为了内存对齐,OpenCV会在每行末尾自动补上3个字节的内存,内存初始化都为0,所以widthStep变为了12。
widthStep大小对IplImage极为重要,在cxarray.cpp中,我们可以找到如下代码行:
image->imageSize = image->widthStep * image->height;
img->imageData = img->imageDataOrigin =
可见widthStep直接影响到imageData的数据长度。在操作imageData时,我们要避开对OpenCV自动补齐的内存进行操作,如直方图计算等。
写到这里,可能有人会问,我们平常都用widthStep = width * nChannels,怎么就没出错?我之前也一直在疑惑,合理的解释是,一般在实际应用中,图像的宽度一般为128, 256, 240, 320, 356,704等,刚好这些数字都能被4整除,widthStep刚好等于width * nChannels, 所以OpenCV并没有为这些图像分配多的内存,因此我们在对imageData做顺序操作也没出错。但是,请问谁能保证图像的宽度一定会是4的倍数?
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/131612.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...