3.opencv由浅入深--Mat类详解与使用

3.opencv由浅入深–Mat类详解与使用

1.opencv核心类Mat

在计算机内存中,数字图像以矩阵的形式存储和运算;在Opencv1.x版本中,图像的处理是通过IplImage结构体来实现,IplImage结构是OpenCV矩阵运算的基本数据结构。到Opencv2.x版本后,OpenCV开源库引入了面向对象编程思想,大量源代码用C++重写,Mat类 是OpenCV用于处理图像而引入的一个封装类。深入了解Mat类对于OpenCV深入开发有着重大意义。

1.1 Mat类概述

Mat-基本图像容器

cv::Mat是OpenCV定义的用于表示任意维度的稠密数组,OpenCV使用它来存储和传递图像。Mat类很大、很全面,基本覆盖计算机视觉对于图像处理的基本要求。其成员变量、函数也比较多,了解其常用的成员变量、函数就可以完成大部分的工作。
Mat类可以分为两个部分:矩阵头和指向像素数据的矩阵指针;
矩阵头包括数字图像的矩阵尺寸、存储方法、存储地址和引用次数等,矩阵头的大小是一个常数,不会随着图像的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,通常数据量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针。

以下是去掉注释后(300行,没有去掉注释1000多行,自己体会)的Mat类,等后面用到具体函数,再具体分析。
在mat.hpp中定义Mat类,包括继承自Mat类的其他类;

