在GDI +中调整大小时的Ghost-border('振铃')

时间:2009-12-11 20:17:52

标签: c# .net gdi+ resize

会发生什么(仅在某些图像上可见)我会看到1像素的白色边框插入一个像素。它似乎发生在光线但不是白色的区域(例如天空)。它类似于某些东西过度锐化并且在高对比度边缘旁边可以看到鬼影边框。

这是完美再现它的repro代码。我正在使用所有最高质量的缩放设置。

ImageCodecInfo encoder = null;
EncoderParameters encoderParams = null;

foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
{
    if (codec.MimeType == "image/jpeg")
    {
        encoder = codec;

        // use highest quality compression settings
        encoderParams = new EncoderParameters(1);
        encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
        break;
    }
}

using (Bitmap input = (Bitmap)Bitmap.FromFile(inputPath, true))
{
    // shrink by multiple of 2
    Rectangle rect = new Rectangle(0, 0, input.Width/32, input.Height/32);

    using (Bitmap output = new Bitmap(rect.Width, rect.Height))
    {
        using (Graphics g = Graphics.FromImage(output))
        {
            // use highest quality settings (updated per Mark Ransom's answer)
            g.CompositingMode = CompositingMode.SourceCopy;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
            g.SmoothingMode = SmoothingMode.HighQuality;

            g.DrawImage(input, rect);
        }

        output.Save(outputPath, encoder, encoderParams);
    }
}

有什么想法吗?我完全不知所措。我已经阅读了大量的问题/答案,但似乎没有一个问题影响我的情况。


修改

这是之前的图像示例:http://img14.imageshack.us/img14/4174/mg1647.jpg

这是图像后的示例:http://img64.imageshack.us/img64/3156/afterringing.jpg

原始文件更加明显(在托管服务“优化”它们之前),但你可以在天空中看到较小图像上的一个像素的较亮波段。

2 个答案:

答案 0 :(得分:40)

我终于找到了一篇谈论此事的文章。

Libor Tinka在继续展示他的广泛过滤器之前随便提到了这一点,这些过滤器的性能优于GDI +缩放:

根据他的建议,听起来它完全符合我们的怀疑:它正在从图像边缘以外的周围像素中提取平均细节。这对我来说似乎是算法中的一个缺陷,但这是有争议的。要解决这个问题,有一个ImageAttributes类,您可以在其中指定超出的像素只是其中像素的镜像。设置此似乎完全消除了响铃:

using (ImageAttributes wrapMode = new ImageAttributes())
{
    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
    g.DrawImage(input, rect, 0, 0, input.Width, input.Height, GraphicsUnit.Pixel, wrapMode);
}

非常感谢Libor Tinka提供解决方案,感谢Mark Ransom帮助我思考这个问题并给我一个“振铃”一词,这使得Libor Tinka的解决方案甚至出现在我的搜索中。

答案 1 :(得分:3)

尝试:

g.CompositingMode = CompositingMode.SourceCopy;

从我的回答here开始,修正了语法。

调整大小会在边界周围创建部分透明度。设置SourceCopy告诉它用完全不透明的像素替换部分透明的像素。