從源碼學習OpenCV(二)Mat

一、Mat

我們有多種方式從現實世界中獲取數字圖像:數碼相機,掃描儀,計算機斷層掃描和磁共振成像等等。在任何情況下,我們(人類)看到的都是圖像。然而,當將其轉換爲數字設備時,我們記錄的是圖像中每個點的數值。
在這裏插入圖片描述
在上述圖像中,您可以看到汽車的鏡像只不過是一個包含像素點所有強度值的矩陣。我們如何獲取和存儲像素值可能會根據我們的需要而有所不同,但最終,計算機世界內的所有圖像可能會被減少到描述矩陣本身的數字矩陣和其他信息。OpenCV是一個計算機視覺庫,其主要重點是處理和操縱這些信息。因此,您需要熟悉的第一件事是OpenCV如何存儲和處理圖像。1

1.Mat類說明

類Mat表示一個n維密集的數值單通道或多通道陣列。它可以用來存儲實值的或復值(real or complex-valued)的向量(vectors)和矩陣(matrices)、灰度或彩色圖像(grayscale or color images)、體素卷(voxel volumes)、向量場(vector fields)、點雲(point clouds)、張量(tensors)、直方圖(histograms )。數組 M 的數據佈局由數組 M.step[] 定義,因此元素的地址(i0,...,iM.dims1)(i_0,...,i_{M.dims−1})可以通過以下計算:
addr(Mi0,...,iM.dims1)=M.data+M.step[0]i0+M.step[1]i1+...+M.step[M.dims1]iM.dims1 addr(M_{i_0,...,i_{M.dims-1}}) = M.data + M.step[0]*i_0 + M.step[1]*i_1 + ... + M.step[M.dims-1]*i_{M.dims-1}
對於二維數組,可將上述公式簡化爲:
addr(Mi,j)=M.data+M.step[0]i+M.step[1]j addr(M_{i,j}) = M.data + M.step[0]*i + M.step[1]*j
注意到M.step[i] >= M.step[i+1](事實上M.step[i] >= M.step[i+1]*M.size[i+1]),這意味着二維矩陣是逐行存儲的三維矩陣是逐平面存儲的,依此類推。 M.step[M.dims-1] 是最小的,並且總是等於元素大小M.elemSize()
因此,Mat中的數據佈局與標準工具包和SDK中的大多數密集數組類型兼容,比如Numpy (ndarray)、Win32(獨立設備位圖)和其他類型,也就是說,與任何使用步幅計算像素位置的數組兼容。由於這種兼容性,可以爲用戶分配的數據製作一個Mat頭文件,並使用OpenCV函數對其進行就地處理。2

2.Mat類聲明

opencv-4.1.1\modules\core\include\opencv2\core\mat.hpp

class CV_EXPORTS Mat
{
public:
	// ------常用構造函數------ //
 	Mat();
 	Mat(int rows, int cols, int type);
 	Mat(Size size, int type);
 	Mat(int rows, int cols, int type, const Scalar &s);
 	Mat(Size size, int type, const Scalar &s);
 	Mat(int ndims, const int *sizes, int type);
 	Mat(const std::vector< int > &sizes, int type);
 	Mat(int ndims, const int *sizes, int type, const Scalar &s);
 	Mat(const std::vector< int > &sizes, int type, const Scalar &s);
 	Mat(const Mat &m);
 	Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);
 	
 	// ------部分方法-------- //
 	void create(int rows, int cols, int type);
 	void create(Size size, int type);
 	void create(int ndims, const int *sizes, int type);
 	void create(const std::vector< int > &sizes, int type);
 	
 	// --------屬性-------- //
 	int flags;
    //! 矩陣的維數, >= 2
    int dims;
    //! 當矩陣的維數大於2時,行數和列數或(- 1,1)
    int rows, cols;
    //! 指向數據的指針
    uchar* data;

    //! 在locateROI和adjustROI中使用的助手字段
    const uchar* datastart;
    const uchar* dataend;
    const uchar* datalimit;

    //! 定製的分配器
    MatAllocator* allocator;
    
    //! 與UMat互動
    UMatData* u;

    MatSize size;
    MatStep step;
	
	// ------靜態函數------- //
	// 創建一個對角矩陣
	static Mat diag(const Mat& d);	
	// 返回指定大小和類型的單位矩陣
	static MatExpr eye(int rows, int cols, int type);
	static MatExpr eye(Size size, int type);
	// 返回指定大小和類型的所有值爲1的數組
	static MatExpr ones(int rows, int cols, int type);
	static MatExpr ones(Size size, int type);
	static MatExpr ones(int ndims, const int* sz, int type);
	// 返回指定大小和類型的零數組
	static MatExpr zeros(int rows, int cols, int type);
	static MatExpr zeros(Size size, int type);
	static MatExpr zeros(int ndims, const int* sz, int type);
 	// ......
 	// 省略部分代碼
 	// ......
}

