opencl - 使用 OpenCL.NET 进行图像处理

标签 opencl opencl.net

我正在尝试使用 .NET 在 GPU 上进行图像处理。我已经下载了OpenCL.NET wrapper 。它有一些很好的示例,但我找不到将图像加载到 GPU 并读回处理后的图像的方法。我必须做什么?

最佳答案

设置上下文后,执行以下操作:

public void ImagingTest (string inputImagePath, string outputImagePath)
{
    Cl.ErrorCode error;

    //Load and compile kernel source code.
    string programPath = Environment.CurrentDirectory + "/../../ImagingTest.cl";    //The path to the source file may vary

    if (!System.IO.File.Exists (programPath)) {
        Console.WriteLine ("Program doesn't exist at path " + programPath);
        return;
    }

    string programSource = System.IO.File.ReadAllText (programPath);

    using (Cl.Program program = Cl.CreateProgramWithSource(_context, 1, new[] { programSource }, null, out error)) {
        CheckErr(error, "Cl.CreateProgramWithSource");

        //Compile kernel source
        error = Cl.BuildProgram (program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero);
        CheckErr(error, "Cl.BuildProgram");

        //Check for any compilation errors
        if (Cl.GetProgramBuildInfo (program, _device, Cl.ProgramBuildInfo.Status, out error).CastTo<Cl.BuildStatus>()
            != Cl.BuildStatus.Success) {
            CheckErr(error, "Cl.GetProgramBuildInfo");
            Console.WriteLine("Cl.GetProgramBuildInfo != Success");
            Console.WriteLine(Cl.GetProgramBuildInfo(program, _device, Cl.ProgramBuildInfo.Log, out error));
            return;
        }

        //Create the required kernel (entry function)
        Cl.Kernel kernel = Cl.CreateKernel(program, "imagingTest", out error);
        CheckErr(error, "Cl.CreateKernel");

        int intPtrSize = 0;
        intPtrSize = Marshal.SizeOf(typeof(IntPtr));

        //Image's RGBA data converted to an unmanaged[] array
        byte[] inputByteArray;
        //OpenCL memory buffer that will keep our image's byte[] data.
        Cl.Mem inputImage2DBuffer;

        Cl.ImageFormat clImageFormat = new Cl.ImageFormat(Cl.ChannelOrder.RGBA, Cl.ChannelType.Unsigned_Int8);

        int inputImgWidth, inputImgHeight;

        int inputImgBytesSize;

        int inputImgStride;

        //Try loading the input image
        using (FileStream imageFileStream = new FileStream(inputImagePath, FileMode.Open) ) {
            System.Drawing.Image inputImage = System.Drawing.Image.FromStream( imageFileStream );

            if (inputImage == null) {
                Console.WriteLine("Unable to load input image");
                return;
            }

            inputImgWidth = inputImage.Width;
            inputImgHeight = inputImage.Height;

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

            //Get raw pixel data of the bitmap
            //The format should match the format of clImageFormat
            BitmapData bitmapData = bmpImage.LockBits( new Rectangle(0, 0, bmpImage.Width, bmpImage.Height),
                                                      ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);//inputImage.PixelFormat);

            inputImgStride = bitmapData.Stride;
            inputImgBytesSize = bitmapData.Stride * bitmapData.Height;

            //Copy the raw bitmap data to an unmanaged byte[] array
            inputByteArray = new byte[inputImgBytesSize];
            Marshal.Copy(bitmapData.Scan0, inputByteArray, 0, inputImgBytesSize);

            //Allocate OpenCL image memory buffer
            inputImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadOnly, clImageFormat,
                                                (IntPtr)bitmapData.Width, (IntPtr)bitmapData.Height,
                                                (IntPtr)0, inputByteArray, out error);
            CheckErr(error, "Cl.CreateImage2D input");
        }

        //Unmanaged output image's raw RGBA byte[] array
        byte[] outputByteArray = new byte[inputImgBytesSize];

        //Allocate OpenCL image memory buffer
        Cl.Mem outputImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.WriteOnly, clImageFormat,
                                                      (IntPtr)inputImgWidth, (IntPtr)inputImgHeight, (IntPtr)0, outputByteArray, out error);
        CheckErr(error, "Cl.CreateImage2D output");

        //Pass the memory buffers to our kernel function
        error = Cl.SetKernelArg(kernel, 0, (IntPtr)intPtrSize, inputImage2DBuffer);
        error |= Cl.SetKernelArg(kernel, 1, (IntPtr)intPtrSize, outputImage2DBuffer);
        CheckErr(error, "Cl.SetKernelArg");

        //Create a command queue, where all of the commands for execution will be added
        Cl.CommandQueue cmdQueue = Cl.CreateCommandQueue(_context, _device, (Cl.CommandQueueProperties)0, out error);
        CheckErr(error, "Cl.CreateCommandQueue");

        Cl.Event clevent;

        //Copy input image from the host to the GPU.
        IntPtr[] originPtr = new IntPtr[] { (IntPtr)0, (IntPtr)0, (IntPtr)0 };  //x, y, z
        IntPtr[] regionPtr = new IntPtr[] { (IntPtr)inputImgWidth, (IntPtr)inputImgHeight, (IntPtr)1 }; //x, y, z
        IntPtr[] workGroupSizePtr = new IntPtr[] { (IntPtr)inputImgWidth, (IntPtr)inputImgHeight, (IntPtr)1 };
        error = Cl.EnqueueWriteImage(cmdQueue, inputImage2DBuffer, Cl.Bool.True, originPtr, regionPtr, (IntPtr)0, (IntPtr)0, inputByteArray, 0, null, out clevent);
        CheckErr(error, "Cl.EnqueueWriteImage");

        //Execute our kernel (OpenCL code)
        error = Cl.EnqueueNDRangeKernel(cmdQueue, kernel, 2, null, workGroupSizePtr, null, 0, null, out clevent);
        CheckErr(error, "Cl.EnqueueNDRangeKernel");

        //Wait for completion of all calculations on the GPU.
        error = Cl.Finish(cmdQueue);
        CheckErr(error, "Cl.Finish");

        //Read the processed image from GPU to raw RGBA data byte[] array
        error = Cl.EnqueueReadImage(cmdQueue, outputImage2DBuffer, Cl.Bool.True, originPtr, regionPtr,
                                    (IntPtr)0, (IntPtr)0, outputByteArray, 0, null, out clevent);
        CheckErr(error, "Cl.clEnqueueReadImage");

        //Clean up memory
        Cl.ReleaseKernel(kernel);
        Cl.ReleaseCommandQueue(cmdQueue);

        Cl.ReleaseMemObject(inputImage2DBuffer);
        Cl.ReleaseMemObject(outputImage2DBuffer);

        //Get a pointer to our unmanaged output byte[] array
        GCHandle pinnedOutputArray = GCHandle.Alloc(outputByteArray, GCHandleType.Pinned);
        IntPtr outputBmpPointer = pinnedOutputArray.AddrOfPinnedObject();

        //Create a new bitmap with processed data and save it to a file.
        Bitmap outputBitmap = new Bitmap(inputImgWidth, inputImgHeight, inputImgStride, PixelFormat.Format32bppArgb, outputBmpPointer);

        outputBitmap.Save(outputImagePath, System.Drawing.Imaging.ImageFormat.Png);

        pinnedOutputArray.Free();
    }
}

