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

前面讲了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个,在第一篇里遇到过:

  1. IPL_DEPTh_8U 无符号8位整数
  2. IPL_DEPTh_8S 有符号8位整数
  3. IPL_DEPTh_16S 有符号16位整数
  4. IPL_DEPTh_32S 有符号32位整数
  5. IPL_DEPTh_32F 有符号32位浮点数单精度
  6. 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 
#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;
}

opencv从入门到精通(4)--IplImage数据结构_第1张图片

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

  1. ROI的使用通过void cvSetImageROI(IplImage * image,CvRect rect)和void cvResetImageROI(IplImage * image)两个函数,前者设定ROI,后者取消ROI。
#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;
}
  1. 运用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;
}

你可能感兴趣的:(计算机视觉)