class CV_EXPORTS Mat
{
public:
    Mat() CV_NOEXCEPT;

    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& sizes, int type);

    Mat(int ndims, const int* sizes, int type, const Scalar& s);

    Mat(const std::vector& sizes, int type, const Scalar& s);

    Mat(const Mat& m);

    Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);

    Mat(Size size, int type, void* data, size_t step=AUTO_STEP);

    Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0);

    Mat(const std::vector& sizes, int type, void* data, const size_t* steps=0);

    Mat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all());

    Mat(const Mat& m, const Rect& roi);

    Mat(const Mat& m, const Range* ranges);

    Mat(const Mat& m, const std::vector& ranges);

    template explicit Mat(const std::vector<_Tp>& vec, bool copyData=false);

    template::value>::type>
    explicit Mat(const std::initializer_list<_Tp> list);

    template explicit Mat(const std::initializer_list sizes, const std::initializer_list<_Tp> list);

    template explicit Mat(const std::array<_Tp, _Nm>& arr, bool copyData=false);

    template explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true);

    template explicit Mat(const Matx<_Tp, m, n>& mtx, bool copyData=true);

    template explicit Mat(const Point_<_Tp>& pt, bool copyData=true);

    template explicit Mat(const Point3_<_Tp>& pt, bool copyData=true);

    template explicit Mat(const MatCommaInitializer_<_Tp>& commaInitializer);

    //! download data from GpuMat
    explicit Mat(const cuda::GpuMat& m);

    //! destructor - calls release()
    ~Mat();

    Mat& operator = (const Mat& m);

    Mat& operator = (const MatExpr& expr);

    //! retrieve UMat from Mat
    UMat getUMat(AccessFlag accessFlags, UMatUsageFlags usageFlags = USAGE_DEFAULT) const;

    Mat row(int y) const;

    Mat col(int x) const;

    Mat rowRange(int startrow, int endrow) const;

    Mat rowRange(const Range& r) const;

    Mat colRange(int startcol, int endcol) const;

    Mat colRange(const Range& r) const;

    Mat diag(int d=0) const;

    CV_NODISCARD_STD static Mat diag(const Mat& d);

    CV_NODISCARD_STD Mat clone() const;

    void copyTo( OutputArray m ) const;

    void copyTo( OutputArray m, InputArray mask ) const;

    void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;

    void assignTo( Mat& m, int type=-1 ) const;

    Mat& operator = (const Scalar& s);

    Mat& setTo(InputArray value, InputArray mask=noArray());

    Mat reshape(int cn, int rows=0) const;

    Mat reshape(int cn, int newndims, const int* newsz) const;

    Mat reshape(int cn, const std::vector& newshape) const;

    MatExpr t() const;

    MatExpr inv(int method=DECOMP_LU) const;

    MatExpr mul(InputArray m, double scale=1) const;

    Mat cross(InputArray m) const;

    double dot(InputArray m) const;

    CV_NODISCARD_STD static MatExpr zeros(int rows, int cols, int type);

    CV_NODISCARD_STD static MatExpr zeros(Size size, int type);

    CV_NODISCARD_STD static MatExpr zeros(int ndims, const int* sz, int type);

    CV_NODISCARD_STD static MatExpr ones(int rows, int cols, int type);

    CV_NODISCARD_STD static MatExpr ones(Size size, int type);

    CV_NODISCARD_STD static MatExpr ones(int ndims, const int* sz, int type);

    CV_NODISCARD_STD static MatExpr eye(int rows, int cols, int type);

    CV_NODISCARD_STD static MatExpr eye(Size size, int type);

    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& sizes, int type);

    void addref();

    void release();

    void deallocate();

    void copySize(const Mat& m);

    void reserve(size_t sz);

    void reserveBuffer(size_t sz);

    void resize(size_t sz);

    void resize(size_t sz, const Scalar& s);

    //! internal function
    void push_back_(const void* elem);

    template void push_back(const _Tp& elem);

    template void push_back(const Mat_<_Tp>& elem);

    template void push_back(const std::vector<_Tp>& elem);

    void push_back(const Mat& m);

    void pop_back(size_t nelems=1);

    void locateROI( Size& wholeSize, Point& ofs ) const;

    Mat& adjustROI( int dtop, int dbottom, int dleft, int dright );

    Mat operator()( Range rowRange, Range colRange ) const;

    Mat operator()( const Rect& roi ) const;

    Mat operator()( const Range* ranges ) const;

    Mat operator()(const std::vector& ranges) const;

    template operator std::vector<_Tp>() const;
    template operator Vec<_Tp, n>() const;
    template operator Matx<_Tp, m, n>() const;

    template operator std::array<_Tp, _Nm>() const;

    bool isContinuous() const;

    //! returns true if the matrix is a submatrix of another matrix
    bool isSubmatrix() const;

    size_t elemSize() const;

    size_t elemSize1() const;

    int type() const;

    int depth() const;

    int channels() const;

    size_t step1(int i=0) const;

    bool empty() const;

    size_t total() const;

    size_t total(int startDim, int endDim=INT_MAX) const;

    int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const;

    uchar* ptr(int i0=0);

    const uchar* ptr(int i0=0) const;

    uchar* ptr(int row, int col);

    const uchar* ptr(int row, int col) const;

    uchar* ptr(int i0, int i1, int i2);

    const uchar* ptr(int i0, int i1, int i2) const;

    uchar* ptr(const int* idx);

    const uchar* ptr(const int* idx) const;
  
    template uchar* ptr(const Vec& idx);
 
    template const uchar* ptr(const Vec& idx) const;

    template _Tp* ptr(int i0=0);
 
    template const _Tp* ptr(int i0=0) const;

    template _Tp* ptr(int row, int col);

    template const _Tp* ptr(int row, int col) const;

    template _Tp* ptr(int i0, int i1, int i2);

    template const _Tp* ptr(int i0, int i1, int i2) const;

    template _Tp* ptr(const int* idx);

    template const _Tp* ptr(const int* idx) const;

    template _Tp* ptr(const Vec& idx);

    template const _Tp* ptr(const Vec& idx) const;

    template _Tp& at(int i0=0);

    template const _Tp& at(int i0=0) const;

    template _Tp& at(int row, int col);

    template const _Tp& at(int row, int col) const;

    template _Tp& at(int i0, int i1, int i2);

    template const _Tp& at(int i0, int i1, int i2) const;

    template _Tp& at(const int* idx);

    template const _Tp& at(const int* idx) const;

    template _Tp& at(const Vec& idx);

    template const _Tp& at(const Vec& idx) const;

    template _Tp& at(Point pt);

    template const _Tp& at(Point pt) const;

    template MatIterator_<_Tp> begin();
    template MatConstIterator_<_Tp> begin() const;

    template std::reverse_iterator> rbegin();
    template std::reverse_iterator> rbegin() const;

    template MatIterator_<_Tp> end();
    template MatConstIterator_<_Tp> end() const;

    template std::reverse_iterator< MatIterator_<_Tp>> rend();
    template std::reverse_iterator< MatConstIterator_<_Tp>> rend() const;

    template void forEach(const Functor& operation);

    template void forEach(const Functor& operation) const;

    Mat(Mat&& m);
    Mat& operator = (Mat&& m);

    enum { MAGIC_VAL  = 0x42FF0000, AUTO_STEP = 0, CONTINUOUS_FLAG = CV_MAT_CONT_FLAG, SUBMATRIX_FLAG = CV_SUBMAT_FLAG };
    enum { MAGIC_MASK = 0xFFFF0000, TYPE_MASK = 0x00000FFF, DEPTH_MASK = 7 };

    /*! includes several bit-fields:
         - the magic signature
         - continuity flag
         - depth
         - number of channels
     */
    int flags;
    //! the matrix dimensionality, >= 2
    int dims;
    //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
    int rows, cols;
    //! pointer to the data
    uchar* data;

    //! helper fields used in locateROI and adjustROI
    const uchar* datastart;
    const uchar* dataend;
    const uchar* datalimit;

    //! custom allocator
    MatAllocator* allocator;
    //! and the standard allocator
    static MatAllocator* getStdAllocator();
    static MatAllocator* getDefaultAllocator();
    static void setDefaultAllocator(MatAllocator* allocator);

    //! internal use method: updates the continuity flag
    void updateContinuityFlag();

    //! interaction with UMat
    UMatData* u;

    MatSize size;
    MatStep step;

