OpenCV源碼閱讀(1)---matx.h---mat類與vec類


matx.h

matx類是opencv中的一個基礎類,其位於core模塊中,所執行的操作時opencv矩陣和向量的運算。如果熟悉基於matlab的圖像處理,那么很容易想到,所有對圖像的操作歸根結底都是對矩陣的操作。盡管matx類不是opencv最基礎的類,但是我認為以此進入圖像處理學習和熟悉c++程序是合適的。

1.頭文件和基礎

#ifndef __OPENCV_CORE_MATX_HPP__
#define __OPENCV_CORE_MATX_HPP__

#ifndef __cplusplus
# error matx.hpp header must be compiled as C++
#endif

#include "opencv2/core/cvdef.h"
#include "opencv2/core/base.hpp"
#include "opencv2/core/traits.hpp"

這是matx類所包含的頭文件。其中cvdef.h是opencv的宏定義,定義了基本的cv數據類型等。base.h和traits.h的意義被我忘了,回頭補吧。

這也說明了寫文檔的重要性,不寫就忘了。

namespace cv
{

這是表示使用cv這個namespace用’{‘擴起來的范圍使用的都是cv

2.矩陣操作定義

struct CV_EXPORTS Matx_AddOp {};
struct CV_EXPORTS Matx_SubOp {};
struct CV_EXPORTS Matx_ScaleOp {};
struct CV_EXPORTS Matx_MulOp {};
struct CV_EXPORTS Matx_DivOp {};
struct CV_EXPORTS Matx_MatMulOp {};
struct CV_EXPORTS Matx_TOp {};

這里定義了矩陣的基本運算,加、減、縮放、乘、除、矩陣乘法、轉置,使用的是結構體定義的方式,但是沒有具體給出結構體里的內容。注意着只是頭文件。繼續往下看。

3.matx類聲明

template<typename _Tp, int m, int n> class Matx
{
public:
    enum { depth    = DataType<_Tp>::depth,
           rows     = m,
           cols     = n,
           channels = rows*cols,
           type     = CV_MAKETYPE(depth, channels),
           shortdim = (m < n ? m : n)
         };

    typedef _Tp                           value_type;
    typedef Matx<_Tp, m, n>               mat_type;
    typedef Matx<_Tp, shortdim, 1> diag_type;

這里進入正題,使用了類模板的定義方式。

template<typename _Tp,int m,int n> class Matx

這種寫法稱為模板操作。
首先是一個枚舉數據結構,給matx的公有成員進行賦值,值得注意的是channels定義為矩陣的行乘以列。也就是矩陣元素總數。接下來利用別名機制,定義了value–矩陣值的類型,mat–type,這個指矩陣的類型,包含矩陣值類型,行,列數目。最后是diag_type,數據類型是matx_是一個k行一列的矩陣,k是m,n中較小的值,有可能是矩陣的秩。

3.1 類的構造函數

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

其實在vs2010里看見的是一個非常漂亮的三角形,但是在網頁上就不那么漂亮了。這里一共14個構造函數,除去第一個是缺省構造函數,最后一個是利用數組來對矩陣進行復制以外。其他都老老實實用參數對matx類進行復制初始化。
這里說一下explicit關鍵字,這是用來防止隱式轉換發生的。搬運百度百科一個很好的例子

class Test1
{
public:
Test1(int n)
{
num=n;
}//普通構造函數
private:
int num;
};
class Test2
{
public:
explicit Test2(int n)
{
num=n;
}//explicit(顯式)構造函數
private:
int num;
};
int main()
{
Test1 t1=12;//隱式調用其構造函數,成功
Test2 t2=12;//編譯錯誤,不能隱式調用其構造函數
Test2 t2(12);//顯式調用成功
return 0;
}
也就是說,opencv允許了使用matx mat(val)這樣以數組初始化矩陣的方式,但是不允許寫成matx mat = val這樣的形式。

繼續看源碼

    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);

這里定義了6個函數,函數返回值的類型都是Matx類,並且這都是靜態成員函數,代表其可以調用類內的靜態數據成員。不能調用非靜態數據成員,據說是因為靜態成員函數不包含this指針。
這些函數的作用是生成特殊矩陣,如:所有元素全部一樣,零矩陣,全部都是1的矩陣,單位陣,對角陣,隨機陣。

3.2 類的成員函數—矩陣操作

    //! 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;

定義了矩陣的點積,其中_Tp是函數模板類型,也就是矩陣元素的類型,在此處屬於重載函數,讓點積的類型和元素類型相同。dot函數的輸入參數是一個矩陣。屬於常成員函數。

常成員函數只能讀取類的成員變量,而不能修改它。是對數據的保護

    //! 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;

reshape函數,返回值是Matx類型。

    //! 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;

上述函數都定義了矩陣的操作,返回類型都是矩陣。唯有diag_type也就是提取對角元素的函數例外,從前面的分析可知,diag_type是矩陣類型的數據,一行,k列,k是m,n中小的。

    //! invert the matrix
    Matx<_Tp, n, m> inv(int method=DECOMP_LU, bool *p_is_ok = NULL) 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;

上面的操作時對矩陣求逆和求取線性方程的值,使用了標識符DECOMP_LU,這個應該屬於一種宏定義,在頭文件中可以找到它的蹤跡。

    //! multiply two matrices element-wise
    Matx<_Tp, m, n> mul(const Matx<_Tp, m, n>& a) const;

    //! divide two matrices element-wise
    Matx<_Tp, m, n> div(const Matx<_Tp, m, n>& a) const;

這里表達的是矩陣乘除對應元素,相當於matlab中的 .*./

    //! 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);

將操作符重載為常成員函數和普通成員函數,操作符的結合數為i和j

    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);
    Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_DivOp);
    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);

