0

Opencl.netを使用していて、GPUで画像処理を実行しようとしています。残念ながら、最初のピクセル([0; 0])のみが正しい値を持ち、残りは(0; 0; 0; 0)です。OpenCLカーネルは、すべてのピクセルのすべてのカラーコンポーネントに0.5を割り当てる必要があります。カーネルが一度だけ実行されているように見えます(または、読み取り関数が最初のピクセルのみを読み取っている可能性があります)。私は何が間違っているのですか?コードから関連のない部分を省略しました:

...
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] + ")");
}

ありがとうございました!

4

1 に答える 1

2

私は問題を理解しました。Cl.EnqueueWriteImage / Cl.EnqueueReadImageの領域は、(1、1、1)ではなく(imageWidth、imageHeight、1)である必要があります。

IntPtr[] regionPtr = new IntPtr[] { (IntPtr)imgWidth, (IntPtr)imgHeight, (IntPtr)1 };
于 2012-11-29T02:51:16.713 に答える