Learning OpenCV 第三章:初识OpenCV学习总结

【注】不同的OpenCV版本会有所不同。

OpenCV的基本数据类型

结构 成员 意义
CvPoint int x, y  图像中的点
CvPoint2D32f float x, y 二维空间中的点
CvPoint3D32f ffloat x, y, z 三维空间中的点
CvSize int width, height 图像的尺寸
CvRect int x, y, width, height 图像的部分区域
CvScalar double val[4] RGBA的值,其中“A”表示透明度

其中,cvScalar有三个构造函数:

1.cvScalar(),它需要一到四个参数,并将这些参数传递给数组val[]中的相应元素。

2.cvRealScalar(), 它需要一个参数,并将这个参数传递给val[0].

3.cvScalarAll(), 它需要一个参数,并且val[]中4个元素都会被设置成这个参数。

矩阵和图像类型

OpenCV提供了大量使用的图像操作符,包括缩放图像,单通道提取,找出特定通道的最大最小值,两个图像求和,对图像进行阈值操作等等。

三种图像的类的层次结构:CvArr、CvMat、IplImage

实际上,IplImage由CvMat派生,而CvMat由CvArr派生。

CvArr,可以被是为一个抽象基类,CvMat由它派生。在函数原型中,会经常看到CvArr(CvArr*),当它出现时,便可以将CvMat*或者IplImage*传递到程序。

CvMat矩阵结构

【注意】在OpenCV中没有向量结构

矩阵元素可以是32位浮点型数据(CV_32FC1),或者无符号的8位三元组的整型数据(CV_8UC3),或者是无数的其他类型的元素。可以改变其中的通道数,如单通道:CV_32FC1,双通道:CV_32FC2,三通道:CV_32FC3。

CvMat结构:矩阵头


