Мой вывод является черным изображением при преобразовании изображения RGB в оттенки серого - PullRequest
0 голосов
/ 12 ноября 2019

Я пытаюсь преобразовать RGB-изображение в оттенки серого, я использую изображение Lena.jpg. Я добавил несколько строк кода в секцию TODO, но, к сожалению, я получаю черное изображение на выходе. Мое ядро:

#define CHANNELS 3
__global__ void colorConvert(float * grayImage,
                float * rgbImage,
                int width, int height) {
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;

    if (x < width && y < height) {
        // get 1D coordinate for the grayscale image 
        int grayOffset = y*width + x;
        // one can think of the RGB image having
        // CHANNEL times columns than the gray scale image
        int rgbOffset = grayOffset*CHANNELS;
        float r = rgbImage[rgbOffset];
        float g = rgbImage[rgbOffset+1];
        float b = rgbImage[rgbOffset+2];
        //perform the rescaling and store it
        // multiply by constant values
        grayImage[grayOffset] = 0.21f*r + 0.71f*g + 0.07f*b;        
    }   
}

и вот моя основная функция:

int main(int argc, char **argv)
{
  if(argc!=3) {cout<<"Program takes two image filenames as parameters"<<endl;exit(3);}
  float *imgIn, *imgOut;
  int nCols, nRows, channels;

  // Allocate images and initialize from file
  imgIn = read_colored_image_asfloat(argv[1],&nCols, &nRows, &channels);
  if(channels!=3){cout<<"Input image is not a colored image"<<endl;exit(4);}
    // Allocate host images
  //imgIn = (float *)calloc(nCols*nRows, sizeof(float));
  imgOut = (float *)calloc(nCols*nRows, sizeof(float));

  // Allocates device images
  float *d_imgIn, *d_imgOut;
  //@TODO@ : Complete for device allocations
    int size = (nCols*nRows)*sizeof(float);
    // allocate memory on device
    cudaMalloc((float**) &d_imgIn, size);
    cudaMalloc((float**) &d_imgOut, size);
  // Copy input data
  //@TODO@ : Complete for data copy
    cudaMemcpy(d_imgIn, imgIn, size, cudaMemcpyHostToDevice);
  // Call the kernel
  //@TODO@ : Compute threads block and grid dimensions
    dim3 GridDim((nCols/16.0)+1, (nRows/16.0)+1, 1);
    dim3 BlockDim(16, 16, 1);
  //@TODO@ : Call the CUDA kernel
    colorConvert<<<GridDim, BlockDim>>>(d_imgOut, d_imgIn, nRows, nCols);
  // Copy output data
  //@TODO@ : Complete for data copy
    cudaMemcpy(imgOut, d_imgOut, size, cudaMemcpyDeviceToHost);

  // Write gray image to file
  write_gray_image_fromfloat(argv[2], imgOut, nCols, nRows, 1);

  // Free memory
  //@TODO@ : Free host and device memory
    // free host
    free(imgIn); free(imgOut);
    // free device
    cudaFree(d_imgIn);cudaFree(d_imgOut);
  return 0;
}

1 Ответ

2 голосов
/ 12 ноября 2019

Вы забыли умножить размер матрицы RGB на 3.

Это должно быть: cudaMalloc((float**) &d_imgIn, size*3); и cudaMemcpy(d_imgIn, imgIn, size*3, cudaMemcpyHostToDevice);.

Вы также поменялись местами nCols и nRows.
Это должно быть: colorConvert<<<GridDim, BlockDim>>>(d_imgOut, d_imgIn, nCols, nRows);

Должен работать следующий код:

int main()
{
    //int nCols = 512;int nRows = 384;int channels = 3;
    float *imgIn, *imgOut;
    int nCols, nRows, channels;

    // Allocate images and initialize from file
    imgIn = read_colored_image_asfloat(argv[1],&nCols, &nRows, &channels);

    //imgIn = (float*)calloc(nCols*nRows*3, sizeof(float));
    //FILE *f = NULL;fopen_s(&f, "rgb32f.raw", "rb");fread(imgIn, sizeof(float), nCols*nRows*3, f);fclose(f);f = NULL;

    imgOut = (float*)calloc(nCols*nRows, sizeof(float));

    // Allocates device images
    float *d_imgIn, *d_imgOut;
    //@TODO@ : Complete for device allocations
    int size = (nCols*nRows)*sizeof(float);
    // allocate memory on device
    cudaMalloc((float**)&d_imgIn, size*3);
    cudaMalloc((float**)&d_imgOut, size);

    // Copy input data
    //@TODO@ : Complete for data copy
    cudaMemcpy(d_imgIn, imgIn, size*3, cudaMemcpyHostToDevice);
    // Call the kernel
    //@TODO@ : Compute threads block and grid dimensions
    dim3 GridDim((nCols/16)+1, (nRows/16)+1, 1);
    dim3 BlockDim(16, 16, 1);
    //@TODO@ : Call the CUDA kernel
    colorConvert<<<GridDim, BlockDim>>>(d_imgOut, d_imgIn, nCols, nRows);
    // Copy output data
    //@TODO@ : Complete for data copy
    cudaMemcpy(imgOut, d_imgOut, size, cudaMemcpyDeviceToHost);

    //fopen_s(&f, "gray32f.raw", "wb");fwrite(imgOut, sizeof(float), nCols*nRows, f);fclose(f);f = NULL;
    // Write gray image to file
    write_gray_image_fromfloat(argv[2], imgOut, nCols, nRows, 1);

    // Free memory
    //@TODO@ : Free host and device memory
    // free host
    free(imgIn); 
    free(imgOut);

    // free device
    cudaFree(d_imgIn);
    cudaFree(d_imgOut);

    return 0;
}

Какая ошибка приводит к черному изображению?

Результат исправленного кода:
enter image description here

Результат обмена nRows с nCols:
enter image description here

Результат cudaMemcpy(d_imgIn, imgIn, size, cudaMemcpyHostToDevice); (вместо size*3):
enter image description here

Результат cudaMalloc((float**)&d_imgIn, size); (вместо size*3):
enter image description here

Вывод:
Халатность cudaMalloc является основной причиной черного результата.


Есть ли индикация ошибки CUDA?

Чтение возвращаемого значения cudaMemcpy:

cudaError_t err = cudaMemcpy(imgOut, d_imgOut, size, cudaMemcpyDeviceToHost);

Возвращает состояние ошибки: cudaErrorIllegalAddress

Вывод:
Проверка статуса возврата важна - иногдаэто помогает обнаруживать ошибки в коде.

...