Mat 类使用
构造
基本参数
Mat对象的构造主要需要提供一些参数,当然其中有些参数是默认的,用户可以不提供。这些参数主要包括对象的通道数,尺寸,数据,步长等,其中数据单独存放,其他统称为头部(Header).
- 矩阵尺寸给出的是矩阵的大小(行列数),通常的方式有枚举形式([rows,cols])、向量形式(vector& size)、数组指针(int * size);
- 类型就是之前定义的Array Type;
- 矩阵数据值通常是一个指向矩阵的指针(int* data);
- 步长也通常是一个数组指针(size_t * step)。
type变量
在构造函数中,通常可以看到需要输入一个整型的变量type,这个参数是通过宏定义在相关头文件中定义过的。用来指明Mat对象的存储的数据类型(主要是data部分)。其各部分含义可以如下:
CV_[位数][带符号与否][类型前缀]C[通道数]
:CV_8UC1表示8位的单通道无符号char型数组, CV_32FC2表示一个2通道的23位浮点型数组。
(depth:深度)
CV_8U: bool或者uchar
CV_8S: schar或者char
CV_16U: ushort
CV_16S: short
CV_32S: int或者unsigned
CV_32F: float
CV_64F: double
//部分宏定义
#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))
//构造函数
Mat();
Mat(int rows, int cols, int type);
type变量是整型,这也就是说如果知道了宏定义对应的整型值则可以直接输入。如下列两个语句是等价的。
Mat matrix(3, 3, CV_8UC1);
Mat matrix(3, 3, 0);
opencv中Mat存在各种类型,其中mat有一个type()的函数可以返回该Mat的类型。类型表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:
Scalar类型
Scalar类型定义的是一个四维的向量,可以和类型CvScalar互相转换。使用Scalar对象可以为Mat对象的每个通道赋值,默认值为0。通常使用三通道就可以表示一幅RGB图像。
class cv::Scalar_< _Tp >;//一个从`类Vec`派生过来的四维向量
typedef Scalar_<double> cv::Scalar;
//构造函数
Mat(int rows, int cols, int type, const Scalar& s);
Mat matrix(3, 3, CV_8UC1,Scalar(0));//为每个通道的对应元素都赋初值0
Size类型
Size(尺寸)类的数据成员是width和 height。注意在Size 中 width是我们通常意义上图像的列数(cols),而 height则对应着图像的行数(rows)。也就是说两者是相反的,这在初始化的时候需要注意。
typedef Size_<int> Size2i;
typedef Size2i Size;
typedef Size_<float> Size2f;
//构造函数
Mat(Size size, int type, const Scalar& s);
维数与通道
维数指的是每个通道的维数,一般指一维或者二维;通道指的是每个元素具有几个值。可以理解为每个元素其实又是一个多维数组,但这个数组的维度最大为4(与scalar类型的定义相同)。当指明维数参数ndims
时,通常搭配 指明尺寸的数组或者向量使用:
Mat(int ndims, const int* sizes, int type, const Scalar& s);
Mat(const std::vector<int>& sizes, int type, const Scalar& s);
Mat(int ndims, const int* sizes, int type);
//代码例子:
int sizes[] = { 3,3 };
Mat matrix(2, sizes, CV_64FC1, Scalar(1));//二维 3*3 单通道矩阵
Mat matrix_(1, sizes, CV_64FC1,Scalar(1)); // 一维 3*1 单通道矩阵,虽然sizes是二维
Range类型
用来指明一个序列的连续子序列。拥有两个公共成员:start 和 end。可以使用这两个成员来表示子序列的范围,左开右闭。可以使用Range.all()表示所有。
Range ();
Range (int _start, int _end);
//构造函数
Mat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all());
Rect类型
创建一个矩形区域,可以用来提取兴趣区域。前两位为一个坐标,后两位表示偏移量。
Mat(const Mat& m, const Rect& roi);
其他类型转化为矩阵
向量、列表、数组、二维点,三维点均可以显式地转换为矩阵,注意并不会隐式地转化。
template<typename _Tp> explicit Mat(const std::vector<_Tp>& vec, bool copyData=false);
template<typename _Tp, typename = typename std::enable_if<std::is_arithmetic<_Tp>::value>::type>
explicit Mat(const std::initializer_list<_Tp> list);
template<typename _Tp> explicit Mat(const std::initializer_list<int> sizes, const std::initializer_list<_Tp> list);
template<typename _Tp, size_t _Nm> explicit Mat(const std::array<_Tp, _Nm>& arr, bool copyData=false);
template<typename _Tp> explicit Mat(const Point_<_Tp>& pt, bool copyData=true);
template<typename _Tp> explicit Mat(const Point3_<_Tp>& pt, bool copyData=true);
运算
加、减、乘
矩阵重载了很多基本的数学运算符: A+B,A−B,A∗B A + B , A − B , A ∗ B 。注意:其中矩阵相乘时,两个矩阵的类型要相同,且需要depth为浮点型,即CV_32F或者CV_64F。
赋值
1。从基本的矩阵赋值方式如下,此种方式不会重新分配内存,只是复制头部并增加引用计数。
Mat& operator = (const Mat& m);
void assignTo( Mat& m, int type=-1 ) const;
2。从矩阵表达式赋值,如果左边的矩阵有着需求的尺寸,则重新利用;否则重新分配。
Mat& operator = (const MatExpr& expr);
3。 将矩阵的元素都设置为某一个标量。
Mat& operator = (const Scalar& s);
Mat& setTo(InputArray value, InputArray mask=noArray());
点乘、叉乘
点乘是将矩阵变成一个向量,两个向量做点积运算,最后的结果是一个实数。
Mat cross(InputArray m) const;
double dot(InputArray m) const;
element-wise 乘、除
对应元素作乘除法。
MatExpr mul(InputArray m, double scale=1) const;
特殊矩阵
0矩阵
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);
全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 eye(int rows, int cols, int type);
static MatExpr eye(Size size, int type);
对角矩阵
static Mat diag(const Mat& d);
Mat diag(int d=0) const;
拷贝
clone()会将矩阵的所有信息(包括头部和数据部分)都拷贝到目标矩阵中,也就是说并不会共享数据。
coyTo()会将矩阵的数据部分拷贝到目的矩阵,且在拷贝之前会调用creat()函数。
Mat clone() const;
void copyTo( OutputArray m ) const;
void copyTo( OutputArray m, InputArray mask) const;
特殊操作
变形
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<int>& newshape) const;
转置
MatExpr t() const;
求逆
MatExpr inv(int method=DECOMP_LU) const;
添加元素
在矩阵的末尾添加元素
void push_back_(const void* elem);
template<typename _Tp> void push_back(const _Tp& elem);
template<typename _Tp> void push_back(const Mat_<_Tp>& elem);
template<typename _Tp> void push_back(const std::vector<_Tp>& elem);
void push_back(const Mat& m);
void pop_back(size_t nelems=1);
类型转换
将矩阵中的元素数据类型转换为所需的类型。但这只是在矩阵内部转化,返回的是 void。 如果需要从数组、向量或列表等形式转化为矩阵,需要显示的使用构造函数。注意,这个函数改变的数据的depth而不会改变channels。其计算方式为:
m(i,j)=m(i,j)∗α+β
m
(
i
,
j
)
=
m
(
i
,
j
)
∗
α
+
β
。在对图像的矩阵进行转换时,有时候需要设置其余两个参数,否则在使用imshow
函数的时候可能会造成显示错误。如:灰度值范围在0~255,其在浮点数范围内是0~1,如果图像数据转换为浮点型而没有进行缩放则会将大于1的的值在显示的时候都是白色。
void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;
ROI提取
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<Range>& ranges) const;
template<typename _Tp> operator std::vector<_Tp>() const;
template<typename _Tp, int n> operator Vec<_Tp, n>() const;
template<typename _Tp, int m, int n> operator Matx<_Tp, m, n>() const;
元素访问
在使用at方法来访问矩阵的元素时,需要注意的是元素的类型(Typename),一旦两者不匹配(depth不同),则会造成访问错误。通常有:
CV_8U: bool或者uchar
CV_8S: schar或者char
CV_16U: ushort
CV_16S: short
CV_32S: int或者unsigned
CV_32F: float
CV_64F: double
template<typename _Tp> _Tp& at(int i0=0);
template<typename _Tp> const _Tp& at(int i0=0) const;
template<typename _Tp> _Tp& at(int row, int col);
template<typename _Tp> const _Tp& at(int row, int col) const;
template<typename _Tp> _Tp& at(int i0, int i1, int i2);
template<typename _Tp> const _Tp& at(int i0, int i1, int i2) const;
template<typename _Tp> _Tp& at(const int* idx);
template<typename _Tp> const _Tp& at(const int* idx) const;
template<typename _Tp, int n> _Tp& at(const Vec<int, n>& idx);
template<typename _Tp, int n> const _Tp& at(const Vec<int, n>& idx) const;
template<typename _Tp> _Tp& at(Point pt);
template<typename _Tp> const _Tp& at(Point pt) const;
迭代器
template<typename _Tp> MatIterator_<_Tp> begin();
template<typename _Tp> MatConstIterator_<_Tp> begin() const;
template<typename _Tp> MatIterator_<_Tp> end();
template<typename _Tp> MatConstIterator_<_Tp> end() const;
template<typename _Tp, typename Functor> void forEach(const Functor& operation);
template<typename _Tp, typename Functor> void forEach(const Functor& operation) const;
返回指针的函数
行指针
const uchar* ptr(int i0=0) const;\\指针为什么是uchar??
uchar* ptr(int i0=0);
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;
const uchar* ptr(const int* idx) const;
template<int n> uchar* ptr(const Vec<int, n>& idx);
template<int n> const uchar* ptr(const Vec<int, n>& idx) const;
template<typename _Tp> _Tp* ptr(int i0=0);
template<typename _Tp> const _Tp* ptr(int i0=0) const;
template<typename _Tp> _Tp* ptr(int row, int col);
template<typename _Tp> const _Tp* ptr(int row, int col) const;
template<typename _Tp> _Tp* ptr(int i0, int i1, int i2);
template<typename _Tp> const _Tp* ptr(int i0, int i1, int i2) const;
template<typename _Tp> _Tp* ptr(const int* idx);
template<typename _Tp> const _Tp* ptr(const int* idx) const;
template<typename _Tp, int n> _Tp* ptr(const Vec<int, n>& idx);
template<typename _Tp, int n> const _Tp* ptr(const Vec<int, n>& idx) const;
内存管理
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);
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);
size_t elemSize() const;//查看元素字节大小.
size_t elemSize1() const;//查询每个元素通道的字节大小.
int type() const;//查询元素的类型.
其他函数
bool isContinuous() const;
bool isSubmatrix() //! 查看矩阵是否是子矩阵
void addref();//增加引用计数
int depth() const;\\查询矩阵元素的深度.enum{CV_8U=0,CV_8S=1,CV_16U=2,CV_16S=3,CV_32S=4,CV_32F=5,CV_64F=6}
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;\\?
公共变量
int flags
含有多个位域的标志:
- the magic signature\\??
- 连续标志
- 深度
- 通道数
int dims
矩阵维度, >= 2
int rows, cols
当矩阵有多个维度时,行数及列数或者(-1, -1)
uchar* data
指向数据的指针