0. 引言
本文将以一个简单的例子展示如何使用 CUDA 将 RGB 图像转换为灰度图,并结合 OpenCV 完成图像的加载与保存。
1. 实现功能概述
我们要实现以下功能:
- 使用 CUDA 内核,将每个像素从 RGBA 格式转换为灰度值。
- 灰度化公式为:
Gray = 0.299 * R + 0.587 * G + 0.114 * B
。 - 使用 OpenCV 进行图像加载和保存处理。
代码分为三个部分:
- CUDA 核心逻辑:负责灰度化转换的 CUDA 内核实现。
- 主机端逻辑:完成内存管理、数据传递以及对 CUDA 内核的调用。
- OpenCV 图像操作:用于读取和保存图像文件。
2. 完整代码
// rgba_to_greyscale.h
#ifndef RGBA_TO_GREYSCALE_H_
#define RGBA_TO_GREYSCALE_H_
#include <cstdint>
// Callback function type for handling the output grey image.
typedef void (*CallbackFun)(int32_t height, int32_t width, uint8_t* h_grey_image);
// Converts an RGBA image to greyscale using CUDA.
// Parameters:
// - height: Image height.
// - width: Image width.
// - data: Pointer to RGBA image data.
// - callback: Callback function to handle the output grey image.
int32_t RgbaToGreyscale(int32_t height, int32_t width, uint8_t* data, CallbackFun callback = nullptr);
#endif // RGBA_TO_GREYSCALE_H_
// rgba_to_greyscale.cu
#include "rgba_to_greyscale.h"
#include <cuda_runtime.h>
#include <cuda_runtime_api.h>
#include <iostream>
#include <cstring>
namespace {
// CUDA kernel for RGBA to greyscale conversion.
__global__ void RgbaToGreyscaleKernel(const uchar4* rgba_image, uint8_t* grey_image,
int32_t num_rows, int32_t num_cols) {
const int32_t id = blockIdx.x * blockDim.x * blockDim.y + threadIdx.y * blockDim.x + threadIdx.x;
if (id < num_rows * num_cols) {
const uint8_t r = rgba_image[id].x;
const uint8_t g = rgba_image[id].y;
const uint8_t b = rgba_image[id].z;
grey_image[id] = static_cast<uint8_t>(0.299f * r + 0.587f * g + 0.114f * b);
}
}
} // namespace
int32_t RgbaToGreyscale(int32_t height, int32_t width, uint8_t* data, CallbackFun callback) {
if (data == nullptr) {
std::cerr << "Input data is null." << std::endl;
return -1;
}
uchar4* h_rgba_image = reinterpret_cast<uchar4*>(data);
int32_t num_pixels = width * height;
uchar4* d_rgba_image = nullptr;
uint8_t* d_grey_image = nullptr;
uint8_t* h_grey_image = nullptr;
if (cudaMalloc(&d_rgba_image, sizeof(uchar4) * num_pixels) != cudaSuccess) {
std::cerr << "Failed to allocate device memory for RGBA image." << std::endl;
return -1