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 的數據總長是:
data=sizeof(dataType)m=1dimssize[m](byte) ||data||=sizeof(dataType)*\prod_{m=1} ^{dims}size[m]\quad (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);

末尾註:以上爲作者學習過程中自己認識的記錄,如有問題,敬請指正。

發佈了8 篇原創文章 · 獲贊 1 · 訪問量 1419
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章