c# - 没有 GetPixel 的索引 8bpp 图像和像素数组

标签 c# alpha getpixel indexed

我需要在调色板中获取位图每个像素的索引(我有一个索引为 8bpp 的图像)。现在我使用以下方式:

List<byte> data = new List<byte>(); // indexes
List<Color> pixels = bitmap.Palette.Entries.ToList(); // palette

for (int i = 0; i <bitmap.Height; i++)
    for (int j = 0; j < bitmap.Width; j++)
        data.Add((byte)pixels[k].IndexOf(bitmap.GetPixel(j, i)));

但是这种方式工作起来很慢,因为我使用了几个高分辨率的图像。

我的问题是:

1)有没有办法加快循环获取每个像素RGBA值的过程?

2) 也许有更好的方法来获取调色板中图像的颜色索引?

最佳答案

也许这样的事情会更快。原因是 GetbitsSetbits 非常慢,每个都在内部调用锁定内部存储器的 lockbits。最好一次完成所有操作

使用 LockBitsunsafefixedDictionary

为了测试结果,我使用了这张图片

来自

我用你原来的版本测试了结果,他们是一样的

基准

----------------------------------------------------------------------------
Mode             : Release (64Bit)
Test Framework   : .NET Framework 4.7.1 (CLR 4.0.30319.42000)
----------------------------------------------------------------------------
Operating System : Microsoft Windows 10 Pro
Version          : 10.0.17134
----------------------------------------------------------------------------
CPU Name         : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
Description      : Intel64 Family 6 Model 42 Stepping 7
Cores (Threads)  : 4 (8)      : Architecture  : x64
Clock Speed      : 3401 MHz   : Bus Speed     : 100 MHz
L2Cache          : 1 MB       : L3Cache       : 8 MB
----------------------------------------------------------------------------

测试 1

--- Random Set ------------------------------------------------------------
| Value    |   Average |   Fastest |    Cycles | Garbage | Test |    Gain |
--- Scale 1 ------------------------------------------------ Time 8.894 ---
| Mine1    |  5.211 ms |  4.913 ms |  17.713 M | 0.000 B | Pass | 93.50 % |
| Original | 80.107 ms | 75.131 ms | 272.423 M | 0.000 B | Base |  0.00 % |
---------------------------------------------------------------------------

完整代码

public unsafe byte[] Convert(string input)
{
   using (var bmp = new Bitmap(input))
   {
      var pixels = bmp.Palette.Entries.Select((color, i) => new {x = color,i})
                                      .ToDictionary(arg => arg.x.ToArgb(), x => x.i);

      // lock the image data for direct access
      var bits = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);


      // create array as we know the size
      var data = new byte[bmp.Height * bmp.Width];

      // pin the data array
      fixed (byte* pData = data)
      {
         // just getting a pointer we can increment
         var d = pData;

         // store the max length so we don't have to recalculate it
         var length = (int*)bits.Scan0 + bmp.Height * bmp.Width;

         // Iterate through the scanlines of the image as contiguous memory by pointer 
         for (var p = (int*)bits.Scan0; p < length; p++, d++)

            //the magic, get the pixel, lookup the Dict, assign the values
            *d = (byte)pixels[*p];
      }

      // unlock the bitmap
      bmp.UnlockBits(bits);
      return data;
   }
}

总结

无论如何我都不是图像专家,如果这不起作用,那么您的索引图像可能有一些我不理解的不同之处

更新

要检查像素格式,如果它有调色板,您可以使用以下命令

bmp.PixelFormat
bmp.Palette.Entries.Any()

更新2

Vlad i Slav 的工作解决方案如下

I needed to replace PixelFormat.Format32bppPArgb to Format32bppArgb and to add this checking

if (pixels.ContainsKey(*p)) 
   *d = (byte)pixels[*p];
else 
   *d = 0;. 

Also need to take a distinct values from palette, because I have been give some errors there.

关于c# - 没有 GetPixel 的索引 8bpp 图像和像素数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51278294/

相关文章:

c# - binaryformatter 如何序列化对象?

c# - 使用正则表达式拆分字符串

android - 在 OpenGL ES 中无缝分层透明 Sprite

c# - 将 .bmp 文件解码为二进制文件

c++ - 获取 B 值错误 : Expression must have integral or unscoped enum type

c# - C#.Net 中的清除密码文本框

c# - 展开扩展器后如何滚动以便控件可见

unity3d - 在 Unity3D 中将 alpha 添加到着色器

css - 如何使 WebGL Canvas 透明

excel - VBA获取像素颜色