【OpenCV学习】矩阵cvInitMatHeader和cvCreateMat

opencv里面矩阵的表示有很多种,以cvCreateMat为例,矩阵操作整体流程大致为:

1. 分配矩阵空间。

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

2. 初始化矩阵。

double  a[] = { 1,   2,   3,   4,   5,   6,   7,   8 };   
CvMat Ma=cvMat(2, 4, CV_64FC1, a);

3. 操作矩阵。

//如复制矩阵: 
CvMat* M1 = cvCreateMat(4,4,CV_32FC1);   
CvMat* M2;   
M2=cvCloneMat(M1);

4. 释放矩阵空间。

CvMat* M = cvCreateMat(4,4,CV_32FC1);   
cvReleaseMat(&M);




OK,下面详细介绍这些个流程

1)分配矩阵空间

常用两种方法:

1.1    CvMat* cvCreateMat( int rows, int cols, int type )。

        a,看他返回是一个CvMat *,所以要先定义一个CvMat *mat;指针;

        b,分配指针空间,mat=cvCreateMat(2,4,CV_64FC1);

        c,分配了指针空间当然要释放掉,用cvReleaseMat(&mat);

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

        a,第一个参数必须是CvMat格式的,官方的文档是CvMat *mat,但是这里要注意,mat必须是初始化过的,单独定义一个指针如CvMat *data1;把data1带入cvInitMatHeader函数后,编译器会报错,显示没有初始化!

        b,分配矩阵头指针,cvInitMatHeader(&mat,3,4,CV_64FC1);

        c,当然是必不可少的释放掉空间,但是这个释放空间是用的函数是free(&mat).


2)矩阵的赋值

矩阵的赋值方式,有一个共同的方式,就是用cvmSet(&mat,i,j,data); 

在前面定义的时候,如果是用的CvMat * ,这个样子的就是CvmSet(mat,i,j,data);

如果是用CvMat ,这个时候就是CvmSet(&mat,i,j,data);

例如:

double a[] = { 1, 2, 3, 4, 5, 6, 7, 8};
CvMat Ma;
cvInitMatHeader( &Ma, 2, 4, CV_64FC1, a );


3)存取矩阵元素

假设需要存取一个2维浮点矩阵的第(i,j)个元素. 

//间接存取矩阵元素: 
cvmSet(M,i,j,2.0); // Set M(i,j)    
t = cvmGet(M,i,j); // Get M(i,j)    
  
//直接存取,假设使用4-字节校正: 
CvMat* M = cvCreateMat(4,4,CV_32FC1);   
int n = M->cols;   
float *data = M->data.fl;   
data[i*n+j] = 3.0;   
  
//直接存取,校正字节任意: 
CvMat* M = cvCreateMat(4,4,CV_32FC1);   
int step = M->step/sizeof (float );   
float *data = M->data.fl;   
(data+i*step)[j] = 3.0;   
  
//直接存取, 一个初始化的矩阵元素: 
double  a[16];   
CvMat Ma = cvMat(3, 4, CV_64FC1, a);   
a[i*4+j] = 2.0; //Ma(i,j)=2.0; 

4)向量操作

//矩阵-矩阵操作: 
CvMat *Ma, *Mb, *Mc;   
cvAdd(Ma, Mb, Mc);       // Ma+Mb    -> Mc    
cvSub(Ma, Mb, Mc);       // Ma-Mb    -> Mc    
cvMatMul(Ma, Mb, Mc);    // Ma*Mb    -> Mc    
  
//按元素的矩阵操作: 
CvMat *Ma, *Mb, *Mc;   
cvMul(Ma, Mb, Mc);       // Ma.*Mb   -> Mc    
cvDiv(Ma, Mb, Mc);       // Ma./Mb   -> Mc    
cvAddS(Ma, cvScalar(-10.0), Mc); // Ma.-10 -> Mc    
  
//向量乘积: 
double  va[] = {1, 2, 3};   
double  vb[] = {0, 0, 1};   
double  vc[3];   
CvMat Va=cvMat(3, 1, CV_64FC1, va);   
CvMat Vb=cvMat(3, 1, CV_64FC1, vb);   
CvMat Vc=cvMat(3, 1, CV_64FC1, vc);   
double  res=cvDotProduct(&Va,&Vb); // 点乘: Va . Vb -> res    
cvCrossProduct(&Va, &Vb, &Vc);     // 向量积: Va x Vb -> Vc    
end{verbatim}   
  
//注意 Va, Vb, Vc 在向量积中向量元素个数须相同.

//单矩阵操作: 
CvMat *Ma, *Mb;   
cvTranspose(Ma, Mb);       // transpose(Ma) -> Mb (不能对自身进行转置)    
CvScalar t = cvTrace(Ma); // trace(Ma) -> t.val[0]     
double  d = cvDet(Ma);   // det(Ma) -> d    
cvInvert(Ma, Mb);  // inv(Ma) -> Mb    
  
//非齐次线性系统求解: 
CvMat* A   = cvCreateMat(3,3,CV_32FC1);   
CvMat* x   = cvCreateMat(3,1,CV_32FC1);   
CvMat* b   = cvCreateMat(3,1,CV_32FC1);   
cvSolve(&A, &b, &x);  // solve (Ax=b) for x    
  
//特征值分析(针对对称矩阵): 
CvMat* A   = cvCreateMat(3,3,CV_32FC1);   
CvMat* E   = cvCreateMat(3,3,CV_32FC1);   
CvMat* l   = cvCreateMat(3,1,CV_32FC1);   
cvEigenVV(&A, &E, &l);   // l = A的特征值 (降序排列) ,E = 对应的特征向量 (每行)    
  
