精确缩放图像

3
我正在尝试使用C#将图像精确可预测地缩放到不同的分辨率,无论是放大还是缩小。当我使用外部工具(如Gimp)打开结果图像时,当前设置下的结果并不令人满意。
public Image Square(Image image, int res) {
    Bitmap sq = new Bitmap(res, res, image.PixelFormat);
    Graphics canvas = Graphics.FromImage(sq);
    canvas.CompositingQuality = CompositingQuality.HighQuality;
    canvas.SmoothingMode = SmoothingMode.None;
    canvas.InterpolationMode = InterpolationMode.Bicubic;
    canvas.DrawImage(sq, 0, 0, res, res);
    return sq;
}

当缩小比例时,结果还可以(但远非完美),但是放大比例时会产生副作用:
此图片的分辨率为2x2像素。所有像素的alpha通道均设置为不透明。 2x2 opaque 将其放大到4x4像素后,得到以下结果: 4x4 with alpha 显然,C#图形库在缩放图片时引入了透明度。如果给定的图片具有透明图片,则该方法仍应有效,因此删除alpha通道不是一个选项。
类似地,当缩小图片时,结果图像的边缘也存在问题,通常要么非常暗,要么是透明的。
有没有办法规避这种行为?

编辑:我已经尝试了仅缩小图像的最近邻算法,但结果却是这样的:

4x4 nearest neighbor


编辑2:使用WrapMode.TileFlipXY,透明边缘消失了,但是红色仅占图像的25%,而不是应有的50%:

4x4 tileflipxy


只有最近邻插值法可以避免插值伪影。别忘了改变PixelOffsetMode。 - Hans Passant
3个回答

2
您在请求双三次插值,并且您已经得到了它。您想要的是“最近邻”选项,如文档中所概述的那样:
canvas.InterpolationMode = InterpolationMode.NearestNeighbor;

谢谢您的回答!我已经更新了我的问题,并附上了结果,但离我想要的还有很大的差距。 - just.me
我认为你手头有一个4x4的图像,其中有3x3个彩色像素和两侧各一个像素的透明边缘。 - tadman
是的,当我将模式更改为“NearestNeighbor”时,我确实得到了这个结果。 - just.me

2
避免边缘伪影的一种方法是对图像进行包裹:
using (ImageAttributes wrapMode = new ImageAttributes())
{
    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
    g.DrawImage(input, rect, 0, 0, input.Width, input.Height, GraphicsUnit.Pixel, wrapMode);
}

直接从以下网址复制/粘贴:GDI + 调整大小时出现幽灵边框("ringing")问题

谢谢您的回答。我已经将结果添加到我的问题中,但仍然没有达到我想要的目标。 - just.me
你是否在使用双三次插值和环绕模式?这是解决双三次缩放边缘伪影问题的方法,正如你所询问的那样,但它显然与最近邻缩放看起来不同。 - j4nw
谢谢,那真的有帮助!不过我更喜欢NearestNeighborTileFlipXY的组合。 - just.me

2

我认为您需要将NearestNeighbor 插值算法Half 像素偏移相结合。如在此处类似问题中所指出。

canvas.InterpolationMode = InterpolationMode.NearestNeighbor;
canvas.PixelOffsetMode = PixelOffsetMode.Half;

谢谢,这最终似乎有效了!我可能会用它来缩小并使用不同的插值模式进行放大。在接受您的答案之前,请让我进行一些测试。 - just.me
@just.me 听起来不错,但你真的需要更多像素吗?也许你可以只改变图像的dpi? - Derrick Moeller
遗憾的是,是的。我们正在使用一种需要所有图像具有完全相同分辨率的算法。 - just.me

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接