protected:
    template void forEach_impl(const Functor& operation);
};

1.2 Mat类成员变量

1、flags 标志

从flags的注释来看,这个变量应该是用来作为标志的。
从定义可以看出flags是int类型,共占32位。
从低位到高位:
0-2位代表depth即数据类型(如CV_8U),OpenCV的数据类型共7类,故只需3位即可全部表示。
3-11位代表通道数channels,因为OpenCV默认最大通道数为512,故只需要9位即可全部表示,可参照下面求通道数的部分。
0-11位共同代表type即通道数和数据类型(如CV_8UC3)
12-13位暂没发现用处,也许是留着后用,待发现了再补上。
14位代表Mat的内存是否连续,一般由creat创建的mat均是连续的,如果是连续,将加快对数据的访问。
15位代表该Mat是否为某一个Mat的submatrix,一般通过ROI以及row()、col()、rowRange()、colRange()等得到的mat均为submatrix。
16-31代表magic signature,暂理解为用来区分Mat的类型,如果Mat和SparseMat

在modules\core\include\opencv2\core\mat.inl.hpp中:
inline
bool UMat::isContinuous() const
{
    return (flags & CONTINUOUS_FLAG) != 0;
}

inline
bool UMat::isSubmatrix() const
{
    return (flags & SUBMATRIX_FLAG) != 0;
}

inline
size_t Mat::elemSize1() const
{
    return CV_ELEM_SIZE1(flags);
}

inline
int Mat::type() const
{
    return CV_MAT_TYPE(flags);
}

inline
int Mat::depth() const
{
    return CV_MAT_DEPTH(flags);
}

inline
int Mat::channels() const
{
    return CV_MAT_CN(flags);
}

inline bool UMatData::hostCopyObsolete() const { return (flags & HOST_COPY_OBSOLETE) != 0; }
inline bool UMatData::deviceCopyObsolete() const { return (flags & DEVICE_COPY_OBSOLETE) != 0; }
inline bool UMatData::deviceMemMapped() const { return (flags & DEVICE_MEM_MAPPED) != 0; }
inline bool UMatData::copyOnMap() const { return (flags & COPY_ON_MAP) != 0; }
inline bool UMatData::tempUMat() const { return (flags & TEMP_UMAT) != 0; }
inline bool UMatData::tempCopiedUMat() const { return (flags & TEMP_COPIED_UMAT) == TEMP_COPIED_UMAT; }

2、dims:矩阵维数
3、rows, cols:矩阵的行、列
4、data:数据存储的起始地址 (uchar类型)
5、u:UMatData
类型,双向链表,包含引用计数

struct CV_EXPORTS UMatData
{
    enum MemoryFlag { COPY_ON_MAP=1, HOST_COPY_OBSOLETE=2,
        DEVICE_COPY_OBSOLETE=4, TEMP_UMAT=8, TEMP_COPIED_UMAT=24,
        USER_ALLOCATED=32, DEVICE_MEM_MAPPED=64,
        ASYNC_CLEANUP=128
    };
    UMatData(const MatAllocator* allocator);
    ~UMatData();

