关于Mat的初始创建方法有很多,下面列举一些我喜欢使用的方法,以及使用过程中的一些注意事项。
使用Mat的一个基本常识是:它可区分为“数据头+数据体”两大部分,并且二者在内存中是可分离的,其产生过程也不需要并发/次序完成全部,因此,一个Mat变量的存在模式有:空头、头+体。另外,数据体部分可与其它Mat变量共享。对于共享的数据区块,只有大家都不使用时才会得以销毁和释放。 膜拜OpenCV的大神们吧,竟能将Mat这一新秀设计得如此漂亮能干! 呵呵
左闭右开”的形式,所以抽取图像时需要稍加注意其边界。
1,单值填充
Mat A(rows, cols, CV_8UC4, Scalar(1,2,3,4)); // A的四个通道依次被全部填充为 1 2 3 4
Mat B(Mat::eye(rows, cols, CV_32S)); //以 min(rows, cols)为边长构成正方形,从(0,0)开始用1填充对角线
2,多值填充
Mat sobelH =(Mat_<char>(3,3) << -1, -2, -1, 0, 0, 0, 1, 2, 1); //填充指定值
Mat A(getGaussianKernel(7, 2)); //
3,引用填充
既然是引用,多数时候就不存在数据拷贝啦,当然有时候(基于vector和指针)也可以指定拷贝。
3.1 来自Mat
抽取部分作为ROI
Mat B(A, Rect(10, 10, 100, 100)); //using a rectangle [10, 100) 之间的矩形区间将被抽取
Mat C(A(Rect(10, 10, 100, 100))); // B 与 C 等价
Mat D(A(Range:all(), Range(1, 3))); //using row and column boundaries 抽取[1,3) 列
3.2 来自vector
OpenCV支持STL下的vector,并对此进行了扩展。
一列数据,只是通道数量和数据类型有些差别,并且,诡异的是,有些函数不支持此类Mat,比如亲测发现 inRang()函数就不支持 Mat C(采用下面3.3的指针方法得到一行Mat, inRang()函数就不再报错---尺寸不匹配),所以还是少用为上。
//A~E 都是60*1的一列,差别在于通道数量和 数据类型
Mat A(vector<int>(60)); //单通道,32S
Mat B(vector<Vec<int, 8>>(60)); //8 通道,32S
Mat C(vector<Vec4i>(60)); //4 通道,32S
Mat D(vector<Point>(60)); //2 通道,32S
Mat E(vector<Point2f>(60)); //2 通道,32F
//虽然编译不报错, 但 F 是无效的,不可使用,因为如此二维动态申请的内存不连续
Mat F(vector<vector<int>>(60, vector<int>(4)));
3.3 来自指针
int rows=15; //
int cols=40;
int size=rows*cols;
vector<int>Va(size);
vector<Vec<int, 8>>Vb(size);
vector<Vec4i>Vc(size);
vector<Point>Vd(size);
vector<Point2f>Ve(size);
vector<vector<int>>Vf(size, vector<int>(4));
Mat A(rows, cols, CV_32SC1, &Va[0]); //单通道,32S
Mat B(rows, cols, CV_32SC(8), &Vb[0][0]); //8 通道,32S
Mat C(rows, cols, CV_32SC4, &Vc[0][0]); //4 通道,32S, 有效,但数据不大正常,估计是里面使用了 Matx类
Mat D(rows, cols, CV_32SC2, &Vd[0].x); //2 通道,32S
Mat E(rows, cols, CV_32FC2, &Ve[0].x); //2 通道,32F
Mat F(rows, cols, CV_32SC4, &Vf[0][0]); //无效,尽管也占据了些内存空间