OpenCV CUDA模块设备层-----双曲正弦函数sinh()

发布于:2025-07-01 ⋅ 阅读:(22) ⋅ 点赞:(0)
  • 操作系统: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;
}

运行结果

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到