    // provide atomic access to the structure
    void lock();
    void unlock();

    bool hostCopyObsolete() const;
    bool deviceCopyObsolete() const;
    bool deviceMemMapped() const;
    bool copyOnMap() const;
    bool tempUMat() const;
    bool tempCopiedUMat() const;
    void markHostCopyObsolete(bool flag);
    void markDeviceCopyObsolete(bool flag);
    void markDeviceMemMapped(bool flag);

    const MatAllocator* prevAllocator;
    const MatAllocator* currAllocator;
    int urefcount;
    int refcount;
    uchar* data;
    uchar* origdata;
    size_t size;

    UMatData::MemoryFlag flags;
    void* handle;
    void* userdata;
    int allocatorFlags_;
    int mapcount;
    UMatData* originalUMatData;
    std::shared_ptr allocatorContext;
};

6、size、step:
step: 每一维元素的通道数
size: 每一维元素的个数

struct CV_EXPORTS MatSize
{
    explicit MatSize(int* _p) CV_NOEXCEPT;
    int dims() const CV_NOEXCEPT;
    Size operator()() const;
    const int& operator[](int i) const;
    int& operator[](int i);
    operator const int*() const CV_NOEXCEPT;  // TODO OpenCV 4.0: drop this
    bool operator == (const MatSize& sz) const CV_NOEXCEPT;
    bool operator != (const MatSize& sz) const CV_NOEXCEPT;

    int* p;
};

struct CV_EXPORTS MatStep
{
    MatStep() CV_NOEXCEPT;
    explicit MatStep(size_t s) CV_NOEXCEPT;
    const size_t& operator[](int i) const CV_NOEXCEPT;
    size_t& operator[](int i) CV_NOEXCEPT;
    operator size_t() const;
    MatStep& operator = (size_t s);

    size_t* p;
    size_t buf[2];
protected:
    MatStep& operator = (const MatStep&);
};

1.3 Mat类成员函数

1.3.1 Mat类构造函数

1、默认构造函数:
Mat()
创建一个空矩阵
2、重载构造函数
Mat(int rows, int cols, int type);
Mat(Size size, int type);
在创建对象同时,提供矩阵的大小(rows,行数;cols ,列数),以及存储类型(type),该类型表示矩阵中每一个元素在计算机内存的存储类型。

Mat(int rows, int cols, int type, const Scalar& s);
Mat(Size size, int type, const Scalar& s);
在创建对象同时,提供矩阵的大小(rows,行数;cols ,列数),以及存储类型(type),该类型表示矩阵中每一个元素在计算机内存的存储类型,同时通过Scalar数据类来初始化元素值

Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);
Mat(Size size, int type, void* data, size_t step=AUTO_STEP);
指定矩阵的大小,类型为type的图像,此构造函数不创建图像数据所需内存,而是直接使用data所指内存,图像的行步长由 step指定。

1.3.2 Mat类析构函数

~Mat(); 析构函数

在matrix.cpp下
Mat::~Mat()
{
    release();
    if( step.p != step.buf )
        fastFree(step.p);
}

1.3.2 Mat类拷贝构造函数

Mat(const Mat& m); 左值引用
这类拷贝方法仅创建了新的矩阵头,共用同一个内存空间,在修改新对象的时候,旧对象也会改变。即为浅拷贝。
要完整拷贝对象,使用clone、copyTo函数来实现深拷贝。

在matrix.cpp下
Mat::Mat(const Mat& m)
    : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data),
      datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator),
      u(m.u), size(&rows), step(0)
{
    if( u )
        CV_XADD(&u->refcount, 1);
    if( m.dims <= 2 )
    {
        step[0] = m.step[0]; step[1] = m.step[1];
    }
    else
    {
        dims = 0;
        copySize(m);
    }
}

Mat(Mat&& m); 右值引用

在matrix.cpp下
Mat::Mat(Mat&& m)
    : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data),
      datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator),
      u(m.u), size(&rows)
{
    if (m.dims <= 2)  // move new step/size info
    {
        step[0] = m.step[0];
        step[1] = m.step[1];
    }
    else
    {
        CV_Assert(m.step.p != m.step.buf);
        step.p = m.step.p;
        size.p = m.size.p;
        m.step.p = m.step.buf;
        m.size.p = &m.rows;
    }
    m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0;
    m.data = NULL; m.datastart = NULL; m.dataend = NULL; m.datalimit = NULL;
    m.allocator = NULL;
    m.u = NULL;
}