3.構造函數實現

opencv-4.1.1\modules\core\include\opencv2\core\mat.inl.hpp

  • Mat()

    inline
    Mat::Mat()
        : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
          datalimit(0), allocator(0), u(0), size(&rows), step(0)
    {}
    
  • Mat(Size size, int type)
    Size size – 二維數組大小。Size(cols, rows),在Size()構造函數中,行數和
    列數的順序相反。查看 Size 類型。
    int type – 數組類型。使用CV_8UC1,…, CV_64FC4創建1-4通道矩陣,或CV_8UC (n),……, CV_64FC(n)創建多通道(最多CV_CN_MAX通道)矩陣。

    inline
    Mat::Mat(Size _sz, int _type)
        : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
          datalimit(0), allocator(0), u(0), size(&rows), step(0)
    {
        create( _sz.height, _sz.width, _type );
    }
    
  • Mat(int rows, int cols, int type)
    int rows – 二維數組中的行數
    int cols – 二維數組中的列數
    查看 create 函數。

    inline
    Mat::Mat(int _rows, int _cols, int _type)
        : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
          datalimit(0), allocator(0), u(0), size(&rows), step(0)
    {
        create(_rows, _cols, _type);
    }
    
  • Mat(int rows, int cols, int type, const Scalar& s);
    const Scalar& s – 參數s是一個可選值,用於初始化每個矩陣元素。查看 Scalar 類型。

    inline
    Mat::Mat(int _rows, int _cols, int _type, const Scalar& _s)
        : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
          datalimit(0), allocator(0), u(0), size(&rows), step(0)
    {
        create(_rows, _cols, _type);
        *this = _s;
    }
    
  • Mat(Size size, int type, const Scalar &s)

    inline
    Mat::Mat(Size _sz, int _type, const Scalar& _s)
        : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
          datalimit(0), allocator(0), u(0), size(&rows), step(0)
    {
        create(_sz.height, _sz.width, _type);
        *this = _s;
    }
    
  • Mat(int ndims, const int* sizes, int type)

    inline
    Mat::Mat(int _dims, const int* _sz, int _type)
        : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
          datalimit(0), allocator(0), u(0), size(&rows), step(0)
    {
        create(_dims, _sz, _type);
    }
    
  • Mat(const std::vector< int > &sizes, int type)
    const std::vector< int > &sizes – 指定n維數組形狀的整數數組的大小。

    inline
    Mat::Mat(const std::vector<int>& _sz, int _type)
        : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
          datalimit(0), allocator(0), u(0), size(&rows), step(0)
    {
        create(_sz, _type);
    }
    
  • Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
    size_t step – 每個矩陣行佔用的字節數。如果有填充字節,則該值應該包括每一行末尾的填充字節。如果缺少參數(設置爲AUTO_STEP),則假定沒有填充,實際的步驟計算爲cols*elemSize()。typedef unsigned int size_t;

    inline
    Mat::Mat(int _rows, int _cols, int _type, void* _data, size_t _step)
        : flags(MAGIC_VAL + (_type & TYPE_MASK)), dims(2), rows(_rows), cols(_cols),
          data((uchar*)_data), datastart((uchar*)_data), dataend(0), datalimit(0),
          allocator(0), u(0), size(&rows)
    {
        CV_Assert(total() == 0 || data != NULL);
    
        size_t esz = CV_ELEM_SIZE(_type), esz1 = CV_ELEM_SIZE1(_type);
        size_t minstep = cols * esz;
        if( _step == AUTO_STEP )
        {
            _step = minstep;
        }
        else
        {
            CV_DbgAssert( _step >= minstep );
            if (_step % esz1 != 0)
            {
                CV_Error(Error::BadStep, "Step must be a multiple of esz1");
            }
        }
        step[0] = _step;
        step[1] = esz;
        datalimit = datastart + _step * rows;
        dataend = datalimit - _step + minstep;
        updateContinuityFlag();
    }
    

