您的位置:首页 > 理论基础 > 数据结构算法

opencv从入门到精通(4)--IplImage数据结构

2016-01-25 11:00 381 查看
前面讲了CvMat矩阵结构,下面介绍IplImage,本质上讲IplImage也是CvMat结构,但是它还有一些成员将矩阵解释为图像。

IplImage结构

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;


其中比较重要的变量是width,height,depth,Channels,imageData和widthStep。前两个和矩阵一样,depth和nChannels在矩阵中写在一起,这里则分开表示。depth即数据类型主要有6个,在第一篇里遇到过:

IPL_DEPTh_8U 无符号8位整数

IPL_DEPTh_8S 有符号8位整数

IPL_DEPTh_16S 有符号16位整数

IPL_DEPTh_32S 有符号32位整数

IPL_DEPTh_32F 有符号32位浮点数单精度

IPL_DEPTh_64F 有符号64位浮点数双精度

nChannels即通道数可取1,2,3和4。imageData包含指向图像第一行的指针。widthStep即每行的字节数。

另一个比较主要的成员是origin,用于设置坐标原点位于图像的左上角(参数IPL_ORIGIN_TL)还是左下角(参数IPL_ORIGIN_BL)。

最后介绍感兴趣的区域–ROI,实际上是图像的一个子图,设定了ROI之后,opencv里的函数便只对子图里的像素进行处理。

访问IplImage数据

与访问矩阵数据的区别在于起始位置指针imgdata是字节类型的,不需要像矩阵数据那样进行转换。指针换算的公式,对于一个宽为img->width,高为img->height的c通道图像,每行的字节长度为img-widthStep,矩阵头的指针为img->imageData,那么a行b列i通道变量的位置为(uchar * )(img->imageData+a * img-widthStep+b*c+i)。

下面举一个看例子,输入是3通道RGB图像,输出它的绿色通道图像。

#include <stdio.h>
#include <fstream>
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "cv.h"
using namespace cv;
using namespace std;

//把红蓝通道的数据置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+0] =0;
ptr[3*x+2] = 0;
}
}
}

int main( )
{
IplImage* img = cvLoadImage( "a1.ppm");
cvNamedWindow("window1", CV_WINDOW_AUTOSIZE );
cvNamedWindow("window2", CV_WINDOW_AUTOSIZE );
cvShowImage("window1", img );
saturate_sv(img);
cvShowImage("window2", img );
cvWaitKey(0);
cvReleaseImage( &img );
cvDestroyWindow("window1");
cvDestroyWindow("window2");
return 0;
}




用ROI和widthStep设定感兴趣的区域

ROI的使用通过void cvSetImageROI(IplImage * image,CvRect rect)和void cvResetImageROI(IplImage * image)两个函数,前者设定ROI,后者取消ROI。

#include <stdio.h>
#include <fstream>
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "cv.h"
using namespace cv;
using namespace std;

int main()
{

IplImage* src=cvLoadImage("a1.ppm",1);
IplImage* dic=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,3);
cvCopy(src,dic);
cvNamedWindow("pre", CV_WINDOW_AUTOSIZE);
cvNamedWindow("post1", CV_WINDOW_AUTOSIZE);
cvNamedWindow("post2", CV_WINDOW_AUTOSIZE);

cvShowImage( "pre", src);
cvSetImageROI(src, cvRect(200,300,400,200));//在点(200,300)开始选择大小为400 *200的区域
cvSetImageROI(dic, cvRect(200,300,400,200));
cvAddS(src, cvScalar(255,0,0),dic);//src每个像素的RGB值加上dic输出dic
cvShowImage( "post1",dic);
cvSaveImage("a2.ppm",dic);
cvResetImageROI(src);
cvResetImageROI(dic);
cvShowImage( "post2",dic);

cvWaitKey();
cvReleaseImage( &src );
cvReleaseImage( &dic );
cvDestroyWindow("pre");
cvDestroyWindow("post1");
cvDestroyWindow("post2");
return 0;
}


运用widthStep。效果和ROI相同,但是有时候设置ROI需要不断重置,用widthStep更为高效。

#include <stdio.h>
#include <fstream>
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "cv.h"
using namespace cv;
using namespace std;

int main()
{

IplImage* src=cvLoadImage("a1.ppm",1);
IplImage *dic = cvCreateImageHeader(
cvSize(400, 200),
src->depth,
src->nChannels
);//该函数不分配内存,设定大小为400*200的区域
dic->origin = src->origin;

dic->widthStep = src->widthStep;

dic->imageData = src->imageData + 300 * src->widthStep + 100 * src->nChannels;//设定区域起始位置
cvAddS(dic, cvScalar(100,34,23),dic);

cvNamedWindow("pre", CV_WINDOW_AUTOSIZE);
cvNamedWindow("post1", CV_WINDOW_AUTOSIZE);
cvNamedWindow("post2", CV_WINDOW_AUTOSIZE);
cvShowImage( "pre", src);
cvShowImage( "post1",dic);
cvShowImage( "post2",src);
cvSaveImage("a3.ppm",dic);

cvWaitKey();
cvReleaseImage( &src );
cvReleaseImageHeader(&dic);
cvDestroyWindow("pre");
cvDestroyWindow("post1");
cvDestroyWindow("post2");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息