在 GDI 中调整大小时出现幽灵边框(“响铃”);

发布于 2024-08-14 16:00:03 字数 1817 浏览 2 评论 0原文

发生的情况(仅在某些图像上明显)是我会看到一个 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

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

What happens (only noticeable on certain images) is I will see a 1 pixel white border that is inset one pixel. It seems to happen in areas that are light but not white (e.g. the sky). It is similar to when something is oversharpened and a ghost border can be seen next to high contrast edges.

Here is the repro code that reproduces it perfectly. I'm using all the highest quality settings for scaling.

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);
    }
}

Any ideas? I'm completely baffled. I've read through a ton of questions/answers and none of them seem to affect my situation.


Edit:

This is an example before image: http://img14.imageshack.us/img14/4174/mg1647.jpg

This is an example after image: http://img64.imageshack.us/img64/3156/afterringing.jpg

It is more pronounced with the original files (before the hosting service "optimizes" them), but you can see in the sky a lighter band one-pixel in on the smaller image.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

她说她爱他 2024-08-21 16:00:03

终于找到一篇文章讲这个了。

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

I finally found an article which talks about this.

Libor Tinka casually mentions this before going on to show his extensive set of filters which way outperform GDI+ scaling:

From his advice, it sounds like it is doing exactly what we suspected: it is pulling averaging detail from surrounding pixels beyond the edge of the image. This seems like a flaw in the algorithm to me, but that is open to debate. To solve this, there is an ImageAttributes class where you can specify that the pixels beyond are simply mirror images of the pixels within. Setting this seems to completely remove the ringing:

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

Huge thanks to both Libor Tinka for the solution, and to Mark Ransom for helping me think through this and for giving me the term "ringing" which was what made Libor Tinka's solution even show up in my searches.

本王不退位尔等都是臣 2024-08-21 16:00:03

尝试:

g.CompositingMode = CompositingMode.SourceCopy;

从我的回答这里,纠正语法。

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

Try:

g.CompositingMode = CompositingMode.SourceCopy;

From my answer here, corrected for syntax.

The resizing is creating partial transparency around the border. Setting SourceCopy tells it to replace that partially transparent pixel with a fully opaque one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文