- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
在 OpenCV 的 CUDA 模块中,与范数(Norm)相关的函数主要用于计算矩阵的范数或者两个矩阵之间的差值范数。
主要函数
1.计算单个 GPU 矩阵的范数:norm
原型
double cv::cuda::norm
(
InputArray src1, // 输入 GPU 矩阵
int normType = NORM_L2, // 范数类型,默认为L2范数
InputArray mask = noArray() // 可选掩码,用于选择性地应用范数计算到src1的部分区域
);
参数
- InputArray src1: 需要计算范数的输入 GPU 矩阵。
- int normType: 指定使用的范数类型。常见的有:
- NORM_INF: 无穷范数,等于绝对值最大的元素。
- NORM_L1: L1范数,所有元素绝对值之和。
- NORM_L2: L2范数,平方和的平方根。
- InputArray mask: 可选参数,如果提供,则只对mask中非零元素对应的src1部分进行计算。
2.计算两个 GPU 矩阵之间的差值范数norm
原型
double cv::cuda::norm
(
InputArray src1, // 第一个输入 GPU 矩阵
InputArray src2, // 第二个输入 GPU 矩阵,尺寸/类型相同
int normType = NORM_L2 // 范数类型,默认为L2范数
);
参数
- InputArray src2: 第二个输入 GPU 矩阵,要求与src1具有相同的尺寸和通道数。
- 其余参数同上。
3.异步计算单个 GPU 矩阵的范数calcNorm
原型
void cv::cuda::calcNorm
(
InputArray src, // 输入 GPU 矩阵
OutputArray dst, // 输出结果,标量
int normType, // 范数类型
InputArray mask = noArray(), // 可选掩码
Stream& stream = Stream::Null() // 可选 CUDA 流
);
参数
- OutputArray dst: 输出结果,通常是一个 GpuMat 或者 Scalar,表示计算出的范数值。
- Stream& stream: 可选参数,指定执行此操作的CUDA流,默认为 Stream::Null() 表示使用默认流。
4.异步计算两个 GPU 矩阵之间的差值范数calcNormDiff
原型
void cv::cuda::calcNormDiff
(
InputArray src1, // 第一个输入 GPU 矩阵
InputArray src2, // 第二个输入 GPU 矩阵,尺寸/类型相同
OutputArray dst, // 输出结果,标量
int normType = NORM_L2, // 范数类型,默认为L2范数
Stream& stream = Stream::Null() // 可选 CUDA 流
);
参数
- InputArray src2: 第二个输入 GPU 矩阵,要求与src1具有相同的尺寸和通道数。
- 其余参数同上。
代码示例
#include <opencv2/opencv.hpp>
#include <opencv2/cudaarithm.hpp>
#include <iostream>
int main() {
// 创建两个 float 类型的 3x3 测试矩阵
cv::Mat h_mat1 = (cv::Mat_<float>(3, 3) <<
1.0f, -2.0f, 3.0f,
-4.0f, 5.0f, -6.0f,
7.0f, -8.0f, 9.0f);
cv::Mat h_mat2 = cv::Mat::zeros(h_mat1.size(), h_mat1.type());
// 创建一个 mask 矩阵(只允许中心区域参与计算)
cv::Mat h_mask = cv::Mat::zeros(h_mat1.size(), CV_8UC1);
cv::rectangle(h_mask, cv::Rect(1, 1, 1, 1), cv::Scalar(255), cv::FILLED); // 中心像素
// 将数据转换为 CV_8UC1 类型
cv::Mat h_mat1_8u, h_mat2_8u;
h_mat1.convertTo(h_mat1_8u, CV_8UC1);
h_mat2.convertTo(h_mat2_8u, CV_8UC1);
// 上传到 GPU
cv::cuda::GpuMat d_mat1, d_mat2, d_mask;
d_mat1.upload(h_mat1_8u);
d_mat2.upload(h_mat2_8u);
d_mask.upload(h_mask);
// 存储异步结果的 GpuMat
cv::cuda::GpuMat d_norm_result;
// 创建 CUDA 流
cv::cuda::Stream stream;
// 1️⃣ 同步:单矩阵 L2 范数(带 mask)
double l2_norm = cv::cuda::norm(d_mat1, cv::NORM_L2, d_mask);
std::cout << "Sync L2 Norm of mat1 (with mask): " << l2_norm << std::endl;
// 2️⃣ 同步:两矩阵之间的 L2 差值范数
double diff_norm = cv::cuda::norm(d_mat1, d_mat2, cv::NORM_L2);
std::cout << "Sync L2 Diff Norm between mat1 and mat2: " << diff_norm << std::endl;
// 3️⃣ 异步:单矩阵 L1 范数
cv::cuda::calcNorm(d_mat1, d_norm_result, cv::NORM_L1, cv::noArray(), stream);
stream.waitForCompletion();
cv::Mat host_norm;
d_norm_result.download(host_norm);
double async_l1_norm = host_norm.at<double>(0, 0);
std::cout << "Async L1 Norm of mat1: " << async_l1_norm << std::endl;
// 4️⃣ ✅ 异步:两个矩阵之间的 L2 差值范数(必须调用 calcNormDiff)
cv::cuda::calcNormDiff(d_mat1, d_mat2, d_norm_result, cv::NORM_L2, stream);
stream.waitForCompletion();
d_norm_result.download(host_norm);
double async_diff_norm = host_norm.at<double>(0, 0);
std::cout << "Async L2 Diff Norm between mat1 and mat2: " << async_diff_norm << std::endl;
return 0;
}
运行结果
Sync L2 Norm of mat1 (with mask): 5
Sync L2 Diff Norm between mat1 and mat2: 12.8452
Async L1 Norm of mat1: 25
Async L2 Diff Norm between mat1 and mat2: 12.8452