1.3.3 Mat类赋值函数

Mat& operator = (const Mat& m);
同拷贝构造函数。
Mat& operator = (Mat&& m); 右值引用

1.3.4 Mat类公共成员函数

1、at函数
访问矩阵元素,根据不同的使用场景,有多个重载函数可供选择。
2、channels函数

int channels() const;

返回图像的通道数
3、clone函数

CV_NODISCARD_STD Mat clone() const;

矩阵复制
4.convertTo函数

void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;

转换矩阵存储类型,m是输入矩阵,rtype是目标类型,alpha是放缩系数,beta是增减标量

在modules\core\src\convert.dispatch.cpp文件中
void Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) const
{
    CV_INSTRUMENT_REGION();

    if( empty() )
    {
        _dst.release();
        return;
    }

    bool noScale = fabs(alpha-1) < DBL_EPSILON && fabs(beta) < DBL_EPSILON;

    if( _type < 0 )
        _type = _dst.fixedType() ? _dst.type() : type();
    else
        _type = CV_MAKETYPE(CV_MAT_DEPTH(_type), channels());

    int sdepth = depth(), ddepth = CV_MAT_DEPTH(_type);
    if( sdepth == ddepth && noScale )
    {
        copyTo(_dst);
        return;
    }

    Mat src = *this;
    if( dims <= 2 )
        _dst.create( size(), _type );
    else
        _dst.create( dims, size, _type );
    Mat dst = _dst.getMat();

    BinaryFunc func = noScale ? getConvertFunc(sdepth, ddepth) : getConvertScaleFunc(sdepth, ddepth);
    double scale[] = {alpha, beta};
    int cn = channels();
    CV_Assert( func != 0 );

    if( dims <= 2 )
    {
        Size sz = getContinuousSize2D(src, dst, cn);
        func( src.data, src.step, 0, 0, dst.data, dst.step, sz, scale );
    }
    else
    {
        const Mat* arrays[] = {&src, &dst, 0};
        uchar* ptrs[2] = {};
        NAryMatIterator it(arrays, ptrs);
        Size sz((int)(it.size*cn), 1);

        for( size_t i = 0; i < it.nplanes; i++, ++it )
            func(ptrs[0], 1, 0, 0, ptrs[1], 1, sz, scale);
    }
}

5、copyTo函数

void copyTo( OutputArray m ) const;
void copyTo( OutputArray m, InputArray mask ) const;

从m矩阵复制data数据单元,与clone函数的作用类似
6、create函数

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& sizes, int type);

分配矩阵的存储单元,一般和默认构造函数配合使用。
7、depth函数

int depth() const;

返回图像深度,即矩阵元素的存储方式
8、diag函数

Mat diag(int d=0) const;
CV_NODISCARD_STD static Mat diag(const Mat& d);

提取矩阵的对角元素
9、矩阵运算函数mul|inv|t

MatExpr t() const;
MatExpr inv(int method=DECOMP_LU) const;
MatExpr mul(InputArray m, double scale=1) const;
Mat cross(InputArray m) const;
double dot(InputArray m) const;

mul函数:矩阵的乘法
inv函数:求逆矩阵
t函数:求转置矩阵
cross函数:矩阵相乘
dot函数:矩阵点乘
10、total函数

size_t total() const;
size_t total(int startDim, int endDim=INT_MAX) const;

返回矩阵的元素总个数
11、行列相关函数

Mat row(int y) const;
Mat col(int x) const;
Mat rowRange(int startrow, int endrow) const;
Mat rowRange(const Range& r) const;
Mat colRange(int startcol, int endcol) const;
Mat colRange(const Range& r) const;

row函数:矩阵行数
col函数:矩阵列数
rowRange函数:为矩阵的指定行区间创建一个矩阵头;
colRange函数:为矩阵的指定列区间创建一个矩阵头;
12、setTo函数

Mat& setTo(InputArray value, InputArray mask=noArray());

把矩阵mask中元素不为0的点全部变为value值;mask为掩膜矩阵。
13、empty函数

