0

我开始使用 cuda 实现一些简单的图像处理,但我的代码中有错误当我将像素从设备复制到主机时发生错误

这是我的尝试

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <stdio.h> 
using namespace cv;

unsigned char *h_pixels;
unsigned char *d_pixels;
int bufferSize;
int width,height;

const int BLOCK_SIZE = 32;
Mat image;

void get_pixels(const char* fileName)
{
    image = imread(fileName);
    bufferSize = image.size().width * image.size().height * 3 * sizeof(unsigned char);
    width = image.size().width;
    height = image.size().height;
    h_pixels = new unsigned char[bufferSize];
    memcpy(h_pixels,image.data,bufferSize);
}

__global__ void invert_image(unsigned char* pixels,int width,int height)
{
    int row = blockIdx.y * BLOCK_SIZE + threadIdx.y;
    int col = blockIdx.x * BLOCK_SIZE + threadIdx.x;
    int cidx = (row  * width + col) * 3;
    pixels[cidx] = 255 - pixels[cidx]; 
    pixels[cidx + 1] = 255 - pixels[cidx + 1]; 
    pixels[cidx + 2] = 255 - pixels[cidx + 2]; 

}
int main()
{
    get_pixels("D:\\photos\\z.jpg");

    cudaError_t err = cudaMalloc((void**)&d_pixels,bufferSize);
    err =  cudaMemcpy(d_pixels,h_pixels,bufferSize,cudaMemcpyHostToDevice);
    dim3 dimBlock(BLOCK_SIZE,BLOCK_SIZE);
    dim3 dimGrid(width/dimBlock.x,height/dimBlock.y);

    invert_image<<<dimBlock,dimGrid>>>(d_pixels,width,height);

    unsigned char *pixels = new unsigned char[bufferSize];


    err= cudaMemcpy(pixels,d_pixels,bufferSize,cudaMemcpyDeviceToHost);// unknown error 
    const char * errStr = cudaGetErrorString(err);
    cudaFree(d_pixels);
    image.data = pixels;
    namedWindow("display image");
    imshow("display image",image);
    waitKey();
    return 0;
}

另外我如何找出cuda设备中发生的错误感谢您的帮助

4

3 回答 3

2
  • 首先确保正确读取图像文件。
  • 检查是否使用 CUDA_SAFE_CALL(cudaMalloc(..)) 分配了设备内存
  • 检查图像的尺寸。如果图像的尺寸不是 BLOCKSIZE 的倍数,那么您可能会丢失一些索引并且图像没有完全反转。
  • 在内核调用后调用 cudaDeviceSynchronize 并检查其返回值。
  • 在不调用内核的情况下运行代码时是否出现任何错误?
  • 您没有释放 h_pixels 并且可能存在内存泄漏。
  • 您可以使用“blockDim.x”,而不是在内核中使用 BLOCKSIZE。所以计算像“blockIdx.x * blockDim.x + threadIdx.x”这样的索引
  • 尽量不要触及内核代码中的内存区域,即注释掉内核中的内存更新(访问像素数组的行)并检查程序是否继续失败。如果它没有继续失败,您可能会越界访问。
于 2012-09-18T20:49:25.803 回答
2

OpenCV 图像不是连续的。每行是 4 字节或 8 字节对齐的。您还应该step将 Mat 的字段传递给 CUDA 内核,以便您可以cidx正确计算。计算输出指数的通用公式是:

cidx = row * (step/elementSize) + (NumberOfChannels * col);

在您的情况下,它将是:

cidx = row * step + (3 * col);

参考图像的对齐方式,您的缓冲区大小等于image.step * image.size().height.

接下来是@phoad 在第三点中指出的。您应该创建足够数量的线程块来覆盖整个图像。

这是网格的通用公式,它将为任何图像大小创建足够数量的块。

dim3 block(BLOCK_SIZE,BLOCK_SIZE);

dim3 grid((width + block.x - 1)/block.x,(height + block.y - 1)/block.y);

于 2012-09-19T05:01:45.590 回答
1

在内核调用后立即使用此命令打印内核错误:

printf("error code: %s\n",cudaGetErrorString(cudaGetLastError()))
于 2012-09-19T11:04:55.487 回答