這里聲明的是矩陣的操作,操作方法是常引用矩陣a,b同時輸入一個結構體Matx_*Op但是這個結構體在定義時並沒有任何成員,為什么要這樣寫呢?需要繼續查看函數的定義。

3.3 類的數據成員

    _Tp val[m*n]; //< matrix elements
};

終於找到你!!!!原來矩陣類的核心就是這個m*n的數組!!!!!
到此為止,整個matx類聲明結束了。

matx.h頭文件matx類閱讀—————20150512未完待續

宏定義——矩陣類型

在matx類的聲明之后,是一串宏定義,用於方便的定義各種矩陣。

typedef Matx<float, 1, 2> Matx12f;
typedef Matx<double, 1, 2> Matx12d;
typedef Matx<float, 1, 3> Matx13f;
typedef Matx<double, 1, 3> Matx13d;
typedef Matx<float, 1, 4> Matx14f;
typedef Matx<double, 1, 4> Matx14d;
typedef Matx<float, 1, 6> Matx16f;
typedef Matx<double, 1, 6> Matx16d;

typedef Matx<float, 2, 1> Matx21f;
typedef Matx<double, 2, 1> Matx21d;
typedef Matx<float, 3, 1> Matx31f;
typedef Matx<double, 3, 1> Matx31d;
typedef Matx<float, 4, 1> Matx41f;
typedef Matx<double, 4, 1> Matx41d;
typedef Matx<float, 6, 1> Matx61f;
typedef Matx<double, 6, 1> Matx61d;

typedef Matx<float, 2, 2> Matx22f;
typedef Matx<double, 2, 2> Matx22d;
typedef Matx<float, 2, 3> Matx23f;
typedef Matx<double, 2, 3> Matx23d;
typedef Matx<float, 3, 2> Matx32f;
typedef Matx<double, 3, 2> Matx32d;

typedef Matx<float, 3, 3> Matx33f;
typedef Matx<double, 3, 3> Matx33d;

typedef Matx<float, 3, 4> Matx34f;
typedef Matx<double, 3, 4> Matx34d;
typedef Matx<float, 4, 3> Matx43f;
typedef Matx<double, 4, 3> Matx43d;

typedef Matx<float, 4, 4> Matx44f;
typedef Matx<double, 4, 4> Matx44d;
typedef Matx<float, 6, 6> Matx66f;
typedef Matx<double, 6, 6> Matx66d;

這里通過給類型名取別名的方式,定義了不同大小,不同數據結構的矩陣型類型名。

vec類

vec類是退化后的matx類,也就是只有一列的矩陣,定義為
template<tempname _Tp,int m> class vec:pulic Matx(_Tp,m,1)

template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>
{
public:
    typedef _Tp value_type;
    enum { depth    = Matx<_Tp, cn, 1>::depth,
           channels = cn,
           type     = CV_MAKETYPE(depth, channels)
         };

    //! default constructor
    Vec();

    Vec(_Tp v0); //!< 1-element vector constructor
    Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor
    Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 10-element vector constructor
    explicit Vec(const _Tp* values);

    Vec(const Vec<_Tp, cn>& v);

    static Vec all(_Tp alpha);

    //! per-element multiplication
    Vec mul(const Vec<_Tp, cn>& v) const;

    //! conjugation (makes sense for complex numbers and quaternions)
    Vec conj() const;

    /*! cross product of the two 3D vectors. For other dimensionalities the exception is raised */
    Vec cross(const Vec& v) const;
    //! convertion to another data type
    template<typename T2> operator Vec<T2, cn>() const;

    /*! element access */
    const _Tp& operator [](int i) const;
    _Tp& operator[](int i);
    const _Tp& operator ()(int i) const;
    _Tp& operator ()(int i);

    Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp);
    Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp);
    template<typename _T2> Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp);
};

/* \typedef Shorter aliases for the most popular specializations of Vec<T,n> */
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<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;

typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;

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;

/*! traits */
template<typename _Tp, int cn> class DataType< Vec<_Tp, cn> >
{
public:
    typedef Vec<_Tp, cn>                               value_type;
    typedef Vec<typename DataType<_Tp>::work_type, cn> work_type;
    typedef _Tp                                        channel_type;
    typedef value_type                                 vec_type;

    enum { generic_type = 0,
           depth        = DataType<channel_type>::depth,
           channels     = cn,
           fmt          = DataType<channel_type>::fmt + ((channels - 1) << 8),
           type         = CV_MAKETYPE(depth, channels)
         };
};

/*! Comma-separated Vec Initializer */
template<typename _Tp, int m> class VecCommaInitializer : public MatxCommaInitializer<_Tp, m, 1>
{
public:
    VecCommaInitializer(Vec<_Tp, m>* _vec);
    template<typename T2> VecCommaInitializer<_Tp, m>& operator , (T2 val);
    Vec<_Tp, m> operator *() const;
};

/*! Utility methods */
template<typename _Tp, int cn> static Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v);

這完全就是matx類的翻版。具體解釋參考matx類。

版權聲明:本文為博主原創文章,未經博主允許不得轉載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM