C/C++中OpenCV 矩陣運算的實現(xiàn)
OpenCV 是一個強大的開源計算機視覺和機器學習庫,它提供了豐富的矩陣運算功能,這對于圖像處理和計算機視覺算法至關(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ù)運算。這些運算可以是矩陣與標量之間的運算,也可以是矩陣與矩陣之間的運算。
矩陣與標量運算
可以直接使用標準的算術(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;
}
矩陣乘法 (標準線性代數(shù)乘法)
使用 * 運算符可以執(zhí)行標準的矩陣乘法 (m x n 矩陣乘以 n x p 矩陣得到 m x p 矩陣)?;蛘呤褂?nbsp;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() 不會復制數(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ù)運算到復雜線性代數(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)絡
這篇文章主要為大家詳細介紹了C++實現(xiàn)神經(jīng)BP神經(jīng)網(wǎng)絡,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05
C語言數(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-09
C++使用boost::lexical_cast進行數(shù)值轉(zhuǎn)換
這篇文章介紹了C++使用boost::lexical_cast進行數(shù)值轉(zhuǎn)換的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06

