本文从图像的处理的角度,以实例的方法展示cv::Mat中各个函数的用法
目录
一.几个属性值的说明
MatSize size;
MatStep step;
void test_variable()
{
cv::Mat macro = cv::imread("D:/EEE.jpg"); //
cout << "macro.step:" << macro.step << endl;
cout << "macro.step[0]:" << macro.step[0] << endl;
cout << "macro.step[1]:" << macro.step[1] << endl;
cout << "macro.step1():" << macro.step1() << endl;
cout << "macro.size:" << macro.size << endl;
cout << "macro.size[0]:" << macro.size[0] << endl;
cout << "macro.size[1]:" << macro.size[1] << endl;
cout << "macro.channels():" << macro.channels() << endl;
cout << "macro.depth():" << macro.depth() << endl;
cout << "macro.elemSize:" << macro.elemSize() << endl;
cout << "macro.elemSize1:" << macro.elemSize1() << endl;
cv::Mat t(100, 100, CV_16UC3);
cout << "t.step:" << t.step << endl;
cout << "t.step[0]:" << t.step[0] << endl;
cout << "t.step[1]:" << t.step[1] << endl;
cout << "t.step1():" << t.step1() << endl;
cout << "t.size:" << t.size << endl;
cout << "t.size[0]:" << t.size[0] << endl;
cout << "t.size[1]:" << t.size[1] << endl;
cout << "t.channels():" << t.channels() << endl;
cout << "t.depth():" << t.depth() << endl;
cout << "t.elemSize:" << t.elemSize() << endl;
cout << "t.elemSize1:" << t.elemSize1() << endl;
cv::Mat s(100, 100, CV_32SC3);
cout << "s.step:" << s.step << endl;
cout << "s.step[0]:" << s.step[0] << endl;
cout << "s.step[1]:" << s.step[1] << endl;
cout << "s.step1():" << s.step1() << endl;
cout << "s.size:" << s.size << endl;
cout << "s.size[0]:" << s.size[0] << endl;
cout << "s.size[1]:" << s.size[1] << endl;
cout << "s.channels():" << s.channels() << endl;
cout << "s.depth():" << s.depth() << endl;
cout << "s.elemSize():" << s.elemSize() << endl;
cout << "s.elemSize1:" << s.elemSize1() << endl;
}
输入如下结果:
macro.step:810
macro.step[0]:810
macro.step[1]:3
macro.step1():810
macro.size:190 x 270
macro.size[0]:190
macro.size[1]:270
macro.channels():3
macro.depth():0
macro.elemSize:3
macro.elemSize1:1
t.step:600
t.step[0]:600
t.step[1]:6
t.step1():300
t.size:100 x 100
t.size[0]:100
t.size[1]:100
t.channels():3
t.depth():2
t.elemSize:6
t.elemSize1:2
s.step:1200
s.step[0]:1200
s.step[1]:12
s.step1():300
s.size:100 x 100
s.size[0]:100
s.size[1]:100
s.channels():3
s.depth():4
s.elemSize():12
s.elemSize1:4
关于CV_32SC3的说明:
格式为:CV_<bit_depth>(S|U|F)C<channels>,如上面的32,16代表一个元素需要16位、32位来表示。
step[0]:一行元素的字节数 ,如macro一行的元素为270*3*1(uchar), t一行的元素为100*3*2(CV_16UC3), s的一行元素数为100*3*4(CV_32FC3)
step[1]:一个元素的通道数*单个元素的字节数,如CV_16UC3的一个元素值为(100,100,100),三个通道,每个分量占2个字节,所以3*2 = 6
step1():一行的元素个数
size:一个图像/矩阵的行(高)*列(宽)
size[0]:行(高)
size[1]:列(宽)
channels():一个元素的通道数
depth():表示用来度量每一个像素中每一个通道的精度,但它本身与图像的通道数无关!depth数值越大,精度越高。在 Opencv中,Mat.depth()得到的是一个0~6的数字,分别代表不同的位数,
对应关系如下:
#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
其中U是unsigned的意思,S表示signed,也就是有符号和无符号数。
elemSize():一个元素所占的字节数
elemSize1():一个元素的分量所占的字节数
Mat.elemSize() = Mat.elemSize1() * Mat.channels()
二:Mat的构造函数
给出如下几种构造方法:
void printMat(cv::Mat&m, string str)
{
cout << str.c_str() << endl;
cout << m;
cout << endl << endl << endl;
}
void MatCreate()
{
cv::Mat m1(2, 3, CV_16UC3);
printMat(m1, "m1");
cv::Mat m2(cv::Size(2, 3), CV_32FC3);
printMat(m2, "m2");
cv::Mat m3(2, 3, CV_16UC3, cv::Scalar(100));//Scalar 的第一个元素为100,后面3个元素为0
printMat(m3, "m3");
cv::Mat m4(2, 3, CV_16UC3, cv::Scalar::all(100));//Scalar 的4个元素都为100
printMat(m4, "m4");
/*
Scalar是一个能存4个数值的数组,
template<typename _Tp> inline
Scalar_<_Tp>::Scalar_(_Tp v0)
{
this->val[0] = v0;
this->val[1] = this->val[2] = this->val[3] = 0;
}
template<typename _Tp> inline
Scalar_<_Tp> Scalar_<_Tp>::all(_Tp v0)
{
return Scalar_<_Tp>(v0, v0, v0, v0);
}
*/
int sz[2] = { 2, 3 };
cv::Mat m5(2, sz, CV_8UC1, cv::Scalar::all(0));
printMat(m5, "m5");
vector<int>a (2, 3);
cv::Mat m6(a, CV_8UC1, cv::Scalar::all(0));
printMat(m6, "m6");
cv::Mat macro = cv::imread("D:/EEE.jpg"); //
cv::Mat m7(macro.rows, macro.cols, CV_8UC(macro.channels()), (void*)macro.data, macro.step1()); //根据uchar* 创建Mat
imshow("m7", m7);
cv::Mat m8(cv::Size(macro.cols, macro.rows), CV_8UC(macro.channels()), (void*)macro.data); //根据uchar* 创建Mat
cv::Mat m9(macro, cv::Range(100, 150)); //取图像的第100~150行
imshow("m9", m9);
cv::Mat m10(macro, cv::Rect(50, 50, 80, 80)); //根据roi创建Mat
imshow("m10", m10);
/*
template<typename _Tp> inline
Rect_<_Tp>::Rect_()
: x(0), y(0), width(0), height(0) {}
template<typename _Tp> inline
Rect_<_Tp>::Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height)
: x(_x), y(_y), width(_width), height(_height) {}
template<typename _Tp> inline
Rect_<_Tp>::Rect_(const Rect_<_Tp>& r)
: x(r.x), y(r.y), width(r.width), height(r.height) {}
*/
}
其输出结果如下:
m1
[640, 31387, 32766, 0, 160, 31387, 32766, 0, 2640;
31387, 32766, 0, 2464, 31387, 32766, 0, 1984, 31387]
m2
[0, 0, 127.5, 0, 0, 0;
0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0]
m3
[100, 0, 0, 100, 0, 0, 100, 0, 0;
100, 0, 0, 100, 0, 0, 100, 0, 0]
m4
[100, 100, 100, 100, 100, 100, 100, 100, 100;
100, 100, 100, 100, 100, 100, 100, 100, 100]
m5
[ 0, 0, 0;
0, 0, 0]
m6
[ 0, 0, 0;
0, 0, 0;
0, 0, 0]
三:Create的用法
说明:如果原来的矩阵尺寸不满足了,则可以用create重新分配尺寸
void create(int rows, int cols, int type);
/** @overload
@param size Alternative new matrix size specification: Size(cols, rows)
@param type New matrix type.
*/
void create(Size size, int type);
/** @overload
@param ndims New array dimensionality.
@param sizes Array of integers specifying a new array shape.
@param type New matrix type.
*/
void create(int ndims, const int* sizes, int type);
/** @overload
@param sizes Array of integers specifying a new array shape.
@param type New matrix type.
*/
void create(const std::vector<int>& sizes, int type);
// make a 7x7 complex matrix filled with 1+3j.
Mat M(7,7,CV_32FC2,Scalar(1,3));
// and now turn M to a 100x60 15-channel 8-bit matrix.
// The old content will be deallocated
M.create(100,60,CV_8UC(15));
四:colRange的用法
cv::Mat t1 = cv::imread("D:/EEE.jpg"); //
cv::Mat t2 = t1.clone();
cv::Mat t3 = t2.clone();
vector<cv::Mat> vec;
vec.push_back(t1);
vec.push_back(t2);
vec.push_back(t3);
cv::Mat res(190, 270 * 3, CV_8UC3);
for (int i = 0; i < 3; i++)
{
res.colRange(i * 270, (i + 1) * 270) = vec[i] + 0; //完成特定列的赋值
}
cv::imshow("colrange.jpg", res);
//完成特定列的选择
cv::Mat sel = t1.colRange(5, 100);
cv::imshow("sel", sel);
cv::waitKey(0);
colRange的源码如下:
inline
Mat Mat::colRange(int startcol, int endcol) const
{
return Mat(*this, Range::all(), Range(startcol, endcol));
}
inline
Mat Mat::colRange(const Range& r) const
{
return Mat(*this, Range::all(), r);
}
说明:返回当前矩阵的第startcol 到endcol 列
五:convertTo的用法
源码如下:
inline
void GpuMat::convertTo(OutputArray dst, int rtype, double alpha, double beta) const
{
convertTo(dst, rtype, alpha, beta, Stream::Null());
}
原理为:m(x,y)=saturate_cast<rType>(α(∗this)(x,y)+β)
示例代码如下:
void test_covertTo()
{
cv::Mat m1 = cv::Mat::ones(4, 4, CV_32F); //得到一个浮点型的4*4的矩阵
cv::Mat m2;
m1.convertTo(m2, CV_8U);
printMat(m1, "m1");
printMat(m2, "m2");
cv::Mat m3;
m1.convertTo(m3, CV_32F, 0.5, 0.8);
printMat(m3, "m3");
}
输出结果为:
m1
[1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1]
m2
[ 1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1]
m3
[1.3, 1.3, 1.3, 1.3;
1.3, 1.3, 1.3, 1.3;
1.3, 1.3, 1.3, 1.3;
1.3, 1.3, 1.3, 1.3]
六:diag的用法
Mat cv::Mat::diag(int d = 0)const
说明:返回矩阵对角线的元素,返回值是一个向量,d>0 时返回主对角线右上交的对角元素,d<0 时返回主对角线左下的对角元素
测试代码如下:
void test_diag()
{
cv::Mat m = (cv::Mat_<int>(3, 3) <<
1, 2, 3,
4, 5, 6,
7, 8, 9);
cv::Mat d0 = m.diag(0);
cv::Mat d1 = m.diag(1);
cv::Mat d_1 = m.diag(-1);
cout << "d0:" << d0 << endl;
cout << "d1:" << d1 << endl;
cout << "d_1:" << d_1 << endl;
}
输出结果如下:
d0:[1;
5;
9]
d1:[2;
6]
d_1:[4;
8]
七:Mat的几个运算
double cv::Mat::dot (InputArray m) const
MatExpr cv::Mat::t () const
MatExpr cv::Mat::inv(int method = DECOMP_LU )const
MatExpr cv::Mat::mul(InputArray m,double scale = 1 )const
void test_compute()
{
//矩阵的点乘
cv::Mat m = (cv::Mat_<int>(3, 3) <<
1, 2, 3,
4, 5, 6,
7, 8, 9);
cv::Mat m1 = (cv::Mat_<int>(3, 3) <<
1, 1, 1,
2, 2, 2,
3, 3, 3);
double d = m.dot(m1);
cout << d << endl;
//求逆矩阵
/*
DECOMP_LU(默认)是LU分解。 矩阵必须是非奇异的。
DECOMP_CHOLESKY是对称正定义矩阵的Cholesky分解。这种类型在大矩阵上比LU大约快两倍。
DECOMP_SVD是SVD分解。如果矩阵是奇异或甚至非正方形,则计算伪逆。
*/
cv::Mat m2 = cv::Mat::eye(3, 3, CV_32FC1);
printMat(m2, "m2");
cv::Mat m3 = m2.inv();
printMat(m3, "m3");
//矩阵的转置
cv::Mat m4 = m1.t();
printMat(m4, "m4");
//矩阵相乘
cv::Mat m5 = m.mul(m1);
printMat(m5, "m5");
}
输出结果如下:
108
m2
[1, 0, 0;
0, 1, 0;
0, 0, 1]
m3
[1, 0, 0;
0, 1, 0;
0, 0, 1]
m4
[1, 2, 3;
1, 2, 3;
1, 2, 3]
m5
[1, 2, 3;
8, 10, 12;
21, 24, 27]
八:locateRoi的用法
void cv::Mat::locateROI (Size & wholeSize,Point & ofs ) const
说明:该函数保存子Mat在原始Mat中的位置和大小
void test_locateRoi()
{
cv::Mat A = cv::Mat::eye(10, 10, CV_32S);
// extracts A columns, 1 (inclusive) to 3 (exclusive).
cv::Mat B = A(cv::Range::all(), cv::Range(1, 3)); //取A的第1,2列
// extracts B rows, 5 (inclusive) to 9 (exclusive).
// that is, C \~ A(Range(5, 9), Range(1, 3))
cv::Mat C = B(cv::Range(5, 9), cv::Range::all());//取B的5-8行
cv::Size size; cv::Point ofs;
C.locateROI(size, ofs);
// size will be (width=10,height=10) and the ofs will be (x=1, y=5)
printMat(A, "A");
printMat(B, "B");
printMat(C, "C");
cout << size << ", " << ofs << endl;
}
输出结果
A
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 1, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 1, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 1, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 1, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 1, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 1, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
B
[0, 0;
1, 0;
0, 1;
0, 0;
0, 0;
0, 0;
0, 0;
0, 0;
0, 0;
0, 0]
C
[0, 0;
0, 0;
0, 0;
0, 0]
[10 x 10], [1, 5]
九:push_back pop_back的用法
void pop_back(size_t nelems=1); //nelems >0 表示删除最下面的nelems行
void push_back(const Mat& m);
void test_push_pos()
{
cv::Mat A = cv::Mat::eye(5, 5, CV_32S);
printMat(A, "A");
A.pop_back();
printMat(A, "A");
cv::Mat m6(5,3, CV_8UC3, cv::Scalar::all(0));
printMat(m6, "m6");
m6.pop_back(2);
printMat(m6, "m6");
cv::Mat m7(4, 3, CV_8UC3, cv::Scalar::all(1));
m6.push_back(m7);
printMat(m6,"m6");
}
输出结果为:
A
[1, 0, 0, 0, 0;
0, 1, 0, 0, 0;
0, 0, 1, 0, 0;
0, 0, 0, 1, 0;
0, 0, 0, 0, 1]
A
[1, 0, 0, 0, 0;
0, 1, 0, 0, 0;
0, 0, 1, 0, 0;
0, 0, 0, 1, 0]
m6
[ 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0]
m6
[ 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0]
m6
[ 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0;
1, 1, 1, 1, 1, 1, 1, 1, 1;
1, 1, 1, 1, 1, 1, 1, 1, 1;
1, 1, 1, 1, 1, 1, 1, 1, 1;
1, 1, 1, 1, 1, 1, 1, 1, 1]
十:setTo的用法
/** @brief Sets all or some of the array elements to the specified value.
This is an advanced variant of the Mat::operator=(const Scalar& s) operator.
@param value Assigned scalar converted to the actual array type.
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels
*/
Mat& setTo(InputArray value, InputArray mask=noArray());
说明:将src中 把mask矩阵中不为0的位置处赋值为value
void test_setTo()
{
cv::Mat src(3, 3, CV_8UC1);
cv::Mat mask = cv::Mat::eye(3, 3, CV_8UC1);
src.setTo(100, mask);
printMat(src, "src");
}
输出结果如下:
src
[100, 0, 0;
0, 100, 0;
0, 0, 100]
十二:copyTo的用法
void copyTo( OutputArray m ) const;
void copyTo( OutputArray m, InputArray mask ) const;
说明:拷贝到m, mask的作用见setTo函数
void test_copyTo()
{
cv::Mat src(3, 3, CV_8UC1,cv::Scalar(5));
cv::Mat mask = cv::Mat::eye(3, 3, CV_8UC1);
cv::Mat dst;
src.copyTo(dst);
printMat(dst, "dst");
cv::Mat dst2;
src.copyTo(dst2, mask);
printMat(dst2, "dst2");
}
输出结果如下:
dst
[ 5, 5, 5;
5, 5, 5;
5, 5, 5]
dst2
[ 5, 0, 0;
0, 5, 0;
0, 0, 5]
十三:reshape的用法
C++: Mat Mat::reshape(int cn,int rows=0) const
cn:通道数(channels),如果设置为0,则表示通道不变;如果设置为其他数字,表示要设置的通道数
rows:矩阵行数,如果设置为0,则表示保持原有行数不变,如果设置为其他数字,表示要设置的行数
void test_reshape()
{
cv::Mat src(3, 3, CV_8UC3, cv::Scalar(5));
printMat(src, "src");
cv::Mat dst = src.reshape(1, 0);
printMat(dst, "通道数改为1,行数不变");
dst = src.reshape(0, 1);
printMat(dst, "通道数不变,行数改为1");
}
十四:几个属性函数
void test_func()
{
cv::Mat src(3, 3, CV_8UC3, cv::Scalar(5));
cout << "src.total():" << src.total() << endl; //矩阵的元素个数 9
cout << "src.type():" << src.type() << endl; //元素类型
}