关于Mat的初始创建方法有很多,下面列举一些我喜欢使用的方法,以及使用过程中的一些注意事项。
使用Mat的一个基本常识是:它可区分为“数据头+数据体”两大部分,并且二者在内存中是可分离的,其产生过程也不需要并发/次序完成全部,因此,一个Mat变量的存在模式有:空头、头+体。另外,数据体部分可与其它Mat变量共享。对于共享的数据区块,只有大家都不使用时才会得以销毁和释放。 膜拜OpenCV的大神们吧,竟能将Mat这一新秀设计得如此漂亮能干! 呵呵
在OpenCV中,表征一个区间时,一般默认为“左闭右开”的形式,所以抽取图像时需要稍加注意其边界。
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
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) 列
OpenCV支持STL下的vector,并对此进行了扩展。
按如下方式创建Mat时,只能得到一列数据,只是通道数量和数据类型有些差别,并且,诡异的是,有些函数不支持此类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)));
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]); //无效,尽管也占据了些内存空间