4.成員函數實現

create

分配新的數組數據。

  • void create(int rows, int cols, int type)

    opencv-4.1.1\modules\core\include\opencv2\core\mat.inl.hpp

    inline
    void Mat::create(int _rows, int _cols, int _type)
    {
        _type &= TYPE_MASK;
        if( dims <= 2 && rows == _rows && cols == _cols && type() == _type && data )
            return;
        int sz[] = {_rows, _cols};
        create(2, sz, _type);
    }
    
  • void create (Size size, int type)

    opencv-4.1.1\modules\core\include\opencv2\core\mat.inl.hpp

    inline
    void Mat::create(Size _sz, int _type)
    {
        create(_sz.height, _sz.width, _type);
    }
    
  • void create(int ndims, const int *sizes, int type)

    opencv-4.1.1\modules\core\src\matrix.cpp

    void Mat::create(int d, const int* _sizes, int _type)
    {
        int i;
        CV_Assert(0 <= d && d <= CV_MAX_DIM && _sizes);
        _type = CV_MAT_TYPE(_type);
    
        if( data && (d == dims || (d == 1 && dims <= 2)) && _type == type() )
        {
            if( d == 2 && rows == _sizes[0] && cols == _sizes[1] )
                return;
            for( i = 0; i < d; i++ )
                if( size[i] != _sizes[i] )
                    break;
            if( i == d && (d > 1 || size[1] == 1))
                return;
        }
    
        int _sizes_backup[CV_MAX_DIM]; // #5991
        if (_sizes == (this->size.p))
        {
            for(i = 0; i < d; i++ )
                _sizes_backup[i] = _sizes[i];
            _sizes = _sizes_backup;
        }
    
        release();
        if( d == 0 )
            return;
        flags = (_type & CV_MAT_TYPE_MASK) | MAGIC_VAL;
        setSize(*this, d, _sizes, 0, true);
    
        if( total() > 0 )
        {
            MatAllocator *a = allocator, *a0 = getDefaultAllocator();
    #ifdef HAVE_TGPU
            if( !a || a == tegra::getAllocator() )
                a = tegra::getAllocator(d, _sizes, _type);
    #endif
            if(!a)
                a = a0;
            try
            {
                u = a->allocate(dims, size, _type, 0, step.p, ACCESS_RW /* ignored */, USAGE_DEFAULT);
                CV_Assert(u != 0);
            }
            catch (...)
            {
                if (a == a0)
                    throw;
                u = a0->allocate(dims, size, _type, 0, step.p, ACCESS_RW /* ignored */, USAGE_DEFAULT);
                CV_Assert(u != 0);
            }
            CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) );
        }
    
        addref();
        finalizeHdr(*this);
    }
    
  • void create(const std::vector< int > &sizes, int type)

    opencv-4.1.1\modules\core\src\matrix.cpp

    void Mat::create(const std::vector<int>& _sizes, int _type)
    {
        create((int)_sizes.size(), _sizes.data(), _type);
    }
    

5.靜態函數實現

  • static Mat diag(const Mat& d)

opencv-4.1.1\modules\core\src\matrix.cpp

Mat Mat::diag(const Mat& d)
{
    CV_Assert( d.cols == 1 || d.rows == 1 );
    int len = d.rows + d.cols - 1;
    Mat m(len, len, d.type(), Scalar(0));
    Mat md = m.diag();
    if( d.cols == 1 )
        d.copyTo(md);
    else
        transpose(d, md);
    return m;
}
  • eyeoneszeros

opencv-4.1.1\modules\core\src\matrix_expressions.cpp

MatExpr Mat::zeros(int rows, int cols, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, '0', Size(cols, rows), type);
    return e;
}

MatExpr Mat::zeros(Size size, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, '0', size, type);
    return e;
}

MatExpr Mat::zeros(int ndims, const int* sizes, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, '0', ndims, sizes, type);
    return e;
}

MatExpr Mat::ones(int rows, int cols, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, '1', Size(cols, rows), type);
    return e;
}

MatExpr Mat::ones(Size size, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, '1', size, type);
    return e;
}

MatExpr Mat::ones(int ndims, const int* sizes, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, '1', ndims, sizes, type);
    return e;
}

