【问题标题】:How can I get better results when shrinking an image缩小图像时如何获得更好的结果
【发布时间】:2011-09-04 11:34:19
【问题描述】:

我在 c# 中缩小图像,并且我将我的方法与 Photoshop cs5 中的最佳方法进行了比较,并且无法复制它。

在 PS 中,我使用的是 bicubic sharper,看起来非常好。但是,当尝试在 c# 中做同样的事情时,我没有得到高质量的结果。我尝试过双三次插值以及 HQ 双三次,平滑模式 HQ/None/AA。构图模式,我尝试了大约 50 种不同的变体,每种变体都非常接近右侧的图像。

你会注意到她背部和标题周围的像素化,以及作者的名字不太清楚。

(左边是PS,右边是c#。)

即使将平滑设置为无,c# bicubic 似乎也进行了过多的平滑处理。我一直在玩弄以下代码的许多变体:

 g.CompositingQuality = CompositingQuality.HighQuality;
 g.InterpolationMode = InterpolationMode.HighQualityBicubic;
 g.PixelOffsetMode = PixelOffsetMode.None;
 g.SmoothingMode = SmoothingMode.None;

编辑:这里要求的是起始图像(1mb)。

【问题讨论】:

  • 原始链接可能会有所帮助。
  • 这是一个非常高质量的 jpeg,不过还是贴出来吧。
  • 正确的图像,你说的那个是用 C# 生成的,有 JPEG 压缩伪像。
  • @Rick,让我困惑的是为什么?我无法通过上面代码的变体摆脱它们。与 Photoshop 版本的 bicubic 不同,HQ bicubic 平滑的图像非常糟糕。
  • @Nick:任何插值模式都不会产生 JPEG 伪影。它们要么在插值之前存在,要么在保存时引入。

标签: c# image-processing


【解决方案1】:

也许我遗漏了一些东西,但我通常使用下面的代码来调整/压缩 JPEG 图像的大小。就个人而言,我认为根据您的源图像,结果非常好。该代码没有处理一些有关输入参数的边缘情况,但总体上可以完成工作(如果有兴趣,我还有额外的裁剪和组合图像转换的扩展方法)。

图像缩放到 25% 的原始大小并使用 90% 的压缩。 (~30KB 输出文件)

图像缩放扩展方法:

public static Image Resize(this Image image, Single scale)
{
  if (image == null)
    return null;

  scale = Math.Max(0.0F, scale);

  Int32 scaledWidth = Convert.ToInt32(image.Width * scale);
  Int32 scaledHeight = Convert.ToInt32(image.Height * scale);

  return image.Resize(new Size(scaledWidth, scaledHeight));
}

public static Image Resize(this Image image, Size size)
{
  if (image == null || size.IsEmpty)
    return null;

  var resizedImage = new Bitmap(size.Width, size.Height, image.PixelFormat);
  resizedImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

  using (var g = Graphics.FromImage(resizedImage))
  {
    var location = new Point(0, 0);
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(image, new Rectangle(location, size), new Rectangle(location, image.Size), GraphicsUnit.Pixel);
  }

  return resizedImage;
}

压缩扩展方法:

public static Image Compress(this Image image, Int32 quality)
{
  if (image == null)
    return null;

  quality = Math.Max(0, Math.Min(100, quality));

  using (var encoderParameters = new EncoderParameters(1))
  {
    var imageCodecInfo = ImageCodecInfo.GetImageEncoders().First(encoder => String.Compare(encoder.MimeType, "image/jpeg", StringComparison.OrdinalIgnoreCase) == 0);
    var memoryStream = new MemoryStream();

    encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, Convert.ToInt64(quality));

    image.Save(memoryStream, imageCodecInfo, encoderParameters);

    return Image.FromStream(memoryStream);
  }
}

用法:

  using(var source = Image.FromFile(@"C:\~\Source.jpg"))
  using(var resized = source.Resize(0.25F))
  using(var compressed = resized.Compress(90))
    compressed.Save(@"C:\~\Output.jpg");

