Learning OpenCV Chapter3 初探OpenCV上

1.   OpenCV基本数据类型

OpenCV提供了多种基本数据类型,可在opencv\sources\modules\core\include\opencv2\core中查看详细定义。当然你用VS的话,直接对任何数据类型右键转到定义就能直接跳转了。

常用的有,通常构造函数同结构类型名称,但是首字母不大写

CvPoint, CvPoint2D32f, CvPoint3D32f

CvSize, CvSize2D32f

CvRect

CvScalar(意义:RGBA值,构造函数还有cvRealScalar(), cvScalarAll())

 

矩阵和图像类型

三种图像的类或结构如下。

CvArr -> CvMat -> IplImage

三者依次为派生关系,IplImage是通常用来对图像进行“编码”的基本结构,这些图像可以是灰度,彩色,4通道且每个通道可包含任意的整数或浮点数,比常见3通道8位RGB图像更通用。

CvMat是OpenCV的矩阵结构,CvArr可视为一个抽象基类,在函数原型中,常看到CvArr (CvArr*),当他出现时,便可以将CvMat*,IplImage*传递到程序。

 

2.   CvMat矩阵结构

创建CvMat结构

CvMat* cvCreateMat(int rows, int cols, inttype)

Type: CV_(S|U|F)C<#channels>,e.g. CV_32FC132位浮点型数据,CV_8UC3无符号8位三元组整型

CvMat结构如下

typedef struct CvMat {
    int type;
    int step;//矩阵中行的长度,单位为字节,可用来在矩阵的不同行之间移动指针
    int* refcount;     // for internal useonly
    union {
         uchar* ptr;
         short* s;
         int*    i;
         float* fl;
         double* db;
    } data; //数据体,存储的是对应数据类型的指针头
    union {
         int rows;
         int height;
    };
    union {
         int cols;
         int width;
    };
} CvMat;


CvMat矩阵的创建与释放

//Create a new rows by cols matrix of type ‘type’.
//
CvMat*cvCreateMat( int rows, int cols, int type );
//Create only matrix header without allocating data
//
CvMat*cvCreateMatHeader( int rows, int cols, int type );
//Initialize header on existing CvMat structure
//
CvMat*cvInitMatHeader(
   CvMat* mat,
   int   rows,
   int   cols,
   int   type,
   void* data = NULL,
   int   step =CV_AUTOSTEP
);
//Like cvInitMatHeader() but allocates CvMat as well.
//
CvMatcvMat(
   int   rows,
   int   cols,
   int   type,
   void* data = NULL
);
//Allocate a new matrix just like the matrix ‘mat’.
//
CvMat*cvCloneMat( const cvMat* mat );
//Free the matrix ‘mat’, both header and data.
//
void cvReleaseMat(CvMat** mat );

例:用固定数据创建矩阵

#include 
 
int main()
{
  // Create an OpenCV Matrix containing some fixed data.
  //
  float vals[] = { 0.866025, -0.500000, 0.500000, 0.866025};
  
  CvMat rotmat;  //空矩阵结构,下面初始化矩阵头
  
  cvInitMatHeader(
    &rotmat,
    2,
    2,
    CV_32FC1,
    vals
  );
  printf("Ex 3_3 matrixinitialized\n");
}

矩阵数据的存取

 

# include 

int main()
{

	CvMat* mat = cvCreateMat( 5, 5, CV_32FC1 );

	//-----------------------------------------
	//方法一:利用宏CV_MAT_ELEM读取矩阵元素
	float element_3_2 = CV_MAT_ELEM( *mat, float, 3, 2 );
	float element_3_3 = 7.7;
	//宏CV_MAT_ELEM_PTR可以同时读取并且设置数据
	*( (float*)CV_MAT_ELEM_PTR( *mat, 3, 3 ) ) = element_3_3;

	//------------------------------------------
	//方法二:利用cvPtr*D, cvGetReal*D, cvGet*D读取
	float a32 = *cvPtr2D(mat,3,2);
	float a33 = cvGetReal2D(mat,3,3);
	printf("a32 = %f; a33 = %f\n",a32,a33);
	//利用cvSetReal*D, cvSet*D,cvmSet设置
	cvSetReal2D( mat, 3, 4, 0.5 );
	cvmSet(mat,4,3,0.2);


	//------------------------------------------
	//方法三:利用指针的偏移来遍历矩阵,对于整型和浮点型数据(32比特4字节),step/4移向下一行,对于双精度(64比特8字节)step/8
	float vals[] = { 0.866025, -0.500000, 0.500000, 0.866025};
	CvMat rotmat;  //空矩阵结构,下面初始化矩阵头
	cvInitMatHeader(
		&rotmat,
		2,
		2, 
		CV_32FC1,
		vals
		);
	//遍历矩阵所有元素并求和
	float s = 0.0f;
	for( int row=0; row < rotmat.height; row++ ) 
	{
		//这里数据类型为float,rotmat.data.fl为数据开头的指针,step/4移向下一行
		float* ptr = rotmat.data.fl + row * rotmat.step/4;
		for( int col = 0; col < rotmat.width; col++ ) 
			s += *ptr++;
	}
	printf("s = %f\nsum = %f \n",s,0.866025 + -0.500000 + 0.500000 + 0.866025);
	return 0;
}

 注意:方法一只能访问1/2维数数组元,且每次调用宏都会重复计算指针,不是存取矩阵的最佳方法,尤其在顺序访问矩阵中所有元素时。对于计算机视觉这种运算密集型的任务,最有效的方法一般是最后一种。 

 

