IplImage数据结构:访问图像像素
的有关信息介绍如下:绪:
在机器视觉领域,图像处理是基础;
OpenCV作为一个视觉图像处理开源库,熟悉理解其访问图像像素方法必要基础;
IplImage是OpenCV中的图像数据结构。
经验目录:
...IplImage数据结构;
...图像数据存储;
...访问图像像素的方法;
...注意事项;
IplImage数据结构:来自于 Intel Image Processing Library。
OpenCV 只支持其中的一个子集:
IplImage图像头:
typedef struct _IplImage
....{
int nSize; /* IplImage大小,=sizeof(IplImage)*/
int ID; /* 版本 (=0)*/
int nChannels;/* 大多数OPENCV函数支持1,2,3 或 4 个通道 */
int alphaChannel;/* 被OpenCV忽略 */
.........int depth; /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S,
................................/*IPL_DEPTH_16U,IPL_DEPTH_16S, IPL_DEPTH_32S,
................................/*IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */
char colorModel; /* 被OpenCV忽略 */
char channelSeq; /* 被OpenCV忽略 */
int dataOrder; /* 0 - 交叉存取颜色通道,对三通道RGB图像,像素存
......................................../*储顺序为BGR BGR BGR ... BGR;
......................................../*1 - 分开的颜色通道,对三通道RGB图像,像素存储顺
......................................../*序为RRR...R GGG...G BBB...B。
......................................./*cvCreateImage只能创建交叉存取图像 */
int origin; /* 0 - 顶—左结构,
1 - 底—左结构 (Windows bitmaps 风格) */
int align; /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */
int width; /* 图像宽像素数 */
int height; /* 图像高像素数*/
struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */
struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */
void *imageId; /* 同上*/
struct _IplTileInfo *tileInfo; /*同上*/
int imageSize; /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/
char *imageData; /* 指向排列的图像数据 */
int widthStep; /* 排列的图像行大小,以字节为单位 */
int BorderMode; /* 边际结束模式, 被OpenCV忽略 */
int BorderConst; /* 同上 */
char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */
}
IplImage;
在IplImage数据类型中,访问图像像素最重要的元素:
....char *imageData; /* 指向排列的图像数据 */
....int widthStep;/*排列的图像行大小,以字节为单位*/
或
....int width;/*图像宽像素数*/
一个m*n的单通道字节型图像,其imageData排列如作图:
多通道(三通道)字节图像中,imageData排列如右图:
访问图像像素方法:
(1)根据上述数据排列,定义指针访问:
语句:
..........pData=(unsigned char*)(pImg->imageData+i*pImg->widthStep)[j];
//像素点的地址
其中,
pImg->imageData:指向图像pImg第一行首地址;
widthStep:图像的行宽,单位字节;
unsigned char*:由于pImg->imageData默认为char类型,图像像素值中有可能出现负数,所以需要强制类型转换为unsigned char;
对于单通道图像;
【注】:先遍历行和先遍历列的区分;
如下图:
(2)对于多通道图像;
IplImage*img=cvCreateImage(cvGetSize (_pImg),IPL_DEPTH_8U,3);
unsigned char*data=(unsigned char*)img->imageData;
intstep=img->widthStep/sizeof(uchar);
intchannels=img->nChannels;
uchar*b,*g,*r;
for(inti=0;i
....for(intj=0;j
..{
....*b=data[i*step+j*chanels+0];
....*g=data[i*step+j*chanels+1];
....*r=data[i*step+j*chanels+2];
..}
其数据访问格式如下:
与数据类型相关,宽度相关;
注意事项:
①OpenCV中使用imread()、cvLoadImage()得到的图像,其数据类型都是char类型;
②对于32为操作系统,内存存储图像数据满足每行数据4字节对齐;
即:
当图像为单通道char/uchar,每行数据大小为sizeof(uchar)*width=widthStep字节;
如果width为4的倍数,那么widthStep=width;
如果width不为4的倍数,则需补齐4个字节。
eg. width=16àwidthStep=16字节;
.......width=18àwidthStep=(width+2)/4*4=20字节;
当图像为3通道float型,widthStep=(width*3*sizeof(float)+3)/4*4;
widthStep只和宽度与数据类型有关。
③示例:
创建一副宽*高为111*113大小的3通道float类型图像,访问第31行、51列的图像数据。
IplImage *image=cvCreateImage(cvSize(111,113),IPL_DEPTH_32F,3);
//则widthStep=(111*3*sizeof(float)+3)/4*4=2664字节;
float *data_1=(float*)image->imageData;
float val_1=*(data_1+31*width+51);
//或
char *data_2=image->imageData;
float val_2=*(float*)(data_2+31*image->widthStep+51*sizeof(float));
④【注】:
对于char、uchar图像数据类型,用widthStep;
对于float、double图像数据类型,用width;否则会出错。
【特别注意】:
在IplImage头中,imageData默认为char*类型;
当 .IplImage* img=cvCreateImage(cvGetSize(_Img),IPL_DEPTH_8U,1)
......unsigned char *data_1;
......for(int i=0;i
.........{
..........for(int j=0;j
....{
...............//①对
...............data_1=(unsigned char*)img->imageData + i*img->widthStep;
...............//②对
...............//data_1=(unsigned char*)(img->imageData + i*img->widthStep);
}
}
当 .IplImage* img=cvCreateImage(cvGetSize(_Img),IPL_DEPTH_32F,1)
......float *data_2;
......for(int i=0;i
.........{
..........for(int j=0;j
..........{
..................//①对
..................data_2=(float*)img->imageData + i*img->width;
.................//②错
.................//data_2=(float*)(img->imageData + i*img->width);
.................//③错
................//data_2=(float*)img->imageData + i*img->widthStep;
................//data_2=(float*)img->imageData + i*img->widthStep/sizeof(float);//④对
}
}