OpenCV学习之CvMat的用法详解及实例

目    录
1.初始化矩阵:    1
2.IplImage 到cvMat的转换    1
3.cvArr(IplImage或者cvMat)转化为cvMat    1
4.图像直接操作    2
5.cvMat的直接操作    3
6.间接访问cvMat    4
7.修改矩阵的形状——cvReshape的操作    5
8.计算彩距离    7
    CvMat是OpenCV比较基础的函数。初学者应该掌握并熟练应用。但是我认为计算机专业学习的方法是,不断的总结并且提炼,同时还要做大量的实践,如编码,才能记忆深刻,体会深刻,从而引导自己想更高层次迈进。
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;
rows函数的使用方法及实例更优化的方法是:
  #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);
        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" );
    }
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。