- 操作系統:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 編程語言:C++11
算法描述
該函數用于在 GPU 上計算圖像的原始矩(spatial moments)。這些矩可用于描述圖像中物體的形狀特征,如面積、質心等。
與 cv::cuda::moments(…) 不同的是,這個函數將結果寫入一個 OutputArray 中,而不是返回結構體。因此它更適合需要手動處理矩數組的應用場景。
參數
參數名 | 類型 | 描述 |
---|---|---|
src | InputArray | 輸入圖像,支持 CV_8U, CV_16U, 或 CV_32S 類型,單通道圖像。如果 binaryImage 為 true,則應為二值圖像(前景非零,背景為零)。 |
moments | OutputArray | 輸出矩數組,是一個一維數組,長度由 order 決定(見下文),數據類型由 momentsType 指定。 |
binaryImage | const bool | 如果為 true,則假設輸入圖像是二值圖像;否則按灰度圖處理。默認為 false。 |
order | const MomentsOrder | 要計算的矩的最大階數,可選: |
- FIRST_ORDER_MOMENTS:僅計算到一階矩(共 4 個矩) | ||
- SECOND_ORDER_MOMENTS:計算到二階矩(共 9 個矩) | ||
- THIRD_ORDER_MOMENTS:計算到三階矩(共 16 個矩) | ||
momentsType | const int | 矩的數據類型,通常為 CV_64F(雙精度浮點數),也可以是 CV_32F。 |
stream | Stream& | 可選的 CUDA 流對象,用于異步執行。默認為同步執行(Stream::Null())。 |
注意:
為了獲得最佳性能,請預先分配一個一維 GpuMat 用于存儲矩(moments),其類型和大小必須足以容納指定階數下的所有圖像矩。
例如:當 order == MomentsOrder::SECOND_ORDER_MOMENTS 且 momentsType == CV_32F 時,可以這樣分配:
GpuMat momentsDevice(1, numMoments(MomentsOrder::SECOND_ORDER_MOMENTS), CV_32F);
下載矩數組后,可以在主機端使用 cv::Moments 構造函數輕松地計算中心矩(central moments)和歸一化矩(normalized moments)。例如:
HostMem momentsHostMem(1, numMoments(MomentsOrder::SECOND_ORDER_MOMENTS), CV_32F);
momentsDevice.download(momentsHostMem, stream);
stream.waitForCompletion();
Mat momentsMat = momentsHostMem.createMatHeader();
cv::Moments cvMoments(momentsMat.at<float>(0), momentsMat.at<float>(1),momentsMat.at<float>(2), momentsMat.at<float>(3),momentsMat.at<float>(4), momentsMat.at<float>(5),momentsMat.at<float>(6), momentsMat.at<float>(7),momentsMat.at<float>(8), momentsMat.at<float>(9)
);
示例詳見 OpenCV 貢獻模塊源碼中的測試文件:
opencv_contrib_source_code/modules/cudaimgproc/test/test_moments.cpp 中的 CUDA_TEST_P(Moments, Async) 測試用例
返回值
無返回值。矩的結果通過 moments 參數輸出。
代碼示例
#include <opencv2/opencv.hpp>
#include <opencv2/cudaimgproc.hpp>
#include <iostream>int main()
{// 加載圖像cv::Mat h_src = cv::imread("/media/dingxin/data/study/OpenCV/sources/images/Lenna.png", cv::IMREAD_GRAYSCALE);if (h_src.empty()){std::cerr << "無法加載圖像!" << std::endl;return -1;}// 上傳圖像到 GPUcv::cuda::GpuMat d_src;d_src.upload(h_src);// 獲取最大階數下的矩數量int nMoments = cv::cuda::numMoments(cv::cuda::MomentsOrder::THIRD_ORDER_MOMENTS);// 創建輸出矩陣cv::cuda::GpuMat d_moments;d_moments.create(1, nMoments, CV_64F); // 存儲所有矩值// 計算空間矩cv::cuda::spatialMoments(d_src, d_moments, false, cv::cuda::MomentsOrder::THIRD_ORDER_MOMENTS);// 下載結果cv::Mat h_moments;d_moments.download(h_moments);// 打印結果std::cout << "原始矩(spatial moments):" << std::endl;for (int i = 0; i < h_moments.cols; ++i){std::cout << "Moment[" << i << "] = " << h_moments.at<double>(i) << std::endl;}return 0;
}
運行結果
原始矩(spatial moments):
Moment[0] = 3.4715e+07
Moment[1] = 9.17605e+09
Moment[2] = 8.59234e+09
Moment[3] = 3.17604e+12
Moment[4] = 2.31525e+12
Moment[5] = 2.88234e+12
Moment[6] = 1.22333e+15
Moment[7] = 8.11918e+14
Moment[8] = 7.81631e+14
Moment[9] = 1.09583e+15