C#中的Bitmap GetPixel()和SetPixel()在GPU中的应用

10

我正在使用Cudafy作为C#的包装器,需要获取位图的颜色信息InputBitmap0.GetPixel(x, y)并生成新的输出位图。

我需要在GPU中完成以下工作。

CPU中的操作

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

简而言之:

如何在GPU中获取输入位图每个像素点的GetPixel(),并为输出位图每个像素点设置SetPixel()。


这个问题的描述太过宽泛,我已经投票将其关闭。 - talonmies
@talonmies 我尽量详细地阐述了问题,以便其他贡献者能够轻松理解!除了关闭它,我能否学习一种可能的解决方法? - Md Sifatul Islam
我认为CUDAfy.NET主要针对非图形相关的密集数值运算,而您正在寻找由CUDA的NPP提供的图形操作(似乎不受CUDAfy.NET支持)。 - Simon Mourier
@Md.Sifatul Islam,你可以尝试在MonoGame中玩像素着色器。 - SeNS
@Md.Sifatul Islam,我应该发布答案以获取赏金分吗?你能提供一些代码片段吗? - SeNS
显示剩余3条评论
2个回答

5

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

这段代码的作用是将InputBitmap0中坐标为x, y的像素点的颜色值设置到OutputBitmap的另一个坐标object_point_x, object_point_y处。

我们有两个位图:OutputBitmap用于输出,InputBitmap0用于输入。

让我们将这个任务分成几个步骤:

  1. xy坐标执行InputBitmap0.GetPixel()
  2. 然后,对不同的坐标object_point_x, object_point_y执行OutputBitmap.SetPixel()

Cudafy不支持BitmapColor类型数据。因此,我将位图转换为byte类型。

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.

我们已经将InputBitmap0的内容复制到了rgbValues数组中。现在我们需要执行GetPixel()函数的工作(获取R、G、B、A的值)。
因为我们将在GPU中执行SetPixel(),但稍后会将数组复制回位图,所以我们也需要为OutputBitmap做同样的工作(创建数组)。
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]; 

现在是GPU计算的时候。让我们初始化GPU。

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

现在将input_ragba_coloroutput_ragba发送到GPU,因为我们可以迭代数组并进行任何计算。
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);

现在在GPU(内核)内部

[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())

我们现在知道GPU已经填充了一个数组(dev_output_rgba_color)用于我们的OutputBitmap
gpu.CopyFromDevice(dev_output_rgba_color, output_ragba);   //dev_output_rgba_color values will be assigned to output_ragba
gpu.FreeAll();

将结果使用内存指针复制回OutputBitmap中,并从内存中解锁它。
Marshal.Copy(output_ragba, 0, ptr_output, output_bytes);// Copy the RGB values of color value into the array.
OutputBitmap.UnlockBits(OutputBitmapData);

现在,OutputBitmap 包含更新后的值。

1

我认为你需要使用一个byte[]并在GPU上分配它。我看过你询问,这个答案还在不断完善中,我会在接下来的几天里随着时间的允许不断更新。

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;

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接