type struct CvMat{

int * refcount;
int step;//行数据长度,用字节表示而不是整型或者浮点型长度int type;//矩阵元素类型,32位浮点数CV_32FC1/无符号8位三元组CV_8UC3

union {

int height;//高度 int rows;//行数 }; union { int cols;//列数 int width;//宽度 }; union { double * db; float * fl;int * i; uchar * ptr;//无符号字符指针,范围是0-255 short * s; }data;}CvMat;

矩阵创建方法:

1.最常用的是cvCreateMat(),它由多个原函数组成,如:cvCreateMatHeader()和cvCreateData()。cvCreateMatHeader()函数创建CvMat结构,不为数据分配内存,而cvCreateDate()函数只负责数据的内存分配。

2.函数cvCloneMat(CvMat*),它依据一个现有矩阵创建一个新矩阵。当这个矩阵不需要时,可以调用cvReleaseMat(CvMat*)释放它。

矩阵的创建与释放:

//Create a new rows by cols matrix of type '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 structer
//在现有的CvMat结构上初始化矩阵头

CvMat* cvInitMatHeader ( CvMat *  mat,
    int  rows,
    int  cols,
    int  type,
    void *  data = NULL,
    int  step = 0x7fffffff 
  )  

Initializes a pre-allocated matrix header.

初始化一个预分配的矩阵头。

This function is often used to process raw data with OpenCV matrix functions.

For example, the following code computes the matrix product of two matrices, stored as ordinary arrays:

以下是两个矩阵乘积的示例:

double a[] = { 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12 };
double b[] = { 1, 5, 9,
2, 6, 10,
3, 7, 11,
4, 8, 12 };
double c[9];
CvMat Ma, Mb, Mc ;
cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a);
cvInitMatHeader(&Mb, 4, 3, CV_64FC1, b);
cvInitMatHeader(&Mc, 3, 3, CV_64FC1, c);
cvMatMulAdd(&Ma, &Mb, 0, &Mc);
// the c array now contains the product of a (3x4) and b (4x3)
参数意义如下:Parameters
mat A pointer to the matrix header to be initialized
rows Number of rows in the matrix
cols Number of columns in the matrix
type Type of the matrix elements, see cvCreateMat .
data Optional: data pointer assigned to the matrix header
step Optional: full row width in bytes of the assigned data. By default, the minimal possible step is used which assumes there are no gaps between subsequent rows of the matrix.
//Like cvInitMatHeader() but allocate CvMat as well.
//类似cvInitMatHeader()但是需要分配
CvMatInline constructor. No data is allocated internally!!!//不会自动分配内存!!!
(Use together with cvCreateData, or use cvCreateMat instead to get a matrix with allocated data)

//Allocate a new matrix just like the matrix 'mat'
//分配一个新的矩阵类似于‘mat’矩阵
CvMat* cvCloneMat(const cvMat mat);
【注】:函数cvCloneMat()和其他的OpenCV包含单词'clone'的函数,不仅创建一个和输入头同样的头,也分配各自的数据区并将数据复制到新对象。

//Free the matrix 'mat', both header and data
//释放一个矩阵,包括它的头部和数据。
void cvReleaseMat(CvMat** mat);
矩阵数据的存取

简单的方法:从矩阵中得到一个元素最简单的方法是利用宏CV_MAT_ELEM()。分别传入四个参数:待提取的矩阵、待提取元素的元素类型、元素所在的行数、列数。返回的是一个数值。有一个类似的宏:CV_MAT_ELEM_PTR(),返回指向这个元素的指针。若果需要对数据进行额外操作(比如同时读取和设置数据),直接调用CV_MAT_ELEM_PTR()即可。

注:虽然这些宏容易使用,但每次调用的时候要通过指针进行多次寻址,所以不是最佳办法。

麻烦的方法:使用cvPtr*D()和cvGet*D()函数族。对于cvPtr*D()来说返回的是一个指向所需元素的指针;对于cvGet*D()来说,返回的是矩阵元素的实际值。

以cvPtr1D为例:

uchar* cvPtr1D (

const CvArr * arr,//矩阵指针,输入的矩阵

int idx0,//表示索引的整数值
int * type = NULL //输出值(矩阵元素)的类型
)

注:CvArr*是只作为函数参数使用的元类型,它表示该函数有时接受多种类型的矩阵,例如IplImage*、CvMat*等。通过分析头的前4个字节,在运行时确定特定数组的类型。在c++接口,担任输入/输出矩阵类型的角色。

对于cvGet*D()函数族:

double cvGetReal1D (

const CvArr * arr,

int idx0 
)

CvScalar cvGet1D (

const CvArr * arr,

int idx0 
)

使用这些函数的时候会有很大空间的浪费,所以只有在认为这种方法比较方便或高效时才使用它们,否则最好使用cvPtr*D。

使用cvPtr*D()函数族还有另外一个原因,即可以用这些指针函数访问矩阵中的特定的点,然后由这个点出发,用指针的算数运算得到指向矩阵中其他数据的指针。在多通道矩阵中,通道是连续的。

IplImage数据结构

typedef struct _IplImage {
int align;
int alphaChannel;
int BorderConst [4];
int BorderMode [4];
char channelSeq [4];
char colorModel [4];
int dataOrder;
int depth;//以比特为单位的像素深度
int height;
int ID;//版本(=0)
char * imageData;//指向图像数据的指针
char * imageDataOrigin;
void * imageId;
int imageSize;
struct _IplImage * maskROI;
int nChannels;
int nSize;//尺寸
int origin;//0-左上角原点,1-左下角原点
struct _IplROI * roi;
struct _IplTileInfo * tileInfo;
int width;
int widthStep;//行长
}IplImage;

注:不常用参数通常被忽略。

重要参数:感兴趣的区域(ROI)。ROI的思想是:一旦设定ROI,通常用作于整幅图像的函数变回只对ROI所表示的子图像进行操作。

要设置或取消ROI,就要使用cvSetImageROI()和cvResetImageROI()。如果想设置ROI,可以使用函数cvSetImageROI(),并为其传递一个图像指针和矩形,而取消ROI,只需要为函数cvResetImageROI()传递图像指针。通过cvRestImageROI()函数释放ROI是非常重要的,否则,将只显示ROI区域。

猜你喜欢

转载自blog.csdn.net/SweetWind1996/article/details/80720786