2012-11-28 6 views
0

Opencl.net을 사용 중이며 GPU에서 일부 이미지 처리를 시도하고 있습니다. 불행히도 첫 번째 픽셀 ([0; 0]) 만 올바른 값을 가지며 나머지는 (0; 0; 0; 0)입니다. OpenCL 커널은 모든 픽셀의 모든 색상 구성 요소에 0.5를 할당해야합니다. 커널이 한 번만 실행되고있는 것 같습니다 (또는 읽기 기능이 첫 번째 픽셀 만 읽는 것일 수도 있습니다). 내가 도대체 ​​뭘 잘못하고있는 겁니까? 내 코드에서 관련 부분을 제외했습니다.OpenCL 이미징 - 하나의 픽셀 만 업데이트됩니다.

... 
int intPtrSize = 0; 
intPtrSize = Marshal.SizeOf(typeof(IntPtr)); 
Cl.Mem srcImage2DBuffer; 
Cl.ImageFormat imageFormat = new Cl.ImageFormat(Cl.ChannelOrder.ARGB, Cl.ChannelType.Float); 
int imgWidth = 0, imgHeight = 0; 

IntPtr srcFloatDataPtr; 

int srcIMGBytesSize = 0; 

GCHandle pinnedSrcFloatArray; 

//Load image from file into OpenCL buffer 
using (FileStream imageFileStream = new FileStream(inputImagePath, FileMode.Open)) { 
    System.Drawing.Image inputImage = System.Drawing.Image.FromStream(imageFileStream); 

    imgWidth = inputImage.Width; 
    imgHeight = inputImage.Height; 

    System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(inputImage); 

    BitmapData bitmapData = bmpImage.LockBits(new Rectangle(0, 0, bmpImage.Width, bmpImage.Height), 
            ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

    srcIMGBytesSize = bitmapData.Stride * bitmapData.Height; 

    //Convert image from byte to float array 
    byte[] inputByteArray = new byte[srcIMGBytesSize]; 
    Marshal.Copy(bitmapData.Scan0, inputByteArray, 0, srcIMGBytesSize); 
    bmpImage.UnlockBits(bitmapData); 

    float[] inputFloatArray = new float[srcIMGBytesSize]; 
    Array.Copy(inputByteArray, inputFloatArray, srcIMGBytesSize); 

    for (int i = 0; i < srcIMGBytesSize; i++) { 
     inputFloatArray[i] /= 255.0f; 
    } 

    pinnedSrcFloatArray = GCHandle.Alloc(inputFloatArray, GCHandleType.Pinned); 
    srcFloatDataPtr = pinnedSrcFloatArray.AddrOfPinnedObject(); 
    srcImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadOnly, imageFormat, 
             (IntPtr)bitmapData.Width, (IntPtr)bitmapData.Height, 
             (IntPtr)0, srcFloatDataPtr, out error); 
} 
float[] outputFloatArray = new float[srcIMGBytesSize]; 

//I'm not sure whether the pointer here is correct or not. 
Cl.Mem resultImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.WriteOnly, imageFormat, 
               (IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)0, outputFloatDataPtr, out error); 

error = Cl.SetKernelArg(kernel, 0, (IntPtr)intPtrSize, srcImage2DBuffer); 
error |= Cl.SetKernelArg(kernel, 1, (IntPtr)intPtrSize, resultImage2DBuffer); 

... 

IntPtr[] originPtr = new IntPtr[] { (IntPtr)0, (IntPtr)0, (IntPtr)0 }; 
IntPtr[] regionPtr = new IntPtr[] { (IntPtr)1, (IntPtr)1, (IntPtr)1 }; 
IntPtr[] workGroupSizePtr = new IntPtr[] { (IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)1 }; 

error = Cl.EnqueueWriteImage(cmdQueue, srcImage2DBuffer, Cl.Bool.True, originPtr, regionPtr, (IntPtr)0, (IntPtr)0, srcFloatDataPtr, 0, null, out clevent); 

pinnedSrcFloatArray.Free(); 
error = Cl.EnqueueNDRangeKernel(cmdQueue, kernel, 2, null, workGroupSizePtr, null, 0, null, out clevent); 

error = Cl.EnqueueReadImage(cmdQueue, resultImage2DBuffer, Cl.Bool.True, originPtr, regionPtr, 
          (IntPtr)0, (IntPtr)0, outputFloatArray, 0, null, out clevent); 

for (int i = 0; i < srcIMGBytesSize; i++) { 
    outputFloatArray[i] *= 255.0f; 
} 

//Right here I'm learning that all of the components are 0 
for (int i = 0; i < srcIMGBytesSize; i+=4) { 
    Console.WriteLine("(" + outputFloatArray[i] + "; " + outputFloatArray[i+1] + "; " 
         + outputFloatArray[i+2] + "; " + outputFloatArray[i+3] + ")"); 
} 

고맙습니다!

답변

2

문제를 파악했습니다. Cl.EnqueueWriteImage/Cl.EnqueueReadImage의 영역은 (1, 1, 1) 대신에 (imageWidth, imageHeight, 1)이되어야합니다 :

IntPtr[] regionPtr = new IntPtr[] { (IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)1 };