【问题标题】:RGB to greyscale conversion using CUDA使用 CUDA 将 RGB 转换为灰度
【发布时间】:2018-01-07 17:58:43
【问题描述】:

所以我正在尝试编写一个将 RGB 图像转换为灰度的程序。 我从 Udacity 问题集中得到了这个想法。问题是,当我在 Udacity Web 环境中写出内核时,它说我的代码可以工作,但是,当我尝试在我的计算机上本地执行它时,我没有收到任何错误,但是我的图像不是灰度出来的,而是出来完全灰色。它看起来像我加载的图像尺寸的一个灰色框。你能帮我找出我的代码中的错误吗,我已经将它与 Udacity 版本进行了比较,我似乎找不到它。

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <string>
#include <cuda.h>
#include <stdio.h>
#include <opencv\cv.h>
#include <opencv\highgui.h>
#include <iostream>



#define CUDA_ERROR_CHECK

#define CudaSafeCall( err ) __cudaSafeCall( err, __FILE__, __LINE__ )
#define CudaCheckError()    __cudaCheckError( __FILE__, __LINE__ )

inline void __cudaSafeCall(cudaError err, const char *file, const int line)
{
#ifdef CUDA_ERROR_CHECK
    if (cudaSuccess != err)
    {
        fprintf(stderr, "cudaSafeCall() failed at %s:%i : %s\n",
            file, line, cudaGetErrorString(err));
        exit(-1);
    }
#endif

    return;
}

inline void __cudaCheckError(const char *file, const int line)
{
#ifdef CUDA_ERROR_CHECK
    cudaError err = cudaGetLastError();
    if (cudaSuccess != err)
    {
        fprintf(stderr, "cudaCheckError() failed at %s:%i : %s\n",
            file, line, cudaGetErrorString(err));
        exit(-1);
    }


    err = cudaDeviceSynchronize();
    if (cudaSuccess != err)
    {
        fprintf(stderr, "cudaCheckError() with sync failed at %s:%i : %s\n",
            file, line, cudaGetErrorString(err));
        exit(-1);
    }
#endif

    return;
}

__global__ void rgb_2_grey(uchar* const greyImage, const uchar4* const rgbImage, int rows, int columns)
{
    int rgb_x = blockIdx.x * blockDim.x + threadIdx.x; //x coordinate of pixel
    int rgb_y = blockIdx.y * blockDim.y + threadIdx.y; //y coordinate of pixel

    if ((rgb_x >= columns) && (rgb_y >= rows)) {
        return;
    }

    int rgb_ab = rgb_y*columns + rgb_x; //absolute pixel position
    uchar4 rgb_Img = rgbImage[rgb_ab];
    greyImage[rgb_ab] = uchar((float(rgb_Img.x))*0.299f + (float(rgb_Img.y))*0.587f + (float(rgb_Img.z))*0.114f);
}
using namespace cv;
using namespace std;

void Proc_Img(uchar4** h_RGBImage, uchar** h_greyImage, uchar4 **d_RGBImage, uchar** d_greyImage);
void RGB_2_Greyscale(uchar* const d_greyImage, uchar4* const d_RGBImage, size_t num_Rows, size_t num_Cols);
void Save_Img();

