您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > opencv基础知识(好资料)
OpenCV的基本数据类型OpenCV提供了多种基本数据类型。虽然这些数据类型在C语言中不是基本类型,但结构都很简单,可将它们作为原子类型。可以在“…/OpenCV/cxcore/include”目录下的cxtypes.h文件中查看其详细定义。在这些数据类型中最简单的就是CvPoint。CvPoint是一个包含integer类型成员x和y的简单结构体。CvPoint有两个变体类型:CvPoint2D32f和CvPoint3D32f。前者同样有两个成员x,y,但它们是浮点类型;而后者却多了一个浮点类型的成员z。CvSize类型与CvPoint非常相似,但它的数据成员是integer类型的width和height。如果希望使用浮点类型,则选用CvSize的变体类型CvSize2D32f。CvRect类型派生于CvPoint和CvSize,它包含4个数据成员:x,y,width和height。(正如你所想的那样,该类型是一个复合类型)。下一个(但不是最后一个)是包含4个整型成员的CvScalar类型,当内存不是问题时,CvScalar经常用来代替1,2或者3个实数成员(在这个情况下,不需要的分量被忽略)。CvScalar有一个单独的成员val,它是一个指向4个双精度浮点数数组的指针。所有这些数据类型具有以其名称来定义的构造函数,例如cvSize()。(构造函数通常具有与结构类型一样的名称,只是首字母不大写)。记住,这是C而不是C++,所以这些构造函数只是内联函数,它们首先提取参数列表,然后返回被赋予相关值的结构。【31】各数据类型的内联构造函数被列在表3-1中:cvPointXXX(),cvSize(),cvRect()和cvScalar()。这些结构都十分有用,因为它们不仅使代码更容易编写,而且也更易于阅读。假设要在(5,10)和(20,30)之间画一个白色矩形,只需简单调用:cvRectangle(myImg,cvPoint(5,10),cvPoint(20,30),cvScalar(255,255,255));表3-1:points,size,rectangles和calar三元组的结构结构成员意义CvPointintx,y图像中的点CvPoint2D32ffloatx,y二维空间中的点CvPoint3D32ffloatx,y,z三维空间中的点CvSizeintwidth,height图像的尺寸CvRectintx,y,width,height图像的部分区域CvScalardoubleval[4]RGBA值cvScalar是一个特殊的例子:它有3个构造函数。第一个是cvScalar(),它需要一个、两个、三个或者四个参数并将这些参数传递给数组val[]中的相应元素。第二个构造函数是cvRealScalar(),它需要一个参数,它被传递给给val[0],而val[]数组别的值被赋为0。最后一个有所变化的是cvScalarAll(),它需要一个参数并且val[]中的4个元素都会设置为这个参数。矩阵和图像类型图3-1为我们展示了三种图像的类或结构层次结构。使用OpenCV时,会频繁遇到IplImage数据类型,第2章已经出现多次。IplImage是我们用来为通常所说的“图像”进行编码的基本结构。这些图像可能是灰度,彩色,4通道的(RGB+alpha),其中每个通道可以包含任意的整数或浮点数。因此,该类型比常见的、易于理解的3通道8位RGB图像更通用。OpenCV提供了大量实用的图像操作符,包括缩放图像,单通道提取,找出特定通道最大最小值,两个图像求和,对图像进行阈值操作,等等。本章我们将仔细介绍这类操作。【32】图3-1:虽然OpenCV是由C语言实现的,但它使用的结构体也是遵循面向对象的思想设计的。实际上,IplImage由CvMat派生,而CvMat由CvArr派生在开始探讨图像细节之前,我们需要先了解另一种数据类型CvMat,OpenCV的矩阵结构。虽然OpenCV完全由C语言实现,但CvMat和IplImage之间的关系就如同C++中的继承关系。实质上,IplImage可以被视为从CvMat中派生的。因此,在试图了解复杂的派生类之前,最好先了解基本的类。第三个类CvArr,可以被视为一个抽象基类,CvMat由它派生。在函数原型中,会经常看到CvArr(更准确地说,CvArr*),当它出现时,便可以将CvMat*或IplImage*传递到程序。CvMat矩阵结构在开始学习矩阵的相关内容之前,我们需要知道两件事情。第一,在OpenCV中没有向量(vector)结构。任何时候需要向量,都只需要一个列矩阵(如果需要一个转置或者共轭向量,则需要一个行矩阵)。第二,OpenCV矩阵的概念与我们在线性代数课上学习的概念相比,更抽象,尤其是矩阵的元素,并非只能取简单的数值类型。例如,一个用于新建一个二维矩阵的例程具有以下原型:cvMat*cvCreateMat(introws,intcols,inttype);这里type可以是任何预定义类型,预定义类型的结构如下:CV_bit_depth(S|U|F)Cnumber_of_channels。于是,矩阵的元素可以是32位浮点型数据(CV_32FC1),或者是无符号的8位三元组的整型数据(CV_8UC3),或者是无数的其他类型的元素。一个CvMat的元素不一定就是个单一的数字。在矩阵中可以通过单一(简单)的输入来表示多值,这样我们可以在一个三原色图像上描绘多重色彩通道。对于一个包含RGB通道的简单图像,大多数的图像操作将分别应用于每一个通道(除非另有说明)。实质上,正如例3-1所示,CvMat的结构相当简单,(可以自己打开文件…/opencv/cxcore/include/cxtypes.h查看)。矩阵由宽度(width)、高度(height)、类型(type)、行数据长度(step,行的长度用字节表示而不是整型或者浮点型长度)和一个指向数据的指针构成(现在我们还不能讨论更多的东西)。可以通过一个指向CvMat的指针访问这些成员,或者对于一些普通元素,使用现成的访问方法。例如,为了获得矩阵的大小,可通过调用函数vGetSize(CvMat*),返回一个CvSize结构,便可以获取任何所需信息,或者通过独立访问高度和宽度,结构为matrix-height和matrix-width。【33~34】例3-1:CvMat结构:矩阵头typedefstructCvMat{inttype;intstep;int*refcount;//forinternaluseonlyunion{uchar*ptr;short*s;int*i;float*fl;double*db;}data;union{introws;intheight;};union{intcols;intwidth;};}CvMat;此类信息通常被称作矩阵头。很多程序是区分矩阵头和数据体的,后者是各个data成员所指向的内存位置。矩阵有多种创建方法。最常见的方法是用cvCreateMat(),它由多个原函数组成,如cvCreateMatHeader()和cvCreateData()。cvCreateMatHeader()函数创建CvMat结构,不为数据分配内存,而cvCreateData()函数只负责数据的内存分配。有时,只需要函数cvCreateMatHeader(),因为已因其他理由分配了存储空间,或因为还不准备分配存储空间。第三种方法是用函数cvCloneMat(CvMat*),它依据一个现有矩阵创建一个新的矩阵。当这个矩阵不再需要时,可以调用函数cvReleaseMat(CvMat*)释放它。【34】例3-2概述了这些函数及其密切相关的其他函数。例3-2:矩阵的创建和释放//Createanewrowsbycolsmatrixoftype'type'.//CvMat*cvCreateMat(introws,intcols,inttype);//Createonlymatrixheaderwithoutallocatingdata//CvMat*cvCreateMatHeader(introws,intcols,inttype);//InitializeheaderonexistiongCvMatstructure//CvMat*cvInitMatHeader(CvMat*mat,introws,intcols,inttype,void*data=NULL,intstep=CV_AUTOSTEP);//LikecvInitMatHeader()butallocatesCvMataswell.//CvMatcvMat(introws,intcols,inttype,void*data=NULL);//Allocateanewmatrixjustlikethematrix'mat'.//CvMat*cvCloneMat(constcvMat*mat);//Freethematrix'mat',bothheaderanddata.//voidcvReleaseMat(CvMat**mat);与很多OpenCV结构类似,有一种构造函数叫cvMat,它可以创建CvMat结构,但实际上不分配存储空间,仅创建头结构(与cvInitMatHeader()类似)。这些方法对于存取到处散放的数据很有作用,可以将矩阵头指向这些数据,实现对这些数据的打包,并用操作矩阵的函数去处理这些数据,如例3-3所示。例3-3:用固定数据创建一个OpenCV矩阵//CreateanOpenCVMatrixcontainingsomefixeddata.//floatvals[]={0.866025,-0.500000,0.500000,0.866025};CvMatrotmat;cvInitMatHeader(&rotmat,2,2,CV_32FC1,vals);一旦我们创建了一个矩阵,便可用它来完成很多事情。最简单的操作就是查询数组定义和数据访问等。为查询矩阵,我们可以使用函数cvGetElemType(constCvArr*arr),cvGetDims(constCvArr*arr,int*sizes=NULL)和cvGet-DimSize(constCvArr*arr,intindex)。第一个返回一个整型常数,表示存储在数组里的元素类型(它可以为CV_8UC1和CV_64FC4等类型)。第二个取出数组以及一个可选择的整型指针,它返回维数(我们当前的实例是二维,但是在后面我们将遇到的N维矩阵对象)。如果整型指针不为空,它将存储对应数组的高度和宽度(或者N维数)。最后的函数通过一个指示维数的整型数简单地返回矩阵在那个维数上矩阵的大小。【35~36】矩阵数据的存取访问矩阵中的数据有3种方法:简单的方法、麻烦的方法和恰当的方法。简单的方法从矩阵中得到一个元素的最简单的方法是利用宏CV_MAT_ELEM()。这个宏(参见例3-4)传入矩阵、待提取的元素的类型、行和列数4个参数,返回提取出的元素的值。例3-4:利用CV_MAT_ELEM()宏存取矩阵CvMat*mat=cvCreateMat(5,5,CV_32FC1);floatelement_3_2=CV_MAT_ELEM(*mat,float,3,2);更进一步,还有一个与此宏类似的宏,叫CV_MAT_ELEM_PTR()。CV_MAT_ELEM_PTR()(参见例3-5)传入矩阵、待返回元素的行和列号这3个参数,返回指向这个元素的指针。该宏和CV_MAT_ELEM()宏的最重要的区别是后者在指针解引用之前将其转化成指定的类型。如果需要同时读取数据和设置数据,可以直接调用CV_MAT_ELEM_PTR()。但在这种情况下,必须自己将指针转化成恰当的类型。例3-5:利用宏CV_MAT_ELEM_PTR()为矩阵设置一个数值CvMat*mat=cvCreateMat(5,5,CV_32FC1);floa
本文标题:opencv基础知识(好资料)
链接地址:https://www.777doc.com/doc-5233481 .html