在这几天查看OpenCv帮助文档的时候,运行其中的一个C++例程,主要是对IplImage的操作,结果没有问题,但是对其中的过程中widthStep 和 width之间的关系产生了兴趣,先看例程代码
////////////////////////////////////////////////////////////////////////
//
// hello-world.cpp
//
// 该程序从文件中读入一幅图像,将之反色,然后显示出来.
//
////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
IplImage* img = 0;
int height,width,step,channels,depth;
uchar *data;
int i,j,k;
if(argc<2){
printf("Usage: main \n\7" );
exit(0);
}
// load an image
img=cvLoadImage(argv[1]);
if(!img){
printf("Could not load image file: %s\n",argv[1]);
exit(0);
}
// get the image data
height = img->height;
width = img->width;
step = (img->widthStep);
channels = img->nChannels;
depth = img->depth;
data = (uchar*)img->imageData;
printf("bef test\n");
printf("Processing a %dx%d image with %d channels , step = %d depth=
%d\n",height,width,channels,step,depth);
// create a window
cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
cvMoveWindow("mainWin", 100, 100);
// invert the image
// 相当于 cvNot(img);
// IplImage *pDstImg = cvCreateImage(cvGetSize(img),img->depth,img->nChannels);
// cvNot(img, pDstImg);
for(i=0;ifor(j=0;jfor(k=0;k//printf("%d-%d-%d value= %d\t",i,j,k,data[i*step+j*channels+k]);
data[i*step+j*channels+k]=255-data[i*step+j*channels+k];
//printf("%d-%d-%d value= %d\n",i,j,k,data[i*step+j*channels+k]);
}
}
}
// show the image
cvShowImage("mainWin", img );
printf("aft test2\n");
// wait for a key
cvWaitKey(0);
// release the image
cvReleaseImage(&img );
printf("aft test3\n");
return 0;
}
结果当然是正确的了,但是看图 2 中的打印出来的结果可以知道,图片的width =375,channels = 3,根据channel的定义(每个像素中的保存信息的字节的个数),这个Matrix的每一行的应该有 width*channels = 1125,但是运行的结果是widthStep = 1128,由此我们应该可以猜测出
width*channels != widthStep
那么widthStep 和 width 什么关系呢???
最好的办法当然是查看IplImage实现的源代码了,参考博客 找到了在OpenCv-2.4.10版本中的位置:
C:\opencv2.4.10\opencv\sources\modules\core\src\array.cpp
分析此问题最重要代码如下:
image->widthStep = (((image->width * image->nChannels *(image->depth &
~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1));
在该公式中,表明了widthStep、width、和nChannels之间的关系
为了方便查看:
A= (((image->width * image->nChannels *(image->depth &
~IPL_DEPTH_SIGN) + 7)/8);
B = align -1;
widthStep = (A+B)&(~B); …… (1)
(1)式主要的作用就是将 widthStep调整为align的倍数,而这里align代表的意思就是OpenCV分配的内存对齐的单位,在OpenCv中一般为4或者8;
所以当align = 4时:
eg1:
如果 A= 9 ,通过(1)式的计算可以得到
widthStep = 12; (调整为了4的倍数);
eg2:
对于我们上面的运行结果分析,
width*channels = 1125
经过(1)式的调整,就可以得到最后结果为 1128,也就是最后打印出来的结果。
到此,我们的疑惑也就解决了,有兴趣的同学也可以去看看源码!
其实,这里这么处理也不无道理,当每个Step被调整为align的倍数,比实际需求多出来的位置全部置0,这样就可以方便对其中数据的管理,比如这N*align中的数据保存的都是这个矩阵中某一行的数据,而不会出现某个align中的数据既有第i行的数据,又有第i+1行的数据。