Mat a(100, 100, CV_32F); randu(a, Scalar::all(1), Scalar::all(std::rand())); cv::log(a, a); a /= std::log(2.);
Mat
用于储存图像(或其他数组型的数据)的容器。
声明
一维数组
1
Mat a_mat;
将声明一个大小为 0 的 Mat 对象。也可以直接指定初始大小:
1
Mat a_mat(nrows, ncols, type[, fillValue]);
这里的 type 是矩阵数据类型。格式为:
1
CV_<bit_depth>(S|U|F)C<number_of_channels>
1 2 3
S = 符号整型 U = 无符号整型 F = 浮点型
根据这个可以灵活定义多种数据类型,例如:
CV_8U:8位无符号整型单通道矩阵,等价于 CV_8UC1 。
CV_8UC3:8位无符号整型三通道矩阵;
CV_32FC2:32位浮点型双通道矩阵。
要获得某个 Mat 对象的数据类型,可以使用 Mat:type() 函数。
高维数组
1 2 3
// create a 100x100x100 8-bit array int sz[] = {100, 100, 100}; Mat bigCube(3, sz, CV_8U, Scalar::all(0));
其他创建方法
使用 cv::create() 函数
1 2
Mat a_mat; a_mat.create(nrows, ncols, type);
通过赋值操作复制一个 Mat 对象。
这种方法只是简单的复制头指针的地址,因此得到的 Mat 对象与原来的 Mat 对象共享同样的数据空间,整个赋值过程只是一个 \(O(1)\) 操作。或者通过 Mat::copyTo() 或 Mat::clone() 操作拷贝一个 Mat 对象,这种方法得到的 Mat 对象申请了新的空间并拷贝了原 Mat 对象的数据。详见 内存管理机制 。
声明一个 Mat 对象,将其头指针并指向另一个数组对象的部分元素。
同样也是个 \(O(1)\) 操作。对该 Mat 对象操作会影响原来的数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// add the 5-th row, multiplied by 3 to the 3rd row M.row(3) = M.row(3) + M.row(5)*3;
// now copy the 7-th column to the 1-st column // M.col(1) = M.col(7); // this will not work Mat M1 = M.col(1); M.col(7).copyTo(M1);
// create a new 320x240 image Mat img(Size(320,240),CV_8UC3); // select a ROI Mat roi(img, Rect(10,10,100,100)); // fill the ROI with (0,255,0) (which is green in RGB space); // the original 320x240 image will be modified roi = Scalar(0,255,0);
声明一个 Mat 对象,并将头指针指向用户分配的数据。
1 2
double m[3][3] = { {a, b, c}, {d, e, f}, {g, h, i} }; Mat M = Mat(3, 3, CV_64F, m).inv();
将 C API 的 CvMat 和 IplImage 转换到 Mat 也是用到这个方式:
1 2 3
Mat img = imread("image.jpg"); IplImage img1 = img; CvMat m = img;
注意上面的命令并没有拷贝数据。
使用类 Matlab 风格的数组初始化函数 zeros(),ones(),eye() 。
1 2
// create a double-precision identity martix and add it to M. M += Mat::eye(M.rows, M.cols, CV_64F);
使用逗号分割的初始化方式:
1 2
// create a 3x3 double-precision identity matrix Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
内存管理机制
Mat 使用计数指针的方式来实现智能指针,以使得多个 Mat 对象可以共享同一份数据,这样可以大幅节省空间。我们可以看看它的定义:
classCV_EXPORTSMat { public: // ... a lot of methods ... ...
/*! includes several bit-fields: - the magic signature - continuity flag - depth - number of channels */ int flags; //! the array dimensionality, >= 2 int dims; //! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions int rows, cols; //! pointer to the data uchar* data;
//! pointer to the reference counter; // when array points to user-allocated data, the pointer is NULL int* refcount;
// other members ... };
其中 refcount 指针用来对该对象的引用次数计数。当引用次数减少到 0 时,说明此时的数据已经没有用了,可以放心的删除,从而释放空间。但这样可能带来的一个问题:对其中一个Mat的数据操作,有可能会对其他指向同一块数据的 Mat 产生灾难性的影响。
因此,如果想要重新拷贝一份原有的 Mat 的数据,不要直接赋值,而应该是用 Mat::copyTo() 或 Mat::clone() 操作:
1 2
Mat img = imread("image.jpg"); Mat img1 = img.clone();
Addition, subtraction, negation: A+B, A-B, A+s, A-s, s+A, s-A, -A
Scaling: A*alpha
Per-element multiplication and division: A.mul(B), A/B, alpha/A
Matrix multiplication: A*B
Transposition: A.t() (means \(A^T\))
Matrix inversion and pseudo-inversion, solving linear systems and least-squares problems: A.inv([method]) (\(\sim A^{-1}\)) , A.inv([method])*B (\(\sim X: AX=B\))
Comparison: A cmpop B, A cmpop alpha, alpha cmpop A, where cmpop is one of : >, >=, ==, !=, <=, <. The result of comparison is an 8-bit single channel mask whose elements are set to 255 (if the particular element or pair of elements satisfy the condition) or 0.
Bitwise logical operations: A logicop B, A logicop s, s logicop A, ~A, where logicop is one of : &, |, ^.
Any function of matrix or matrices and scalars that returns a matrix or a scalar, such as norm, mean, sum, countNonZero, trace, determinant, repeat, and others.
Matrix initializers ( Mat::eye(), Mat::zeros(), Mat::ones() ), matrix comma-separated initializers, matrix constructors and operators that extract sub-matrices (see Mat description).
Mat_<destination_type>() constructors to cast the result to the proper type.
示例
1 2 3 4 5 6 7 8 9 10 11 12 13
// compute pseudo-inverse of A, equivalent to A.inv(DECOMP_SVD) SVD svd(A); Mat pinvA = svd.vt.t()*Mat::diag(1./svd.w)*svd.u.t();
// compute the new vector of parameters in the Levenberg-Marquardt algorithm x -= (A.t()*A + lambda*Mat::eye(A.cols,A.cols,A.type())).inv(DECOMP_CHOLESKY)*(A.t()*err);
// sharpen image using "unsharp mask" algorithm Mat blurred; double sigma = 1, threshold = 5, amount = 1; GaussianBlur(img, blurred, Size(), sigma, sigma); Mat lowConstrastMask = abs(img - blurred) < threshold; Mat sharpened = img*(1+amount) + blurred*(-amount); img.copyTo(sharpened, lowContrastMask);