SkiaSharp的SKBitmap.GetPixel和SKBitmap.SetPixel – 改进性能

huangapple go评论104阅读模式
英文:

SkiaSharp SKbitmap.GetPixel and SKbitmap.SetPixel - improve performance

问题

I am trying to use C# and SkiaSharp to implement image processing.
The code below is trying to implement edge detection.

The result of the code below is quite good, it needs improving, but this is not my point:

Image for testing the code

  1. canvas.Clear(SKColors.White);
  2. // USerskbitmapNEW has been loaded earlier.
  3. SKBitmap image = new SKBitmap(USerskbitmapNEW.Width, USerskbitmapNEW.Height);
  4. for (int i = 0; i < image.Width; i++)
  5. {
  6. for (int j = 0; j < image.Height; j++)
  7. {
  8. SKColor c1 = USerskbitmapNEW.GetPixel(i, j - 1);
  9. SKColor c2 = USerskbitmapNEW.GetPixel(i, j + 1);
  10. int xval = 0;
  11. int yval = 0;
  12. xval = (int)(c1.Red * .3 + c2.Blue * 0.11 - (c2.Red * .3));
  13. yval = (int)(c2.Red * .3 + c2.Green * .29 + c2.Blue * 0.11);
  14. if (xval > yval )
  15. {
  16. SKColor c = SKColors.Black;
  17. image.SetPixel(i, j, c);
  18. }
  19. }
  20. }
  21. canvas.DrawBitmap(image, myframe);

My problem is that the methods: SKBitmap.GetPixel(i, j); and SKBitmap.SetPixel(i, j, color); are extremely slow when used with images larger than 200kb in size.

In contrast to the above methods (.GetPixel, .SetPixel), when you apply various filters to the image, for example, var cf = SKColorFilter.CreateTable(null, null, colorTable, colorTable); ..., SkiaSharp is very fast.

My question: Is there any other way, using SkiaSharp, to read and modify pixels of the image with better performance than the methods I described?

Thanks in advance,
Michalis

英文:

I am trying to use C# and SkiaSharp to implement image processing.
The code below is trying to implement edge detection.

The result of the code below is quite good, it needs improving, but this is not my point:

Image for testing the code

  1. canvas.Clear(SKColors.White);
  2. // USerskbitmapNEW has been loaded earlier.
  3. SKBitmap image = new SKBitmap(USerskbitmapNEW.Width, USerskbitmapNEW.Height);
  4. for (int i = 0; i < image.Width; i++)
  5. {
  6. for (int j = 0; j < image.Height; j++)
  7. {
  8. SKColor c1 = USerskbitmapNEW.GetPixel(i, j - 1);
  9. SKColor c2 = USerskbitmapNEW.GetPixel(i, j + 1);
  10. int xval = 0;
  11. int yval = 0;
  12. xval = (int)(c1.Red * .3 + c2.Blue * 0.11 - (c2.Red * .3));
  13. yval = (int)(c2.Red * .3 + c2.Green * .29 + c2.Blue * 0.11);
  14. if (xval > yval )
  15. {
  16. SKColor c = SKColors.Black;
  17. image.SetPixel(i, j, c);
  18. }
  19. }
  20. }
  21. canvas.DrawBitmap(image, myframe);

My problem is that the methods : SKbitmap.GetPixel(i, j); and SKbitmap.SetPixel(i, j, color); are extremely slow when use them with images bigger than 200kb size.

In contrast to the above methods( .GetPixel .SetPixel) , when you apply image various filters , for example , var cf = SKColorFilter.CreateTable(null, null, colorTable, colorTable); .... skiasharp is very fast.

My question: is there any other way, using skiasharp, to read and modify pixels of the image, with better performance than the methods I described?

Thanks in advance
Michalis

答案1

得分: 1

请忘记 GetPixel/SetPixel 方法,如果你想直接访问像素数据。

首先,你可以使用 SKBitmapGetPixels 方法直接访问像素数据:

  1. IntPtr pixelsPtr = image.GetPixels();

然后,在 unsafe 上下文中,你可以快速操作数据(你需要手动计算像素偏移,以及通过 uint 或字节值设置颜色)。

  1. unsafe
  2. {
  3. var unsafePtr = (uint*)pixelsPtr.ToPointer();
  4. for (int y = 1; y < image.Height - 1; y++)
  5. {
  6. var rowOffset = y * image.Width;
  7. for (int x = 0; x < image.Width; x++)
  8. {
  9. uint c1 = unsafePtr[rowOffset - image.Width + x];
  10. uint c2 = unsafePtr[rowOffset + image.Width + x];
  11. // 现在你应该有 c1/c2 uints 代表 RGBA 像素数据
  12. // 你可以对它们进行操作并通过 unsafePtr 存储回去
  13. // ...
  14. }
  15. }
  16. }

我不会为你重新编写整个逻辑,我可以看到还有一个问题,你实时更改像素颜色,所以在 (x, y) 坐标设置黑色将导致在像素 (x, y + 1) 处出现错误的计算。

英文:

You need to forget about GetPixel/SetPixel methods if you want to have direct access to pixels.

For starters, you access pixel data directly for SKBitmap using GetPixels method:

  1. IntPtr pixelsPtr = image.GetPixels();

Then, in unsafe context, you can manipulate the data quickly (you need to calculate pixel offset manually, as well as setting colors via uint or byte values).

  1. unsafe
  2. {
  3. var unsafePtr = (uint*)pixelsPtr.ToPointer();
  4. for (int y = 1; y &lt; image.Height - 1; y++)
  5. {
  6. var rowOffset = y * image.Width;
  7. for (int x = 0; x &lt; image.Width; x++)
  8. {
  9. uint c1 = unsafePtr [rowOffset - image.Width + x];
  10. uint c2 = unsafePtr [rowOffset + image.Width + x];
  11. // now you should have c1/c2 uints representing RGBA pixel data
  12. // you can manipulate those and store back via unsafePtr
  13. ...
  14. }
  15. }
  16. }

I will not rewrite the whole logic for you, I can see there is also a problem that you change the pixel colors on the fly, so setting a black color at (x, y) coordinates will cause false calculation at pixel (x, y + 1)

huangapple
  • 本文由 发表于 2023年3月31日 19:04:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75897809.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定