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

    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的转换 
A.CvMat-> IplImage
IplImage* img = cvCreateImage(cvGetSize(mat),8,1);
 cvGetImage(matI,img);cvSaveImage("rice1.bmp",img);
B.IplImage -> CvMat
IplImage* img = cvLoadimage("leda.jpg",1);
法2:CvMat *mat = cvCreateMat( img->height, img->width, CV_64FC3 );
      cvConvert( img, mat ); 法1:CvMat mathdr;
          CvMat  *mat = cvGetMat( img, &mathdr );
3.IplImage <--->Mat的转换 
(1)将IplImage----- > Mat类型
Mat::Mat(const IplImage* img, bool copyData=false);
默认情况下,新的Mat类型与原来的IplImage类型共享图像数据,转换只是创建一个Mat矩阵头。当将参数copyData设为true后,就会复制整个图像数据。
例:
IplImage*iplImg = cvLoadImage("greatwave.jpg", 1);
Matmtx(iplImg); // IplImage* ->Mat 共享数据
// or : Mat mtx = iplImg; 或者是:Mat mtx(iplImg,0); // 0是不复制影像,也就是iplImg的data共用同个记意位置,header各自有
(2)将Mat类型转换-----> IplImage类型
同样只是创建图像头,而没有复制数据。
例:
IplImage ipl_img = img; // Mat -> IplImage
IplImage*-> BYTE*
BYTE* data= img->imageData;
4.CvMat<--->Mat的转换
(1)将CvMat类型转换为Mat类型
B.CvMat->Mat
与IplImage的转换类似,可以选择是否复制数据。
CvMat*m= cvCreatMat(int rows ,int cols , int type);
Mat::Mat(const CvMat* m, bool copyData=false);
在openCV中,没有向量(vector)的数据结构。任何时候,但我们要表示向量时,用矩阵数据表示即可。
但是,CvMat类型与我们在线性代数课程上学的向量概念相比,更抽象,比如CvMat的元素数据类型并不仅限于基础数据类型,比如,下面创建一个二维数据矩阵:
              CvMat*m= cvCreatMat(int rows ,int cols , int type);
这里的type可以是任意的预定义数据类型,比如RGB或者别的多通道数据。这样我们便可以在一个CvMat矩阵上表示丰富多彩的图像了。
(2)将Mat类型转换为CvMat类型
与IplImage的转换类似,不复制数据,只创建矩阵头。
例:
// 假设Mat类型的imgMat图像数据存在
CvMat cvMat = imgMat; // Mat -> CvMat
5.cv::Mat--->const cvArr*
cvArr * 数组的指针。就是opencv里面的一种类型。Mat img;
 const CvArr* s=(CvArr*)&img;
 上面就可以了,CvArr是Mat的虚基类,所有直接强制转换就可以了void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR ); // src 就是之前的lplimage类型的一个指针变量
6.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__;
 } 7.图像直接操作
 方式一:直接数组操作 int col, row, z;
 uchar b, g, r;
 for( row = 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 )