//奇异值分解SVD: 
CvMat* A   = cvCreateMat(3,3,CV_32FC1);   
CvMat* U   = cvCreateMat(3,3,CV_32FC1);   
CvMat* D   = cvCreateMat(3,3,CV_32FC1);   
CvMat* V = cvCreateMat(3,3,CV_32FC1);   
cvSVD(A, D, U, V, CV_SVD_U_T|CV_SVD_V_T); // A = U D V^T  

好吧,思路有些乱,用OpenCV也有很长时间了,但是一直没有整理过,导致感觉知识很散,这段时间相对较闲,从以前的笔记、网络上搜集的资料,一起整理下自己知识体系。


===附注:如果知晓CV_32FC1和CV_64FC1,请忽略此部分===

关于cvInitMatHeader之CV_32FC1和CV_64FC1的说明:

type: 矩阵元素类型. 格式为CV_<bit_depth>(S|U|F)C<number_of_channels>. 
例如: CV_8UC1 表示8位无符号单通道矩阵, CV_32SC2表示32位有符号双通道矩阵.
例程: CvMat* M = cvCreateMat(4,4,CV_32FC1); 

CV_32FC1和CV_64FC1,前者是32位数据,后者是64位数据。因此前者类型的数据必须以指向32位数据类型的指针存取,否则会报错,而后者类型的数据必须以指向64位数据类型的指针存取,否则会报错。

如果用cv_32fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是float,这在32位编译器上是32位浮点数,也就是单精度。如果用cv_64fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是double,这在32位编译器上是64位浮点数,也就是双精度。

好吧,看下网上的一个例子,稍作修改:

#include "cv.h"
#include "highgui.h"
#include <stdio.h>

void PrintMat(CvMat *A); // 显示矩阵
void Test_Multiply(); // 测试矩阵乘法
void Test_Multiply64();
int main()
{
	printf("=== Test multiply ===\n");
	printf("CV_32FC1:");
	Test_Multiply(); // pass
	printf("\n\nCV_64FC1:");
	Test_Multiply64();
	getchar();
	return 0;
}

// 显示矩阵
void PrintMat(CvMat* A)
{
	int i,j;
	printf("\nMatrix:");
	for(i=0;i<A->rows;i++)
	{
		printf("\n");
		switch( CV_MAT_DEPTH(A->type) )
		{
		case CV_32F:
		case CV_64F:
			for(j=0;j<A->cols;j++)
				printf("%9.3f ", (float) cvGetReal2D( A, i, j ));
			break;
		case CV_8U:
		case CV_16U:
			for(j=0;j<A->cols;j++)
				printf("%6d",(int)cvGetReal2D( A, i, j ));
			break;
		default:
			break;
		}
	}
	printf("\n");
}


void Test_Multiply()
{
	float a[] = { 1, 2, 3, 4 };
	float b[] = { 1, 2, 3, 4 };
	float c[1];

	CvMat Ma, Mb, Mc;

	//CV_32FC1和CV_64FC1,前者是32位数据,后者是64位数据。
	//因此前者类型的数据必须以指向32位数据类型的指针存取,否则会报错,
	//而后者类型的数据必须以指向64位数据类型的指针存取,否则会报错。
	//cvInitMatHeader( &Ma, 3, 4, CV_64FC1, a, CV_AUTOSTEP );
	//cvInitMatHeader( &Mb, 4, 3, CV_64FC1, b, CV_AUTOSTEP );
	//cvInitMatHeader( &Mc, 3, 3, CV_64FC1, c, CV_AUTOSTEP );

	//如果用cv_32fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是float,这在32位编译器上是32位浮点数,也就是单精度。
	//如果用cv_64fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是double,这在32位编译器上是64位浮点数,也就是双精度。
	cvInitMatHeader( &Ma, 1, 4, CV_32FC1, a, CV_AUTOSTEP );
        cvInitMatHeader( &Mb, 4, 1, CV_32FC1, b, CV_AUTOSTEP );
        cvInitMatHeader( &Mc, 1, 1, CV_32FC1, c, CV_AUTOSTEP );

	cvMatMulAdd( &Ma, &Mb, 0, &Mc );

	PrintMat(&Ma);
	PrintMat(&Mb);
	PrintMat(&Mc);
	return;
}

void Test_Multiply64()
{
	double a[] = { 1, 2, 3, 4 };
	double b[] = { 1, 2, 3, 4 };
	double c[1];

	CvMat Ma, Mb, Mc;
	//CV_32FC1和CV_64FC1,前者是32位数据,后者是64位数据。
	//因此前者类型的数据必须以指向32位数据类型的指针存取,否则会报错,
	//而后者类型的数据必须以指向64位数据类型的指针存取,否则会报错。
	cvInitMatHeader( &Ma, 1, 4, CV_64FC1, a, CV_AUTOSTEP );
	cvInitMatHeader( &Mb, 4, 1, CV_64FC1, b, CV_AUTOSTEP );
	cvInitMatHeader( &Mc, 1, 1, CV_64FC1, c, CV_AUTOSTEP );
	
	//如果用cv_32fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是float,这在32位编译器上是32位浮点数,也就是单精度。
	//如果用cv_64fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是double,这在32位编译器上是64位浮点数,也就是双精度。
        //cvInitMatHeader( &Ma, 1, 4, CV_32FC1, a, CV_AUTOSTEP );
        //cvInitMatHeader( &Mb, 4, 1, CV_32FC1, b, CV_AUTOSTEP );
        //cvInitMatHeader( &Mc, 1, 1, CV_32FC1, c, CV_AUTOSTEP );

	cvMatMulAdd( &Ma, &Mb, 0, &Mc );

	PrintMat(&Ma);
	PrintMat(&Mb);
	PrintMat(&Mc);
	return;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值