MatExpr Mat::eye(int rows, int cols, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, 'I', Size(cols, rows), type);
    return e;
}

MatExpr Mat::eye(Size size, int type)
{
    CV_INSTRUMENT_REGION();

    MatExpr e;
    MatOp_Initializer::makeExpr(e, 'I', size, type);
    return e;
}

相關代碼

Size

用於指定圖像或矩形大小。

opencv-4.1.1\modules\core\include\opencv2\core\types.hpp

typedef Size2i Size;

typedef Size_<int> Size2i;

template<typename _Tp> class Size_
{
public:
    typedef _Tp value_type;

    //! default constructor
    Size_();
    Size_(_Tp _width, _Tp _height);
    Size_(const Size_& sz);
    Size_(Size_&& sz) CV_NOEXCEPT;
    Size_(const Point_<_Tp>& pt);

    Size_& operator = (const Size_& sz);
    Size_& operator = (Size_&& sz) CV_NOEXCEPT;
    //! the area (width*height)
    _Tp area() const;
    //! aspect ratio (width/height)
    double aspectRatio() const;
    //! true if empty
    bool empty() const;

    //! conversion of another data type.
    template<typename _Tp2> operator Size_<_Tp2>() const;

    _Tp width; //!< the width
    _Tp height; //!< the height
};

數組類型

opencv-4.1.1\modules\core\include\opencv2\core\hal\interface.h

CV_8U - 8位無符號整數(0…255)
CV_8S - 8位帶符號整數(-128…127)
CV_16U - 16位無符號整數(0…65535)
CV_16S - 16位帶符號整數(-32768…32767)
CV_32S - 32位帶符號整數(-2147483648…2147483647)
CV_32F - 32位浮點數(- flt_max …FLT_MAX, INF, NAN)
CV_64F - 64位浮點數(- dbl_max …DBL_MAX, INF, NAN)

#define CV_CN_MAX     512
#define CV_CN_SHIFT   3
#define CV_DEPTH_MAX  (1 << CV_CN_SHIFT)

#define CV_8U   0
#define CV_8S   1
#define CV_16U  2
#define CV_16S  3
#define CV_32S  4
#define CV_32F  5
#define CV_64F  6
#define CV_16F  7

#define CV_MAT_DEPTH_MASK       (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags)     ((flags) & CV_MAT_DEPTH_MASK)

#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_MAKE_TYPE CV_MAKETYPE

#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))

#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))

#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))

#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))

#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))

#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))

#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))

#define CV_16FC1 CV_MAKETYPE(CV_16F,1)
#define CV_16FC2 CV_MAKETYPE(CV_16F,2)
#define CV_16FC3 CV_MAKETYPE(CV_16F,3)
#define CV_16FC4 CV_MAKETYPE(CV_16F,4)
#define CV_16FC(n) CV_MAKETYPE(CV_16F,(n))

Scalar

包含四個double型值元素的數值向量

opencv-4.1.1\modules\core\include\opencv2\core\types.hpp

typedef Scalar_<double> Scalar;

template<typename _Tp> class Scalar_ : public Vec<_Tp, 4>
{
public:
    //! default constructor
    Scalar_();
    Scalar_(_Tp v0, _Tp v1, _Tp v2=0, _Tp v3=0);
    Scalar_(_Tp v0);

    Scalar_(const Scalar_& s);
    Scalar_(Scalar_&& s) CV_NOEXCEPT;

    Scalar_& operator=(const Scalar_& s);
    Scalar_& operator=(Scalar_&& s) CV_NOEXCEPT;

    template<typename _Tp2, int cn>
    Scalar_(const Vec<_Tp2, cn>& v);

    //! returns a scalar with all elements set to v0
    static Scalar_<_Tp> all(_Tp v0);

    //! conversion to another data type
    template<typename T2> operator Scalar_<T2>() const;

    //! per-element product
    Scalar_<_Tp> mul(const Scalar_<_Tp>& a, double scale=1 ) const;

    //! returns (v0, -v1, -v2, -v3)
    Scalar_<_Tp> conj() const;

    //! returns true iff v1 == v2 == v3 == 0
    bool isReal() const;
};

  1. Mat-基本圖像容器 - w3cschool ↩︎

  2. Mat - The Basic Image Container - opencv.org ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章