主要是手册中关于该部分的翻译;
有很多的创建Mat对象的方法,主要的有以下:
1、使用create(nrow,ncols,type)函数,或者相似的构造函数Mat(nrow,ncols,type[,fillValue]),将分配新的指定大小和格式的数组,
type的意义和cvCreateMat函数一样,例如CV_8UC1意思是创建8位单通道的数组,而CV_32FC2则是两通道的浮点数数组;例如:
//创建一个7*7的复数矩阵并且初始化为1+3j; cv::Mat M(7,7,CV_32FC2, Scalar(1,3)); //然后将M转换为100*60的15通道的8位矩阵; M.create(100,60,CV_8UC(15));
正如开始时介绍的一样,create()函数只在当前数组大小或者类型与指定的不一样时才分配新的数组。
2、与1类似的,还可以创建一个多维数组:
//创建100*100*100的8位数组 int sz[]={100,100,100}; cv::Mat bigCube(3, sz, CV_8U, Scalar::all(0));
即使传递给构造函数的维数参数dimensions=1,创建的数组也会是2维数组,即参数dims=2,函数会将矩阵视为只有多行一列的矩阵,所以Mat::dims一直是大于等于2的(数组为空时是0);
3、使用复制构造函数或者复制操作符,如下所示;正如介绍的那样,赋值操作的计算复杂度是O(1)的,因为只是进行对象头的复制和引用计数的增加(并没有真的复制数据),当需要时可以使用函数Mat.clone()
来获得数组的完整拷贝。
4、为其他的Mat数组构造一个新的头,Mat数组可以是一行,一列,多行,多列,矩阵数组中的一块矩形区域或者对角线,这些操作的复杂度也是O(1),因为新的头指向相同的数据,
可以使用这种特点来改变数组的一部分,例如:
//将第5行的三倍加到第3行上 M.row(3)=M.row(3)+M.row(5)*3; //将第7列复制到第1列,使用 M.col(1)=M.col(7) 将不会奏效,应该使用如下方法: Mat M1 = M.col(1); M.col(7).copyTo(M1); //创建一幅320×240的图像 Mat img(Size(320,240), CV_8UC3); //选择一块ROI Mat roi(img, Rect(10, 10, 100, 100)); //将ROI的颜色填充为绿色,原始的img图像将会改变。 roi=Scalar(0,255,0);
因为额外的成员:datastart和dataend的帮助,可以使用locateROI()函数计算子块在主数组中的相对位置;
Mat A=Mat::eye(10,10, CV_32S); //析取A的列[1,3),左闭右开区间; Mat B = A(Range::all(), Range::(1,3)); //析取B的行[5,9),这样C就是A的5-8行,1-2列; Mat C = B(Range::(5,9),Range::all()); Size size;Point ofs; C.locateROI(size, ofs); //size为(10,10),ofs(x=1,y=5)
如果需要,可以使用clone()函数来复制析取的子矩阵。
5、给用户外部数据分配对象头,这种方法在下面情况中有用:
(1)、使用OpenCV处理外部数据(如自己实现的DirectShow的过滤器或者gstreamer的处理模块等),例如
void process_video_frame(const unsigned char *pixels, int width, int height, int step) { Mat img(height, width, CV_8UC3, pixels, step);//注意此处height和width的与cols和rows的对应关系; GaussianBlur(img, img, Size(7,7), 1.5,1.5); }
(2)、快速初始化小的矩阵并且\或者获得super-fast的元素获取速度;
double m[3][3] = {{a,b,c},{d,e,f},{g,h,i}}; Mat M = Mat(3,3, CV_64F, m).inv();
不常用但是非常普遍的使用用户分配数据的情况就是从CvMat或者IplImage向Mat转换时【partial yet very common cases of this..case】,
为此有专门的以指向CvMat或IplImage的指针和可选的指出是否进行数据复制的标志flag为参数的Mat构造函数。
从Mat到CvMat或IplImage的反向转换由重载的操作符Mat::operator CvMat()和Mat::operator IplImage()完成,该操作不会复制数据!
IplImage *img = cvLoadImage("greatewave.jpg",1); Mat mtx(img); //IplImage*->Mat CvMat oldmat = mtx; //Mat->CvMat CV_Assert(oldmat.cols==img->width && oldmat.rows==img->height && oldmat.data.ptr==(uchar *)img->imageData && oldmat.step==img->widthStep);
6、使用MATLAB样式的矩阵初始化函数,zeros(),ones(),eys(),例如:
//创建双精度的单位矩阵并将其加到M上;
M += Mat::eye(M.rows, M.cols, CV_64F);
7、使用逗号分隔初始化;
//创建3×3的双精度单位阵;
Mat M = (Mat_<double>(3,3) << 1,0,0,0,1,0,0,0,1);
使用该方法可以先调用一个给定了合适参数的Mat_类的构造函数,然后就可以使用<<操作符将用逗号分隔的值输入,这些值可以使常量,变量,表达式等;注意为避免编译错误则加上的额外的括号;
【到此基本上创建Mat矩阵的常用方法就比较全了,看了一下构造函数中还有几个实用模板实现的构造函数,参数是Vec,Matx以及vector的;
8、使用模板的构造函数;
const int dimss=40; vector<float> stl_vec; Vec<short, dimss> vecs; Matx<double, 30, 50> matxs; for (int i=0; i<dimss; ++i) { vecs[i] = i*3; stl_vec.push_back(i*10.f); } Mat vecMat(vecs); Mat matxMat(matxs); Mat stlvecMat(stl_vec,true);
使用该方法主要是用于将向量表示转换为Mat的矩阵表示方便处理,关键是向量的构造,像使用findContour获得的轮廓,
可以将Point的vector转换为Mat处理;
】
--------------------------------------------------------------------------------
Mat的构造创建以及初始化常用的基本上就这几种。下一次将总结一下Mat元素的获取方法。