前面讲了CvMat矩阵结构,下面介绍IplImage,本质上讲IplImage也是CvMat结构,但是它还有一些成员将矩阵解释为图像。
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个,在第一篇里遇到过:
nChannels即通道数可取1,2,3和4。imageData包含指向图像第一行的指针。widthStep即每行的字节数。
另一个比较主要的成员是origin,用于设置坐标原点位于图像的左上角(参数IPL_ORIGIN_TL)还是左下角(参数IPL_ORIGIN_BL)。
最后介绍感兴趣的区域–ROI,实际上是图像的一个子图,设定了ROI之后,opencv里的函数便只对子图里的像素进行处理。
与访问矩阵数据的区别在于起始位置指针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
#include
#include
#include
#include
#include "cv.h"
using namespace cv;
using namespace std;
//把红蓝通道的数据置0
void saturate_sv( IplImage* img ) {
for( int y=0; yheight; y++ ) {
uchar* ptr = (uchar*) (img->imageData + y * img->widthStep);
for( int x=0; xwidth; 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;
}
#include
#include
#include
#include
#include
#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;
}
#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;
}