bool empty() const;

判断Mat对象是否为空;
14、ptr函数

uchar* ptr(int i0=0);
const uchar* ptr(int i0=0) const;
uchar* ptr(int row, int col);
const uchar* ptr(int row, int col) const;
uchar* ptr(int i0, int i1, int i2);
const uchar* ptr(int i0, int i1, int i2) const;
uchar* ptr(const int* idx);
const uchar* ptr(const int* idx) const;
template uchar* ptr(const Vec& idx);
template const uchar* ptr(const Vec& idx) const;
template _Tp* ptr(int i0=0);
template const _Tp* ptr(int i0=0) const;
template _Tp* ptr(int row, int col);
template const _Tp* ptr(int row, int col) const;
template _Tp* ptr(int i0, int i1, int i2);
template const _Tp* ptr(int i0, int i1, int i2) const;
template _Tp* ptr(const int* idx);
template const _Tp* ptr(const int* idx) const;
template _Tp* ptr(const Vec& idx);
template const _Tp* ptr(const Vec& idx) const;

返回指定矩阵行的指针
15、reshape函数

Mat reshape(int cn, int rows=0) const;
Mat reshape(int cn, int newndims, const int* newsz) const;
Mat reshape(int cn, const std::vector& newshape) const;

改变矩阵的通道数或者矩阵的行数;
cn: 表示通道数(channels), 如果设为0,则表示保持通道数不变,否则则变为设置的通道数。
rows: 表示矩阵行数。 如果设为0,则表示保持原有的行数不变,否则则变为设置的行数。

2.Mat应用实例

#include 

#include 

using namespace cv;
using namespace std;

void PrintMat(const Mat& mat)
{
    static int count = 0;

    cout << "==========================" << endl;
    cout << count << ":" << endl;
    cout << "size: " << sizeof(mat) << endl;

    if (mat.empty())
    {
        cout << "mat is empty" << endl;
    }
    else
    {
        cout << "mat size: " << mat.size << endl;
        cout << "mat channels: " << mat.channels() << endl;
        cout << "mat depth: " << mat.depth() << endl;
        cout << "mat total: " << mat.total() << endl;
    }

    cout << "==========================" << endl;
    count++;
}

int main(int argc, char** argv)
{
    // 1.Mat类创建对象
    // 使用无参数构造函数,创建Mat对象
    Mat src;
    PrintMat(src);

    // 使用create创建
    src.create(2, 2, CV_8UC3);
    PrintMat(src);

    // 使用行、列、类型带这个三个参数的构造函数创建Mat对象
    Mat src1(3, 3, CV_8UC3); // Mat src1 = Mat(3, 3, CV_8UC3);
    PrintMat(src1);

    // 使用行、列、类型、Scalar向量四个参数的构造函数创建Mat对象
    Mat src2 = Mat(3, 3, CV_8UC3, Scalar(100, 100, 100));
    PrintMat(src2);

    // 使用大小、类型两个参数的构造函数创建Mat对象
    Mat src3 = Mat(Size(4, 4), CV_8UC3);
    PrintMat(src3);

    // 使用大小、类型、Scalar向量三个参数的构造函数创建Mat对象
    Mat src4 = Mat(Size(5, 5), CV_8UC3, Scalar(100, 100, 100));
    PrintMat(src4);

    // 使用Mat::zeros函数实现,两个参数一个是Size表示图像宽与高
    Mat src5 = Mat::zeros(Size(6, 6), CV_8UC3);
    PrintMat(src5);

    // 使用Mat::ones函数实现,两个参数一个是Size表示图像宽与高
    Mat src6 = Mat::zeros(Size(7, 7), CV_8UC1);
    PrintMat(src6);

    // 通过读入一张图像,直接转换为Mat对象
    Mat image = imread("G:/opencv/vs_opencv/lena.jpg");
    PrintMat(image);

    //2.Mat类的复制
    // 浅拷贝
    Mat mat(image);
    PrintMat(mat);

    Mat equal = image;
    PrintMat(equal);

    // 深拷贝
    Mat clone = image.clone();
    PrintMat(clone);

    Mat copy;
    image.copyTo(copy);
    PrintMat(copy);

    return 0;
}

你可能感兴趣的:(opencv由浅入深,opencv,计算机视觉,图像处理)