3.   IplImage数据结构

IplImage数据头结构

//IplImageheader structure
typedef struct _IplImage {
  int                 nSize;
  int                 ID;
  int                 nChannels;//通道数
  int                 alphaChannel;
  int                 depth;//图像深度,取值有IPL_DEPTH_8U|S, IPL_DEPTH_16S, IPL_DEPTH_32S|F, IPL_DEPTH_64F等
  char                colorModel[4];
  char                channelSeq[4];
  int                 dataOrder;//IPL_DATA_ORDER_PIXEL(像素点不同通道的值排在一起)或 IPL_DATA_ORDER_PLANE(同通道值排在一起)
  int                 origin;//IPL_ORIGIN_BL(图像原点左下),IPL_ORIGIN_TL(图像原点左上)
  int                 align;
  int                 width;//宽
  int                 height;//高
  struct _IplROI*      roi;//感兴趣的区域,一旦被设定则所有操作只限于此区域
  struct _IplImage*    maskROI;
  void*               imageId;
  struct _IplTileInfo* tileInfo;
  int                 imageSize;
  char*               imageData;//指向第一行图像数据的指针
  int                 widthStep;//同CvMat中的step,注意不能用width代替,单位仍是字节数
  int                 BorderMode[4];
  int                 BorderConst[4];
  char*               imageDataOrigin;
} IplImage;


下面的程序设置图像ROI,对于感兴趣区域,增加他的蓝色通道像素值

//main image_name x y width height add#

#include 
#include 
 
int main(int argc, char** argv)
{
 
    IplImage* src;
    cvNamedWindow("Example3_12_pre", CV_WINDOW_AUTOSIZE);
    cvNamedWindow("Example3_12_post", CV_WINDOW_AUTOSIZE); 
    if( argc == 7 && ((src=cvLoadImage(argv[1],1)) != 0 ))
    {
        int x = atoi(argv[2]);//atoi(将字符串转为整数)
        int y = atoi(argv[3]);
        int width = atoi(argv[4]);
        int height = atoi(argv[5]);
        int add = atoi(argv[6]);
        cvShowImage( "Example3_12_pre", src);
        //cvSetImageROI设置图像中的感兴趣区域
        cvSetImageROI(src,cvRect(x,y,width,height));
        //蓝色通道增加像素add
        cvAddS(src, cvScalar(add),src);
        cvShowImage( "Example3_12_post",src);//只会显示感兴趣区域
        cvWaitKey();
        cvResetImageROI(src);
        cvShowImage( "Example3_12_post",src);
        cvWaitKey();
    }
    cvReleaseImage( &src );
    cvDestroyWindow("Example3_12_pre");
    cvDestroyWindow("Example3_12_post");  
    return 0;
}


对于cvSetImageROI()还可以设置掩码或模板,即他的第四个参数const CvArr* mask = NULL,一个8位单通道数组,将操作限制到任意形状的非0像素的掩码区。

 

当然也可以利用widthstep与指针遍历来构造一个子区域,相对于直接利用ROI的好处是,在需要对同一张图片的多个子区域进行处理时,不需要反复设置并取消ROI

int main(int argc, char** argv)
{
    IplImage* interest_img;
    CvRect interest_rect;
    if( argc == 7 && ((interest_img=cvLoadImage(argv[1],1)) != 0 ))
    {
        interest_rect.x = atoi(argv[2]);
        interest_rect.y = atoi(argv[3]);
        interest_rect.width = atoi(argv[4]);
        interest_rect.height = atoi(argv[5]);
        int add = atoi(argv[6]);
		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 );  
		//sub_img的数据部分指针指向的是interest_img的数据部分,因此下面只需要释放其header
        cvReleaseImageHeader(&sub_img);
        cvNamedWindow( "Roi_Add", CV_WINDOW_AUTOSIZE );
        cvShowImage( "Roi_Add", interest_img );
		cvReleaseImage(&interest_img);
		cvDestroyWindow("ROI_ADD");
        cvWaitKey();
    }
    return 0;
}

你可能感兴趣的:(learning,opencv,学习笔记)