OpenCV3.4.0学习笔记(二)——cv::Mat的代数运算、变形与分割

cv::Mat的代数运算、变形与分割

关于cv::Mat最基础的内存结构与元素访问笔记在以下博文中:
OpenCV3.4.0学习笔记(一)——cv::Mat的内存结构与访问

可以自由读写cv::Mat数组中的任一元素后,以下考虑 cv::Mat 的一些常用操作。
这里将常用操作分为三类:

  1. 代数运算
  2. 变形
  3. 分割

代数运算

cv::Mat 的代数运算接近矩阵运算,以下给出常用的几种代数运算代码。

	cv::Mat a,b,c;
	
	/*矩阵级运算*/
	c = a + b;	//矩阵加法
	c = a - b;	//矩阵减法
	c = a + 1;	//矩阵数加,位置可互换
	c = a - 1;	//矩阵数减,位置可互换
	c = a * 1;	//矩阵数乘,位置可互换
	c = a * b;	//矩阵乘,限二维单通道矩阵
	c = a.inv();	//矩阵求逆,限二维单通道矩阵
	c = a.t();	//矩阵转置,限二维单通道矩阵
	cv::Scalar trace = cv::trace(a); //矩阵求迹
	double det = cv::determinant(a); //矩阵行列式,要求a为单通道浮点型矩阵
	cv::eigen(a,eigenValue,eigenVector); //对称单通道浮点型矩阵a的特征值特征向量特征向量
		//eigenValue与eigenVector均为cv::Mat型变量,eigenValue存放了特征值,
		//行向量eigenVector[m]对应eigenValue[m],也就是有如下关系成立:
		//src*eigenvectors.row(i).t() = eigenvalues.at<srcType>(i)*eigenvectors.row(i).t()
	cv::solve(a,b,c); //求解线性方程 A*C = B 中C的最佳值。C与B规模相同,为多个列向量,A必须为方阵
	
	/*元素级运算*/
	//元素级代数运算
	cv::multiply(a,b,c,2);	//矩阵元素相乘并放大给定的因子
	cv::divide(a,b,c); // c=a./b,逐元素除法
	cv::exp(a,c); //逐元素求自然底数为底的指数
	cv::log(a,c); //逐元素求自然底数为底的对数
	cv::pow(a,2,c); //逐元素求指定数的幂次方,注意,对a中非整数对象,则先取绝对值再幂次方
	cv::phase(a,b,c); //c = arctan2(b,a);逐元素运算
	//不等运算,逐元素比较,返回0\255矩阵
	c = a > b;
	c = a >= b;
	c = a < b;
	c = a <= b;
	c = a == b;
	//矩阵元素位运算
	c = a & b;
	c = a | b;
	c = a ^ b;
	c = ~a;
	c = a & 1;
	//按元素求绝对值
	c = cv::abs(a);
	//矩阵元素比较并取值
	c = cv::max(a,b);
	c = cv::max(a,1);
	c = cv::min(a,b);
	c = cv::min(a,1);
	cv::Scalar sum = cv::sum(a); //矩阵元素求和(适用于多通道)
	cv::Scalar means = cv::mean(a); //求a全部元素平均值(适用于多通道)

变形

变形是指改变 cv::Mat 的维度以及维度上的数据长度。常用 cv::Mat::reshape() 函数来实现。
reshape的本质是改变 cv::Mat 的 dims,step,size,channals的矩阵头数据,不改变data中的储存顺序。
因此reshape函数的执行效率很高。同时注意 Mat 的数据总长是:
∣ ∣ d a t a ∣ ∣ = s i z e o f ( d a t a T y p e ) ∗ ∏ m = 1 d i m s s i z e [ m ] ( b y t e ) ||data||=sizeof(dataType)*\prod_{m=1} ^{dims}size[m]\quad (byte) data=sizeof(dataType)m=1dimssize[m](byte)

以下给出几种常用的reshape函数重载格式:

	cv::Mat& cv::Mat::reshape(int channalsCount, std::vector<int> newshape);
	cv::Mat& cv::Mat::reshape(int channalsCount, int newdims, int* newsize);
	cv::Mat& cv::Mat::reshape(int channalsCount, int newrows = 0);

需要注意的是,reshape()的返回值是更改后的矩阵信息头。以下面代码为例:

	cv::Mat a = cv::Mat::zeros(2, 2, CV_32FC1);
	cv::Mat b = a.reshape(1,1); //调用第三个重载的reshape
	cout << a.size() << endl; //a的size不发生改变,为 2*2
	cout << b.size() << endl; //b的size为 1*4
	cout << (unsigned long long)a.data << endl; //a.data与b.data相等
	cout << (unsigned long long)b.data << endl;

分割

常用的矩阵分割包括矩阵指定区域截取、通道分离与合成等。

先给出矩阵指定区域截取的几个重载操作符的代码:

	cv::Mat operator ()(std::vector<cv::Range> &ranges);
	cv::Mat operator ()(cv::Range* ranges);
	cv::Mat operator ()(cv::Rect &roi); //限于二维矩阵
	cv::Mat operator ()(cv::Range rowRange, cv::Range colRange); //限于二维矩阵
	cv::Mat row(int index) //返回矩阵第index行,限于二维矩阵
	cv::Mat col(int index) //返回矩阵第index列,限于二维矩阵

需要注意,矩阵分割的返回值是原有矩阵的引用,也即通过返回值可以修改原有矩阵的数据。
通过以下代码加以说明:

	cv::Mat a = cv::Mat::zeros(3, 3, CV_32FC1);
	cv::Mat b = a(cv::Range(0,1),cv::Range(0,1)); //调用第4个重载的()
	cout << a.at<float>(0, 0) << endl; //输出0
	b.at<float>(0,0) = 1;
	cout << a.at<float>(0, 0) << endl; //输出1

再给出通道分离与融合的几个重载方法

	//通道分离函数
	void cv::split(cv::Mat &muiltChannalMat, std::vector<cv::Mat> channalsMaps);
	//muiltChannalMat为多通道Mat,channalsMaps为单通道Mat向量,多通道与单通道Mat的规模一样,
	//channalsMaps共有muiltChannalMat.channals个元素

	//通道整合函数,参数意义同split
	void cv::merge(std::vector<cv::Mat> channalsMaps, cv::Mat &muiltChannalMat);

末尾注:以上为作者学习过程中自己认识的记录,如有问题,敬请指正。

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值