【转载】cvReshape用法详解

修改矩阵的形状——cvReshape的操作
经实验表明矩阵操作的进行的顺序是:首先满足通道,然后满足列,最后是满足行。
 
注意:1 这和Matlab是不同的,Matlab是行、列、通道的顺序;
            2.cvGetMat和cvReshape都只生成一个新的矩阵头,而数据都指向原来的地址,所以是两个矩阵共有一组数据,这一点在使用中要注意,原来的数据撤消是否会影响后生成的矩阵的使用;
           3.cvReshape是按行形成向量,如果想按列形成向量,就先调用cvTranspose对矩阵进行转置,再调用cvReshape;
          4.同样大小的IplImage和CvMat,IplImage->widthStep不等于CvMat->step???(待验证)

我们在此举例如下:
对于一通道:
// 1 channel
CvMat *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 34
mat = cvReshape( orig, &mathdr, 1, 1 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 11 12 13 14 21 22 23 24 31 32 33 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14
//21 22 23 24
//31 32 33 34
mat = cvReshape( orig, &mathdr, 1, 12 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 11
// 12
// 13
// 14
// 21
// 22
// 23
// 24
// 31
// 32
// 33
// 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14
//21 22 23 24
//31 32 33 34
mat = cvReshape( orig, &mathdr, 1, 2 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14 21 22
//23 24 31 32 33 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//11 12 13 14
//21 22 23 24
//31 32 33 34
mat = cvReshape( orig, &mathdr, 1, 6 ); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 11 12
// 13 14
// 21 22
// 23 24
// 31 32
// 33 34
mat = cvReshape( mat, &mathdr, 1, 3 ); // new_ch, new_rows
cvDoubleMatPrint( 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 channels
CvMat 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_rows
cv3DoubleMatPrint( mat ); // above
// (111,112,113) (121,122,123) (211,212,213) (221,222,223)
// concatinate in column first order
mat = cvReshape( orig, &mathdr, 1, 1 );// new_ch, new_rows
cvDoubleMatPrint( mat ); // above
// 111 112 113 121 122 123 211 212 213 221 222 223
// concatinate in channel first, column second, row third
mat = cvReshape( orig, &mathdr, 1, 3); // new_ch, new_rows
cvDoubleMatPrint( mat ); // above
//111 112 113 121
//122 123 211 212
//213 221 222 223
// channel first, column second, row third
mat = cvReshape( orig, &mathdr, 1, 4 ); // new_ch, new_rows
cvDoubleMatPrint( 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 channels
CvMat* 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 223
cvReleaseMat( &mat2 );

计算色彩距离
我们要计算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 pixels
CvMat 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 buff
cvSub( mat1, mat2, diff );
cvMul( diff, diff, diff );
dist = cvReshape( dist, &disthdr, 1, N ); // nRow x nCol to N x 1
cvReduce( diff, dist, 1, CV_REDUCE_SUM ); // N x D to N x 1
dist = cvReshape( dist, &disthdr, 1, img1->height ); // Restore N x 1 to nRow x nCol
cvReleaseMat( &diff );
 

 

 

#pragma comment( lib, "cxcore.lib" )
#include "cv.h"
#include <stdio.h>
int main()
{
CvMat* mat = cvCreateMat(3,3,CV_32FC1);
cvZero(mat);//将矩阵置0
//为矩阵元素赋值
CV_MAT_ELEM( *mat, float, 0, 0 ) = 1.f;
CV_MAT_ELEM( *mat, float, 0, 1 ) = 2.f;
CV_MAT_ELEM( *mat, float, 0, 2 ) = 3.f;
CV_MAT_ELEM( *mat, float, 1, 0 ) = 4.f;
CV_MAT_ELEM( *mat, float, 1, 1 ) = 5.f;
CV_MAT_ELEM( *mat, float, 1, 2 ) = 6.f;
CV_MAT_ELEM( *mat, float, 2, 0 ) = 7.f;
CV_MAT_ELEM( *mat, float, 2, 1 ) = 8.f;
CV_MAT_ELEM( *mat, float, 2, 2 ) = 9.f;
//获得矩阵元素(0,2)的值
float *p = (float*)cvPtr2D(mat, 0, 2);
printf("%f/n",*p);
return 0;
}

原文地址:https://www.cnblogs.com/jiayouwyhit/p/3045761.html