reshape

来源:互联网 发布:决战武林弩炮4 5数据 编辑:程序博客网 时间:2024/05/03 22:22

You can slice a Mat object using the Range class in OpenCV. Ranges are exclusive which means thatRange(0, 4) will refer to rows 1, 2 and 3 (it will not refer to row 4).

Here is an example that copies a 4x3 matrix into a 6x3 matrix. You can use this with any number of rows and columns:

Mat onesMat = Mat::ones(4, 3, CV_8UC1);Mat zerosMat = Mat::zeros(6, 3, CV_8UC1);cout<<"Before copying:"<<endl;cout<<onesMat<<endl<<zerosMat<<endl;// Copy onesMat to zerosMat. Destination rows [0,4), columns [0,3)onesMat.copyTo(zerosMat(Range(0,4), Range(0,3)));cout<<"After copying:"<<endl;cout<<onesMat<<endl<<zerosMat<<endl;

And here is the output of the program:

Before copying:[1, 1, 1;  1, 1, 1;  1, 1, 1;  1, 1, 1][0, 0, 0;  0, 0, 0;  0, 0, 0;  0, 0, 0;  0, 0, 0;  0, 0, 0]After copying:[1, 1, 1;  1, 1, 1;  1, 1, 1;  1, 1, 1][1, 1, 1;  1, 1, 1;  1, 1, 1;  1, 1, 1;  0, 0, 0;  0, 0, 0]
=================================================

Mat::reshape

Changes the shape and/or the number of channels of a 2D matrix without copying the data.

C++: Mat Mat::reshape(int cn, int rows=0) const
Parameters:
  • cn – New number of channels. If the parameter is 0, the number of channels remains the same.
  • rows – New number of rows. If the parameter is 0, the number of rows remains the same.

The method makes a new matrix header for *this elements. The new matrix may have a different size and/or different number of channels. Any combination is possible if:

  • No extra elements are included into the new matrix and no elements are excluded. Consequently, the productrows*cols*channels() must stay the same after the transformation.
  • No data is copied. That is, this is an O(1) operation. Consequently, if you change the number of rows, or the operation changes the indices of elements row in some other way, the matrix must be continuous. See Mat::isContinuous() .

For example, if there is a set of 3D points stored as an STL vector, and you want to represent the points as a 3xN matrix, do the following:

std::vector<Point3f> vec;...Mat pointMat = Mat(vec). // convert vector to Mat, O(1) operation                  reshape(1). // make Nx3 1-channel matrix out of Nx1 3-channel.                              // Also, an O(1) operation                     t(); // finally, transpose the Nx3 matrix.                          // This involves copying all the elements
===========================================================================================
  • http://docs.opencv.org/java/org/opencv/core/Mat.html#reshape(int, int)

  • reshape

    public Mat reshape(int cn)

    Changes the shape and/or the number of channels of a 2D matrix without copying the data.

    The method makes a new matrix header for *this elements. The new matrix may have a different size and/or different number of channels. Any combination is possible if:

    • No extra elements are included into the new matrix and no elements are excluded. Consequently, the product rows*cols*channels() must stay the same after the transformation.
    • No data is copied. That is, this is an O(1) operation. Consequently, if you change the number of rows, or the operation changes the indices of elements row in some other way, the matrix must be continuous. See "Mat.isContinuous".

    For example, if there is a set of 3D points stored as an STL vector, and you want to represent the points as a 3xN matrix, do the following:

    // C++ code:

    std.vector vec;...

    Mat pointMat = Mat(vec). // convert vector to Mat, O(1) operation

    reshape(1). // make Nx3 1-channel matrix out of Nx1 3-channel.

    // Also, an O(1) operation

    t(); // finally, transpose the Nx3 matrix.

    // This involves copying all the elements

    cn
  • reshape

    public Mat reshape(int cn,          int rows)

    Changes the shape and/or the number of channels of a 2D matrix without copying the data.

    The method makes a new matrix header for *this elements. The new matrix may have a different size and/or different number of channels. Any combination is possible if:

    • No extra elements are included into the new matrix and no elements are excluded. Consequently, the product rows*cols*channels() must stay the same after the transformation.
    • No data is copied. That is, this is an O(1) operation. Consequently, if you change the number of rows, or the operation changes the indices of elements row in some other way, the matrix must be continuous. See "Mat.isContinuous".

    For example, if there is a set of 3D points stored as an STL vector, and you want to represent the points as a 3xN matrix, do the following:

    // C++ code:

    std.vector vec;...

    Mat pointMat = Mat(vec). // convert vector to Mat, O(1) operation

    reshape(1). // make Nx3 1-channel matrix out of Nx1 3-channel.

    // Also, an O(1) operation

    t(); // finally, transpose the Nx3 matrix.

    // This involves copying all the elements

    Parameters:
    cn - New number of channels. If the parameter is 0, the number of channels remains the same.
    rows - New number of rows. If the parameter is 0, the number of rows remains the same.
    See Also:
    org.opencv.core.Mat.reshape
http://www.cnblogs.com/gnuhpc/archive/2012/12/04/2802172.html
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 input 
CVAPI( 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 7 
int 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.间接访问cvMat 
cvmGet/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 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 ); 
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 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 );
0 0
原创粉丝点击