C# 重新着色图像像素化

C# Recolored Image Pixelated

我正在尝试从文件系统加载图像,重新着色,然后将其保存到流中。有问题的图像非常简单,单色几何形状。

我让它工作了,但是生成的图像沿边缘严重像素化。

我试过了System.Drawing:

var colorMap = new ColorMap
{
    OldColor = Color.FromArgb(255, 255, 255, 255),
    NewColor = Color.FromArgb(255, 255, 0, 0)
};
var imageAttrs = new ImageAttributes();
imageAttrs.SetRemapTable(new[] {colorMap});

var newImage = new Bitmap(image.Width, image.Height);
var graphics = Graphics.FromImage(newImage);

graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

graphics.DrawImage(image,
    new Rectangle(0, 0, image.Width, image.Height),
    0, 0,
    image.Width,
    image.Height,
    GraphicsUnit.Pixel,
    imageAttrs);

我也尝试过 ImageProcessor 库,使用它的 ReplaceColor() 方法,但我得到了相同的结果(虽然没有那么糟糕)。

有什么方法可以做到这一点并保留我的原始图像的漂亮光滑边缘?

The images in question are fairly simple, single-color, geometric shapes.

听起来不错,但问题是您的 'Table' 颜色太短,除非图像真的只包含您放入地图中的一种颜色!但是这些图像肯定是在启用抗锯齿的情况下绘制的,因此所有抗锯齿像素都不会被 Table 覆盖。你需要

  • 要么使用没有抗锯齿的图像,但它们不会像您想要的那样平滑
  • 构建一个合适的ColorMap,见下文
  • 或者自己写一个函数,最好用Lockbits来提高速度..
  • 您可以尝试使用结合了速度和'color smartness'的ColorMatrix来实现颜色变化。然而,并非所有更改都适合使用它。因此,您可能想告诉我们您需要进行哪些更改...

你并不孤单:

我刚刚在 msdn 上尝试了 example,因为它看起来很不对劲:保存 Jpg 文件应该不起作用(因为它总是会生成自己的颜色表)并观察 它可以工作,但仅 因为在我的机器上创建的文件是 Png 扩展名为 错误 的文件!一旦你添加 ImageFormat.Jpeg 到保存它停止工作..:[=​​28=]

原始 MSDN 代码:

myBitmap.Save("Circle2.jpg");

改为

myBitmap.Save("Circle2.jpg", ImageFormat.Jpeg);

结果:

要构建合适的 ColorMap,您需要 a) 遍历所有像素并收集所有不同的颜色(简单但缓慢),然后计算目标颜色(快速但不一定简单或定义明确) .)

这里有两个例程展示了如何构建一个完整的 ColorMap:

List<Color> GetDistinctColors(Bitmap bmp)
{
    List<Color> colors = new List<Color>();
    for (int y = 0; y < bmp.Height; y++)
        for (int x = 0; x < bmp.Width; x++)
        {
            Color c = bmp.GetPixel(x,y);
            if (!colors.Contains(c)) colors.Add(c);
        }

    return colors;
}

List<Color> ChangeColors(List<Color> colors)
{
    List<Color> newColors = new List<Color>();
    foreach(Color c in colors)
    {
        int A = 255;   //  here you need..
        int R = c.G;   //  ..to write..
        int G = c.R;   //  ..your custom .
        int B = c.B;   //  ..color change code!!
        newColors.Add(Color.FromArgb(A,R,G,B));
    }
    return newColors;
}

要使用它你写:

// prepare the two lists:
List<Color> colors = GetDistinctColors((Bitmap)myImage);
List<Color> newColors = ChangeColors(colors);


// Create a complete color map
ColorMap[] myColorMap = new ColorMap[colors.Count];
for (int i = 0; i < colors.Count; i++)
{
   myColorMap[i] = new ColorMap();
   myColorMap[i].OldColor = colors[i];
   myColorMap[i].NewColor = newColors[i];
}

请注意,为 ChangeColor 函数编写正确的代码绝非易事。您不仅必须知道自己想要什么,还需要正确的工具来实现它。在我上面的代码示例中,我做了一个非常简单的频道交换。这通常不会产生您想要的结果:原色和抗锯齿像素都不能如此简单地更改。相反,您应该从 RGB 转换为 HSL 或 HSV 并更改那里的色调!在这里查看 SetHue example!