【问题标题】:Converting only 1/3 of RGB image to greyscale using CUDA使用 CUDA 仅将 1/3 的 RGB 图像转换为灰度
【发布时间】:2021-01-22 10:47:58
【问题描述】:

我正在尝试使用 CUDA 将 RGB 图像转换为灰度图像。我想用 stbi_load 读取图像,将其传递给 convertToGreyscale() 我调用内核并将图像保存在 unsigned char* 中 - 我可以从中使用它并应用变量阈值、sobel、多个阈值等问题是只有 1/3 的图像正在被处理并且实际上受到内核(灰度内核)的影响。 这是我的内核:

__global__ void greyscale(unsigned char* originalImg, unsigned char* d_greyImg, int width, int height, int channels) {

    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    unsigned int id = x + y * width;
    if (x < width && y < height) {
        unsigned char r = originalImg[id];
        unsigned char g = originalImg[id + 1];
        unsigned char b = originalImg[id + 2];
        int offset = (r+g+b) / channels;
        for (int i = 0; i < channels; i++) {
            d_greyImg[id + i] = offset;
        }
    }
}

这是代码的另一部分:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

#include "cuda_runtime.h"
#include "cuda_runtime_api.h"

#include "device_launch_parameters.h"

#include <stdio.h>
#define THREADS 8

void convertToGreyscale(unsigned char* originalImg, unsigned char* greyImg, int width, int height, int channels)
{
    unsigned char* d_originalImg = NULL;
    unsigned char* d_greyImg = NULL;
    int size = width * height * channels * sizeof(unsigned char);

    cudaMalloc(&d_originalImg, size);
    cudaMalloc(&d_greyImg, size);

    cudaMemcpy(d_originalImg, originalImg, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_greyImg, greyImg, size, cudaMemcpyHostToDevice);

    dim3 dimBlock(THREADS, THREADS);
    dim3 dimGrid(width / dimBlock.x, height / dimBlock.y);
    greyscale << <dimGrid, dimBlock >> > (d_originalImg, d_greyImg, width, height, channels);

    cudaMemcpy(greyImg, d_greyImg, size, cudaMemcpyDeviceToHost);

    cudaFree(d_originalImg);
}

void sobelFilter(unsigned char* originalImg, unsigned char* sobelImg, int width, int height, int channels)
{
    dim3 dimBlock(THREADS, THREADS, 1);
    dim3 dimGrid(width / dimBlock.x, height / dimBlock.y);
    unsigned char* d_originalImg = NULL;
    int size = width * height;

    cudaMalloc(&d_originalImg, size * channels * sizeof(unsigned char));

    cudaMemcpy(d_originalImg, originalImg, size * channels * sizeof(unsigned char), cudaMemcpyHostToDevice);

    sobel << <dimGrid, dimBlock >> > (d_originalImg, width, height);

    cudaMemcpy(sobelImg, d_originalImg, size * channels , cudaMemcpyDeviceToHost);

    cudaFree(d_originalImg);
}

int main()
{
    // read the image
    int width, height, channels;
    unsigned char* originalImg = stbi_load("lenna.png", &width, &height, &channels, 0);

    size_t img_size = width * height * channels;
    unsigned char* greyImg = (unsigned char*) malloc(img_size);
    unsigned char* sobelImg = (unsigned char*) malloc(img_size);

    convertToGreyscale(originalImg, greyImg, width, height, channels);
    stbi_write_jpg("greyscale.png", width, height, channels, greyImg, 100);

    /*sobelFilter(originalImg, sobelImg, width, height, channels);
    stbi_write_jpg("sobel.png", width, height, channels, sobelImg, 100);*/

    return 0;

}

【问题讨论】:

  • 无符号整数 id = x + y * 宽度;应该是 (...) * 个频道

标签: image-processing cuda


【解决方案1】:

您可能需要dimGrid((width+dimBlock.x-1) / dimBlock.x, (height+dimBlock.y-1) / dimBlock.y); 以确保您不会错过任何角落。

我认为主要问题是您的输入图像在没有考虑通道的情况下被读取。 您的线程在某些时候将具有值x,但也值x+1(和相同的y)。但是如果你看到你是如何定义id的,你会注意到不是3乘3读取,而是1接1读取,因为这两个线程将idid+1作为值。您需要确保id 的计算已考虑到channels,但请注意,它不适用于grryscale,您需要一个不同的(或除以3)。

【讨论】:

    猜你喜欢
    • 2013-10-25
    • 1970-01-01
    • 2014-02-26
    • 2014-12-22
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多