Mat img_RGB;
Mat img_Grey;
uchar4 *d_rgbImg;
uchar *d_greyImg; 
int main()
{
        uchar4* h_rgbImg;
        //uchar4* d_rgbImge=0;
        uchar* h_greyImg;
        //uchar* d_greyImge=0;

        Proc_Img(&h_rgbImg, &h_greyImg, &d_rgbImg, &d_greyImg);
        RGB_2_Greyscale(d_greyImg, d_rgbImg, img_RGB.rows, img_RGB.cols);
        Save_Img();





    return 0;
}
void Proc_Img(uchar4** h_RGBImage, uchar** h_greyImage, uchar4 **d_RGBImage, uchar** d_greyImage){
    cudaFree(0);
    CudaCheckError();

    //loads image into a matrix object along with the colors in BGR format (must convert to rgb).
    Mat img = imread("C:\\Users\\Austin\\Pictures\\wallpapers\\IMG_3581.JPG", CV_LOAD_IMAGE_COLOR);
    if (img.empty()){
        cerr << "couldnt open file dumbas..." << "C:\\Users\\Austin\\Pictures\\wallpapers\\IMG_3581.JPG" << endl;
        exit(1);
    }

    //converts color type from BGR to RGB
    cvtColor(img, img_RGB, CV_BGR2RGBA);

    //allocate memory for new greyscale image. 
    //img.rows returns the range of pixels in y, img.cols returns range of pixels in x
    //CV_8UC1 means 8 bit unsigned(non-negative) single channel of color, aka greyscale.
    //all three of the parameters allow the create function in the Mat class to determine how much memory to allocate
    img_Grey.create(img.rows, img.cols, CV_8UC1);

    //creates rgb and greyscale image arrays
    *h_RGBImage = (uchar4*)img_RGB.ptr<uchar>(0); //.ptr is a method in the mat class that returns a pointer to the first element of the matrix.
    *h_greyImage = (uchar*)img_Grey.ptr<uchar>(0);        //this is just like a regular array/pointer mem address to first element of the array. This is templated
                                                          //in this case the compiler runs the function for returning pointer of type unsigned char. for rgb image it is
                                                          //cast to uchar4 struct to hold r,g, and b values.

    const size_t num_pix = (img_RGB.rows) * (img_RGB.cols); //amount of pixels 

    //allocate memory on gpu
    cudaMalloc(d_RGBImage, sizeof(uchar4) * num_pix); //bites of 1 uchar4 times # of pixels gives number of bites necessary for array
    CudaCheckError();
    cudaMalloc(d_greyImage, sizeof(uchar) * num_pix);//bites of uchar times # pixels gives number of bites necessary for array
    CudaCheckError();
    cudaMemset(*d_greyImage, 0, sizeof(uchar) * num_pix);
    CudaCheckError();


    //copy array into allocated space
    cudaMemcpy(*d_RGBImage, *h_RGBImage, sizeof(uchar4)*num_pix, cudaMemcpyHostToDevice);
    CudaCheckError();


    d_rgbImg = *d_RGBImage;
    d_greyImg = *d_greyImage; 
}


void RGB_2_Greyscale(uchar* const d_greyImage, uchar4* const d_RGBImage, size_t num_Rows, size_t num_Cols){

    const int BS = 16;
    const dim3 blockSize(BS, BS);
    const dim3 gridSize((num_Cols / BS) + 1, (num_Rows / BS) + 1); 

    rgb_2_grey <<<gridSize, blockSize>>>(d_greyImage, d_RGBImage, num_Rows, num_Cols);

    cudaDeviceSynchronize(); CudaCheckError();


}



void Save_Img(){

    const size_t num_pix = (img_RGB.rows) * (img_RGB.cols);
    cudaMemcpy(img_Grey.ptr<uchar>(0), d_greyImg, sizeof(uchar)*num_pix, cudaMemcpyDeviceToHost);
    CudaCheckError();


    imwrite("C:\\Users\\Austin\\Pictures\\wallpapers\\IMG_3581GR.JPG", img_Grey);

    cudaFree(d_rgbImg);
    cudaFree(d_greyImg);

}

编辑:我意识到我的 main 中的本地 var 与全局 var 同名,我在这里编辑了代码,现在我从 Visual Studio 得到错误,即

变量d_rgbIme 正在使用而未初始化

当我已经在上面初始化它时。如果我将它们设置为零,我会收到一个 CUDA 错误提示

遇到非法内存访问

我尝试运行 cuda-memcheck,但随后我收到无法运行文件的错误...

