IplImage是OpenCV中CxCore部分基础的数据结构,用来表示图像,其中Ipl是Intel Image Processing Library的简写。

OpenCV2.1版本之前使用IplImage*数据结构来表示图像,2.1之后的版本使用图像容器Mat来存储。IplImage结构体如下所示。
typedef struct _IplImage { int nSize; /* 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[4]; /* 被OpenCV忽略 */ char channelSeq[4]; /* 同上 */ int dataOrder; /* 0
- 交叉存取颜色通道, 1 - 分开的颜色通道. 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[4]; /* 边际结束模式, 被OpenCV忽略 */ int BorderConst[4]; /* 同上 */ char
*imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */ } IplImage;
分配与释放图像空间:
//分配图像空间 IplImage* cvCreateImage(CvSize size, int depth, int channels); size:
cvSize(width,height); depth: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F channels: 1, 2, 3 or
4. //注意数据为交叉存取.彩色图像的数据编排为b0 g0 r0 b1 g1 r1 ... //分配一个单通道字节图像 IplImage*
img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); //分配一个三通道浮点图像 IplImage*
img2=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); //释放图像空间 IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); cvReleaseImage(&img);  
//复制图像 IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); IplImage*
img2; img2=cvCloneImage(img1);   //设定/获取兴趣区域: void cvSetImageROI(IplImage*
image, CvRect rect); void cvResetImageROI(IplImage* image); vRect
cvGetImageROI(const IplImage* image); //设定/获取兴趣通道: void cvSetImageCOI(IplImage*
image, int coi); // 0=all int cvGetImageCOI(const IplImage* image);
读取储存图像:
//从文件中载入图像: IplImage* img=0; img=cvLoadImage(fileName); if(!img) printf("Could
not load image file: %s/n",fileName); Supported image formats: BMP, DIB, JPEG,
JPG, JPE, PNG, PBM, PGM, PPM, SR, RAS, TIFF, TIF //载入图像默认转为3通道彩色图像.
如果不是,则需加flag: img=cvLoadImage(fileName,flag); //flag: >0 载入图像转为三通道彩色图像 =0
载入图像转为单通道灰度图像 <0 不转换载入图像(通道数与图像文件相同).   //图像存储为图像文件:
if(!cvSaveImage(outFileName,img)) printf("Could not save: %s/n",outFileName);
//输入文件格式由文件扩展名决定.
存取图像元素:
//假设需要读取在i行j列像点的第k通道. 其中, 行数i的范围为[0, height-1], 列数j的范围为[0, width-1],
通道k的范围为[0, nchannels-1].   /*间接存取: (比较通用, 但效率低, 可读取任一类型图像数据)*/   //对单通道字节图像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); CvScalar s;
s=cvGet2D(img,i,j); // get the (i,j) pixel value
printf("intensity=%f/n",s.val[0]); s.val[0]=111; cvSet2D(img,i,j,s); // set the
(i,j) pixel value   //对多通道浮点或字节图像: IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); CvScalar s;
s=cvGet2D(img,i,j); // get the (i,j) pixel value printf("B=%f, G=%f,
R=%f/n",s.val[0],s.val[1],s.val[2]); s.val[0]=111; s.val[1]=111; s.val[2]=111;
cvSet2D(img,i,j,s); // set the (i,j) pixel value   /*直接存取: (效率高, 但容易出错)*/  
//对单通道字节图像: IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
((uchar *)(img->imageData + i*img->widthStep))[j]=111;   //对多通道字节图像: IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); ((uchar *)(img->imageData +
i*img->widthStep))[j*img->nChannels + 0]=111; // B ((uchar *)(img->imageData +
i*img->widthStep))[j*img->nChannels + 1]=112; // G ((uchar *)(img->imageData +
i*img->widthStep))[j*img->nChannels + 2]=113; // R   //对多通道浮点图像: IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); ((float *)(img->imageData +
i*img->widthStep))[j*img->nChannels + 0]=111; // B ((float *)(img->imageData +
i*img->widthStep))[j*img->nChannels + 1]=112; // G ((float *)(img->imageData +
i*img->widthStep))[j*img->nChannels + 2]=113; // R   /*用指针直接存取 : (在某些情况下简单高效)*/
  //对单通道字节图像: IplImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
int height = img->height; int width = img->width; int step =
img->widthStep/sizeof(uchar); uchar* data = (uchar *)img->imageData;
data[i*step+j] = 111;   //对多通道字节图像: IplImage* img =
cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); int height = img->height; int
width = img->width; int step = img->widthStep/sizeof(uchar); int channels =
img->nChannels; uchar* data = (uchar *)img->imageData;
data[i*step+j*channels+k] = 111;   //对单通道浮点图像(假设用4字节调整): IplImage* img =
cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); int height = img->height; int
width = img->width; int step = img->widthStep/sizeof(float); int channels =
img->nChannels; float * data = (float *)img->imageData;
data[i*step+j*channels+k] = 111;     /*使用 c++ wrapper 进行直接存取: (简单高效)*/  
//对单/多通道字节图像,多通道浮点图像定义一个 c++ wrapper: template<class T> class Image { private:
IplImage* imgp; public: Image(IplImage* img=0) {imgp=img;} ~Image(){imgp=0;}
void operator=(IplImage* img) {imgp=img;} inline T* operator[](const int
rowIndx) { return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));} };
typedef struct{ unsigned char b,g,r; } RgbPixel; typedef struct{ float b,g,r; }
RgbPixelFloat; typedef Image<RgbPixel> RgbImage; typedef Image<RgbPixelFloat>
RgbImageFloat; typedef Image<unsigned char> BwImage; typedef Image<float>
BwImageFloat;   //单通道字节图像: IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); BwImage imgA(img);
imgA[i][j] = 111;   //多通道字节图像: IplImage*
img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); RgbImage imgA(img);
imgA[i][j].b = 111; imgA[i][j].g = 111; imgA[i][j].r = 111;   //多通道浮点图像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3); RgbImageFloat
imgA(img); imgA[i][j].b = 111; imgA[i][j].g = 111; imgA[i][j].r = 111;

从本质上讲,IplImage是一个CvMat对象,但CvMat中的data和IplImage中的imageData是有区别的,imageData指针是字节类型指针,所以指向的数据是uchar类型的。所以,在图像上进行指针运算时,你可以简单增加widthStep。

下面讲讲另一个变量ROI
(感兴趣的区域)的故事,实际上它是一个IPL/IPP结构IplROI的实例。IplROI包含xOffset,yOffset,height,width和coi(感兴趣的通道)成员变量。

ROI的思想是:一旦设定ROI,通常作用于整幅图像的函数只会对ROI所表示的子图像进行操作。若果IplImage变量设置了ROI,则所有的OpenCV函数就会使用该ROI变量。

ROI在实际工作中有很重要的作用,很多情况下,使用它会提高计算机视觉代码的执行速度。如果想设置ROI,使用函数cvSetImageROI(),并为其传递一个
    图像指针和矩形。取消ROI,只需要为函数cvResetImageROI(),传递一个图像指针。

而CvMat需要在另一篇进行详细理解。

革命尚未成功,同志仍需努力。

技术
下载桌面版
GitHub
百度网盘(提取码:draw)
Gitee
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:766591547
关注微信