- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
OpenCV的CUDA 模块(cv::cudev)中的一个设备端数学函数,用于在 GPU 上对 uchar3 类型的像素值(如RGB图像中的一个像素)逐通道计算双曲正弦函数(hyperbolic sine),并将结果转换为float3类型返回。
函数原型
__device__ __forceinline__ float3 cv::cudev::sinh ( const uchar3 & a )
参数
- a const uchar3& 输入的 3 通道无符号字符向量(如 RGB 图像中的一个像素)。
返回值
- 返回一个新的 float3 值;
- 每个通道的值为 sinh((float)a.x), sinh((float)a.y), sinh((float)a.z);
- 使用的是 CUDA 内建函数 sinhf(…) 来计算双曲正弦。
代码
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/cudev/util/vec_math.hpp>
using namespace cv;
using namespace cv::cudev;
// CUDA 核函数:对 uchar3 像素计算 sinh,并确保输出在 [0,1]
template <typename SrcPtr, typename DstPtr>
__global__ void sinhKernel(SrcPtr src, DstPtr dst, int width, int height) {
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < width && y < height) {
// 获取原始像素值
uchar3 val = src(y, x);
// Step 1: 将 uchar3 归一化到 [0,1]
float scale = 1.0f / 255.0f;
float fx = val.x * scale;
float fy = val.y * scale;
float fz = val.z * scale;
// Step 2: 构造一个 "fake" uchar3 输入,表示 [0,1] 区间
uchar3 fake_input;
fake_input.x = static_cast<unsigned char>(fx * 255.0f);
fake_input.y = static_cast<unsigned char>(fy * 255.0f);
fake_input.z = static_cast<unsigned char>(fz * 255.0f);
// Step 3: 调用 OpenCV 提供的 sinh 函数(唯一一次调用)
float3 sinhVal = sinh(fake_input); // ←←← 这里才是你想要的 cv::cudev::sinh(...)
// Step 4: 将 sinh 输出压缩到 [0,1]
const float inv_sinh1 = 1.0f / sinhf(1.0f); // sinh([0,1]) ∈ [0, ~1.175]
sinhVal.x *= inv_sinh1;
sinhVal.y *= inv_sinh1;
sinhVal.z *= inv_sinh1;
// Step 5: 写入输出图像
dst(y, x) = sinhVal;
}
}
int main() {
// 加载图像
Mat h_img = imread("/media/dingxin/data/study/OpenCV/sources/images/img0.jpg", IMREAD_COLOR);
if (h_img.empty()) {
std::cerr << "Failed to load image!" << std::endl;
return -1;
}
// 上传到 GPU
cuda::GpuMat d_img, d_result;
d_img.upload(h_img);
d_result.create(d_img.size(), CV_32FC3); // float3 对应 CV_32FC3
// 构造 PtrStepSz 访问器
auto ptr = PtrStepSz<uchar3>(d_img);
auto dptr = PtrStepSz<float3>(d_result);
// 设置核函数参数
dim3 block(16, 16);
dim3 grid((d_img.cols + block.x - 1) / block.x,
(d_img.rows + block.y - 1) / block.y);
// 启动核函数
sinhKernel<<<grid, block>>>(ptr, dptr, d_img.cols, d_img.rows);
cudaDeviceSynchronize();
// 下载并显示结果
Mat h_result;
d_result.download(h_result);
imshow("Sinh Image", h_result); // 已经是 [0,1] 浮点图像
imwrite("output_sinh_image.png", h_result * 255); // 保存为 PNG
waitKey(0);
return 0;
}