转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7557063
!!此篇是基于IplImage* (C接口或者说2.1之前版本的接口,新的Mat的访问方式请参考博文:
IplImage是OpenCV中CxCore部分基础的数据结构,用来表示图像,其中Ipl是Intel Image Processing Library的简写。以下是IplImage的结构分析(来自OpenCV中文网站:http://www.opencv.org.cn/index.php/Cxcore基础结构#IplImage)
- typedef
struct _IplImage -
{ -
int nSize; -
int ID; -
int nChannels; -
int alphaChannel; -
int depth; -
char colorModel[4]; -
char channelSeq[4]; -
int dataOrder; -
int origin; -
int align; -
int width; -
int height; -
struct _IplROI *roi; -
struct _IplImage *maskROI; -
void *imageId; -
struct _IplTileInfo *tileInfo; -
int imageSize; -
char *imageData; -
int widthStep; -
int BorderMode[4]; -
int BorderConst[4]; -
char *imageDataOrigin; -
} -
IplImage;
直接访问:
对我们来说比较重要的两个元素是:char *imageData以及widthStep。imageData存放图像像素数据,而widStep类似CvMat中的step,表示以字节为单位的行数据长度。
一个m*n的单通道字节型图像,其imageData排列如下:
如果我们要遍历图像中的元素,只需:
- IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); - uchar*
tmp; - for(int
i=0;iheight;i++) -
for(int j=0;jwidth;j++) -
*tmp=((uchar *)(img->imageData + i*img->widthStep))[j];
这种直接访问的方法速度快,但容易出错,我们可以通过定义指针来访问。即:
- IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); - ucha*
data=(uchar *)img->imageData; - int
step = img->widthStep/sizeof(uchar); - uchar*
tmp; - for(int
i=0;iheight;i++) -
for(int j=0;jwidth;j++) -
*tmp=data[i*step+j];
而多通道(三通道)字节图像中,imageData排列如下:
其中(Bi,Bj)(Gi,Gj)(Ri,Rj)表示图像(i,j)处BGR分量的值。使用指针的遍历方法如下:
- IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); - IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); - uchar*
data=(uchar *)img->imageData; - int
step = img->widthStep/sizeof(uchar); - int
channels = img->nChannels; - uchar
*b,*g,*r; - for(int
i=0;iheight;i++) -
for(int j=0;jwidth;j++){ -
*b=data[i*step+j*chanels+0]; -
*g=data[i*step+j*chanels+1]; -
*r=data[i*step+j*chanels+2]; -
}
*如果要修改某像素值,则直接赋值。
使用cvGet2D()函数访问:
cvGet*D系列函数可以用来返回特定位置的数组元素(一般使用cvGet2D),原型如下:
- CvScalar
cvGet1D( const CvArr* arr, int idx0 ); - CvScalar
cvGet2D( const CvArr* arr, int idx0, int idx1 ); - CvScalar
cvGet3D( const CvArr* arr, int idx0, int idx1, int idx2 ); - CvScalar
cvGetND( const CvArr* arr, int* idx );
因此,单通道图像像素访问方式如下:
- IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); - double
tmp; - for(int
i=0;iheight;i++) -
for(int j=0;jwidth;j++) -
tmp=cvGet2D(img,i,j).val[0];
- IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); - double
tmpb,tmpg,bmpr; - for(int
i=0;iheight;i++) -
for(int j=0;jwidth;j++){ -
tmpb=cvGet2D(img,i,j).val[0]; -
tmpg=cvGet2D(img,i,j).val[1]; -
tmpr=cvGet2D(img,i,j).val[2]; -
}
如果是修改元素的值,可用cvSet*D(一般是cvSet2D)函数:
- void
cvSet1D( CvArr* arr, int idx0, CvScalar value ); - void
cvSet2D( CvArr* arr, int idx0, int idx1, CvScalar value ); - void
cvSet3D( CvArr* arr, int idx0, int idx1, int idx2, CvScalar value ); - void
cvSetND( CvArr* arr, int* idx, CvScalar value );