1.IplImage数据结构
(1)IplImage的结构
typedef struct _IplImage { int nSize; //IplImage大小 int ID; //ID int nChannels; //通道数,大多数OPENCV函数支持1,2,3 或 4 个通道。 int alphaChannel; 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]; char channelSeq[4]; int dataOrder; //颜色通道排列规则 0 - 交叉存取颜色通道, 1 - 分开的颜色通道.cvCreateImage只能创建交叉存取图像 int origin; // 坐标原点位置,0 - 顶—左结构,1 - 底—左结构 (Windows bitmaps 风格) int align; int width; //图像宽像素数 int height; //图像高像素数 struct _IplROI *roi;// 图像感兴趣区域. 当该值非空只对该区域进行处理 struct _IplImage *maskROI; // 在 OpenCV中必须置NULL void *imageId; // 在 OpenCV中必须置NULL struct _IplTileInfo *tileInfo; // 在 OpenCV中必须置NULL int imageSize; // 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节 char *imageData; // 指向排列的图像数据 int widthStep; //排列的图像行大小,以字节为单位 int BorderMode[4]; //边际结束模式// int BorderConst[4]; char *imageDataOrigin; // 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 } IplImage;
(2)访问数据图像
imageData里存放的是HSV空间数据,所以下面的程序是将S和V部分加满。
#include <cv.h> #include <highgui.h> #include <iostream> using namespace std; int main(int argc, char** argv) { IplImage* img = cvLoadImage("460.jpg"); void saturate_sv(IplImage *img); saturate_sv(img); cvNamedWindow("Example1", CV_WINDOW_AUTOSIZE ); cvShowImage("Example1", img ); cvWaitKey(0); cvReleaseImage( &img ); cvDestroyWindow("Example1"); return 0; } void saturate_sv(IplImage *img) { for(int y = 0;y<img->height;y++){ uchar* ptr = (uchar*)( img->imageData + y * img->widthStep ); for(int x = 0;x < img->width;x++) { ptr[3*x+1] = 255; ptr[3*x+2] = 255; } } }
加满S和V后的结果为
(3)对ROI和widthStep的补充
ROI和widthStep在实际工作中有很重要的作用,在很多情况下,使用它们会提高计算机视觉代码的执行速度。这是因为它们运行对图像的某一小部分进行操作,而不是对整个图像进行运算。
实例代码,利用imageROI来增加某范围的像素
#include <cv.h> #include <highgui.h> #include <iostream> using namespace std; int main(int argc, char** argv) { IplImage* src; if( ((src=cvLoadImage("460.jpg")) != 0 )) { int x = atoi("80"); int y = atoi("150"); int width = atoi("270"); int height = atoi("250"); int add = atoi("-100"); cvShowImage( "大脸猫", src); cvSetImageROI(src, cvRect(x,y,width,height)); cvAddS(src, cvScalar(add),src); cvResetImageROI(src); cvShowImage( "大脸猫1",src); cvWaitKey(); } cvReleaseImage( &src ); return 0; }
显示结果:
利用widthStep方法同样可以把选中区域内所有像素的值加200
#include <cv.h> #include <highgui.h> #include <iostream> using namespace std; int main(int argc, char** argv) { IplImage* interest_img; CvRect interest_rect; if( ((interest_img=cvLoadImage("460.jpg")) != 0 )) { interest_rect.x = atoi("80"); interest_rect.y = atoi("150"); interest_rect.width = atoi("270"); interest_rect.height = atoi("250"); int add = atoi("1"); IplImage *sub_img = cvCreateImageHeader( cvSize( interest_rect.width, interest_rect.height ), interest_img->depth, interest_img->nChannels ); sub_img->origin = interest_img->origin; sub_img->widthStep = interest_img->widthStep; sub_img->imageData = interest_img->imageData + interest_rect.y * interest_img->widthStep + interest_rect.x * interest_img->nChannels; cvAddS( sub_img, cvScalar(add), sub_img ); cvReleaseImageHeader(&sub_img); cvShowImage( "大脸猫22", interest_img ); cvWaitKey(); } return 0; }
实验结果:
看起来ROI的方法更方便些,为什么还要使用widthStep呢?原因在于有些时候在处理过程中,想在操作过程中设置和保持一幅图像的多个子区间处于活动状态,但是ROI只能串行处理并且必须不断地设置和重置。所以在实际工作中widthStep更好。
to be continued
《学习opencv》笔记——IplImage数据结构
时间: 2024-10-11 04:12:48