在SkiaSharp中重新映射任意灰度颜色

时间:2019-01-18 22:07:25

标签: c# image-processing skiasharp

我正在构建一个程序来生成热图。我正在利用为GDI +编写的代码,但是对于various reasons,我决定将其移至SkiaSharp

我目前有一个灰度图像图块,其中白色代表最大值,纯黑色是透明的。在GDI + / C#中,我可以快速使用ColorMapSetRemapTable。我已经看过ColorFilter了,但是接缝要使用矩阵变换,而不是我有些武断的重新映射。

SkiaSharp与此类似吗?还是应该手动遍历每个像素并重新着色?

使用GDI +的原始代码:

ImageAttributes imageAttributes = new ImageAttributes();
ColorMap[] remapTable = new ColorMap[256];
Color[] scale = IncandescentHeatScale();

for (int i = 0; i < 256; i++)
{
    remapTable[i] = new ColorMap()
    {
        OldColor = Color.FromArgb(i, i, i),
        NewColor = scale[i]
    };
}

imageAttributes.SetRemapTable(remapTable);

var outTile = new Bitmap(TileSize, TileSize);
using (var g = Graphics.FromImage(outTile))
{
    g.DrawImage(tile, new Rectangle(0, 0, TileSize, TileSize), padding, padding, TileSize, TileSize, GraphicsUnit.Pixel, imageAttributes);
}

相关功能,供参考:

static Color[] GetHeatScale(float[] points, Color[] colors)
{
    var bm = new Bitmap(256, 1);
    using (Graphics g = Graphics.FromImage(bm))
    {
        LinearGradientBrush brush = new LinearGradientBrush(new Point(0, 0), new Point(256, 0), colors[0], colors[colors.Length - 1]);
        var cb = new ColorBlend();
        cb.Colors = colors;
        cb.Positions = points;
        brush.InterpolationColors = cb;
        g.FillRectangle(brush, 0, 0, 256, 1);
    }
    return Enumerable.Range(0, 256).Select(x => bm.GetPixel(x, 0)).ToArray();
}


static Color[] IncandescentHeatScale()
{
    float[] points = new float[] { 0.0f, 0.333f, 0.6666f, 1f };
    Color[] colors = new Color[] { Color.Black, Color.DarkRed, Color.Yellow, Color.White };
    return GetHeatScale(points, colors);
}

2 个答案:

答案 0 :(得分:1)

是的,Skia / SkiaSharp将让您变换颜色。除了使用Matrix变换之外,您还可以使用颜色重映射表。

使用SKColorFilter.CreateTable(alphaRemapTable, redRemapTable, blueRemapTable, greeenRemapTable)

创建一个SKColorFilter

这些表是字节数组,长256个元素。重新映射的工作方式是将起始颜色的成分用作索引,以查找应重新映射到的值,例如。 10个红色将转换为红色数组中索引为10的值。

将null传递给任何参数将使该颜色分量保持不变。

进一步阅读:https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/effects/color-filters

答案 1 :(得分:0)

这是我的解决方案,适用于所有实际上只想快速复制一些代码的人。我知道这个问题已经两年了,但这是您在这个主题上唯一能找到的。此代码将 SKBitmap 转换为彩色位图。

public Bitmap Colorize(SKBitmap bitmap, SKImageInfo info)
    {
        using (SKSurface surface = SKSurface.Create(info))
        {
            SKCanvas canvas = surface.Canvas;

            using (SKPaint paint = new SKPaint())
            {
                paint.ColorFilter = CreatePaletteIndex_skia(255);

                canvas.DrawBitmap(bitmap, info.Rect, paint);
            }

            using (SKImage image = surface.Snapshot())
            using (SKData data = image.Encode(SKEncodedImageFormat.Png, 100))
            using (MemoryStream memoryStream = new MemoryStream(data.ToArray()))
            {
                Bitmap bm = new Bitmap(memoryStream, false);
                return bm;
            }

        }
     }

    private static SKColorFilter CreatePaletteIndex_skia(byte Alpha)
    {
        byte[] R = new byte[256];
        byte[] G = new byte[256];
        byte[] B = new byte[256];
        byte[] A = new byte[256];

        string dirExe = System.AppDomain.CurrentDomain.BaseDirectory;

        string colorImg = "ColorPalette.png";
        string pathColorPalette = dirExe + "Content\\" + colorImg;

        Bitmap Palette = (Bitmap)Bitmap.FromFile(pathColorPalette);
        // Loop through each pixel and create a new color mapping
        for (int X = 0; X <= 255; X++)
        {
            R[X] = Palette.GetPixel(X, 0).R;
            G[X] = Palette.GetPixel(X, 0).G;
            B[X] = Palette.GetPixel(X, 0).B;
            A[X] = Alpha;
        }

        SKColorFilter colorFilter = SKColorFilter.CreateTable(A, R, G, B);

        return colorFilter;
    }

您只需将一张 256 像素宽的渐变图片 (gradient) 放入项目的文件夹中,并通过变量 pathColorPalette 将其链接。

代码基于这个项目,关于如何在没有skia的情况下做到这一点:http://dylanvester.com/2015/10/creating-heat-maps-with-net-20-c-sharp/