C# Bitmap GetPixel(), SetPixel() in GPU

2.7k Views Asked by At

I am using Cudafy as c# wrapper I need to get colour info InputBitmap0.GetPixel(x, y) of a bitmap and make an new bitmap for output .

I need the following work to be done in GPU.

IN CPU

OutputBitmap.SetPixel(object_point_x, object_point_y, InputBitmap0.GetPixel(x, y));

In short:

How to GetPixel() for each pixel point of the input Bitmap, SetPixel() for each pixel point of the outputbitmap Bitmap in GPU.

2

There are 2 best solutions below

0
On BEST ANSWER

OutputBitmap.SetPixel(object_point_x, object_point_y, InputBitmap0.GetPixel(x, y))

It took time but finally, I , cracked my case.

We have two Bitmap : one for output OutputBitmap and another for input InputBitmap0

Lets divide this task into parts:

  1. do InputBitmap0.GetPixel() for x ,y coordinate
  2. then , OutputBitmap.SetPixel() for a different coordinate object_point_x, object_point_y

Cudafy does not support Bitmap or Color type data. So I converted the Bitmaps to byte type.

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

IntPtr ptr0 = InputBitmapData0.Scan0;//pointer for color

int stride0 = InputBitmapData0.Stride;

byte[]  input_ragba_color = new byte[InputBitmapData0.Stride * InputBitmap0.Height];

Marshal.Copy(ptr0, input_ragba_color, 0, bytes0);// Copy the RGB values of color value into the array.

We have copied the content of the InputBitmap0 to the rgbValues array. Now we need to do the work of GetPixel() (get the values of R,G,B,A).

We need to do the above work ( make array) for OutputBitmap too because we will be doing SetPixel() in GPU but we will copy the array back to the bitmap later.

BitmapData OutputBitmapData = OutputBitmap.LockBits(new Rectangle(0, 0, OutputBitmap.Width, OutputBitmap.Height), ImageLockMode.WriteOnly, OutputBitmap.PixelFormat);
IntPtr ptr_output = OutputBitmapData.Scan0;

byte[] output_ragba = new byte[OutputBitmapData.Stride * OutputBitmap.Height]; 

Its GPU time for calculation. Lets initialize gpu.

CudafyModule km = new CudafyTranslator.Cudafy();
GPGPU gpu = new CudafyHost.getDevice(CudafyModes.Target, CudafyModes.DeviceId);
gpu.LoadModule(km);

Now send input_ragba_color and output_ragba to the gpu because we can iterate the array and do any calculation.

byte[] dev_output_rgba_color = gpu.Allocate<byte>(output_ragba.Length);
byte[] dev_input_ragba_color = gpu.CopyToDevice(input_ragba_color);
gpu.Launch(N, 1).update_bitmap(x, y, object_point_x, object_point_y,int stride0, int OutputBitmapData.Stride,dev_input_ragba_color,dev_output_rgba_color);

Now inside GPU(kernel)

[Cudafy]
public static void update_bitmap(GThread thread, int x,int y,int object_point_x,int  object_point_y,int stride0, int OutputBitmapData_Stride,byte [] dev_input_ragba_color,byte [] dev_output_rgba_color)
{
   dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4)] = input_ragba_color[(y * stride0) + (x * 4)];  
   dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4) + 1] = input_ragba_color[(y * stride0) + (x * 4) + 1];
   dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4) + 2] = input_ragba_color[(y * stride0) + (x * 4) + 2];
   dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4) + 3] = input_ragba_color[(y * stride0) + (x * 4) + 3];

}

I am taking values of each R,G,B,A ,ex: input_ragba_color[(y * stride0) + (x * 4) + 1] which is solving 1st task (InputBitmap0.GetPixel())

dev_output_rgba_color is taking the values of input_ragba_color example:

dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4)] = input_ragba_color[(y * stride0) + (x * 4)]; 

which is solves our 2nd task (OutputBitmap.SetPixel())

We now know that gpu has populated an array(dev_output_rgba_color) for our OutputBitmap.

gpu.CopyFromDevice(dev_output_rgba_color, output_ragba);   //dev_output_rgba_color values will be assigned to output_ragba
gpu.FreeAll();

Copy the result back to the OutputBitmap using the memory pointer and unlock it from the memory.

Marshal.Copy(output_ragba, 0, ptr_output, output_bytes);// Copy the RGB values of color value into the array.
OutputBitmap.UnlockBits(OutputBitmapData);

Now the OutputBitmap contains the updated values.

0
On

I think you will need to use a byte[] and allocate that on the GPU. I've seen you asking around and this answer is a work in progress, I'll keep updating it over the next few days as I get time.

CudafyModule km = new CudafyTranslator.Cudafy();
GPGPU gpu = new CudafyHost.getDevice(CudafyModes.Target, CudafyModes.DeviceId);
gpu.LoadModule(km);

var image = new Bitmap(width, height);
image = (Bitmap)Image.FromFile(@"C:\temp\a.bmp", true);
byte[] imageBytes = new byte[width * height * 4];
using(MemoryStream ms = new MemoryStream())
{
    image.Save(ms, format);
    imageBytes = ms.ToArray();
}
byte[] device_imageBytes = _gpu.CopyToDevice(imageBytes);

byte r = 0;
byte g = 0;
byte b = 0;

byte device_r = _gpu.Allocate<byte>(r);
byte device_g = _gpu.Allocate<byte>(g);
byte device_b = _gpu.Allocate<byte>(b);

//Call this in a loop
gpu.Launch(N, 1).GetPixel(x, y, device_imageBytes, device_r, device_g, device_b);

...

[Cudafy]
public static void GetPixel(GThread thread, int x, int y, byte[] imageBytes, byte blue, byte green, byte red)
{
    int offset = x * BPP + y * stride;
    blue = imageBytes[offset++];
    green = imageBytes[offset++];
    red = imageBytes[offset];

    double R = red;
    double G = green * 255;
    double B = blue * 255 * 255;

}