深入浅出 cv::Mat 的用法

本文从图像的处理的角度,以实例的方法展示cv::Mat中各个函数的用法

目录

一.几个属性值的说明

二:Mat的构造函数

三:Create的用法

四:colRange的用法

五:convertTo的用法

 六:diag的用法

七:Mat的几个运算

八:locateRoi的用法

九:push_back pop_back的用法

十:setTo的用法

十二:copyTo的用法

十三:reshape的用法

十四:几个属性函数


一.几个属性值的说明

    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; //元素类型
}

 

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值