2016-04-26 44 views
1

我试图将黑白图像作为输出与彩色图像作为输入。我正在使用OpenCV来获取图像并写入输出,并使用CUDA在内核中将图像变成黑白。我尝试了相同的代码,但没有OpenCV,它运行良好。但是现在输出与我真正期望得到的稍有不同。CUDA处理图像时出错

我认为CUDA代码需要修改才能使用OpenCV。我对它做了一些工作,但没有找到办法做到这一点。也许有人可以给我一个建议或修改我的代码吗?我真的很困惑这个问题。

__global__ void addMatrix(uchar4 *DataIn, unsigned char *DataOut) 
    { 
     int idx = blockIdx.x * blockDim.x + threadIdx.x; 
     DataOut[idx] = (DataIn[idx].x + DataIn[idx].y + DataIn[idx].z)/3; 
    } 

int main() 
{ 
     cudaDeviceProp deviceProp; 
     cudaGetDeviceProperties(&deviceProp, 0); 

     char* c = ""; 
     printf("Input source of image\n Example of right directory file: E:\henrik-evensen-castle-valley-v03.jpg\n Your turn:\n"); 
     char *tbLEN; 
     tbLEN = new char [1024]; 

     cin.getline(tbLEN,1024); 

     cout<< endl << "Your image: " << tbLEN << endl; 

     //Data for input image 
     IplImage* image; 
     image = cvLoadImage(tbLEN, 1); 
     int height = image->height; 
     int width = image->width; 
     int step = image->widthStep; 
     int SizeIn = (step*height); 
     printf("\nProcessing image\n"); 
     //Data for output image 
     IplImage *image2 = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); 
     int step2 = image2->widthStep; 
     int SizeOut = step2 * height; 

     //GPU 
     uchar4* DatIn = (uchar4*)image->imageData; 
     unsigned char* DatOut = (unsigned char*)image2->imageData; 
     uchar4 *datIndev; 
     unsigned char *datOutdev; 

     printf("Allocating memory on Device\n"); 
     /* Allocate memory on Device */ 
     cudaMalloc(&datIndev, SizeIn * sizeof(unsigned char)); 
     cudaMalloc(&datOutdev, SizeOut * sizeof(unsigned char)); 

     printf("Copy data on Device\n"); 
     /* Copy data on Device */ 
     cudaMemcpy(datIndev, DatIn, SizeIn * sizeof(unsigned char), cudaMemcpyHostToDevice); 
     cudaMemcpy(datOutdev, DatOut, SizeOut * sizeof(unsigned char), cudaMemcpyHostToDevice); 

     int NumThreadsX = deviceProp.maxThreadsPerBlock; 
     int NumBlocksX = (width * height)/NumThreadsX; 

     dim3 blocks(NumBlocksX, 1, 1); 
     dim3 threads(NumThreadsX, 1, 1); 
     addMatrix <<< blocks, threads >>> (datIndev, datOutdev); 


     cudaMemcpy(DatOut, datOutdev, SizeOut * sizeof(unsigned char), cudaMemcpyDeviceToHost); 
     cvNamedWindow("Imagecolor"); 
     cvShowImage("Imagecolor", image); 

     cvNamedWindow("Gray"); 
     cvShowImage("Gray", image2); 
     const char* filename1 = "CcPwSwMW4AELPUc.jpg"; 
     printf("Saving an output image\n"); 
     cvSaveImage(filename1, image2); 
     cudaFree(datOutdev); 
     cudaFree(datIndev); 
     cvWaitKey(0); 
     return 0; 
} 

Input

Output

+2

也许你想验证图像的实际步骤,使得每个像素有4个通道。乍一看,我会说图像是每个像素3个字节,因此uchar4不是适当的类型。 –

+0

我很肯定OpenCV只是放弃了alpha通道,所以你的BGR而不是BGRA数据在源图像 – talonmies

+1

'cvLoadImage'中,标志1将是** BGR **,所以你有** 3 **通道.. 。如果你想用alpha,它应该是-1(并且图像必须有alpha)。另外,我只是想知道为什么如果你使用'c'函数opencv – api55

回答

3

这里有几个问题:

  1. 你的假设,约四通道数据不正确。您的代码将从文件中将三通道BGR图像加载到内存中。因此,您需要将参考文件uchar4更改为uchar,然后让每个线程从内核中的源映像加载三个字节。

  2. 您的内核本身包含一个潜在的算术错误。三个无符号字符像素值的总和可能会溢出一个无符号字符中间结果并产生不正确的平均值。您应该使用更大的类型进行计算。

总之,你的核心应该是这个样子:

__global__ void addMatrix(unsigned char *DataIn, unsigned char *DataOut) 
{ 
    int idx = blockIdx.x * blockDim.x + threadIdx.x; 
    int b = DataIn[3*idx]; 
    int g = DataIn[3*idx+1]; 
    int r = DataIn[3*idx+2]; 

    DataOut[idx] = (unsigned char)((b + r + g)/3); 
} 

然后,你可能会发现你的形象看起来是正确的。

+0

非常感谢!我现在看到我做错了什么,非常感谢你。 – Generwp