我需要获取调色板中位图每个像素的索引(我有一个索引为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)也许有一种更优化的方法来获取调色板中图像的颜色索引?
解决了:
请参阅TheGeneral的帖子.
解决方法:
也许这样的事情会更快.推理,Getbits和Setbits非常慢,每个调用内部调用锁定位以锁定内部存储器.最好一次完成所有操作
使用LockBits,不安全,固定和字典
为了测试结果,我使用了这张图片
> https://upload.wikimedia.org/wikipedia/commons/7/7c/Adaptative_8bits_palette_sample_image.png
从
> https://en.wikipedia.org/wiki/Indexed_color
我根据原始版本测试了结果,它们是相同的
基准测试
----------------------------------------------------------------------------
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
toFormat32bppArgb
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.