本例中使用的 OpenCL 内核:

__kernel void imagingTest(__read_only  image2d_t srcImg, 
                       __write_only image2d_t dstImg)
{
  const sampler_t smp = CLK_NORMALIZED_COORDS_FALSE | //Natural coordinates
    CLK_ADDRESS_CLAMP_TO_EDGE | //Clamp to zeros
    CLK_FILTER_LINEAR;

  int2 coord = (int2)(get_global_id(0), get_global_id(1)); 

  uint4 bgra = read_imageui(srcImg, smp, coord);    //The byte order is BGRA 

  float4 bgrafloat = convert_float4(bgra) / 255.0f; //Convert to normalized [0..1] float

  //Convert RGB to luminance (make the image grayscale).
  float luminance =  sqrt(0.241f * bgrafloat.z * bgrafloat.z + 0.691f * bgrafloat.y * bgrafloat.y + 0.068f * bgrafloat.x * bgrafloat.x);
  bgra.x = bgra.y = bgra.z = (uint) (luminance * 255.0f);

  bgra.w = 255;

  write_imageui(dstImg, coord, bgra);
}

*完整文章可在 codeproject.com 获取

关于opencl - 使用 OpenCL.NET 进行图像处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13624016/

相关文章:

opencl - OpenCL 中目标平台的示例是什么?

concurrency - 并行编程入门

OpenCL 全局内存获取

c++ - clGetDeviceInfo 和 clGetPlatformInfo 在 OpenCL 中失败,错误代码为 -30 (CL_INVALID_VALUE)

cuda - OpenCl 相当于在 CUDA 中查找连续索引

c - 如何在 OpenCL 的内核函数中声明一个函数?

python - 参数列表的长度 (3) 和 CL 生成的参数数量 (9) 不一致

c# - 完整的 .NET OpenCL 实现

c# - 异步API