分享

(转载)OpenCV中矩阵的定义

 昵称14479769 2013-11-03

OpenCV中矩阵的定义(Learning OpenCV第三章)

OpenCV是Intel?开源计算机视觉库。它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法。
关于OpenCV的基本使用,大家可以去看网站http://www.。我这里是学习一本书Learning OpenCV时,所进行的资料整理。
当使用OpenCV时,你会经常使用IplImage类型,该类型是OpenCV的基础图像类型。图像可能是灰度图,彩色图,四通道图(RGB+Alpha)等,而每个通道可能是整数或浮点数类型。OpenCV提供了对图像的大量处理操作函数。
在我们讨论IplImage之前,我们需要看另一个数据类型:CvMat,即OpenCV的矩阵类型。尽管OpenCV是用C语言实现的,但是CvMat和IplImage的关系其实就类似于C++中的类的继承关系。IplImage类继承自CvMat类。所以,我们最好先了解一下IplImage的基类CvMat类的情况,然后再看更复杂的IplImage类。而CvArr类,是CvMat类的抽象基类。正因为CvArr类是基类,所以当我们看到OpenCV的函数参数为CvArr*类型的参数时,我们可以代入CvMat*或者IplImage*类型的实参。
CvMat矩阵数据结构
当我们学习CvMat之前,我们必须知道两个事情,首先OpenCV中是没有"vector(向量)"数据类型的,当我们需要一个"vector"时,我们就使用一个三行一列的矩阵。其次,OpenCV中矩阵的概念比线性代数中矩阵的概念更抽象和复杂一些一些。例如,创建矩阵的函数:CvMat* cvCreateMat(int rows,int cols,int type),其中type代表预定义的数据类型,即矩阵中每一个元素的数据类型,该类型的形式是:CV_<bit数>(S|U|F)C<通道数>,例如,数据类型可能是CV32FC1,即32bit的浮点数,或CV_8UC3,8bit的无符号整数,或CV_8UC3,无符号8bit整数,3通道,等等。我们会发现,cvMat里,矩阵中行和列上的每一个元素,不必是一个单独的数字,可能是一系列数字(有几个通道就有几个数字)。每一个元素可以代表多个值,就允许了我们在矩阵中包含一个RGB的图像。
从内部的结构上看,CvMat相当的简单,我们可以通过代码看一下该数据结构的原型(代码在.../opencv/cxcore/include/cxtypes.h):
其中包含了width,height,type,step(是一行元素的长度,与width类似,但以字节计算),以及指向数据的指针.你可以通过CvMat数据类型的变量直接接触该类型内部的成员,例如,CvMat* matrix ,就可以用matrix->height,matrix->width来获得矩阵的尺寸。又或者通过OpenCV的函
数来获得。例如,可以用cvGetSize(CvMat*)来获得CvSize对象,这代表该矩阵的长和宽。
typedef struct CvMat
{
    int type;
    int step;

    /* for internal use only */
    int* refcount;
    int hdr_refcount;

    union
    {
        uchar* ptr;
        short* s;
        int* i;
        float* fl;
        double* db;
    } data;

#ifdef __cplusplus
    union
    {
        int rows;
        int height;
    };

    union
    {
        int cols;
        int width;
    };
#else
    int rows;
    int cols;
#endif

}
CvMat;

以上,是该CvMat类型的数据的“头部”,即矩阵的定义部分。许多OpenCV的函数,将矩阵的头部和数据部分分开处理。
矩阵的创建可以用多种方法,最简单的一种是CvMat* cvCreateMat(int rows,int cols,int type),该方法既设置了矩阵的头部,又为数据部分分配了内存空间,该函数是cvCreateMatHeader()和cvCreateData()的合并缩写。cvCreateMatHeader()只创建CvMat头部,但不为数据部分分配空间。而cvCreateData()则是为矩阵的数据部分分配了内存空间。有时候,我们只需要cvCreateMatHeader()就可以了,因为基于一些理由,我们可能已经为数据部分分配了空间,或者此时分配空间还不是时候。另一个创建矩阵的方法cvCloneMat(CvMat*)是从一个已经有的矩阵,来“克隆”出一个新的矩阵来。当我们不再需要某矩阵时,我们需要调用长cvReleaseMat(CvMat*)来释放它。
就象其他的OpenCV数据类型一样,矩阵数据类型有一个构造函数,CvMat cvMat( int rows, int cols, int type, void* data=NULL );这个函数没有为矩阵的数据部分分配空间,只是初始化了矩阵的头部,类似cvInitMatheader()。

以下是这些函数的原型:

1,CreateMat

创建矩阵

CvMat* cvCreateMat( int rows, int cols, int type );

rows
    矩阵行数。
cols
    矩阵列数。
type
    矩阵元素类型。 通常以 CV_<比特数>(S|U|F)C<通道数>型式描述, 例如:

   CV_8UC1 意思是一个8-bit 无符号单通道矩阵, CV_32SC2 意思是一个32-bit 有符号二个通道的矩阵。