注意: 对于任何可能发表评论的人,在释放图像之前,您无法释放在 Compress 方法中创建的 MemoryStream。如果你反思一下 Dispose 在 MemoryStream 上的实现,实际上不显式调用 dispose 是省事的。唯一的选择是将图像/内存流包装在实现 Image/IDisposable 的类的自定义实现中。

【讨论】:

  • @Calgary,我会选择这个答案,因为它解决了设置质量级别的问题,这正是我想要的。
  • 我没有尝试过,但一直在寻找更好的图像处理方法。但我的问题是,这对于较低分辨率的图像有多好。我的方法对他们做得很糟糕。 stackoverflow.com/q/2025240/90764
  • 我一定会在今晚晚些时候尝试这种方法。
  • @Tim - 上面的代码适用于您的示例图像...如果您遇到特定问题,最好打开一个新问题。
  • @Tim,不;上面的代码是整个压缩/调整大小的功能。我唯一可用的附加项目是基本的裁剪支持(以及一些用于组合步骤的混合扩展)。您是否正在寻找特别的东西?
【解决方案2】:

JPEG artifacts的数量,尤其是在图片的顶部,我认为你将jpg压缩设置为高。这会导致文件更小(文件大小),但会降低图像质量并且似乎会增加更多模糊。

您可以尝试以更高的质量保存它吗?我假设包含CompositingQuality.HighQuality 的行已经这样做了,但也许你可以找到更高质量的模式。 Photoshop 和 C# 之间的文件大小有什么区别?保存并重新打开后,Photoshop 图像的外观如何?仅在 Photoshop 中调整大小不会导致任何 jpg 数据丢失。您只会注意到,在您将图像保存为 jpg 然后关闭并重新打开它之后。

【讨论】:

  • PS 是 34kb 与 21kb。 Graphics 类有一个详尽的属性和方法列表,但我相信上面的 4 个是主要的。我不知道有什么比 HighQuality 设置更高的质量。
  • 我也不知道,但是您在此处粘贴的结果图像似乎质量不是很高。在 Photoshop 中,您获得了高,但也非常高。每个“命名”级别代表一系列实际值,其中非常高表示 80 到 100 的质量,高表示 60。我不知道这些数字如何转换为 c#,但正如您所知,Photoshop 图像是几乎是两倍的大小,因此它的存储质量可能更高。
  • @Nick - 质量是一个介于 0 和 100 之间的数值。值越高,压缩越少,图像质量越高。
  • 我偶然发现了这个问答。也许它对你也有用:stackoverflow.com/questions/249587/high-quality-image-scaling-c
  • Drawing2D 类也有 QualityMode 属性,但由于它是通用绘图类,我不知道这些属性是否会在存储文件时真正影响 Jpeg 压缩。在我看来,这些是不相关的,并且提到的属性主要影响屏幕渲染质量。
【解决方案3】:

我偶然发现了this question.

我使用这段代码不使用 jpeg 的压缩,它像 PS 版本一样出来:

ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); 
    ImageCodecInfo ici = null; 
    foreach (ImageCodecInfo codec in codecs)
    { 
        if (codec.MimeType == "image/jpeg") 
            ici = codec; 
    } 

    EncoderParameters ep = new EncoderParameters(); 
    ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);

【讨论】:

  • 是的,与上面显示的压缩扩展方法中的方法几乎相同。实际上,您可以将图像质量降低到 90/95,而不会显着降低质量以减小图像尺寸。
  • 您可以使用 100L 而不是 (long)100 甚至只是 100 作为参数。如果需要,C# 会将整数转换为长整数,而 100L 是长文本。
  • @Kim,是的,我知道,你知道为什么它一开始就被投射到 long 吗?如果它需要一个 0-100 的数字,那么 int16(short) 就可以了。
猜你喜欢
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
  • 1970-01-01
  • 2021-10-25
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
相关资源
最近更新 更多