C/C++中OpenCV 矩陣運算的實現(xiàn)
OpenCV 是一個強大的開源計算機視覺和機器學(xué)習(xí)庫,它提供了豐富的矩陣運算功能,這對于圖像處理和計算機視覺算法至關(guān)重要。本文將詳細介紹如何使用 C/C++ 和 OpenCV 進行常見的矩陣運算。
矩陣的創(chuàng)建與初始化
在進行矩陣運算之前,我們首先需要知道如何創(chuàng)建和初始化矩陣。OpenCV 提供了 cv::Mat
類來處理矩陣。
創(chuàng)建矩陣
有多種方法可以創(chuàng)建 cv::Mat
對象:
使用構(gòu)造函數(shù):可以指定行數(shù)、列數(shù)、數(shù)據(jù)類型以及可選的初始值。
#include <opencv2/opencv.hpp> #include <iostream> int main() { // 創(chuàng)建一個 3x3 的浮點型矩陣,所有元素初始化為 0 cv::Mat matrix1 = cv::Mat::zeros(3, 3, CV_32F); std::cout << "Matrix1:\n" << matrix1 << std::endl; // 創(chuàng)建一個 2x4 的整型矩陣,所有元素初始化為 1 cv::Mat matrix2 = cv::Mat::ones(2, 4, CV_8UC1); // 8位無符號單通道 std::cout << "Matrix2:\n" << matrix2 << std::endl; // 創(chuàng)建一個具有特定尺寸和類型的矩陣,不初始化 cv::Mat matrix3(4, 2, CV_64FC3); // 64位浮點型三通道 // 使用 Scalar 初始化 cv::Mat matrix4 = cv::Mat(3, 3, CV_32F, cv::Scalar(5.0)); std::cout << "Matrix4:\n" << matrix4 << std::endl; // 通過 C/C++ 數(shù)組創(chuàng)建 double data[] = {1, 2, 3, 4, 5, 6}; cv::Mat matrix5 = cv::Mat(2, 3, CV_64F, data); std::cout << "Matrix5:\n" << matrix5 << std::endl; return 0; }
cv::Mat::create()
方法:如果矩陣已經(jīng)存在,此方法會重新分配內(nèi)存(如果需要)。
cv::Mat matrix; matrix.create(4, 4, CV_32F);
cv::Mat::eye()
方法:創(chuàng)建單位矩陣。
cv::Mat identityMatrix = cv::Mat::eye(3, 3, CV_64F); std::cout << "Identity Matrix:\n" << identityMatrix << std::endl;
訪問矩陣元素
可以使用 at()
方法或者直接通過指針訪問矩陣元素。at()
方法更安全,因為它會進行邊界檢查。
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrix = (cv::Mat_<double>(3,3) << 1, 2, 3, 4, 5, 6, 7, 8, 9); std::cout << "Original Matrix:\n" << matrix << std::endl; // 使用 at() 方法訪問和修改元素 double& elem = matrix.at<double>(0, 0); // 獲取 (0,0) 處的元素引用 elem = 100.0; std::cout << "Modified Matrix (at()):\n" << matrix << std::endl; // 直接通過指針訪問 (效率更高,但不安全) // 注意:需要確保數(shù)據(jù)類型匹配 double* p = matrix.ptr<double>(1); // 獲取第二行的指針 p[1] = 200.0; // 修改第二行第二列的元素 (1,1) std::cout << "Modified Matrix (ptr):\n" << matrix << std::endl; return 0; }
基本的算術(shù)運算 ?????
OpenCV 支持對矩陣進行各種基本的算術(shù)運算。這些運算可以是矩陣與標(biāo)量之間的運算,也可以是矩陣與矩陣之間的運算。
矩陣與標(biāo)量運算
可以直接使用標(biāo)準的算術(shù)運算符:
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(2,2) << 1, 2, 3, 4); double scalar = 5.0; cv::Mat result; // 加法 result = matrixA + scalar; std::cout << "MatrixA + Scalar:\n" << result << std::endl; // 減法 result = matrixA - scalar; std::cout << "MatrixA - Scalar:\n" << result << std::endl; result = scalar - matrixA; std::cout << "Scalar - MatrixA:\n" << result << std::endl; // 乘法 result = matrixA * scalar; std::cout << "MatrixA * Scalar:\n" << result << std::endl; // 除法 result = matrixA / scalar; std::cout << "MatrixA / Scalar:\n" << result << std::endl; return 0; }
矩陣與矩陣運算 (逐元素)
對于加法、減法和逐元素的乘法、除法,可以使用重載的運算符或 OpenCV 提供的函數(shù)。
- 加法 (+ 或 cv::add())
- 減法 (- 或 cv::subtract())
- 逐元素乘法 (cv::multiply())
- 逐元素除法 (cv::divide())
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(2,2) << 1, 2, 3, 4); cv::Mat matrixB = (cv::Mat_<double>(2,2) << 5, 6, 7, 8); cv::Mat result; // 加法 result = matrixA + matrixB; // 或者 cv::add(matrixA, matrixB, result); std::cout << "MatrixA + MatrixB:\n" << result << std::endl; // 減法 result = matrixA - matrixB; // 或者 cv::subtract(matrixA, matrixB, result); std::cout << "MatrixA - MatrixB:\n" << result << std::endl; // 逐元素乘法 cv::multiply(matrixA, matrixB, result); // 注意: matrixA * matrixB 是矩陣乘法,而不是逐元素乘法 std::cout << "Element-wise multiplication (A .* B):\n" << result << std::endl; // 逐元素除法 cv::divide(matrixA, matrixB, result); std::cout << "Element-wise division (A ./ B):\n" << result << std::endl; return 0; }
矩陣乘法 (標(biāo)準線性代數(shù)乘法)
使用 *
運算符可以執(zhí)行標(biāo)準的矩陣乘法 (m x n 矩陣乘以 n x p 矩陣得到 m x p 矩陣)。或者使用 cv::gemm()
函數(shù) (通用矩陣乘法)。
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(2,3) << 1, 2, 3, 4, 5, 6); cv::Mat matrixB = (cv::Mat_<double>(3,2) << 7, 8, 9, 10, 11, 12); cv::Mat result; // 矩陣乘法 result = matrixA * matrixB; std::cout << "MatrixA * MatrixB (Matrix Multiplication):\n" << result << std::endl; // 使用 cv::gemm() // gemm(src1, src2, alpha, src3, beta, dst, flags) // dst = alpha*src1*src2 + beta*src3 cv::Mat matrixC = cv::Mat::zeros(2, 2, CV_64F); cv::gemm(matrixA, matrixB, 1.0, cv::Mat(), 0.0, result, 0); // result = 1.0 * matrixA * matrixB std::cout << "MatrixA * MatrixB (using gemm):\n" << result << std::endl; return 0; }
注意: 參與矩陣乘法的兩個矩陣的維度必須兼容 (第一個矩陣的列數(shù)等于第二個矩陣的行數(shù))。
其他重要的矩陣運算 ??
OpenCV 還提供了許多其他有用的矩陣運算函數(shù)。
轉(zhuǎn)置 (cv::transpose() 或 Mat::t())
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(2,3) << 1, 2, 3, 4, 5, 6); cv::Mat transposedMatrix; cv::transpose(matrixA, transposedMatrix); // 或者 transposedMatrix = matrixA.t(); std::cout << "Original MatrixA:\n" << matrixA << std::endl; std::cout << "Transposed MatrixA:\n" << transposedMatrix << std::endl; return 0; }
逆矩陣 (cv::invert() 或 Mat::inv())
只有方陣且非奇異矩陣(行列式不為零)才有逆矩陣。
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(2,2) << 4, 7, 2, 6); cv::Mat inverseMatrix; // method 可以是 DECOMP_LU, DECOMP_SVD, DECOMP_CHOLESKY (對于對稱正定矩陣) double det = cv::determinant(matrixA); if (det != 0) { cv::invert(matrixA, inverseMatrix, cv::DECOMP_LU); // 或者 inverseMatrix = matrixA.inv(cv::DECOMP_LU); std::cout << "Original MatrixA:\n" << matrixA << std::endl; std::cout << "Inverse MatrixA:\n" << inverseMatrix << std::endl; // 驗證 A * A_inv = I std::cout << "A * A_inv:\n" << matrixA * inverseMatrix << std::endl; } else { std::cout << "MatrixA is singular, cannot compute inverse." << std::endl; } return 0; }
行列式 (cv::determinant())
計算方陣的行列式。
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(3,3) << 1, 2, 3, 0, 1, 4, 5, 6, 0); double det = cv::determinant(matrixA); std::cout << "MatrixA:\n" << matrixA << std::endl; std::cout << "Determinant of MatrixA: " << det << std::endl; return 0; }
跡 (cv::trace())
計算方陣的跡(主對角線元素之和)。
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(3,3) << 1, 2, 3, 4, 5, 6, 7, 8, 9); cv::Scalar traceValue = cv::trace(matrixA); std::cout << "MatrixA:\n" << matrixA << std::endl; std::cout << "Trace of MatrixA: " << traceValue[0] << std::endl; // trace返回一個Scalar return 0; }
范數(shù) (cv::norm())
計算矩陣的范數(shù)(例如 L1 范數(shù)、L2 范數(shù)、無窮范數(shù))。
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(1,3) << 3, -4, 0); // 也可以是多維矩陣 double normL1 = cv::norm(matrixA, cv::NORM_L1); double normL2 = cv::norm(matrixA, cv::NORM_L2); double normInf = cv::norm(matrixA, cv::NORM_INF); std::cout << "MatrixA: " << matrixA << std::endl; std::cout << "L1 Norm: " << normL1 << std::endl; // |3| + |-4| + |0| = 7 std::cout << "L2 Norm: " << normL2 << std::endl; // sqrt(3^2 + (-4)^2 + 0^2) = 5 std::cout << "Infinity Norm: " << normInf << std::endl; // max(|3|, |-4|, |0|) = 4 cv::Mat matrixB = (cv::Mat_<double>(2,2) << 1, 2, 3, 4); double frobeniusNorm = cv::norm(matrixB, cv::NORM_L2); // 對于矩陣,NORM_L2 是 Frobenius 范數(shù) std::cout << "MatrixB:\n" << matrixB << std::endl; std::cout << "Frobenius Norm of MatrixB: " << frobeniusNorm << std::endl; return 0; }
矩陣操作 ???
改變形狀 (Mat::reshape())
在不改變數(shù)據(jù)的情況下改變矩陣的維度。
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = (cv::Mat_<double>(2,3) << 1, 2, 3, 4, 5, 6); std::cout << "Original MatrixA (2x3):\n" << matrixA << std::endl; // 改變?yōu)橐粋€通道,3行 (列數(shù)自動計算) cv::Mat reshaped1 = matrixA.reshape(1, 3); std::cout << "Reshaped to 3 rows (1 channel):\n" << reshaped1 << std::endl; std::cout << "Reshaped1 channels: " << reshaped1.channels() << ", rows: " << reshaped1.rows << ", cols: " << reshaped1.cols << std::endl; // 改變?yōu)?3 通道,2 行 (假設(shè)原始數(shù)據(jù)可以這樣組織) // 注意:reshape(cn, rows) cn是新的通道數(shù) // 原始矩陣是單通道,6個元素。如果reshape(3, 2),則變成2行1列,3通道。 // (1,2,3) 像素1 // (4,5,6) 像素2 cv::Mat matrixB = cv::Mat::arange(1, 7).reshape(1, 2); // 2行3列,單通道 matrixB = matrixB.reshape(3, 2); // 2行1列,3通道 std::cout << "Original MatrixB (2x3, 1 channel then reshaped to 2x1, 3 channels):\n" << matrixB << std::endl; std::cout << "MatrixB value at (0,0) Ch0: " << matrixB.at<cv::Vec3b>(0,0)[0] << std::endl; // 假設(shè)是 CV_8UC3 // arange 默認是 CV_32S cv::Mat matrixC = (cv::Mat_<int>(1,6) << 1,2,3,4,5,6); std::cout << "Original MatrixC (1x6, 1 channel):\n" << matrixC << std::endl; cv::Mat reshapedC = matrixC.reshape(3, 2); // 2行1列,3通道 std::cout << "ReshapedC (2x1, 3 channels):\n" << reshapedC << std::endl; // 訪問 reshapedC.at<cv::Vec3i>(0,0)[0] 等 return 0; }
注意: reshape()
不會復(fù)制數(shù)據(jù)。新的矩陣頭指向原始數(shù)據(jù)。
合并與拼接 (cv::hconcat(), cv::vconcat())
cv::hconcat()
: 水平拼接矩陣 (列數(shù)增加)cv::vconcat()
: 垂直拼接矩陣 (行數(shù)增加)
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat matrixA = cv::Mat::ones(2, 2, CV_64F); cv::Mat matrixB = cv::Mat::zeros(2, 2, CV_64F); cv::Mat matrixC = cv::Mat::eye(2, 2, CV_64F) * 2; cv::Mat horizontalConcat; cv::hconcat(matrixA, matrixB, horizontalConcat); // 可以傳遞多個矩陣 cv::hconcat(horizontalConcat, matrixC, horizontalConcat); std::cout << "Horizontal Concatenation:\n" << horizontalConcat << std::endl; cv::Mat matrixD = cv::Mat::ones(2, 2, CV_64F) * 3; cv::Mat matrixE = cv::Mat::ones(2, 2, CV_64F) * 4; cv::Mat verticalConcat; std::vector<cv::Mat> matrices_to_stack = {matrixD, matrixE}; cv::vconcat(matrices_to_stack, verticalConcat); // 可以傳遞一個Mat的vector // 或者 cv::vconcat(matrixD, matrixE, verticalConcat); std::cout << "Vertical Concatenation:\n" << verticalConcat << std::endl; return 0; }
總結(jié) ??
OpenCV 提供了非常全面且易于使用的矩陣運算功能。通過 cv::Mat
類及其相關(guān)函數(shù),可以高效地執(zhí)行從基本算術(shù)運算到復(fù)雜線性代數(shù)運算的各種操作。熟練掌握這些運算是進行圖像處理和計算機視覺算法開發(fā)的基礎(chǔ)。記得查閱 OpenCV 官方文檔以獲取更詳細的信息和更多高級功能。
到此這篇關(guān)于C/C++中OpenCV 矩陣運算的實現(xiàn)的文章就介紹到這了,更多相關(guān)OpenCV 矩陣運算內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實現(xiàn)神經(jīng)BP神經(jīng)網(wǎng)絡(luò)
這篇文章主要為大家詳細介紹了C++實現(xiàn)神經(jīng)BP神經(jīng)網(wǎng)絡(luò),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05C語言數(shù)據(jù)結(jié)構(gòu) link 鏈表反轉(zhuǎn)的實現(xiàn)
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu) link 鏈表反轉(zhuǎn)的實現(xiàn)的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09C++實現(xiàn)簡單學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細介紹了C++實現(xiàn)簡單學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03C++使用boost::lexical_cast進行數(shù)值轉(zhuǎn)換
這篇文章介紹了C++使用boost::lexical_cast進行數(shù)值轉(zhuǎn)換的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06