函数 cvCreateMat 为新的矩阵分配头和下面的数据,并且返回一个指向新创建的矩阵的指针。是下列操作的缩写型式:

CvMat* mat = cvCreateMatHeader( rows, cols, type );
cvCreateData( mat );
矩阵按行存贮。所有的行以4个字节对齐。


2,CreateMatHeader

创建新的矩阵头

CvMat* cvCreateMatHeader( int rows, int cols, int type );

rows

   矩阵行数.

cols
    矩阵列数.
type
    矩阵元素类型(见 cvCreateMat).

函数 cvCreateMatHeader 分配新的矩阵头并且返回指向它的指针. 矩阵数据可被进一步的分配,使用cvCreateData 或通过 cvSetData明确的

分配数据.


3,ReleaseMat

删除矩阵

void cvReleaseMat( CvMat** mat );

mat
    双指针指向矩阵.

函数cvReleaseMat 缩减矩阵数据参考计数并且释放矩阵头 :

if( *mat )
    cvDecRefData( *mat );
cvFree( (void**)mat );

4,InitMatHeader

初始化矩阵头

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

mat
    指针指向要被初始化的矩阵头.
rows
    矩阵的行数.
cols
    矩阵的列数.
type
    矩阵元素类型.
data
    可选的,将指向数据指针分配给矩阵头.
step
    排列后的数据的整个行宽,默认状态下,使用STEP的最小可能值。也就是说默认情况下假定矩阵的行与行之间无隙.

函数 cvInitMatHeader 初始化已经分配了的 CvMat 结构. 它可以被OpenCV矩阵函数用于处理原始数据。

例如, 下面的代码计算通用数组格式存贮的数据的矩阵乘积.

计算两个矩阵的积

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 );
// c 数组存贮 a(3x4) 和 b(4x3) 矩阵的积


5,Mat

初始化矩阵的头

CvMat cvMat( int rows, int cols, int type, void* data=NULL );

rows
    矩阵行数
cols
    列数.
type
    元素类型(见CreateMat).
data
    可选的分配给矩阵头的数据指针 .

函数 cvMat 是个一快速内连函数,替代函数 cvInitMatHeader. 也就是说它相当于:

CvMat mat;
cvInitMatHeader( &mat, rows, cols, type, data, CV_AUTOSTEP );

6,CloneMat

创建矩阵拷贝

CvMat* cvCloneMat( const CvMat* mat );

mat
    输入矩阵.

函数 cvCloneMat 创建输入矩阵的一个拷贝并且返回该矩阵的指针.

以下的例子中,我们让矩阵的数据部分指向了已经分配好了的数据:

float vals[] = { 0.866025, -0.500000, 0.500000, 0.866025};
  
CvMat rotmat;
  
cvInitMatHeader(
    &rotmat,
    2,
    2,
    CV_32FC1,
    vals
);
当我们定义好了矩阵,我们可以通过一些函数查看矩阵的属性,例如:cvGetElemType(const cvArr* arr),cvGetDims(const CvArr* arr,int*

sizes=NULL),cvGetDimSize(const CvArr* arr,index)

7.GetElemType

返回数组元素类型

int cvGetElemType( const CvArr* arr );

arr
    输入数组.

函数 GetElemType 返回数组元素类型就像在cvCreateMat 中讨论的一样:

    CV_8UC1 ... CV_64FC4


8.GetDims, GetDimSize

返回数组维数和他们的大小或者特殊维的大小

int cvGetDims( const CvArr* arr, int* sizes=NULL );
int cvGetDimSize( const CvArr* arr, int index );

arr
    输入数组.
sizes
    可选的输出数组维尺寸向量,对于2D数组第一位是数组行数(高),第二位是数组列数(宽)
index
    以0为基准的维索引下标(对于矩阵0意味着行数,1意味着列数,对于图象0意味着高,1意味着宽。

函数 cvGetDims 返回维数和他们的大小。如果是 IplImage 或 CvMat 总是返回2,不管图像/矩阵行数。函数 cvGetDimSize 返回特定的维大小(每维的元素数)。

以下是一个例子:
#pragma comment( lib, "cxcore.lib" )
#include "cv.h"
#include <stdio.h>
void main()
{
CvMat rotmat;
int sizes[2];
float array[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
//注意,此句更改为 cvInitMatHeader(&rotmat,3,5,CV_32FC1,NULL);时,cvGetDimSize不能起作用
cvInitMatHeader(&rotmat,3,5,CV_32FC1,array);
int type = cvGetElemType(&rotmat);
cvGetDims(&rotmat,sizes);
printf("type=%d\n",type);
printf("height=%d,width=%d\n",sizes[0],sizes[1]);
printf("height=%d,width=%d\n",cvGetDimSize(&rotmat, 0),cvGetDimSize(&rotmat, 1));
}


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多