引言
矩阵和图像的使用与操作是掌握OpenCV(C语言版)的基本功能。本节主要介绍OpenCV中C语言版(OpenCV2.0以下)的矩阵使用方法。
矩阵分配与释放
OpenCV有一个矩阵操作的C语言接口,另外也有一些C++语言的矩阵操作接口,通常C++语言接口更方便,且同样有效。在OpenCV中,向量被当成是行或列为1的矩阵,并且矩阵在内存中的存储方式是按行存储,且每行按4字节对齐。
分配矩阵
分配矩阵的函数原型为:
CvMat* cvCreateMat(int rows, in cols,int type);
其中,type表示矩阵元素的类型,可以用形式表达为
CV_<bit_depth>(C|U|F)C<number_of_channels>.
如:CvMat* cMat = cvCreateMat(3,5,CV_32FC1);
释放矩阵
释放矩阵的函数原型为:
void cvReleaseMat(CvMat**);
如:
CvMat* cMat = cvCreateMat(3,5,CV_32FC1);
cvReleaseMat(&cMat);
复制矩阵
复制矩阵的函数原型为:
CvMat* cvCloneMat(CvMat*);
如:CvMat* cMat = cvCreateMat(3,5,CV_32FC1);
CvMat* cMat1;
cMat1 = cvCloneMat(cMat);
初始化矩阵
按如下方法初始化矩阵。
double data[] = {1,2,3,4,5,6,7,8,9,10,11,12};
CvMat cMat = cvMat(3,4,CV_64FC1,data);
或者
CvMat cMat;
cvInitMatHeader(&cMat, 3, 4, CV_64FC1,data);
访问矩阵元素
若访问一个浮点数矩阵的第i行第j列元素,可采用以下几种方式。
直接访问
下列元素M(i, j)进行数据赋值和读取。
cvmSet(M,i,j, 2,0); //set M(i,j)
cMat = cvmGet(M,i,j); //get M(i,j)
已知对齐方式的直接访问
以32元素对齐方式存储的元素进行数据赋值。
CvMat* cMat = cvCreateMat(3,4, CV_32FC1);
int n = cMat ->cols;
float * data = cMat ->data.fl;
data[i*n+j] = 5.0;
未知对齐方式的直接访问
对以某种对齐方式存储的元素进行数据赋值。
CvMat* cMat = CvCreateMat(3,4,CV_32FC1);
int step = cMat->step/sizeof(float);
float *data = cMat ->data.fl;
(data+i*step)[j] = 5.0;
直接访问一个已初始化的矩阵
对已初始化的矩阵a进行数据赋值
double a[10];
CvMat cMat = cvMat(2,4,CV_64FC1,a);
a[i*4+j] = 5.0; //cMat(i,j) = 5.0
矩阵和向量操作
对矩阵和向量的操作分为几种类型.即:矩阵与矩阵之间的操作,矩阵元素之间的操作,向量乘法操作,单个矩阵操作,非齐次线性系统的求解操作,对称矩阵操作和奇齐值分解操作。在此给出矩阵操作的实例。体会如何进行矩阵操作,参考代码如下所示:
二维序列排序实例
// Testing: Sort 2d points in top-to-bottom left-to-right order.
void cvMatTest::Test_SeqSort()
{
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* seq = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage );
int i;
printf("\n=== Test sequence sorting ===");
for( i = 0; i < 10; i++ ){
CvPoint pt;
pt.x = rand() % 1000;
pt.y = rand() % 1000;
cvSeqPush( seq, &pt );
}
printf("\nOriginal point set:\n");
for( i = 0; i < seq->total; i++ ){
CvPoint* pt = (CvPoint*)cvGetSeqElem( seq, i );
printf( "(%d,%d)\n", pt->x, pt->y );
}
cvSeqSort( seq, cmp_func, 0 /* userdata is not used here */ );
/* print out the sorted sequence */
printf("\nAfter sorting:\n");
for( i = 0; i < seq->total; i++ ){
CvPoint* pt = (CvPoint*)cvGetSeqElem( seq, i );
printf( "(%d,%d)\n", pt->x, pt->y );
}
cvClearSeq( seq ); // Sequence clearing should be done before storage clearing
cvReleaseMemStorage( &storage );
}
测试输出结果:
生成随机数实例
/*
Generate normally distributed random numbers.
Fill random numbers to arr, of a normal distribution
with mean zero and variance one.
seed is the random generator seed.
Array arr should be pre-allocated before calling this function
*/
void cvMatTest::GenRandn(CvMat* arr, int seed)
{
// let's noisy_screen be the floating-point 2d array that is to be "crapped"
CvRandState rng;
// modify RNG to make it produce normally distributed values
rng.state = cvRNG(0xffffffff);
cvRandInit( &rng,
0, 1, // use dummy parameters now and adjust them further
seed, // use input seed here
CV_RAND_NORMAL // specify uniform type
);
// fill random numbers to arr, with mean zero and variance one
cvRandArr( &rng.state, arr, CV_RAND_NORMAL,
cvRealScalar(0), // average intensity
cvRealScalar(1) // deviation of the intensity
);
// RNG state does not need to be deallocated
}
void cvMatTest::Test_Rand(){
CvMat* a = cvCreateMat( 10, 6, CV_32F );
int i;
printf("\n=== Test generating random matrix ===");
for(i=0;i<5;i++){
cvMatTest::GenRandn(a, i);
PrintMat(a);
}
cvReleaseMat(&a);
}
测试输出结果:
计算DCT变换实例
// test 1-d and 2-d dct transform
void cvMatTest::Test_DCT(){
float data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
CvMat a;
a = cvMat(2,4,CV_32FC1,data);
printf("\n=== Test DCT ===");
printf("\nOriginal matrix = "); PrintMat(&a);
cvDCT(&a, &a, CV_DXT_FORWARD);
printf("\n2-D DCT = "); PrintMat(&a);
cvDCT(&a, &a, CV_DXT_INVERSE);
printf("\n2-D IDCT = "); PrintMat(&a);
}
测试输出结果:
测试矩阵乘法和将缓存数据填入CvMat数组中实例
// Test matrix multiply
void cvMatTest::Test_Multiply(){
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;
printf("\n=== Test multiply ===");
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 );
cvMatMulAdd( &Ma, &Mb, 0, &Mc );
PrintMat(&Ma);
PrintMat(&Mb);
PrintMat(&Mc);
return;
}
// Get raw data from data buffer and pass them to a matrix
void cvMatTest::Test_cvGetRawData(){
float* data;
int step;
float a[] = {1, 2, 3, 4, -5, 6, 7, 8, 9, -10, -11, 12 };
CvMat array;
CvSize size;
int x, y;
printf("\n=== Test get raw data ===");
cvInitMatHeader( &array, 3, 4, CV_32FC1, a, CV_AUTOSTEP );
cvGetRawData( &array, (uchar**)&data, &step, &size );
step /= sizeof(data[0]);
printf("\nCvMat = ");
PrintMat(&array);
printf("\nData = ");
for( y = 0; y < size.height; y++, data += step ){
printf("\n");
for( x = 0; x < size.width; x++ ) {
data[x] = (float)fabs(data[x]);
printf("%8.2f",data[x]);
}
}
printf("\n");
return;
}
测试输出结果:
关于Image Engineering & Computer Vision的更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.