在CUDA中处理图像处理的麻烦

时间:2016-04-13 11:41:07

标签: c++ image cuda

我是CUDA的新手,我试图在其中完成我的第一个项目。我试图将图像数据推送到GPU,在那里将其设置为黑白,并将其写入新图像。但是程序给了我一个黑色图像而不是黑白版本。我究竟做错了什么?图像的宽度和高度为3840x2160。Source image

Output image

__global__ void addMatrix(unsigned char *DataOut, unsigned char *DataIn)
{
    int idx = threadIdx.x;
    DataOut[idx] = (DataIn[idx] + DataIn[idx + 1] + DataIn[idx + 2]) / 3;
    //
}
int main()

{

int iWidth, iHeight, iBpp, iHeightOut, iWidthOut;

vector<unsigned char> pDataIn;
vector<unsigned char> pDataOut;


int error1 = LoadBmpFile(L"3840x2160.bmp", iWidth, iHeight, iBpp, pDataIn);

if (error1 != 0 || pDataIn.size() == 0 || iBpp != 32)
{
    std::cout << "erroror load input file!\n";
}


pDataOut.resize(pDataIn.size()/4);

unsigned int SizeIn, SizeOut;
unsigned char *devDatOut, *devDatIn, *PInData, *POutData;

int i = 0;
SizeIn = pDataIn.size();
SizeOut = pDataOut.size();
PInData = pDataIn.data();
POutData = pDataOut.data();

i = cudaMalloc((void**)&devDatIn, SizeIn * sizeof(unsigned char));
if(i != 0)
{
printf("cudaMalloc __e FAIL! Code: %d\n", i);
_getch();
}
i = cudaMalloc((void**)&devDatOut, SizeOut * sizeof(unsigned char));
if(i != cudaSuccess)
printf("cudaMalloc __e FAIL! Code: %d\n", i);

i = cudaMemcpy(devDatIn, PInData, SizeIn * sizeof(unsigned char), cudaMemcpyHostToDevice);
if(i != cudaSuccess)
printf(" cudaMemcpy __e FAIL! Code: %d\n", i);
i = cudaMemcpy(devDatOut, POutData, SizeOut * sizeof(unsigned char), cudaMemcpyHostToDevice);
if(i != cudaSuccess)
printf(" cudaMemcpy __e FAIL! Code: %d\n", i);

dim3 gridSize = dim3(1, 1, 1);   
dim3 blockSize = dim3(SizeIn, 1, 1);

addMatrix<<<gridSize, blockSize>>>(devDatIn, devDatOut);
if ( i == cudaGetLastError() )
{
printf( "Error! %d\n", cudaGetLastError() );
_getch;
}

 cudaEvent_t syncEvent;

cudaEventCreate(&syncEvent); 
cudaEventRecord(syncEvent, 0); 
 cudaEventSynchronize(syncEvent);  

 cudaMemcpy(POutData, devDatOut, SizeOut * sizeof(unsigned char), cudaMemcpyDeviceToHost);

  cudaEventDestroy(syncEvent);

i = WriteBmpFile(L"3840x2160_test2.bmp", iWidth, iHeight, 8, pDataOut.size(), pDataOut.data(), false);
    if(i != 0)
    printf(" cudaMemcpy __e FAIL! Code: %d\n", i);

    cudaFree(devDatOut);
  cudaFree(devDatIn);

}

编辑1:

Output image after editing

1 个答案:

答案 0 :(得分:2)

正如评论中所见,您为每个块启动了太多线程,并且启动可能失败,但您的错误检查不完整,您无法看到它。 启动内核后,请参阅this answer以了解正确的错误检查。

顺便说一下,你必须启动几个较少线程的块,而不是一个包含所有这些线程的块。 例如,它可能是1024个1024个线程的块。在我当前的卡上,1024个线程是我在每个块中可以拥有的最大值,因此如果我需要更多线程,我会启动几个块,并且通常我会启动更多具有更少线程的块以实现更好的占用率。 您可以详细了解入住with this presentation

因此,例如,如果您总共有10到3000个像素,则可以启动20个块,每个块500个线程。 您可以在一个维度上执行此操作:

dim3 blocks(20, 1, 1);
dim3 threads(500, 1, 1);

myKernel<<<blocks, threads>>>(...);

在你的内核中需要稍加改动才能将每个特定块中的线程索引正确映射到内存中图片缓冲区中的唯一线性索引(在浏览器中写入,未经过特定项目测试,但线性化通过用旧笔在纸上思考它很容易理解:

__global__ void addMatrix(unsigned char *DataOut, unsigned char *DataIn)
{
    int idx = BlockIdx.x * BlockDim.x + threadIdx.x;

    unsigned char average = (unsigned char)((DataIn[idx] + DataIn[idx + 1] + DataIn[idx + 2]) / 3);

    DataOut[idx + 0] = average;
    DataOut[idx + 1] = average;
    DataOut[idx + 2] = average;
}