1.初始化矩阵:方式一、逐点赋值式:CvMat* mat = cvCreateMat( 2, 2, CV_64FC1 );cvZero( mat );cvmSet( mat, 0, 0, 1 );cvmSet( mat, 0, 1, 2 );cvmSet( mat, 1, 0, 3 );cvmSet( mat, 2, 2, 4 );cvReleaseMat( &mat );方式二、连接现有数组式:double a[] = { 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12 };CvMat mat = cvMat( 3, 4, CV_64FC1, a ); // 64FC1 for double// 不需要cvReleaseMat,因为数据内存分配是由double定义的数组进行的。2.IplImage 到cvMat的转换方式一、cvGetMat方式:CvMat mathdr, *mat = cvGetMat( img, &mathdr );方式二、cvConvert方式:CvMat *mat = cvCreateMat( img->height, img->width, CV_64FC3 );cvConvert( img, mat ); // #define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 )3.cvArr(IplImage或者cvMat)转化为cvMat方式一、cvGetMat方式:int coi = 0;cvMat *mat = (CvMat*)arr;if( !CV_IS_MAT(mat) ){mat = cvGetMat( mat, &matstub, &coi );if (coi != 0) reutn; // CV_ERROR_FROM_CODE(CV_BadCOI);}写成函数为:// This is just an example of function // to support both IplImage and cvMat as an inputCVAPI( void ) cvIamArr( const CvArr* arr ){CV_FUNCNAME( "cvIamArr" );__BEGIN__;CV_ASSERT( mat == NULL );CvMat matstub, *mat = (CvMat*)arr;int coi = 0;if( !CV_IS_MAT(mat) ){CV_CALL( mat = cvGetMat( mat, &matstub, &coi ) );if (coi != 0) CV_ERROR_FROM_CODE(CV_BadCOI);}// Process as cvMat__END__;}4.图像直接操作方式一:直接数组操作 int col, row, z;uchar b, g, r;for( y = 0; row < img->height; y++ ){for ( col = 0; col < img->width; col++ ){b = img->imageData[img->widthStep * row + col * 3]g = img->imageData[img->widthStep * row + col * 3 + 1];r = img->imageData[img->widthStep * row + col * 3 + 2];}}方式二:宏操作:int row, col;uchar b, g, r;for( row = 0; row < img->height; row++ ){for ( col = 0; col < img->width; col++ ){b = CV_IMAGE_ELEM( img, uchar, row, col * 3 );g = CV_IMAGE_ELEM( img, uchar, row, col * 3 + 1 );r = CV_IMAGE_ELEM( img, uchar, row, col * 3 + 2 );}}注:CV_IMAGE_ELEM( img, uchar, row, col * img->nChannels + ch )5.cvMat的直接操作数组的直接操作比较郁闷,这是由于其决定于数组的数据类型。对于CV_32FC1 (1 channel float):CvMat* M = cvCreateMat( 4, 4, CV_32FC1 );M->data.fl[ row * M->cols + col ] = (float)3.0;对于CV_64FC1 (1 channel double):CvMat* M = cvCreateMat( 4, 4, CV_64FC1 );M->data.db[ row * M->cols + col ] = 3.0;一般的,对于1通道的数组:CvMat* M = cvCreateMat( 4, 4, CV_64FC1 );CV_MAT_ELEM( *M, double, row, col ) = 3.0;注意double要根据数组的数据类型来传入,这个宏对多通道无能为力。对于多通道:看看这个宏的定义:#define CV_MAT_ELEM_CN( mat, elemtype, row, col ) /(*(elemtype*)((mat).data.ptr + (size_t)(mat).step*(row) + sizeof(elemtype)*(col)))if( CV_MAT_DEPTH(M->type) == CV_32F )CV_MAT_ELEM_CN( *M, float, row, col * CV_MAT_CN(M->type) + ch ) = 3.0;if( CV_MAT_DEPTH(M->type) == CV_64F )CV_MAT_ELEM_CN( *M, double, row, col * CV_MAT_CN(M->type) + ch ) = 3.0;更优化的方法是:#define CV_8U 0#define CV_8S 1#define CV_16U 2#define CV_16S 3#define CV_32S 4#define CV_32F 5#define CV_64F 6#define CV_USRTYPE1 7int elem_size = CV_ELEM_SIZE( mat->type );for( col = start_col; col < end_col; col++ ) {for( row = 0; row < mat->rows; row++ ) {for( elem = 0; elem < elem_size; elem++ ) {(mat->data.ptr + ((size_t)mat->step * row) + (elem_size * col))[elem] = (submat->data.ptr + ((size_t)submat->step * row) + (elem_size * (col - start_col)))[elem];}}}对于多通道的数组,以下操作是推荐的:for(row=0; row< mat->rows; row++){p = mat->data.fl + row * (mat->step/4);/* 除以4是因为一个float占4个字节,若为double则除以8,uchar不除*/for(col = 0; col < mat->cols; col++){*p = (float) row+col;*(p+1) = (float) row+col+1;*(p+2) =(float) row+col+2;p+=3;}}对于两通道和四通道而言:CvMat* vector = cvCreateMat( 1, 3, CV_32SC2 );CV_MAT_ELEM( *vector, CvPoint, 0, 0 ) = cvPoint(100,100);CvMat* vector = cvCreateMat( 1, 3, CV_64FC4 );CV_MAT_ELEM( *vector, CvScalar, 0, 0 ) = cvScalar(0,0,0,0);6.间接访问cvMatcvmGet/Set是访问CV_32FC1 和 CV_64FC1型数组的最简便的方式,其访问速度和直接访问几乎相同cvmSet( mat, row, col, value );cvmGet( mat, row, col );举例:打印一个数组inline void cvDoubleMatPrint( const CvMat* mat ){int i, j;for( i = 0; i < mat->rows; i++ ){for( j = 0; j < mat->cols; j++ ){printf( "%f ",cvmGet( mat, i, j ) );}printf( "/n" );}}而对于其他的,比如是多通道的后者是其他数据类型的,cvGet/Set2D是个不错的选择CvScalar scalar = cvGet2D( mat, row, col );cvSet2D( mat, row, col, cvScalar( r, g, b ) );注意:数据不能为int,因为cvGet2D得到的实质是double类型。举例:打印一个多通道矩阵:inline void cv3DoubleMatPrint( const CvMat* mat ){int i, j;for( i = 0; i < mat->rows; i++ ){for( j = 0; j < mat->cols; j++ ){CvScalar scal = cvGet2D( mat, i, j );printf( "(%f,%f,%f) ", scal.val[0], scal.val[1], scal.val[2] );}printf( "/n" );}}7.修改矩阵的形状——cvReshape的操作经实验表明矩阵操作的进行的顺序是:首先满足通道,然后满足列,最后是满足行。注意:这和Matlab是不同的,Matlab是行、列、通道的顺序。我们在此举例如下:对于一通道:// 1 channelCvMat *mat, mathdr;double data[] = { 11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34 };CvMat* orig = &cvMat( 3, 4, CV_64FC1, data );//11 12 13 14//21 22 23 24//31 32 33 34mat = cvReshape( orig, &mathdr, 1, 1 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above// 11 12 13 14 21 22 23 24 31 32 33 34mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above//11 12 13 14//21 22 23 24//31 32 33 34mat = cvReshape( orig, &mathdr, 1, 12 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above// 11// 12// 13// 14// 21// 22// 23// 24// 31// 32// 33// 34mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above//11 12 13 14//21 22 23 24//31 32 33 34mat = cvReshape( orig, &mathdr, 1, 2 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above//11 12 13 14 21 22//23 24 31 32 33 34mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above//11 12 13 14//21 22 23 24//31 32 33 34mat = cvReshape( orig, &mathdr, 1, 6 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above// 11 12// 13 14// 21 22// 23 24// 31 32// 33 34mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above//11 12 13 14//21 22 23 24//31 32 33 34// Use cvTranspose and cvReshape( mat, &mathdr, 1, 2 ) to get// 11 23// 12 24// 13 31// 14 32// 21 33// 22 34// Use cvTranspose again when to recover对于三通道// 3 channelsCvMat mathdr, *mat;double data[] = { 111, 112, 113, 121, 122, 123,211, 212, 213, 221, 222, 223 };CvMat* orig = &cvMat( 2, 2, CV_64FC3, data );//(111,112,113) (121,122,123)//(211,212,213) (221,222,223)mat = cvReshape( orig, &mathdr, 3, 1 ); // new_ch, new_rowscv3DoubleMatPrint( mat ); // above// (111,112,113) (121,122,123) (211,212,213) (221,222,223)// concatinate in column first ordermat = cvReshape( orig, &mathdr, 1, 1 );// new_ch, new_rowscvDoubleMatPrint( mat ); // above// 111 112 113 121 122 123 211 212 213 221 222 223// concatinate in channel first, column second, row thirdmat = cvReshape( orig, &mathdr, 1, 3); // new_ch, new_rowscvDoubleMatPrint( mat ); // above//111 112 113 121//122 123 211 212//213 221 222 223// channel first, column second, row thirdmat = cvReshape( orig, &mathdr, 1, 4 ); // new_ch, new_rowscvDoubleMatPrint( mat ); // above//111 112 113//121 122 123//211 212 213//221 222 223// channel first, column second, row third// memorize this transform because this is useful to // add (or do something) color channelsCvMat* mat2 = cvCreateMat( mat->cols, mat->rows, mat->type );cvTranspose( mat, mat2 ); cvDoubleMatPrint( mat2 ); // above //111 121 211 221//112 122 212 222//113 123 213 223cvReleaseMat( &mat2 );8.计算色彩距离我们要计算img1,img2的每个像素的距离,用dist表示,定义如下IplImage *img1 = cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 3 );IplImage *img2 = cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 3 );CvMat *dist = cvCreateMat( h, w, CV_64FC1 );比较笨的思路是:cvSplit->cvSub->cvMul->cvAdd代码如下:IplImage *img1B = cvCreateImage( cvGetSize(img1), img1->depth, 1 );IplImage *img1G = cvCreateImage( cvGetSize(img1), img1->depth, 1 );IplImage *img1R = cvCreateImage( cvGetSize(img1), img1->depth, 1 );IplImage *img2B = cvCreateImage( cvGetSize(img1), img1->depth, 1 );IplImage *img2G = cvCreateImage( cvGetSize(img1), img1->depth, 1 );IplImage *img2R = cvCreateImage( cvGetSize(img1), img1->depth, 1 );IplImage *diff = cvCreateImage( cvGetSize(img1), IPL_DEPTH_64F, 1 );cvSplit( img1, img1B, img1G, img1R );cvSplit( img2, img2B, img2G, img2R );cvSub( img1B, img2B, diff );cvMul( diff, diff, dist );cvSub( img1G, img2G, diff );cvMul( diff, diff, diff);cvAdd( diff, dist, dist );cvSub( img1R, img2R, diff );cvMul( diff, diff, diff );cvAdd( diff, dist, dist );cvReleaseImage( &img1B );cvReleaseImage( &img1G );cvReleaseImage( &img1R );cvReleaseImage( &img2B );cvReleaseImage( &img2G );cvReleaseImage( &img2R );cvReleaseImage( &diff );比较聪明的思路是int D = img1->nChannels; // D: Number of colors (dimension)int N = img1->width * img1->height; // N: number of pixelsCvMat mat1hdr, *mat1 = cvReshape( img1, &mat1hdr, 1, N ); // N x D(colors)CvMat mat2hdr, *mat2 = cvReshape( img2, &mat2hdr, 1, N ); // N x D(colors)CvMat diffhdr, *diff = cvCreateMat( N, D, CV_64FC1 ); // N x D, temporal buffcvSub( mat1, mat2, diff );cvMul( diff, diff, diff );dist = cvReshape( dist, &disthdr, 1, N ); // nRow x nCol to N x 1cvReduce( diff, dist, 1, CV_REDUCE_SUM ); // N x D to N x 1dist = cvReshape( dist, &disthdr, 1, img1->height ); // Restore N x 1 to nRow x nColcvReleaseMat( &diff );