【问题标题】:Image processing with OpenCL.NET使用 OpenCL.NET 进行图像处理
【发布时间】:2012-11-17 10:08:09
【问题描述】:

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

【问题讨论】:

    标签: opencl opencl.net


    【解决方案1】:

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

    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获取

    【讨论】:

      猜你喜欢
      • 2011-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      相关资源
      最近更新 更多