【问题标题】:Ghost-borders ('ringing') when resizing in GDI+在 GDI+ 中调整大小时出现鬼边框(“响铃”)
【发布时间】:2010-12-25 19:48:13
【问题描述】:

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

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

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

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

【问题讨论】:

  • 我已经仔细阅读了您的描述,您所描述的称为“响铃”。它可以出现在边缘或离它很短的距离。不过,我在您的代码中看不到任何明显的原因。之前/之后的示例图像可能会有所帮助。
  • 是的,就好像它正在执行一种锐化算法,试图查看图像边缘以外的像素值。我正在寻找一个发布前后图像的好地方。
  • 该示例 after 图像并没有像我在应用程序中看到的那样发音,但您仍然可以看出它是不正确的。

标签: c# .net gdi+ resize


【解决方案1】:

我终于找到了一篇关于这个的文章。

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 的解决方案甚至出现在我的搜索中。

【讨论】:

  • 根本原因似乎是在调整大小时使用了过于激进的过滤器,再加上边缘的像素掩蔽不当。图像边缘的像素根本不应该对结果产生影响,但显然它们是因为包装修复了它。您仍然可以在暗/亮过渡中看到振铃,例如示例中的车顶线。
  • 真正有趣的是,沿车顶线的振铃现在似乎也已修复。添加所有其他HighQuality 设置(如CompositingModePixelOffsetMode)可能会产生副作用。调整后图像的当前状态得到了很大改善。
  • 太好了,搜索并尝试了很多解决方案,但这个有效。
  • 多年来,我一直在盯着我们的应用程序中这些神秘的环形边界。这行得通。谢谢!
  • 我的图像现在平铺而不是使用此方法调整大小
【解决方案2】:

试试:

g.CompositingMode = CompositingMode.SourceCopy;

根据我的回答 here,已更正语法。

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

【讨论】:

  • 我认为您是正确的,因为它将其视为部分透明。如果我在绘制之前添加g.Clear(Color.Black);,那么白色仍然存在,但现在最边缘的像素变暗了。不幸的是,设置g.CompositingMode=CompositingMode.SourceCopy; 可以消除后面的任何渗色(例如深色边框),但它仍然具有 1 像素的插入白色边框。
  • 我没有看到你定义quality的任何地方,你确定你使用的是最高质量的JPEG压缩吗?
  • 是的,我要通过 100L 的质量。我将更新示例。感谢您对此的帮助。
  • +1 表示马克的回答。这纠正了缩放图像顶部和左侧奇怪的 1px 白色边框
猜你喜欢
  • 2011-06-03
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-11
  • 1970-01-01
  • 2010-12-02
相关资源
最近更新 更多