0

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

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

我试过 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() 方法,但我得到了相同的结果(虽然没有那么糟糕)。

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

4

1 回答 1

2

有问题的图像是相当简单的单色几何形状。

听起来不错,但问题是你的“颜色表”太短了,除非图像真的真的只包含你放入地图的一种颜色!但是这些图像肯定是使用抗锯齿绘制的,因此所有抗锯齿像素都没有包含在表格中。你需要

  • 要么使用没有抗锯齿的图像,但它们不会像你想要的那样平滑
  • 或者建立一个适当的ColorMap,见下文
  • 或者编写自己的函数,最好使用Lockbits来提高速度。
  • 或者您可以尝试使用ColorMatrix结合了速度和“色彩智能”的方法来实现颜色变化。但是,并非所有更改都适合使用它。所以您可能想告诉我们您需要的更改类型。

你不是一个人:

我刚刚在 msdn 上尝试了这个示例,因为它看起来很错误:保存Jpg文件不应该工作(因为它总是会生成自己的颜色表)并且看起来它可以工作,但这只是因为在我的机器上创建的Png文件是错误的文件扩大!一旦你添加 ImageFormat.Jpeg到保存它停止工作..:

原始 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 示例!

于 2015-03-04T08:02:35.977 回答