【问题讨论】:

  • 您正在启动一个比您的图像更大的线程网格。但是您的内核中没有线程检查。这意味着内核中的某些线程将越界访问您的图像。尝试在内核中添加线程检查,例如if ((rgb_x &lt; columns) &amp;&amp; (rgb_y &lt; rows)) {,然后再在内核中进行任何读取或写入。还可以尝试使用cuda-memcheck 运行您的代码,并将proper cuda error checking 添加到您的代码中。
  • 在 (rgb_Img.x)*0.299f 乘法之前,您需要将 int 转换为 float。将其更改为 (float(rgb_Img.x))*0.299f。
  • @AndreySmorodov 这将发生在automatically。当乘法参数之一已经是float(0.299f 是float 常量)时,不必显式转换为float
  • 明确地转换类型总是更好的。
  • 大家好,感谢 cmets。我已经采纳了您的所有建议并将其实现到我的代码中,不幸的是,它仍然无法在我的计算机上正常运行,只能在 Udacity 的在线环境中运行。

标签: c++ opencv cuda


【解决方案1】:

感谢 Robert Crovella 的其中一位 cmets,我发现了错误,他对此非常有帮助!在我的内核中,if 语句应为 if ((rgb_x &gt;= columns) || (rgb_y &gt;= rows)) {

【讨论】:

    【解决方案2】:

    我在 JCUDA 中解决了同样的问题。看看您是否可以使用此解决方案的任何部分:

    //Read Height and Width of image in Height & Width variables
    int Width = image.getWidth();
    int Height = image.getHeight();
    
    int N = Height * Width;
    int[] grayScale = new int[N];
    
    //Allocate separate arrays to store Alpha, Red, Green and 
    //Blue values for every pixel 
    int[] redHost = new int[N];
    int[] greenHost = new int[N];
    int[] blueHost = new int[N];
    int[] alphaHost = new int[N];
    
    for(int i=0; i<Height; i++)
    {
        for(int j=0; j<Width; j++)
        {
            int pixel = image.getRGB(j, i);
            //Read the ARGB data
            alphaHost[i*Width+j] = (pixel >> 24) & 0xff;
            redHost[i*Width+j] = (pixel >> 16) & 0xff;
            greenHost[i*Width+j] = (pixel >> 8) & 0xff;
            blueHost[i*Width+j] = (pixel) & 0xff;
        }
    }
    

    /* 以下是CUDA内核参数*/

    Pointer kernelParameters = Pointer.to(
                                    Pointer.to(new int[]{N}), //Total size of each array W * H 
                                    Pointer.to(redDev),       // Pointer to redArray on device
                                    Pointer.to(greenDev),     // Pointer to greenArray on device
                                    Pointer.to(blueDev),      // Pointer to blueArray on device
                                    Pointer.to(Output));      //Pointer to output array
    

    /*以下是我的 RGBToGrayScale.cu..即CUDA 内核 */

    __global__ void RGBtoGrayScale(int N, int *red, int *green, int *blue, int *Output)
    {
            int id = blockIdx.x * blockDim.x + threadIdx.x;
    
        if(id<N)
        {
            Output[id] = (red[id]*0.2989) + (green[id]*0.587) + (blue[id]*0.114);
        }
    
    }
    

    /* 将输出数据取回主机内存 */

    cuMemcpyDtoH(Pointer.to(grayScale), Output, N * Sizeof.INT);
    

    /* 用新的 RBG 值写入图像*/

    BufferedImage im = new BufferedImage(Width,Height,BufferedImage.TYPE_BYTE_GRAY);
            WritableRaster raster = im.getRaster();
            for(int i=0;i<Height;i++)
            {
                for(int j=0;j<Width;j++)
                {
                    raster.setSample(j, i, 0, grayScale[i*Width+j]);
                }
            }
            try 
            {
                ImageIO.write(im,"JPEG",new File("glpattern.jpeg"));
            } catch (IOException e) 
            {
                e.printStackTrace();
            } 
    

    【讨论】:

      猜你喜欢
      • 2013-10-25
      • 1970-01-01
      • 2020-04-29
      • 1970-01-01
      • 2010-10-15
      • 2013-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多