p = new int *[m];注解
new int[10] 新申请一段可以保存10个int型整数的内存空间 int* p 定义一个int型指针 int *p=new int[10] 让int型指针指向申请的内存空间的首地址!
s = cvGet2D(src, j,i);//获取src图像中坐标为(i,j)的像素点的值
uchar* ptr=(uchar*) (img->imageData+y*img->widthStep); please翻译一下这句话。。。不理解
img是指向IplImage类型的指针吧? img->imageData是这个数组的首地址,指向存储图像的坐标原点。 widthStep是指图像每行所占的字节数,y*img->widthStep就是y行的字节数。 img->imageData+y*img->widthStep指向了图像的y行。 (uchar*)是强制类型转换。一、结构IplImage
|-- int nChannels; // Number of color channels (1,2,3,4) |-- int depth; // Pixel depth in bits: | // IPL_DEPTH_8U, IPL_DEPTH_8S, | // IPL_DEPTH_16U,IPL_DEPTH_16S, | // IPL_DEPTH_32S,IPL_DEPTH_32F, | // IPL_DEPTH_64F |-- int width; // image width in pixels |-- int height; // image height in pixels |-- char* imageData; // pointer to aligned image data | // Note that color images are stored in BGR order 这就是传说中的数据矩阵 |-- int dataOrder; // 0 - interleaved color channels, | // 1 - separate color channels | // cvCreateImage can only create interleaved images |-- int origin; // 0 - top-left origin, | // 1 - bottom-left origin (Windows bitmaps style) |-- int widthStep; // size of aligned image row in bytes |-- int imageSize; // image data size in bytes = height*widthStep |-- struct _IplROI *roi;// image ROI. when not NULL specifies image | // region to be processed. |-- char *imageDataOrigin; // pointer to the unaligned origin of image data | // (needed for correct image deallocation) | |-- int align; // Alignment of image rows: 4 or 8 byte alignment | // OpenCV ignores this and uses widthStep instead |-- char colorModel[4]; // Color model - ignored by OpenCV
矩阵:
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
s.val[0]=111; //单通道就只有这个有效 s.val[1]=111; s.val[2]=111; cvSet2D(img,i,j,s);//set 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 )
cvConvertScale( (src), (dst), 1, 0 )
四、从一幅图像中截出一小块,把它转成一维向量
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 channelsCvMat 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类型较CvMat和IplImage有更强的矩阵运算能力,支持常见的矩阵运算(参照Matlab中的各种矩阵运算),所以将IplImage类型和CvMat类型转换为Mat类型更易于数据处理。
Mat类型可用于直接存储图像信息,通过函数imread、imwrite、imshow等实现(与Matlab中的函数相似),似乎在某种程度上可以取代IplImage类型。
(1)将IplImage类型转换到Mat类型
Mat::Mat(const IplImage* img, bool copyData=false);
默认情况下,新的Mat类型与原来的IplImage类型共享图像数据,转换只是创建一个Mat矩阵头。当将参数copyData设为true后,就会复制整个图像数据。
例:
IplImage* iplImg = cvLoadImage("greatwave.jpg", 1);
Mat mtx(iplImg); // IplImage* ->Mat 共享数据
// or : Mat mtx = iplImg;
(2)将Mat类型转换到IplImage类型
同样只是创建图像头,而没有复制数据。
例:
IplImage ipl_img = img; // Mat -> IplImage
(3)将CvMat类型转换为Mat类型
与IplImage的转换类似,可以选择是否复制数据。
Mat::Mat(const CvMat* m, bool copyData=false);
(4)将Mat类型转换为CvMat类型
与IplImage的转换类似,不复制数据,只创建矩阵头。
例:
// 假设Mat类型的imgMat图像数据存在
CvMat cvMat = imgMat; // Mat -> CvMat