OpenCV 矩阵运算小结
这份总结适用于OpenCV 2 以上版本,官方详尽的文档在 这里。
概述
OpenCV 里的矩阵分静态和动态两种:
- 动态就是 Mat 类,已经实现了引用计数,编程时几乎不用考虑内存问题;你可以将Mat看作一个头——包含矩阵内存区域的指针和矩阵的大小、类型等信息。
- 静态以 Matx 类为代表,需要程序员自己开辟内存区域,其存储方式和数组完全一样,没有额外的存储空间,矩阵自身的信息都以模板的方式静态编译了。
对于能确定大小和类型的矩阵,尽量使用静态的存储方式。
Matx Vec
创建时需要给定模板参数(类型、行数、列数),例如:
1 | Matx<float, 3, 3> matrix; |
Vec 向量就是列数为 1 的 Matxs
1 | template<typename _Tp, int n> class Vec : public Matx<_Tp, n, 1> {...}; |
可以从 Mat 初始化,也可以用 ones(), zeros(), eye() 等等
1 | Matx<float, 10, 1> ui = mat.col(0); |
可以执行一些简单的运算,例如加减乘除和 mul(), dot()
1 | cv::Matx31f r1, r2, r3; |
稍复杂的就要转换成 Mat 来操作了,这里给个简单的例子
1 | r3 = Mat(r1, false).cross(r2); |
Mat
其实 Mat 才是矩阵运算的主角,各种矩阵运算都与这个类相关。但是 Mat 是动态分配的,涉及到内存分配释放的代价,请自己权衡。
前面提到,Mat 是一个指针加上数据类型、步长等信息,为了减少不必要的拷贝,OpenCV 中经常会出现两个 Mat 指向同一片内存区域(比如 ROI 就用到了这个特性)。这时候,对他们的修改会相互影响。
Mat 也可以从给定的指针初始化,这种情况下,Mat 不去管理内存。
常用的构造函数
1 | Mat(int rows, int cols, int type) |
例如
1 | cv::Mat(LANDMARK_NUM, 2, CV_32F, (void *)landmarks.data()); |
静态构造方法,以 zeors() 为例
1 | Mat::zeros(int rows, int cols, int type) |
此外还有 Mat::ones()
, Mat::eye()
MatExpr
这是 Mat 运算中经常出现的一个类,可以理解成还未计算的矩阵表达式。它和 Mat 可以隐式地相互转换。这一点很方便,但要小心
1 | cv::Mat A, B, C; |
如果要实现矩阵拷贝,应该用
1 | B.copyTo(A); |
其他
用以下函数取出一个 ROI,返回值类型仍是 Mat,共享对应的内存区域。
1 | Mat::row(int x) |
resize 把一个矩阵改变形状而不改变实际内存数据
1 | Mat::resize(size_t sz) |