每个基本类型实际上都是一个相对复杂的对象,包括自己的接口函数、重载操作符等。在本节中,我们将更全面地了解每种类型,以及一些看似相似的类型之间有何不同。我们将学习它们重要的接口,但不会深入到每一个具体的细节实现。我们将根据例子进行说明。
point 类
在 OpenCV 基本类型中,point 类可能是最简单的。如前所述,这些都是基于模板结构实现的,因此可以有任何类型的点:整数、浮点等等。实际上有两个这样的模板,一个用于二维,另一个用于三维点。point 类的最大优势是它们很简单,开销很小。它们没有定义很多操作,但当需要时,可以将它们转换为某种更通用的类型,如 fixed vector 类或 fixed matrix 类。
一般点类是通过cv::Point2i
或cv::Point3f
等 typedef 形式的别名实例化的,最后一个字母表示要从其构建点的所需基本类型。(这里,b
是unsigned char
,s
是short int
,i
是32-bit int
,f
是32-bit float
,d
是64-bit float
或者double
。)
操作 | 举例 |
---|---|
默认构造 | cv::Point2i p; |
拷贝构造 | cv::Point3f p2(p1); |
赋值构造 | cv::Point2i p( x0, x1 ); |
强转为 fix vector 类 | (cv::Vec3f) p; |
访问成员 | p.x; p.y; p.z; |
点乘 | float x = p1.dot( p2 ) |
双精度点乘 | double x = p1.ddot( p2 ) |
叉乘 | p1.cross( p2 ) |
查询 pont p 是否在 rectangle r 内 | p.inside( r ) |
cv::Scalar 类
cv::Scalar
实际上是一个四维点类,所有成员都是双精度浮点数。cv::Scalar
类还具有一些与在计算机视觉中使用四维向量相关联的特殊成员函数。
操作 | 举例 |
---|---|
默认构造 | cv::Scalar s; |
拷贝构造 | cv::Scalar s2( s1 ); |
赋值构造 | cv::Scalar s( x0 ); 或cv::Scalar s( x0, x1, x2, x3 ); |
逐元素相乘 | s1.mul( s2 ); |
共轭四元数 | s.conj(); // (returns cv::Scalar(s0,-s1,-s2,-s2)) |
四元数实数测试 | s.isReal(); // (returns true iff s1==s2==s3==0) |
有没有发现,对于cv::Scalar
,强制转换为 fix vector 类的操作没有出现在上表中。这是因为与 point 类不同,cv::Scalar
直接继承自 fix vector 类实例。因此,它继承了所有向量代数运算、成员访问函数(即运算符[]
)和来自 fix vector 类的其他属性。我们稍后会讲到 fix vector 类,但现在请记住,cv::Scalar
是四维双精度向量的简写形式,它附加了几个特殊的成员函数,对各种类型的四维向量都很有用。
size 类
实际上,size 类类似于相应的 point 类,并且它们之间可以相互转换。两者之间的主要区别是 point 类的数据成员命名为x
和y
,而 size 类中相应的数据成员命名为width
和height
。size 类的三个 typedef 是cv::Size
、cv::Size2i
和cv::Size2f
。前两个是等效的,表示整数大小,而最后一个是32位浮点大小。
操作 | 举例 |
---|---|
默认构造 | cv::Size sz; cv::Size2i sz; cv::Size2f sz; |
拷贝构造 | cv::Size sz2( sz1 ); |
赋值构造 | cv::Size2f sz( w, h ); |
访问成员 | sz.width; sz.height; |
计算面积 | sz.area(); |
与 point 类不同,size 类不支持强制转换为固定矢量类。这意味着 size 类应用的时候更加受限。另一方面,point 类和 fix vector 类可以转换成 size 类。
cv::Rect 类
Rect 类既包括 point 类的成员x
和y
(表示矩形的左上角)也包括 size 类的成员width
和height
(表示矩形的大小)。但是,Rect 类不继承自这两个类,因此也不继承它们的运算符。
操作 | 举例 |
---|---|
默认构造 | cv::Rect r; |
拷贝构造 | cv::Rect r2( r1 ); |
赋值构造 | cv::Rect( x, y, w, h ); |
左上角点和大小构造 | cv::Rect( p, sz ); |
对角点构造 | cv::Rect( p1, p2 ); |
访问成员 | r.x; r.y; r.width; r.height; |
计算面积 | r.area(); |
左上角点 | r.tl(); |
右下角点 | r.br(); |
point p 是否在 rectangle r 内 | r.contains( p ); |
两个矩形相交的部分 | cv::Rect r3 = r1 & r2; or r1 &= r2; |
包含矩形 R1 和 R2 的最小矩形 | cv::Rect r3 = r1 | r2; or r1 |= r2; |
将矩形平移 | cv::Rect rx = r + x; or r += x; |
将矩形放大 size s 倍 | cv::Rect rs = r + s; or r += s; |
矩形是否完全相等 | bool eq = (r1 == r2); |
矩形是否不等 | bool ne = (r1 != r2); |
cv::RotatedRect 类
cv::RotatedRect
类是 OpenCV 中为数不多的不是底层模板的类之一。它是一个容器,其中包含一个名为center
的cv::Point2f
、一个名为size
的cv::Size2f
和一个名为angle
的float
,后者表示矩形围绕中心的旋转。cv::RotatedRect
和cv::Rect
之间一个非常重要的区别是,cv::RotatedRect
相对于其中心,而cv::Rect
相对于其左上角。
操作 | 举例 |
---|---|
默认构造 | cv::RotatedRect rr(); |
拷贝构造 | cv::RotatedRect rr2( rr1 ); |
对角点构造 | cv::RotatedRect( p1, p2 ); |
赋值构造 | cv::RotatedRect rr( p, sz, theta ) ; |
访问成员 | rr.center; rr.size; rr.angle; |
返回角点 | rr.points( pts[4] ); |
fixed matrix 类
fixed matrix 类用于其维数在编译时已知的矩阵(因此称为“fix”)。因此,其数据的所有内存都分配到堆栈上,这意味着它们可以快速分配和销毁。它们的运算速度很快,并且有专门针对小矩阵(2×2、3×3等)的优化实现。fixed matrix 类也是 OpenCV 的 C++ 接口中许多其他基本类型的核心。fixed vector 类派生自 fixed matrix 类,而其他类要么派生自 fixed vector 类(如cv::scalar
),要么依赖于强制转换为 fixed vector 类进行许多重要运算。与往常一样,fixed matrix 类实际上是一个模板。模板名为cv::matx<>
,但是各个矩阵通常通过是typedef,基本形式是cv::matx{1,2,...}{1,2,...}{f,d}
,其中数字可以是1到6之间的任何数字,尾随字母的含义与前面的类型相同。(写代码时,core.hpp 的相关头文件实际上并不包含这些整数的所有可能组合。例如,没有1×1的矩阵typedef,也没有5×5的矩阵typedef。这一点在以后的版本中可能会改变,也可能不会改变,如果确实想要其中的一个,你可以自己实例化模板(例如,cv::matx<5,5,float>
)。)
一般说来,当你表示一些已知的需要做矩阵代数运算的东西时,你应该使用fixed matrix 类。如果您的对象确实是一个大数据数组,比如一幅图像或一个巨大的点列表,那么fixed matrix 类不是正确的解决方案;而应该使用cv::mat
(之后介绍)。fixed matrix 类用于在编译时知道大小的小矩阵(例如,相机矩阵)。
操作 | 举例 |
---|---|
默认构造 | cv::Matx33f m33f; cv::Matx43d m43d; |
拷贝构造 | cv::Matx22d m22d( n22d ); |
赋值构造 | cv::Matx21f m(x0,x1); cv::Matx44d m(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15); |
所有元素相同的矩阵 | m33f = cv::Matx33f::all( x ); |
零矩阵 | m23d = cv::Matx23d::zeros(); |
所有元素为1 | m16f = cv::Matx16f::ones(); |
单位矩阵 | m33f = cv::Matx33f::eye(); |
元素均匀分布的矩阵 | m33f = cv::Matx33f::randu( min, max ); |
元素正态分布的矩阵 | m33f = cv::Matx33f::nrandn( mean, variance ); |
访问成员 | m( i, j ), m( i ); |
矩阵代数运算 | m1 = m0; m0 * m1; m0 + m1; m0 – m1; |
两矩阵比较 | m1 == m2; m1 != m2; |
提取一个3×3矩阵的对角线 | m31f = m33f::diag(); |
数量乘法 | m * a; a * m; m / a; |
逐元素相乘之和 | m1.dot( m2 ); |
逐元素相乘之和双精度 | m1.ddot( m2 ); |
reshape | m91f = m33f.reshape<9,1>(); |
强转 | m44f = (Matx44f) m44d; |
提取子矩阵 | m44f.get_minor<2, 2>( i, j ); |
i行 | m14f = m44f.row( i ); |
j列 | m41f = m44f.col( j ); |
矩阵对角线 | m41f = m44f.diag(); |
转置 | n44f = m44f.t(); |
求逆 | n44f = m44f.inv( method ); |
解线性系统 | m31f = m33f.solve( rhs31f, method ); or m32f = m33f.solve<2>( rhs32f, method ); |
逐元素相乘 | m1.mul( m2 ); |
fixed vector 类
fixed vector 类继承自 fixed matrix 类。从继承意义上说,fixed vector 类的模板cv::Vec<>
是列数为1的cv::Matx<>
。cv::Vec<>
特定typedef的形式为cv::Vec{2,3,4,6}{b,s,w,i,f,d}
,其中最后一个字符的含义之前说过。
操作 | 举例 |
---|---|
默认构造 | Vec2s v2s; Vec6f v6f; |
拷贝构造 | Vec3f u3f( v3f ); |
赋值构造 | Vec2f v2f(x0,x1); Vec6d v6d(x0,x1,x2,x3,x4,x5); |
访问成员 | v4f[ i ]; or v3w( j ); |
叉乘 | v3f.cross( u3f ); |
fixed vector 类的主要便利在于能够访问具有单个序数的元素,以及一些对一般矩阵(例如,叉乘)没有意义的特定函数。在从 fixed matrix 类继承的大量方法的基础上添加了相对较少的新方法。
complex number 类
在基本类型中还包括一种类型:complex number 类。OpenCV的 complex number 类与STL复数类模板complex<>
不同,但它们与STL复数类模板complex<>
的类兼容,并且可以相互转换。OpenCV和STL复数类之间最大的区别在于成员访问。在STL类中,实部和虚部通过成员函数real()
和imag()
访问,而在OpenCV类中,它们可以作为(公共)成员变量re
和im
直接访问。cv::Complexf
和cv::Complexd
分别是单精度和双精度的typedef。
操作 | 举例 |
---|---|
默认构造 | cv::Complexf z1; cv::Complexd z2; |
拷贝构造 | cv::Complexf z2( z1 ); |
来自 fix vector 类的拷贝构造 | cv::Complexf u2f( v2f ); |
赋值构造 | cv::Complexd z1(re0); cv::Complexd(re0,im1) ; |
访问成员 | z1.re; z1.im; |
共轭 | z2 = z1.conj(); |