一、结构
IplImage
矩阵:
CvMat // 2维矩阵
|-- int type; // 元素类型(uchar,short,int,float,double)
|-- int step; // 一行所占字节长度
|-- int rows, cols; // 尺寸大小
|-- int height, width; // 备用尺寸参照
|-- union data;
|-- uchar* ptr; // 针对unsigned char矩阵的数据指针
|-- short* s; // 针对short矩阵的数据指针
|-- int* i; // 针对integer矩阵的数据指针
|-- float* fl; // 针对float矩阵的数据指针
|-- double* db; // 针对double矩阵的数据指针
CvMatND // N-维矩阵
|-- int type; // 元素类型(uchar,short,int,float,double)
|-- int dims; // 数组维数
|-- union data;
| |-- uchar* ptr; // 针对unsigned char矩阵的数据指针
| |-- short* s; // 针对short矩阵的数据指针
| |-- int* i; // 针对integer矩阵的数据指针
| |-- float* fl; // 针对float矩阵的数据指针
| |-- double* db; // 针对double矩阵的数据指针
|
|-- struct dim[]; // 每个维的信息
|-- size; // 该维内元素个数
|-- step; // 该维内元素之间偏移量
通用数组:
CvArr* // 仅作为函数参数,说明函数接受多种类型的数组,例如: // IplImage*, CvMat* 或者 CvSeq*. // 只需通过分析数组头部的前4字节便可确定数组类型
二、修改单个像素:
1.3通道时:CV_IMAGE_ELEM(image, unsigned char, i, j*3+k) = gray_val; //0<=k<3
2.单通道时:CV_IMAGE_ELEM(image, unsigned char, i, j) = gray_val;
3.通用方法:CvScalar s;
s=cvGet2D(img,i,j); // get the (i,j) pixel value
三、图像到矩阵
方式一、cvGetMat方式:
CvMat mathdr, *mat = cvGetMat( img, &mathdr );
mathdr只是根据img生成一个矩阵头,而其数据指向img的数据。
但只是把原来图像img头变成了CvMat头,数据体部分并没有复制,所以如果此时Release了img,则再访问mat就会出现错误。
方式二、cvConvert方式:
CvMat *mat = cvCreateMat( img->height, img->width, CV_64FC3 );
cvConvert( img, mat );
// #define cvConvert( src, dst )
四、从一幅图像中截出一小块,把它转成一维向量
cvSetImageROI(srcImg,blockRect);//blockRect为CvRect类型
cvCopy(srcImg,block);//srcImg为IplImage类型,block为CvMat类型
cvResetImageROI(srcImg);
CvMat vecHead,*vec;
vec=cvReshape( block, &vecHead, 0, 1 );//vec是得到的一维向量
说明:
1 同样大小的IplImage和CvMat,IplImage->widthStep不等于CvMat->step;
2 cvGetMat和cvReshape都只生成一个新的矩阵头,而数据都指向原来的地址,所以是两个矩阵共有一组数据,这一点在使用中要注意,原来的数据撤消是否会影响后生成的矩阵的使用。
3 cvGetMat得到的矩阵的step,等于原来IplImage的widthStep,再调用cvReshape时会出错。
4 cvReshape是按行形成向量,如果想按列形成向量,就先调用cvTranspose对矩阵进行转置,再调用cvReshape.
5 用cvCopy可以在IplImage和CvMat之间转换,比cvGetMat好,但其数据必须是同样的type和size.
6 如果是不同的type之间转换,可以用cvScale.
五、矩阵元素操作
一般的,对于1通道的数组:
CvMat* M = cvCreateMat( 4, 4, CV_64FC1 );
CV_MAT_ELEM( *M, double, row, col ) = 3.0;
注意double要根据数组的数据类型来传入。
对于两通道和四通道而言:
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);
六、数组到矩阵
// 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)