您的位置:首页 > 运维架构

CvMat、Mat、IplImage之间的转换

2015-08-26 11:51 363 查看

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);法1:CvMat 
mathdr;
CvMat *mat = cvGetMat( img, &mathdr );
法2:CvMat *mat = cvCreateMat( img->height, img->width, CV_64FC3 );
cvConvert( img, mat );


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_
4000
IMAGE_ELEM( img, uchar, row, col * 3 + 2 );
}
}


注:CV_IMAGE_ELEM( img, uchar, row, col * img->nChannels + ch ) 8.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);
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);

9.间接访问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" );
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opencv