Matx
Matx是用于在编译期间就知道类型和大小的小矩阵模板类。其类定义如下:
template<typename _Tp, int m, int n> class Matx
{
public:
typedef _Tp value_type;
typedef Matx<_Tp, (m < n ? m : n), 1> diag_type;
typedef Matx<_Tp, m, n> mat_type;
enum { depth = DataDepth<_Tp>::value, rows = m, cols = n, channels = rows*cols,
type = CV_MAKETYPE(depth, channels) };
//! default constructor
Matx();
Matx(_Tp v0); //!< 1x1 matrix
Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 1x10, 2x5 or 5x2 or 10x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3,
_Tp v4, _Tp v5, _Tp v6, _Tp v7,
_Tp v8, _Tp v9, _Tp v10, _Tp v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3,
_Tp v4, _Tp v5, _Tp v6, _Tp v7,
_Tp v8, _Tp v9, _Tp v10, _Tp v11,
_Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix
explicit Matx(const _Tp* vals); //!< initialize from a plain array
static Matx all(_Tp alpha);
static Matx zeros();
static Matx ones();
static Matx eye();
static Matx diag(const diag_type& d);
static Matx randu(_Tp a, _Tp b);
static Matx randn(_Tp a, _Tp b);
//! dot product computed with the default precision
_Tp dot(const Matx<_Tp, m, n>& v) const;
//! dot product computed in double-precision arithmetics
double ddot(const Matx<_Tp, m, n>& v) const;
//! convertion to another data type
template<typename T2> operator Matx<T2, m, n>() const;
//! change the matrix shape
template<int m1, int n1> Matx<_Tp, m1, n1> reshape() const;
//! extract part of the matrix
template<int m1, int n1> Matx<_Tp, m1, n1> get_minor(int i, int j) const;
//! extract the matrix row
Matx<_Tp, 1, n> row(int i) const;
//! extract the matrix column
Matx<_Tp, m, 1> col(int i) const;
//! extract the matrix diagonal
diag_type diag() const;
//! transpose the matrix
Matx<_Tp, n, m> t() const;
//! invert matrix the matrix
Matx<_Tp, n, m> inv(int method=DECOMP_LU) const;
//! solve linear system
template<int l> Matx<_Tp, n, l> solve(const Matx<_Tp, m, l>& rhs, int flags=DECOMP_LU) const;
Vec<_Tp, n> solve(const Vec<_Tp, m>& rhs, int method) const;
//! multiply two matrices element-wise
Matx<_Tp, m, n> mul(const Matx<_Tp, m, n>& a) const;
//! element access
const _Tp& operator ()(int i, int j) const;
_Tp& operator ()(int i, int j);
//! 1D element access
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_AddOp);
Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp);
template<typename _T2> Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp);
Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp);
template<int l> Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp);
Matx(const Matx<_Tp, n, m>& a, Matx_TOp);
_Tp val[m*n]; //< matrix elements
};
看着是不是很头疼,不着急,我们不妨宏观的大致了解一下。首先,这个类可以为我们创建一个m*n大小的矩阵。我们可以利用上面所列举的这么多构造函数来创建一个自己想要的矩阵。那么,我们如何去访问这些元素呢,我们可以看到这个类为我们重载了()操作符。所以我们可以通过简单的传递行号和列号来访问这个数组,是不是很方便呢?当然了,这个类也为我们提供了row、col、diag、t和inv方法,这些可以让我们更加方便的获得这个矩阵的某一行,某一列,对角线元素,转置后的矩阵以及矩阵的逆。功能很强大,不是吗?现在,对上面的代码是不是少了点恐惧感。事实上,我们可以像在数学符号中表示的那样去使用这些类。具体使用方法将在Mat类中进行讲解。
Vec
大家看一下Vec的声明,就可以明白Vec类是干嘛的了。
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>
很明显,Vec类是从Matx类继承下来的。其中Matx的n被设置成为了1,所以Vec可以看做是用来存储的一个向量。
当然,为了方便性,opencv也为它定义了很多别名,如下所示:
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
那么同样,它也实现了很多向量间的加减等算术运算:
v1 = v2 + v3
v1 = v2 - v3
v1 = v2 * scale
v1 = scale * v2
v1 = -v2
v1 += v2 and other augmenting operations
v1 == v2, v1 != v2
norm(v1) (euclidean norm)
Scalar_
废话不多说,直接上代码:
template<typename _Tp> class Scalar_ : public Vec<_Tp, 4>
{
public:
//! various constructors
Scalar_();
Scalar_(_Tp v0, _Tp v1, _Tp v2=0, _Tp v3=0);
Scalar_(const CvScalar& s);
Scalar_(_Tp v0);
//! returns a scalar with all elements set to v0
static Scalar_<_Tp> all(_Tp v0);
//! conversion to the old-style CvScalar
operator CvScalar() const;
//! conversion to another data type
template<typename T2> operator Scalar_<T2>() const;
//! per-element product
Scalar_<_Tp> mul(const Scalar_<_Tp>& t, double scale=1 ) const;
// returns (v0, -v1, -v2, -v3)
Scalar_<_Tp> conj() const;
// returns true iff v1 == v2 == v3 == 0
bool isReal() const;
};
typedef Scalar_<double> Scalar;
已经不需要我来说明了,可以很清楚的看到Scalar_类是继承于Vec<_Tp, 4 >类,也就是说Scalar_是一个有四个值的向量。(v0, v1, v2, v3)。
Range
这个类经常被用于指示一个在矩阵中的行或者列区域。在这个范围内,开始被包含在左边的区域内,而结束不被包含在右边的边界内。类似一个半开半闭的区间,[start, end)
class CV_EXPORTS Range
{
public:
Range();
Range(int _start, int _end);
Range(const CvSlice& slice);
int size() const;
bool empty() const;
static Range all();
operator CvSlice() const;
int start, end;
};
静态方法Range::all()返回一个意味着全部序列或全部范围的特殊变量。
Ptr
这个就是OpenCV中的安全指针。自从opencv2.0开始,很多opencv中的C数据结构变成了C++中的类,在内存管理方面,opencv2.0提供了安全指针类Ptr,让在此以前旧的需要手动管理内存的数据结构无需手动释放。
template<typename _Tp> class Ptr
{
public:
//! empty constructor
Ptr();
//! take ownership of the pointer. The associated reference counter is allocated and set to 1
Ptr(_Tp* _obj);
//! calls release()
~Ptr();
//! copy constructor. Copies the members and calls addref()
Ptr(const Ptr& ptr);
template<typename _Tp2> Ptr(const Ptr<_Tp2>& ptr);
//! copy operator. Calls ptr.addref() and release() before copying the members
Ptr& operator = (const Ptr& ptr);
//! increments the reference counter
void addref();
//! decrements the reference counter. If it reaches 0, delete_obj() is called
void release();
//! deletes the object. Override if needed
void delete_obj();
//! returns true iff obj==NULL
bool empty() const;
//! cast pointer to another type
template<typename _Tp2> Ptr<_Tp2> ptr();
template<typename _Tp2> const Ptr<_Tp2> ptr() const;
//! helper operators making "Ptr<T> ptr" use very similar to "T* ptr".
_Tp* operator -> ();
const _Tp* operator -> () const;
operator _Tp* ();
operator const _Tp*() const;
_Tp* obj; //< the object pointer.
int* refcount; //< the associated reference counter
};
上述指针类除了有一个指向封装对象的指针obj外,还增加了一个指针引用数refcount。并对一些操作符进行了重载。
Ptr类把封装的对象看成一个黑盒。引用指针的分配和管理是分开的。这个指针类唯一需要知道的事情是这个对象如何释放。释放被封装在Ptr::delete_obj()方法中,这个方法当引用计数(refcount)变成0的时候自动被调用。如果对象是一个C++类实例,那么就不要增加任何额外的代码,因为默认实现的方法是delete obj; 然而,如果这个对象是通过其他方式被释放,那么这个特殊的释放方式需要被说明。(在上述代码的delete_obj()方法的注释中写道,如果需要的话需要重载)比如,如果封装的是FILE,则delete_obj()应定义如下:
template<> inline void Ptr<FILE>::delete_obj()
{
fclose(obj); // no need to clear the pointer afterwards,
// it is done externally.
}
那么我们就可以这样来使用它。
Ptr<FILE> f(fopen("myfile.txt", "r"));
if(f.empty())
throw ...;
fprintf(f, ....);
...
文件将会随着Ptr<FILE>的析构自动关闭。