⚠️ 这是一个非官方翻译网站,与 ImageMagick Studio LLC 无关。准确信息请参阅原文(https://usage.imagemagick.org/filter/index.html)

ImageMagick 示例 -- 重采样滤镜

这里会进入图像调整尺寸和畸变的更底层层面,查看用于决定结果图像中每个像素最终颜色的重采样滤镜。这是一个范围很广、研究很久的主题,而且常常充满意见和个人观点,而不是明确的定性事实,因为不可能判定什么才算完美的调整尺寸图像。这一点已经被证明,也使它成为一个永远不会结束的庞大研究领域。建议先阅读并理解 调整尺寸与缩放运算符


重采样伪影 - IM 的调整尺寸效果有多好

图像调整尺寸必须应对一个非常困难的问题。怎样把一组数值缩减或扩展成更小或更大的数值数组,并且让它在我们眼中看起来不错。尝试这样做时会有很多问题,但它们基本可以归入四类。

分块

本质上,如果只是复制像素来放大图像,就会产生更大的矩形像素块。事实上,用 "[-scale](https://imagemagick.org/command-line-options/#scale)" 或 "[-sample](https://imagemagick.org/command-line-options/#sample)" 放大图像正是这样做的,会得到放大的像素化图像。例如,这里我缩放一张小图,生成的是大块颜色,而不是漂亮平滑的图像。旁边是一个“调整尺寸”版本,最后一个使用 Gaussian 滤镜比通常更强地模糊,并把孤立像素替换成圆点,以去除一部分块状感。

  magick storm.gif  -scale  300%  storm_scaled.gif
  magick storm.gif  -resize 300%  storm_resized.gif
  magick storm.gif -filter Gaussian -resize 300%  storm_resized_gas.gif

[IM Output]
原图 | | [IM Output]
缩放 | [IM Output]
调整尺寸 | [IM Output]
Gaussian 调整尺寸
---|---|---|---|---

“分块”的主要原因,要么是源图像抗锯齿做得很差,要么是在像素之间没有足够的平滑(颜色混合或模糊)来改善图像整体外观。当很低分辨率的图像被调整到大得多的尺度,或用于高分辨率设备时,也常会看到它。最常见的场景,是用户制作的新闻简报和杂志使用位图图像,然后在很高分辨率的激光打印机上打印。简报在屏幕上看起来很好,但打印出来就显得“块状”。这种情况非常难修复,通常最好通过使用更高分辨率的剪贴画,或使用可缩放的矢量图像(如 SVG 和 WMF 格式图像)来避免。当然在某些情况下,分块伪影实际上是想要的,并会在结果中被强化。例如,在新的高分辨率显示器上重现旧的低分辨率电子游戏时,保留图像旧有的“块状感”会增强“复古”观感。又或者,你想旋转图像,但不想生成任何新的颜色或混合色。真正保留“块状感”、同时用斜线填充方块的技术称为 像素艺术缩放算法,已经发展出很多方案。其中一种方案已经内置于 ImageMagick,也就是 Magnify 运算符。

振铃

振铃是在非常低质量的 JPEG 图像中、靠近锐利边缘处经常看到的效果。它通常是因为调整尺寸或图像压缩算法对边缘过度补偿,或者在不合适的 support 大小下使用高质量滤镜造成的。这里例如我用一个特殊选项,在非常尖锐的颜色变化上选择原始 Sinc 滤镜。我还用 IM 的默认调整尺寸运算符重复了同一操作,也就是使用其针对图像放大的默认滤镜选择。

  magick -size 8x16 xc:'#444' xc:'#AAA' +append  gray_edge.gif
  magick gray_edge.gif -filter Sinc \
                         -resize 100x100\!  gray_edge_ringing.gif
  magick gray_edge.gif  -resize 100x100\!  gray_edge_resize.gif

[IM Output] [IM Output] [IM Output]

上面的例子很清楚地显示了在没有 IM 提供的任何优化时,直接使用原始调整尺寸滤镜会产生的过度补偿。第二张图像由默认的 IM 放大滤镜生成,也显示出非常轻微的振铃效果,但几乎不可察觉,而且从感知上会让边界更锐利,因此实际上是有益的。这里是另一个振铃效果示例,这次是在灰色背景上放大一个单独像素。 |

  magick -size 1x1 xc: -bordercolor '#444' -border 4x4 \
          -define filter:lobes=5  -filter Sinc \
          -resize 100x100\!   dot_sinc.gif

[IM Output]
这张图还清楚显示了使用一维滤镜带来的次级效果。也就是说,振铃效果在水平和垂直(正交)方向最强,并在 45 度方向出现次级振铃。这次再用圆柱型滤镜(通过 Distort 调整尺寸操作),展示它与 Resize 运算符 使用的更常见的 2 遍正交对齐(张量)滤镜有何不同。 |

  magick -size 1x1 xc: -bordercolor '#444' -border 4x4 \
          -define filter:lobes=5  -filter Jinc \
          -distort resize 100x100\! +repage dot_jinc.gif

[IM Output]
这些效果通常不可见,这里能看到只是因为在一些极端放大中使用了原始的 'Sinc' 或 'Jinc' 滤镜(见下方 加窗滤镜)。通常不会使用这种“原始”滤镜。

混叠与摩尔纹效果

混叠效果一般表现为图像边缘上出现类似“阶梯”的效果。它通常是由对图像进行原始采样(例如使用 "[-sample](https://imagemagick.org/command-line-options/#sample)")造成的,或由调整尺寸时过度锐化图像造成。阶梯效果在强烈缩小图像时最明显,不过在 IM 中很少见。然而,混叠还有其他效果,尤其是在包含某种像素级图案的图像中出现大尺度摩尔纹图案。这些低层图案经常产生大尺度摩尔纹,包括:平行线图案、布料织纹(丝绸在现实中就会表现出这种效果!),以及砖楼、围栏和铺地照片中的砖块与瓷砖图案。[IM Output] 关于调整尺寸图像产生强烈摩尔纹效果的示例,请参见 Wikipedia, Moiré Pattern 页面。检查某次调整尺寸是否会产生混叠问题的经典方法,是缩小一张 环形图像(见右侧)。这张图像在任何尺度应用任何形式的调整尺寸时,常常会显示摩尔纹效果。Web 浏览器尤其会因为使用超快(但往往很差)的调整尺寸技术,在显示这种图像时表现出摩尔纹效果。
这里我展示用强混叠的 "[-sample](https://imagemagick.org/command-line-options/#sample)" 运算符、块平均的 "[-scale](https://imagemagick.org/command-line-options/#scale)" 运算符,以及普通默认的 "[-resize](https://imagemagick.org/command-line-options/#resize)" 调整 'rings' 图像尺寸的结果。

  magick rings_sm_orig.gif  -sample 100x100  rings_sample.png
  magick rings_sm_orig.gif  -scale  100x100  rings_scale.png
  magick rings_sm_orig.gif  -resize 100x100  rings_resize.png

[IM Output]
sample | [IM Output]
scale | [IM Output]
resize
---|---|---

如你所见,所有调整尺寸方法都产生了一些摩尔纹效果,不过 IM 的默认调整尺寸运算符在最终图像中产生的这种不想要的次级图案最少。为了展示一次轻微调整尺寸的效果,我从 大环形图像 的角上裁剪一块,先显示它的结果,然后只把它缩小 5%。

  magick rings_lg_orig.png -crop 105x105+0+0  rings_crop.png
  magick rings_crop.png    -sample 100x100    rings_crop_sample.png
  magick rings_crop.png    -scale  100x100    rings_crop_scale.png
  magick rings_crop.png    -resize 100x100    rings_crop_resize.png

[IM Output]
裁剪的原图 | | [IM Output]
sample | [IM Output]
scale | [IM Output]
resize
---|---|---|---|---

如你所见,即使只是轻微调整尺寸,也会暴露调整尺寸运算符可能具有的任何混叠。事实上,如果仔细看,你甚至可能在原始起始图像未经缩放的裁剪结果中看到非常轻微的摩尔纹效果,这是由于只使用适合电脑屏幕显示密度的栅格图像所带来的限制。也就是说,这张测试图像对显示图像缩小造成的混叠效果非常敏感。

模糊

大多数人都熟悉使用 "[-resize](https://imagemagick.org/command-line-options/#resize)" 可能产生的模糊。事实上,这可能是对任何调整尺寸图像的头号抱怨,而且理由充分。通常,非常小幅的调整尺寸会倾向于产生模糊图像,再调整一次只会让情况更糟。问题在于,调整图像尺寸时,你是在把作为像素“网格”或数组(称为“栅格”)存储的图像,改成适配一套完全不同的像素“网格”。除了非常特殊的情况,这两套“网格”不会匹配,因此图像数据必须被修改以适配新的点阵。基本上,不可能直接调整一张图像尺寸并期待它自然变得漂亮,不过可以获得合理的结果。其结果通常是像素数据略微模糊。调整尺寸算法越好,锐利边缘的模糊就越少。不过某些调整尺寸滤镜,特别是专门为放大图像设计的滤镜,常常会添加比必要更多的模糊。这是为了对抗上面展示的 “分块” 伪影。在图像缩小时,模糊边缘常用来避免锐利边缘上的 “振铃” 伪影,并减少可能的 混叠 效果。不过这是不得已的折中,也是 IM 极力避免的。即便如此,仍可使用一个专家级的特殊 滤镜模糊 设置来调整滤镜提供的模糊程度。但请注意,虽然小于 1.0 的数字本应减少模糊,但它也可能让情况更糟,具体取决于确切的滤镜以及所使用的调整尺寸比例。没有任何保证。 在 IM v6.3.6-3 之前,滤镜模糊 设置称为 "[-support](https://imagemagick.org/command-line-options/#support)",这个名称对它实际做什么非常误导。该选项已经废弃,不再可用。
修正调整尺寸造成的模糊效果,更好的方法是使用锐化运算符重新过滤图像。更多细节见 锐化调整尺寸后的图像

IM 调整尺寸 vs 其他程序

Bart van der Wolf 提供了一个实际比较,把 IM 的默认调整尺寸运算符与其他许多程序在调整真实世界图像尺寸时的效果进行对比,见……

下采样示例

具体来说,关于 IM 调整尺寸的总结是……

虽然锐化量是品味问题,但没有混叠伪影,使它生成了所有图像中最干净、最自然的一张。

他还继续查看一个 'rings' 测试,直接比较各种 Photoshop 调整尺寸方法与 ImageMagick……

下采样方法

这些文章说明,正确地进行调整尺寸(并使用正确的滤镜方法)对图像处理有多么重要。下一节会更仔细地查看这一点。


重采样滤镜

"[-filter](https://imagemagick.org/command-line-options/#filter)" 设置是控制 "[图像调整尺寸](resize.html#resize)" 以及 "[通用 Distort 运算符](distorts.html#distort)" 如何以最少的 重采样伪影 生成干净结果的关键。这是 1980 年代后期被深入研究的主题,这一领域的重要研究者 Paul Heckbert 从中制作并公开发布了他的 "**[zoom](http://www.xmission.com/~legalize/zoom.html)**" 图像调整尺寸程序。该程序成为今天大多数图像调整尺寸程序的源头,尽管后来的许多程序实现得很差,因为它很容易做错。例如可以看看 Web 浏览器如何调整图像尺寸 的测试结果。在很多方面,这些滤镜与 图像卷积,甚至与 模糊核 密切相关。它们甚至会遇到类似问题。不过,滤镜的设计目标是在调整图像尺寸或以其他方式使图像畸变时,改善最终结果的观感。滤镜的名字几乎是一份过去一个世纪(或更久)图像处理专家和数学家的“名人录”。它们通常不是对滤镜的描述,而只是最早发表该滤镜(或滤镜族)的人,或对该滤镜研究最多的人的标签。不过这也让人更难知道 'Lagrange' 滤镜(以 Joseph-Louis Lagrange 命名)是否比例如 'Catrom' 滤镜(以 Edwin Catmull 和 Raphael Rom 命名)更好。这里我会说明滤镜的主要方面。学习这些内容并不是必需的,但在完成这一领域的研究,并作为 IM 调整尺寸滤镜系统一次重大重做和扩展(IM 6.3.7-1)的一部分之后,我决定把自己学到的摘要记录下来。特别感谢 Fred Weinhaus 在重新开发调整尺寸滤镜期间对研究的帮助。他尤其热切希望加入 '[Lagrange](#lagrange)' 滤镜族,而这个滤镜族在这次重做之前并不存在于 IM 调整尺寸中。也感谢 Nicolas Robidoux,他的数学帮助解决了 通用 Distort 运算符 中的一个重大缺陷,并进一步开发了 圆柱型滤镜,它们能产生比 Resize 运算符 更好的结果。

滤镜的工作方式

调整图像尺寸时,你基本是在根据原始源图像中的像素,决定新图像中每个像素的正确值。然而这些新像素并不精确对应旧像素的位置,因此必须以某种方式决定这些像素的正确值。实际做法是尝试使用原始源像素值的某种加权平均,来为新像素确定一个好的值。新像素位置周围的真实像素形成一组贡献值的“邻域”。这个邻域越大,调整尺寸就越慢。这是一种称为 卷积 的技术。每个真实相邻像素(称为“样本”)对生成最终像素贡献多少,由一个加权函数决定。这就是你可以用 "[-filter](https://imagemagick.org/command-line-options/#filter)" 设置选择的“滤镜”。该滤镜通常又有一个理想的邻域大小,称为滤镜的“support”,也称为“window”。预定义的二维“滤镜”也称为“卷积核”。

_未来:这里放一些图可能会有帮助_

这些加权函数,也就是“滤镜”的设计,是一件非常复杂的事情,涉及复杂数学、频率分析,甚至傅里叶变换。如果你对此感兴趣,一个好的起点是 Wikipedia: Nyquist-Shannon sampling theorem。不过,要理解现有滤镜及其对图像的影响,实在不必走得那么远。

滤镜

插值滤镜

最简单的一类调整尺寸滤镜函数是 插值 方法。它们取源图像中的一个特定像素位置,并尝试根据周围像素的颜色,简单地决定图像在该位置的逻辑颜色值。由于参与的像素数量始终固定且很少,这类滤镜是调整尺寸或以其他方式使图像畸变的非常快速方法。然而,这也是该滤镜的弱点,因为它不会把更多像素合并起来,形成远小于原图的图像。这反过来可能导致强烈的 混叠和摩尔纹效果。插值通常只用于图像的“点”采样,也就是图像缩放未知或不需要时。例如,在旋转图像或轻微畸变时,图像的缩放或大小没有改变,因此插值可以产生合理结果,尽管并不非常准确。更多信息见 IM 的 插值设置。不过,它不适合一般的图像调整尺寸。

Point

使用 '**Point**' 作为 "[-filter](https://imagemagick.org/command-line-options/#filter)" 设置,基本意味着使用未缩放的插值滤镜。对于 Resize 运算符,它只会选择离新像素位置最近的像素,仅此而已。这意味着 Resize 运算符 会直接使用源图像中实际像素的颜色。不会尝试合并颜色,也不会为结果图像生成更好的颜色。因此,使用 "-filter point -resize ..." 会产生与 "[-sample](https://imagemagick.org/command-line-options/#sample)"(见 Sampling 运算符)相同的结果,不过后者更快,因为其代码专门设计用于通过点采样调整图像尺寸,并带有调节精确采样点的控制。 | _对于 Distort 运算符,选择 "[-filter](https://imagemagick.org/command-line-options/#filter) Point" 会强制使用 插值点采样,而不是 圆柱型滤镜。更多细节见 Distort 运算符中的图像滤镜

如果你希望在普通图像调整尺寸中得到同样的 插值点采样,可以改用 插值调整尺寸 运算符。或者使用 point 滤镜的 Distort 调整尺寸 来得到相同结果。

_
---|---
这里我从一个 10x10 像素的网纹图案开始,先缩小它的尺寸,再放大显示,以便看清结果。

  magick -size 10x10 pattern:gray50  checks_10.gif
  magick checks_10.gif -filter point -resize 9x9  checks_point-1.gif
  magick checks_10.gif -filter point -resize 8x8  checks_point-2.gif
  magick checks_10.gif -filter point -resize 7x7  checks_point-3.gif
  magick checks_10.gif -filter point -resize 6x6  checks_point-4.gif
  magick checks_10.gif -filter point -resize 5x5  checks_point-5.gif

[IM Output]
| | [IM Output]
Point-1 | [IM Output]
Point-2 | [IM Output]
Point-3 | [IM Output]
Point-4 | [IM Output]
Point 50%
---|---|---|---|---|---|---

真正发生的只是图像中单独的像素行和列被删除了。即使在这个层面,结果图像也会产生极端的 分块混叠,并且在上面这种特定情况下会产生完全不真实的结果。因此,'Point' 滤镜,或速度更快的等价 Sampling 运算符,不建议用于普通图像调整尺寸。

Box

'**Box**' 滤镜设置与 'point' 几乎完全相同,只有一个小变化。缩小图像时,它会对像素求平均并合并在一起。结果图像越小,被一起平均的像素就越多。[IM Output] 这里是一张滤镜加权函数的图,从中可以看出它为什么称为 'Box' 滤镜。基本上,任何落在“Box”内部的像素都会被直接用来计算新像素的颜色。现在,由于滤镜只有 1/2 像素宽,这意味着对于实际并未调整尺寸的图像,只会使用一个像素,也就是最近的像素。换句话说,当没有缩放(或只有放大)时,离新位置最近的像素会形成新像素的颜色。不过如果图像被缩小,源图像中更多部分会被压缩到这个“box”的边界内。结果就是更多像素被一起平均,用来产生较小图像中像素的颜色。例如,下面是一个棋盘格像素图案使用 'Box' 滤镜缓慢压缩时的放大视图。

  magick checks_10.gif -filter box -resize 9x9  checks_box-1.gif
  magick checks_10.gif -filter box -resize 8x8  checks_box-2.gif
  magick checks_10.gif -filter box -resize 7x7  checks_box-3.gif
  magick checks_10.gif -filter box -resize 6x6  checks_box-4.gif
  magick checks_10.gif -filter box -resize 5x5  checks_box-5.gif

[IM Output]
| | [IM Output]
Box-1 | [IM Output]
Box-2 | [IM Output]
Box-3 | [IM Output]
Box-4 | [IM Output]
Box 50%
---|---|---|---|---|---|---

如你所见,使用 'Box' 滤镜把图像调整得更小时,越来越多的像素会被合并在一起,但这种合并发生在特定的、等间距的行和列上。这会在图像缩小和放大时引起各种伪影、摩尔纹或 混叠 效果。建议把 'Box' 滤镜用于图像的“分箱”。也就是说,以整数倍缩小图像,确保结果中的每个像素都是相同数量相邻像素(“箱”)的平均。这样结果图像会像上面最后一张那样保持干净外观。还建议使用速度快得多的 Scale 运算符 来替代 'Box 滤镜'。它会产生几乎相同的结果,只有图像只缩小几个像素这种特殊情况例外。用于“分箱”时,它会产生相同结果。 Scale 运算符 与 'Box 滤镜' 并不完全相同,因为它使用特殊的“像素混合”算法实现。精确细节见 Scale 内部原理
放大时,'Point' 和 'Box' 两种滤镜都会产生相同行列的“像素复制”,因为它们最终都使用简单的“最近邻”选择。
  magick -size 5x5 pattern:gray50  checks_5.gif
  magick checks_5.gif -filter box   -resize 6x6    checks_box+1.gif
  magick checks_5.gif -filter box   -resize 7x7    checks_box+2.gif
  magick checks_5.gif -filter box   -resize 8x8    checks_box+3.gif
  magick checks_5.gif -filter box   -resize 9x9    checks_box+4.gif
  magick checks_5.gif -filter box   -resize 10x10  checks_box+5.gif

[IM Output]
| | [IM Output]
Box+1 | [IM Output]
Box+2 | [IM Output]
Box+3 | [IM Output]
Box+4 | [IM Output]
Box+5
---|---|---|---|---|---|---

| Scale 运算符 也会产生类似结果,但在放大时会有一些像素颜色混合,除非按整数缩放因子放大。
---|---

Triangle

[IM Output] 'Triangle' 或 '[Bilinear](misc.html#bilinear)' 插值滤镜只是把最近邻补间向前推进了一步。它不像 'Box' 那样直接把附近像素简单平均,而是根据新像素位置与邻域(或“support”区域)内原始像素的距离进行加权。新像素越靠近某个源图像像素,该像素贡献的颜色就越多。当图像缩小时,这会产生更全局的颜色平均。

  magick checks_10.gif -filter triangle -resize 9x9 checks_tri-1.gif
  magick checks_10.gif -filter triangle -resize 8x8 checks_tri-2.gif
  magick checks_10.gif -filter triangle -resize 7x7 checks_tri-3.gif
  magick checks_10.gif -filter triangle -resize 6x6 checks_tri-4.gif
  magick checks_10.gif -filter triangle -resize 5x5 checks_tri-5.gif

[IM Output]
| | [IM Output]
Tri-1 | [IM Output]
Tri-2 | [IM Output]
Tri-3 | [IM Output]
Tri-4 | [IM Output]
Tri
---|---|---|---|---|---|---

如你所见,由于角上的像素几乎完美对应原图的角,所以它们更明显;但靠近中间时,附近没有任何像素能与正在生成的新像素精确对齐,于是会得到整个邻域更平均的颜色。对于棋盘格像素图案,结果倾向于在平均灰色中淡入淡出。不过由于“support”邻域更大,放大图像时会涉及更多像素。因此,在生成添加到图像中的像素时,会产生颜色平均。

  magick checks_5.gif -filter triangle -resize 6x6  checks_tri+1.gif
  magick checks_5.gif -filter triangle -resize 7x7  checks_tri+2.gif
  magick checks_5.gif -filter triangle -resize 8x8  checks_tri+3.gif
  magick checks_5.gif -filter triangle -resize 9x9  checks_tri+4.gif
  magick checks_5.gif -filter triangle -resize 10x10 checks_tri+5.gif

[IM Output]
| | [IM Output]
Tri+1 | [IM Output]
Tri+2 | [IM Output]
Tri+3 | [IM Output]
Tri+4 | [IM Output]
Tri+5
---|---|---|---|---|---|---

在大尺度放大中,结果就像在每个像素之间都加入了颜色渐变。例如,这里我生成一张非常小的图像,其中只有一个白色像素(显示为放大视图)。然后我把这张图像大幅放大。

  magick xc: -bordercolor black -border 2x0 pixel_5.gif
  magick pixel_5.gif  -filter triangle -resize 300x  pixel_triangle.gif

[IM Output]
单像素图像
(放大显示) | | [IM Output]
Triangle 滤镜放大
---|---|---

如果把上图中的颜色绘成曲线(使用 "[im_profile](../static/img/scripts/im_profile)" 脚本),你会看到三角形滤镜图形的一份复制。

[IM Profile]
图像的剖面

如你所见,中心像素与相邻像素合并,在这些点之间生成了线性的颜色渐变。所有插值滤镜都会在相邻像素之间产生类似的渐变图案,这也是它们非常适合图像放大的原因。

其他插值滤镜

[IM Output] 右侧绘出了各种插值滤镜,不过不包括 'Point',因为它实际上是未缩放 'Box' 滤镜的一个非常特殊的情况(纯 '[NearestNeighbor](misc.html#nearest)' 插值)。其他插值滤镜包括 '**Hermite**',其结果与 triangle 非常相似,但在放大时会生成更平滑的圆滑过渡,让渐变变化更柔和。点击 右侧图形 可查看这三个滤镜函数的图。
[IM Output] '**Lagrange**' 滤镜曾被称为“通用”插值滤镜。通过改变 'support' 大小(见下方 Support 专家设置),它可以生成前面看过的所有插值滤镜(除 'Hermite' 外)。默认设置(Lagrange 3 阶滤镜,support=2.0,如右侧图中的紫线)提供了一个合理的 “cubic” 滤镜。它工作得很好,不过渐变变化可能会在放大时造成一些明显的 分块 效果;但对于位图图像和线稿,这可能是好事。其他 Lagrange 滤镜 阶数稍后再说。[IM Output] '**Catrom**'(Catmull-Rom)滤镜是一个知名的标准 Cubic 滤镜,常被用作插值函数,并以同名提供。这个滤镜生成相当锐利的边缘,但不像 'Lagrange' 滤镜那样在大尺度图像放大中产生显著的渐变变化。它基本相当于内置的 “unsharp resize”(见 锐化调整尺寸后的图像),不过有人认为它过于锐利,而且不提供任何锐化控制。让 'Catrom' 滤镜更有意思的是,它几乎是 2-lobe '[Lanczos](#lanczos)' 滤镜的 cubic 等价物,而后者可能是最常用的 加窗 Sinc 滤镜(见下文)。我们也会在后面的 Cubic 滤镜 中更仔细地查看这个滤镜。

插值与 IM 的 Interpolate 设置

IM 的 Interpolate 设置用于在 FX DIY 运算符("[-fx](https://imagemagick.org/command-line-options/#fx)")、颜色查找替换运算符("[-clut](https://imagemagick.org/command-line-options/#clut)")以及一些较旧的 圆形畸变 函数等运算符中,对图像进行未缩放的“point”查找;它们基于这些简单的插值调整尺寸滤镜。不过它们目前使用独立代码实现,也有不同的设置名称。这些 插值设置 包括:'[NearestNeighbor](misc.html#nearestneighbor)',实现 'Point'(或未缩放 'Box')滤镜;以及 '[BiLinear](misc.html#bilinear)',用于得到未缩放 'Triangle' 滤镜。旁注:目前平滑 triangle 滤镜 'Hermite' 尚未直接实现为 插值设置,这有些可惜,因为它是相当不错的插值滤镜。

Gaussian 模糊滤镜

在傅里叶变换到频域的复杂数学中,调整尺寸滤镜应当去除可能存在的任何高频噪声。这种噪声由现实世界图像采样成像素而产生;当你调整图像尺寸时,该噪声会表现为混叠和摩尔纹效果。因此,Gaussian 钟形曲线很自然地成为早期的调整尺寸或重采样滤镜候选,因为它是现实世界效果的理想模型。

Gaussian

[IM Output] Gaussian 滤镜是一个非常特殊的滤镜,会在频域生成同样的“钟形曲线”形状。这使它作为图像滤镜非常有用,因为它保证能以高度可控的方式良好去除这种高频噪声。然而,如果检查滤镜图形,你会看到在距离采样点 1 像素处仍有非零值。事实上这个值还相当高。这会导致单个像素产生大量模糊,即使实际上并未执行调整尺寸。例如,这里我用 Gaussian 滤镜调整标准 IM 标志尺寸,并再次使用普通 IM 滤镜(本例是 'Lanczos',稍后会看)进行调整。

  magick logo:  -filter Gaussian  -resize 150x logo_gaussian.png
  magick logo:                    -resize 150x logo_normal.png

| [IM Output]
Gaussian | [IM Output]
普通调整尺寸
---|---|---

仔细看会发现,左侧使用 'Gaussian' 滤镜的图像比普通调整尺寸更模糊。尤其是魔杖周围和巫师帽子上较小星星的细节。这种图像模糊,是换取图像缩小时去除所有 混叠 效果,以及图像放大时去除所有 分块 效果的代价。它也(在完美应用时)绝不会产生任何 振铃 效果。但这一切都以结果图像的极端 模糊 为代价。事实上,在大尺度放大中,这个滤镜会生成圆点,而不是方块状的点。例如,这里我大幅放大一张中心只有一个点的 3x3 像素图像。 |

  magick xc:red -bordercolor yellow -border 1 \
          -filter Gaussian   -resize 99x99  -normalize dot_gaussian.jpg

[IM Output]
如你所见,单个像素被放大成完美的圆点。只有 Gaussian 和类 Gaussian 滤镜会这样做。

Gaussian Sigma 专家控制

你可以使用特殊专家选项 "[-define](https://imagemagick.org/command-line-options/#define) filter:sigma=_{value}_",指定 Gaussian 曲线实际的 'sigma' 值,从而直接控制 Gaussian 滤镜。默认情况下该值为 '0.5',也与 Box 滤镜 的大小相同。在许多方面,可以把 Gaussian 滤镜看作本质上的“模糊 box”。加入这个专家选项,是为了在不缩小 滤镜 Support 范围(见下文)的情况下,创建非常非常小的 Gaussian 模糊。不过增大 'sigma' 可能导致滤镜被截断。因此,当增大 'sigma' 值时,默认 'support'(2.0)也会相应增加。只有在默认 'sigma' 值增大时才会发生这种情况。Support 专家设置 可用于覆盖这个自动效果,但通常没有必要。 | _'filter:sigma' 专家选项只对 Gaussian 滤镜 有效。其他滤镜不受这个专家控制影响。

更通用的、面向其他滤镜的控制,可以用稍后介绍的 Blur 滤镜专家控制 实现。

_
---|---

其他类 Gaussian 滤镜

[IM Output] 如果研究右侧的比较图,你会看到 'Quadratic' 滤镜以及稍复杂一些的 'Spline' 滤镜都相当好地跟随了 'Gaussian' 滤镜的加权曲线。由于它们是多项式函数,计算也快得多,这正是它们最初被发明的原因。'Quadratic' 只比 Gaussian 滤镜 略微更模糊,而 'Spline' 滤镜甚至更模糊,大约相当于 Sigma 设置 '0.65'。这使 'Spline' 滤镜成为未经修改时所提供的最模糊滤镜。查看图形会发现,像 Gaussian 滤镜 一样、不同于 插值滤镜,它们在距离采样点 1.0 的位置仍有非零值。这会让附近像素合并颜色,也就是你看到模糊的原因。'Spline' 滤镜在 1.0 距离处具有最高值,因此在任何调整尺寸(或畸变)的图像中产生最大程度的模糊。这种额外模糊会去除大尺度放大中可能仍存在的最后一点“分块”效果,并可与 锐化调整尺寸后的图像 技术结合,用极少的“阶梯效果”放大线稿。比较图中还显示了 '[Mitchell](#mitchell)' 滤镜。这个滤镜在距离采样点 1.0 处也有一些模糊,因此像我们已经看到的其他滤镜一样,也略微模糊。不过它的曲线中也有一些负权重,这虽然会产生 振铃 效果(稍后见 加窗 Sinc 滤镜),但会在锐利边缘附近抵消这种模糊。

滤镜 Support 专家控制

Gaussian 滤镜称为 IIR(无限冲激响应)滤镜,意思很简单:它使用的响应“曲线”永远不会到达零。也就是说,无论离采样点多远,非常远的像素仍会对结果有某种非零贡献。在数学上这实际上是好事,因为这意味着结果在数学上更加完美。但在实际应用中非常糟糕,因为无限滤镜要求你对原始图像中的每个像素做加权平均,才能生成目标图像中的每一个新像素。这意味着用这个滤镜完美调整大图像尺寸会花非常非常长的时间。不过对于 'Gaussian' 滤镜而言,超过采样点约 2 像素(默认 'sigma' 设置的 4 倍)的范围,通常对最终结果的影响很小,因此一般可以忽略。甚至 3 倍 sigma 通常也被认为是合理的。这个范围称为滤镜的“support window”,是程序对该滤镜的实用限制。如果真的想改,可以使用特殊专家设置 "[-define](https://imagemagick.org/command-line-options/#define) filter:support=_{value}_" 改变滤镜的 'support'。例如,这里我用较小的 support 值 1.25,也就是 sigma 值的 2 又 1/2 倍,调整一张单像素图像的尺寸(见右侧 结果图)。这当然小于通常接受的最小值,也就是 sigma 值的 3 倍。 |

  magick pattern:gray5 -crop 5x1+0+3 +repage pixel_5.gif
  magick pixel_5.gif  -filter gaussian -define filter:support=1.25 \
          -resize 300x  pixel_gaussian.png

[IM Output]

[IM Output]
单像素图像 | | [IM Output]
Gaussian 滤镜处理
---|---|---
[IM Profile]
图像的剖面

使用较小的 'support' 设置后,“step”(support window 截断函数的位置)移动到了 1.25 处。这进而在滤镜剖面中形成更大的“stop”,并导致你在放大图中看到的“混叠”效果。也就是图形“峰值”附近的摆动,以及滤镜 'support' 限制边缘处突然的“下降”。你可以把 'support' 看成一个滑过像素的“window”,这些像素会被一起平均来产生放大图像结果。由于 support 大小为 1.25,滤镜的总 support 区域宽 2.5 像素(图像放大时未缩放),因此水平调整尺寸阶段可能涉及 2 个或 3 个像素。随着这个 support “window”滑过图像,每个进入或离开的像素都会在滤镜“曲线”中产生突然的“变化”。这就是结果中轻微抖动的原因。也就是说,在这些位置,一个像素会按滤镜加权曲线被加入或移出参与平均的总像素数。进而在调整后的图像中产生四个这样的“抖动”或“之字形”:最初两个在外侧边缘,出现在单个白色像素进入/离开 support 范围时;第二对抖动则在第二个黑色像素(形成三像素加权平均)进入/离开 support 范围时。如果滤镜中没有这种突然的“stop”,也就是滤镜在 support 限制设置处降为零,那么你就看不到这些“抖动”,也不会有可见效果。使用整数或半整数的 support 大小(如 'Gaussian' 滤镜默认 'support' 设置 '2.0')总能保证每当一个新像素进入 support 范围时,另一个像素正在离开,从而同样数量的像素始终参与平均。这会去掉两个“中心”抖动,但不会去掉外侧最初标记 support 限制的抖动。即使是滤镜中陡峭的斜率变化(不连续),比如 TriangleLagrange 滤镜中的情况,也可能在结果图像中产生可见伪影。 | _在 IM v6.3.6-3 之前,Gaussian 滤镜的 'support' 设置为这个 '1.25' 值,在放大中会产生 振铃 效果(如上所示)。因此,Gaussian 的 'support' 改为 '1.5',以确保总是有相同数量的像素被平均,并减少较小的 step。

自 IM v6.6.5-0 起,Gaussian 的默认 'support' 设置增加到 '2.0'。这对滤镜整体速度影响很小,但让“stop”几乎不存在。它还简化了该滤镜其他特殊用途的滤镜代码,特别是 EWA 畸变可变模糊映射

_
---|---
不过请注意,如果使用非常大的 support 设置,当然会有更多像素需要一起平均,使调整尺寸操作变慢,却不会真正改善结果。通常只有 加窗 Sinc/JincLagrange 滤镜,能够通过使用大于 2.0 的 support window 得到更好的结果。请记住这些是“专家”选项,因此使用这些选项更可能把事情弄坏,而不是弄好。这也是它们不是简单命令行选项,而是通过特殊 "[-define](https://imagemagick.org/command-line-options/#define)" 选项提供的原因。当然,欢迎你像我上面那样试着玩一玩,以便更好地理解它们;IM 提供这些选项正是为了让你可以这样做。

滤镜 Blur 专家控制

特殊专家选项 "[-define](https://imagemagick.org/command-line-options/#define) filter:blur=_{value}_" 可用来调整滤镜提供的模糊量。值 '1.0' 产生默认行为,较小或较大的值会调整整体“模糊度”。基本上,这会沿 X 轴(像素距采样点的距离)线性放大或缩小滤镜曲线,通常会让滤镜整体上更多或更少地模糊。使用较小设置会让滤镜函数(以及它的 support window)变小。对于 Gaussian类 Gaussian 滤镜,其效果就像把滤镜的 'sigma' 值(默认=0.5)乘以这个 'blur' 因子。这个设置也会按相同量放大或缩小滤镜 Support Window 以防止截断,不过可以用 Support 专家滤镜设置 覆盖。例如,这里我使用 类 Gaussian 的 Spline 滤镜,用三个不同的 'blur' 设置调整图像尺寸。

  for blur in 0.5 1.0 1.5; do \
    magick logo: -define filter:blur=$blur -filter Spline \
            -resize 150x logo_blur_$blur.png; \
  done

[IM Output]
blur 0.5 | | [IM Output]
blur 1.0 | | [IM Output]
blur 1.5
---|---|---|---|---

如你所见,这个特殊设置能让你控制 'Spline' 滤镜结果的整体模糊度。由于 “support window” 的大小也会被 滤镜 Blur 设置缩放,使用非常小的缩放值可能导致重采样“错过”所有像素,或只生成零权重像素。结果会生成规则的“黑色”线条或块。例如…… |

  magick rose: -define filter:blur=0.1 -filter Gaussian \
          -resize 100x100  rose_black_bars.png

[IM Output]
增大 support window 的大小(在它被 blur 缩放之前)可能有助于防止这些效果,但由于大多数滤镜只会对落在其“自然”support 范围之外的像素产生零权重,这并不适用于所有滤镜。通常只有 Box 滤镜Sinc/Jinc 加窗滤镜 会在整个 support 范围内生成有用的非零值。类似效果也可在 圆柱型滤镜 中看到,当滤镜 support 太小,以至于不总能找到至少一个可采样像素时就会发生。Lagrange 滤镜 使用 Support 专家滤镜设置 来确定适合 'support window' 的合适“阶数”,从而变形成各种其他形式(见下文)。 | _对含有负权重的滤镜(基本上就是接下来要看的任何滤镜)使用不良 support 设置,可能产生反向锐化和反相效果,以及不成比例地更强的混叠效果。少数情况下,它甚至可能生成无限加权颜色(在普通非 HDRI 版本的 IM 中会被钳制为纯黑和纯白)。

建议在任何滤镜上使用这个特殊选项时都保持谨慎,并具备相应专业知识。
---|---
| _在 IM v6.3.6-3 之前,'filter:blur' define 被错误地由选项 "-support" 设置,这对它实际做什么非常误导。该选项已经废弃,不再可用。

---|---

Gaussian 插值器滤镜变体

[IM Output] 使用 Blur 控制 值 '0.75' 作用于 类 Gaussian 滤镜,或使用 Sigma 控制 值 '0.375' 作用于 Gaussian 滤镜,会生成一个我称为 Gaussian Interpolator 的变体。这个锐化后的 Gaussian 滤镜具有与前面看过的 插值滤镜 类似的性质,但不包含任何会在放大图像中变得明显的锐利 stop 或其他渐变变化。在这一点上,它很像 "[Hermite](#hermite)" 滤镜(见图),但带有非对称偏斜,作为插值器似乎效果更好。

  magick logo: -filter Gaussian -resize 150x logo_gaussian.png
  magick logo: -define filter:blur=0.75 -filter Gaussian \
          -resize 150x logo_gaussian_interpolate.png

[IM Output]
Gaussian | | [IM Output]
Gaussian Interpolator
(blur=0.75 or sigma=0.375)
---|---|---

事实上,我发现它能让 Gaussian 滤镜产生更可接受的结果,既不过锐,也不过模糊。不过减少滤镜的 模糊 会增强 混叠 效果,因此更容易从低像素级图案中产生大尺度摩尔纹效果。这就是使用较少模糊滤镜形式的代价。

  magick rings_crop.png -filter gaussian -resize 100x100  rings_gaussian.png
  magick rings_crop.png -filter gaussian -define filter:blur=0.75 \
                              -resize 100x100  rings_gaussian_interpolate.png

[IM Output]
Gaussian | | [IM Output]
Gaussian Interpolator
(blur=0.75 or sigma=0.375)
---|---|---

加窗 Sinc 滤镜

Sinc 滤镜

数学已经确定,对图像进行调整尺寸(使用 2 遍“张量”调整尺寸技术)的理想滤镜是 Sinc() 函数。(参见 Nyquist-Shannon sampling theorem)。[IM Output] Sinc() 在数学上是完美的,它有一些我想指出的特殊特性。首先,在距采样点每一个整数距离处,滤镜的加权函数都会变成零。这非常重要,因为这意味着滤镜不会比必要程度更多地模糊图像(不同于 Gaussian 滤镜)。它还意味着,如果图像被重采样但没有调整尺寸(一次“no-op”调整尺寸),图像会完全不受滤镜影响。因此它是一个插值滤镜,只不过非常复杂。Jinc() 函数与 Sinc() 密切相关,并具有一些性质,使它适合作为二维过滤的滤镜,例如 通用图像畸变运算符 所使用的过滤。稍后在 圆柱型滤镜 中会更详细讨论这个函数。现在只需注意,它也可以用作 加窗 Jinc 滤镜 的基函数。基于 Sinc()Jinc() 的滤镜与前面看过的滤镜之间另一个主要差异,是许多权重为负。也就是说,它们会从图像每个像素的最终颜色中减去一些附近颜色像素。这可能看起来有点奇怪,但结果是强烈锐化对象边缘。当然,任何负权重通常都需要由曲线后面更多正权重抵消,于是形成你看到的从采样点向外延伸很远的波形函数。这些额外的正(和负)权重“瓣”会在包含非常强颜色边界的图像中造成 振铃 伪影,例如高对比线稿,或红屋顶与蓝天之间的边界。如果基于这些函数的滤镜应用不当,这些振铃效果会变得更加明显。

窗函数

不幸的是,这个函数也是 IIR(无限冲激响应)函数。也就是说,和前面的 Gaussian 滤镜 一样,它的影响一直延伸到无限远。这意味着要使用 'Sinc',你需要对图像中(以及图像之外)的每个像素求加权平均,才能为目标图像中的每一个新像素创建最佳表示。这代价极高,使这些完美滤镜的直接使用并不现实。更不用说你可能也不希望出现振铃效果。但与 Gaussian 滤镜 不同,'Sinc' 函数并不会在离采样点很短距离处就逐渐接近零。事实上,即使距采样点 10 个像素(见上图),也会对最终结果产生可观影响。然而,使用 support 距离为 10 的滤镜调整图像尺寸,需要对最终结果中的每个像素至少平均 20x20,也就是 400 个像素。这会产生非常慢的调整尺寸。因此,不建议使用原始形式的 "Sinc" 滤镜,而且几乎从不使用;不过如果你真的想这样做,使用 专家滤镜控制 时 IM 不会阻止你。推荐并提供的是 Sinc 函数的“加窗”形式,它们由图像处理专家开发,可用来把无限的 Sinc(和 Jinc)函数“限制”到更实用的大小。这些 加窗滤镜 包括:'Blackman'、'Bohman'、'Hann'、'Hamming'、'Lanczos'、'Kaiser'、'Welch'、'Bartlett' 和 'Parzen' 等滤镜。

加窗滤镜的工作方式

[IM Output] 例如,右侧图中显示了三个函数(点击可放大查看)。红色函数是数学上理想的 Sinc() 函数,它会一直延伸到无限远。绿色函数是 "Hann" 窗函数(基于简单 Cosine() 曲线)。它与 Sinc() 相乘,用来调制滤镜中更远的成分,并在 support window 的边缘(该滤镜默认距离为 4.0 像素单位)达到零(或接近零)。基本上,在 "[-filter](https://imagemagick.org/command-line-options/#filter)" 选择中选择 'Hann' 时,实际上是在选择 'Hann()' 这个“窗函数”,去调制 'Sinc()'(或 'Jinc()')这样的“加权函数”。因此,“加窗滤镜”实际上是两个函数:Sinc 或 Jinc 函数(取决于图像处理运算符),以及你明确选择作为要使用滤镜的“窗函数”。(见下方 专家滤镜控制)。 在 v6.3.6-3 之前,IM 犯了一个严重错误,实际上直接把窗函数用作滤镜的加权函数。这反过来导致这些滤镜(Lanczos 除外)在用于调整尺寸时都产生严重 混叠 的图像。因此这些滤镜经常被 IM 用户误解或很少使用。现在已经修正。

各种加窗滤镜

[IM Output] 右侧是本文写作时 IM 可用的各种窗函数图(后来还增加了更多)。是的,数量很多,因为窗函数一直是众多信号处理专家深入研究的主题。所有加窗滤镜函数通常会根据所用窗函数的类别(见下文),使用 Sinc 的 3 或 4 support(3 或 4 个瓣)来调制 Sinc(或 Jinc)加权函数。例如 'Blackman' 窗滤镜会使用 4 个瓣,但 'Lanczos' 会使用 3 个瓣。这取决于你的 IM 版本,因此如果想确定,请查看 Verbose 滤镜专家选项。如你所见,所有加窗滤镜函数都会产生所示原始 Sinc() 函数的弱化形式。除了特定滤镜产生的 振铃 量之外,通常很难区分一个加窗滤镜和另一个。最好的加窗滤镜之一大概是 'Lanczos'。也有人非常推崇作为窗函数的 'Blackman'、'Bohman'、'Hann'(余弦渐缩钟形)、'Hamming'(余弦钟形变体)、'Cosine'(单个余弦瓣)。这些函数的构造都基于 Sinc 或 Sine/Cosine 函数的使用,据称这能保证函数具有良好的频率响应。其他窗滤镜包括 'Welch'(抛物线)、'Parzen'(三次样条)、'Kaiser'(Bessel),以及可能最简单的 'Bartlett'(三角形或线性)。通常这些函数是为了简单和快速计算而创建的,尽管它们通常被认为“频率响应”较差。此外,许多这类窗函数本身也作为重采样滤镜使用。例如 'Bartlett'(它可能是所有窗函数中真正的异类)实际上与 'Triangle' 滤镜以及 'Bilinear' 插值滤镜使用的是同一个数学函数。所有函数(除 'Bartlett' 外)形成两类基本窗函数。

  • 渐缩的“钟形”曲线,例如 'Hamming'、'Hann'、'Kaiser'、'Blackman'、'Bohman' 和 'Parzen'。
  • 以及未渐缩的“瓣”型窗函数,它们会先快速落到零,再被窗口 support “截断”,例如 'Lanczos'、'Welch' 和 'Cosine'。

如果研究上面的窗函数图,可以看出两种滤镜风格的形状如何不同。不过这两类窗函数似乎没有使用三角函数定义曲线所得到的整体“频率响应”那么重要。渐缩“钟形”的窗函数会在 Sinc 加权函数(或圆柱型(distort)重采样中的 Jinc 函数)的 4 个瓣上使用 Lobes Support。未渐缩“瓣”型的窗滤镜默认使用 3 个瓣的 support。由于窗函数 roll-off 的差异,这会让两类窗滤镜大致等价。这也意味着未渐缩的加窗滤镜默认会比渐缩的稍快。滤镜应具有的默认瓣数曾在 IM 论坛讨论 Add Cosine windowing? 中讨论。当然,如果愿意,你可以改变任何调整尺寸滤镜的 Lobes Support,甚至一般 support。它们基本都差不多,只是在产生的振铃和分块效果数量上有很小差异。[IM Output] 右侧是相同的窗函数,但根据函数渐缩/未渐缩的性质,使用 IM 定义的默认 Lobes Support。如你所见,在前两个瓣(影响最大的主要瓣)上,各滤镜之间差异很小,并且在该范围内都显示出非常相似的“roll-off”。不过函数的排序变化不大,两个极端仍在 'Welch' 和 'Parzen' 之间,而 'Lanczos' 正好落在最终曲线 roll-off 的中间。[IM Output] 右侧则是用户用上述默认值选择这些窗函数时会得到的加窗 Sinc 滤镜。如你所见,最终加权曲线都非常相似,并且如预期一样,都夹在 'Welch' 和 'Parzen' 两个极端之间。关于这些不同窗函数中大多数的更详细定义和图形,以及它们在傅里叶频谱中的结果,可参见 Wikipedia, Window function
总结: 我没有发现这些不同窗函数在结果上有很大差别。此外,我阅读的结果研究论文似乎更多是对适用性的定性意见,而不是任何具体事实。我的感觉是,几乎任何窗函数都可以使用;但如果只能选一个,最好坚持使用最流行的 'Lanczos' 窗滤镜。它位于上述所有滤镜的中间,具有良好的频率谱响应,通常是一个不错的重采样滤镜选择。另一方面,一位对 ImageMagick 重采样滤镜贡献很大的图像处理专家不同意这一点。不过他更多基于特定图像的具体需求来选择滤镜。你可以在 Nicolas Robidoux 推荐的技术 中看到他的建议和评论。

Lanczos 滤镜

我们已经多次提到 'Lanczos' 滤镜。它可能是最知名的 加窗滤镜,处在我们所见加窗滤镜范围的中间。基本上,它的 “roll-off” 不会太快,也不会太慢,并且在得到的傅里叶变换中有良好的频率响应。基本上,'Lanczos' 是任何滤镜工作的绝佳起点,并已大量用于最近 加窗 Jinc 圆柱型滤镜 的开发(见下文)。'Lanczos' 滤镜基本上使用 Sinc() 函数的第一个“瓣”来为 Sinc() 函数加窗。也就是说,滤镜的加权函数被用来设置滤镜自身的窗函数。许多人认为这是选择它而不是许多其他加窗 Sinc 滤镜的好理由。虽然几乎没有真实证据证明它最好,但它是一个扎实的中间范围滤镜。默认情况下,IM 将 'Lanczos' 滤镜定义为具有 3 个“瓣”。原因是窗函数本身是“未渐缩”的,也就是只有一个被截断的瓣,其函数的第一个零交叉点与 window support 限制重合。见上方 加窗滤镜的工作方式[IM Output] 不过,2 瓣的 'Lanczos2' 滤镜(默认瓣数为 2 的 Lanczos,为便于用户选择而添加)也很受欢迎,因为它能避免加窗 Sinc 滤镜可能产生的正向 振铃伪影。'Catrom'(实际上是 'Catmull-Rom Filter')几乎完全复制了 'Lanczos2' 滤镜,不过由于它是 Cubic 滤镜,数学上生成得更快。然而以 IM 在处理图像前缓存滤镜值的方式来看,这通常不是问题。话虽如此,IM 论坛中的一篇长 讨论 似乎表明,对于正交(张量)调整尺寸,4 瓣 'Lanczos' 在缩小图像时实际上效果更好,并能在含有非常精细图案的物体图像中防止 摩尔纹,但代价是更多 振铃

以瓣数表示的窗口大小

如前所述,底层 Sinc(和 Jinc)滤镜函数实际上是无限大的。不过默认情况下,IM 会用指定的窗函数把它们限制到小得多、更实用的大小。但也可能有些情况下,你真的想尝试使用更大、更慢的窗口(support)大小,以得到更好、更准确的图像调整尺寸。这甚至可以通过 Filter Support 专家控制相当简单地完成,就像我们对 类 Gaussian 滤镜所做的那样。窗函数本身会在(大多数情况下)使 Sinc(和 Jinc)在 support 设置范围内降到零。但由于窗函数会缩放以适配 'support' window,得到的滤镜函数也会变化。[IM Output] 例如,右侧我绘出了以 Sinc() 函数为参考、使用从 2 到 8 的各种 'support' 设置的 'Lanczos' 加窗滤镜。注意,滤镜的实际大小受所用实际 support 大小限制。'support' 越小滤镜越快,但该函数越不精确地跟随数学理想的 Sinc() 函数。仔细看每条曲线。“绿色”(support=2)曲线只有主中心峰,以及一个负“瓣”(等同于 'Lanczos2' 滤镜)。之后函数就是零,不再使用。下一条“紫色”(support=3,也是默认 'Lanczos' 滤镜)曲线有一个大得多的第一个负“瓣”,然后是一个较小的正“瓣”。随着 support 大小按整数增大,会继续添加更多瓣。额外的瓣高度越来越小,对最终结果影响越来越小,但初始“瓣”会变得更高(影响更大,因此 振铃 效果更多)。为了获得最佳效果,应使用一个 support 设置,生成含有相同数量上下“瓣”的滤镜。也就是说,窗函数以及滤镜的 'support' 应该在“零交叉点”结束。不过,虽然 Sinc() 函数在整数 'support' 设置处具有“瓣”(零交叉点),Jinc() 加权函数并没有。这给希望调整 Distort 运算符 所用滤镜 support window 的用户带来了问题。事实上,Jinc() 的“零交叉点”位于高度 无理数 的位置。如果不是数学专家,这些零交叉点很难算出来。为了更容易用“瓣”数设置滤镜,又创建了一个特殊设置 "[-define](https://imagemagick.org/command-line-options/#define) filter:lobes=_{integer}_"。如果滤镜由二维图像重采样运算符使用,例如通常以 Jinc() 为基函数的 通用畸变运算符,它会查找滤镜前 20 个零交叉点的表,并把 'support' 设置为该值。这意味着你不必试图为 Jinc() 函数找到合适的 support 设置,只需指定想使用的瓣数。因此,最好用希望滤镜包含的“瓣”数来指定加窗 Sinc 或 Jinc 滤镜,而不是指定更直接的 'support' 设置。如果滤镜定义既不使用 Sinc() 也不使用 Jinc() 函数,那么 'filter:lobes' 设置会用于计算滤镜使用时合适的 'support' 设置。不过请注意,'filter:support' 设置会覆盖任何给定的 'filter:lobes' 设置,因此最好只定义 'filter:lobes' 专家选项,尤其是在使用 通用畸变运算符 时。

Lagrange 滤镜

正如 '[Gaussian](#gaussian)' 滤镜是数学上较慢的函数(不过由于 IM 会缓存结果,它对整体速度影响不大),Sinc/Jinc 加窗滤镜 由于需要计算用于加权函数和窗函数的三角函数,计算起来更慢也更复杂。不过 'Lagrange' 滤镜会生成一个分段三次多项式函数来近似加窗滤镜。(参见 Wikipedia: Lagrange Polynomial)。就像 加窗滤镜 可按 Support 设置 调整一样,'Lagrange' 滤镜也会按该设置自行调整。默认 support 设置 2.0 会生成一个 'Lagrange' 滤镜(3 阶)。这个滤镜对图像放大和缩小都相当不错,只有很少的 分块振铃 效果,并且没有 模糊 效果。 | _Support 专家控制 实际上是在定义应使用的 Lagrange 滤镜“阶数”。也就是说,默认 2.0 support 的 Lagrange 滤镜会生成 3 阶 Lagrange 滤镜(阶数 = support × 2 - 1,因此 support=2.0 => Lagrange-3 滤镜)。这就是为什么你实际上只能使用半整数大小的设置。

因此,要得到 Lagrange 4 阶滤镜,可以使用选项_ -define filter:support=2.5
---|---
[IM Output] 使用较大的 support 设置时,'Lagrange' 滤镜无需复杂三角函数计算,甚至无需额外窗函数,就能生成 加窗 Sinc 滤镜。support 设置越大,滤镜越接近模拟 Sinc() 函数,但计算也越慢。(见左侧较大 support Lagrange 滤镜图)。
[IM Output] 使用较小的 support 设置时,'Lagrange' 滤镜会模拟大多数不同的 插值滤镜。也就是说,'0.5' 的 support 大小会生成 'Box' 滤镜,'1.0' 会生成 'Triangle' 滤镜。support 设置限制为按半整数调整,使用其他 support 因子并不太有意义。
[IM Output] 其他半整数 support 的 Lagrange 滤镜(生成偶数阶)会产生一组非常不连续的滤镜权重,并且很像 'Box' 滤镜,可能产生一些强烈的 分块 调整尺寸伪影。另一方面,对于小尺度调整尺寸,这能确保图像在非常小的尺寸调整中保持锐利。这些“偶数”阶 'Lagrange' 滤镜实际上突出了使用该滤镜的主要缺点:加权函数不是“平滑”的渐变。在大尺度放大中,这意味着生成的渐变可能出现可见变化。不过除了那些极端情况,这很少成为问题。基本上,它表示一种无论当前 'support' 设置多大或多小,都能普遍为该设置创建合适形式的滤镜。它是一个自加窗的调整尺寸滤镜。 | '[Lagrange](#lagrange)' 滤镜直到 IM 版本 v6.3.7-1 才被完整定义并可用。
---|---

Cubic 滤镜

由于许多图像专家都在寻找一种更好、计算更快的图像调整尺寸滤镜,一个滤镜族逐渐演化出来,并被称为 Cubic 滤镜。它们很像前面展示的 Lagrange 滤镜,由一组较小的固定分段组成。不过与 Lagrange 滤镜不同,这些片段被设计为拼接成平滑曲线,以减少锐利的 分块 效果。[IM Output] 左侧图中显示了四种这样的“平滑”cubic 滤镜,它们在 IM 中预定义,并且作为调整尺寸滤镜广为人知。'Spline' 滤镜(也作为通用 'Cubic' 滤镜函数的别名和默认设置)模拟 Gaussian 模糊滤镜。这条曲线也称为 “B-Spline” 插值曲线,常用于穿过一组点绘制平滑线条。它也经常用于动画中的相机和对象运动,以通过用户提供的控制点产生平滑流动。图中还显示了 'Catrom',更准确地说是 “Catmull-Rom Filter” 或 “Keys Cubic Convolution”,它会生成一种平滑但不模糊的 插值滤镜。不过它可能会稍微过冲。它本质上是一种理想的自锐化滤镜,因此也是基本 Bi-Cubic Interpolation 常用的函数。最后是 'Hermite' Cubic 滤镜,它是一种平滑化的三角 插值滤镜,会在输入坐标处平滑衰减(roll off)。基本上,它会在保留原图中平坦“颜色层级”的同时圆滑强边缘。

Cubic 滤镜族

上面这些是 Cubic 曲线中最常见的“命名”滤镜,但它们也属于特定的 Cubic 滤镜族。cubic 的 'B-Spline' 族 本质上等价于结果中不同程度的 模糊。典型范围从非常 模糊 的 'Spline' 滤镜,到会圆滑边缘但结果 块状 的 'Hermite' 滤镜。然后有 'Cardinal' 族,它产生在 分块振铃 伪影之间折中的滤镜,'Catmull-Rom Filter'('Catrom')就是从中演化而来的,用作这些伪影的平衡折中。这两个族随后合并形成 'Keys Cubic Filter Family',把 'Catmull-Rom Filter'(Keys α = 0.5)与 'B-Spline Cubic Filter'(Keys α = 0.0)连接起来。Keys 滤镜族还有一个特殊性质:能保留图像中可能存在的任何线性(仿射)渐变。Keys 族滤镜的 振铃模糊 效果,只会在图像包含强烈颜色变化,而不是平滑颜色渐变时出现。被这种多样性弄糊涂了吗?当然会。其他人也是!问题在于,滤镜结果通常非常主观,取决于图像,也取决于你使用的“族”的限制。什么才算好滤镜,实际上取决于你问谁、你是在放大还是缩小,以及你正在处理什么图像。某种意义上,它现在仍然令人困惑。我花了两年多时间摸索、阅读并把各种滤镜拿来试,才形成这份摘要的开端,而它现在仍在演变。图像调整尺寸是一个非常主观的领域,很难(事实上已经证明不可能)用任何真正的方式量化。不存在所谓“完美”的调整尺寸。

Mitchell-Netravali 滤镜

在这样的背景下,Don P. Mitchell 和 Arun N. Netravali 发表了论文 'Reconstruction Filters in Computer Graphics',提出了两个变量,称为 'B'(用于 'B-spline' 曲线)和 'C'(用于 'Cardinal' 曲线,并等价于 'Keys' 滤镜的 α 值)。用这两个值可以生成任何平滑衔接(一阶导数连续)的分段 cubic 滤镜。[IM Output] 更重要的是,他们没有只依靠自己的意见,而是调查了一组 9 位图像处理专家,对使用不同 B 和 C 值略微放大图像所产生的 伪影 进行分类。该调查的结果显示在右侧重绘的图中。“绿色”区域表示专家认为能产生可接受结果的值,其他区域则会产生不同类型的 伪影。这张图很重要,因为它真正展示了各种 伪影 与可生成的不同类型滤镜之间的关系。你还可以从结果看出,为什么 'Keys' 滤镜族会变得如此重要,因为它是生成良好 cubic 滤镜的较好方法之一。其滤镜基本沿着一条直接穿过图像处理专家认为“可接受”区域的线分布。根据这项调查,Mitchell 和 Netravali 认定最佳滤镜是一个 'Keys' 族滤镜,它位于可接受区域的中间,使用 B,C 值 1/3,1/3。这个滤镜现在称为 'Mitchell-Netravali Filter',并在 IM 中作为 'Mitchell' 滤镜设置提供。基本上,它是所有调整尺寸伪影之间的折中。它也是 IM 图像放大所用的默认滤镜。所有内置“命名”Cubic 滤镜:'Mitchell'、'Robidoux'、'Catrom'、'Spline' 和 'Hermite',也标在上图中,显示那些专家会如何看待这些具体滤镜。图中还显示了表示 'B-Spline'、'Cardinal' 和 'Keys' 滤镜族的线。内部而言,这些滤镜只在预定义的 B,C 设置上不同;事实上 IM 使用同一个内部函数生成所有 cubic 滤镜,只用不同的 B,C 设置定义这些滤镜。

Cubic B,C 专家控制

你可以使用特殊专家设置来设定 Cubic 滤镜 使用的 B,C 设置。为此,需要选择通用 'Cubic' 滤镜“函数”(或其他任何命名 cubic 滤镜),以及所需的 'b' 和 'c' 专家设置。例如……

   -filter Cubic
   -define filter:b=_value_
   -define filter:c=_value_

当给定滤镜被调整尺寸或 distort 运算符使用时,专家设置会覆盖该滤镜的内部默认值。因此,只要在使用图像处理运算符之前,已经用 "[-define](https://imagemagick.org/command-line-options/#define)" 或 "[-set](https://imagemagick.org/command-line-options/#set)" 设置了所需的所有全局专家设置,上述选项的顺序并不重要。如果 'b' 或 'c' 设置中的一个没有被定义或设置,其值会在假设你想要一个 'Keys' 族滤镜(沿 Mitchell-Netravali 调查图中的虚线)的前提下,由另一个值计算得出。请记住,'c' 等价于 Keys α 设置,而 'b' 可以看作 cubic spline 的“blur”设置。这些专家设置为用户“调节”图像调整尺寸提供了很好的方法,以便得到他们确切想要的结果(无论使用 Resize 还是 Distort)。两个设置中 'b' 更容易理解。只要把 'b' 想成“模糊度”。b=0 的值非常锐利(Catmull-Rom 滤镜),倾向于产生负 halo 振铃,以及一些 混叠或摩尔纹 效果。b=1 的值倾向于产生过度模糊(Spline 或类 Gaussian)的效果。这使专家(甚至普通用户)可以方便地调整这个值,找到“对自己来说不错”的滤镜。右侧是特定“命名”Cubic 滤镜 的 B,C 值表。请记住,'Hermite' 是唯一不属于 'Keys' 滤镜族的内置 cubic 滤镜。它也是所有 BC Cubic 滤镜中 support 最小('1.0')的,并且不包含负瓣。'[Robidoux](#robidoux)' 和 '[RobidouxSharp](#robidoux_sharp)' 滤镜与 'Mitchell' 非常相似,但不是调查结果,而是为作为 圆柱型滤镜 的特殊用途从数学上确定的。'[Robidoux](#robidoux)' 滤镜是 通用 Distort 运算符 使用的默认滤镜(见下文)。 | | | Filter | B
blur | C
Keys α
---|---|---
Hermite | 0.0 | 0.0
Spline | 1.0 | 0.0
Catrom | 0.0 | 1/2
Mitchell | 1/3 | 1/3
Robidoux | 0.3782 | 0.3109
Robidoux
Sharp | 0.2620 | 0.3690
Robidoux
Soft | 0.6796 | 0.1602
| 'Parzen' 窗滤镜使用 'Spline' 滤镜作为其窗函数。因此,你可以用 B,C 专家选项重新定义这个窗滤镜。这有多大用处,以及它对最终加窗 Sinc(或 Jinc)有什么影响,目前未知,也不推荐这样做。
---|---

圆柱型滤镜 - 用于 Distort

正如前面已经多次提到的,Distort 运算符 使用滤镜设置来重采样图像的方式,与 Resize 运算符 稍有不同。具体来说,Distort 使用“样本点”和源图像采样区域中实际像素之间的“径向”距离来应用滤镜,决定每个像素的权重,从而决定样本点处的最终颜色。相比之下,Resize 使用正交对齐的滤镜对图像处理两次,先在 X 方向,再在 Y 方向,因此它局限于简单的矩形图像调整尺寸,并不涉及 虚拟像素 的使用。也就是说,Distort 会应用滤镜生成“圆柱型”形状,而不是“Box”形状,以便允许图像的自由形式畸变,包括旋转以及任意方向上的可变缩放(拉伸和压缩),而不只是沿 X 或 Y 轴。因此,滤镜本身往往需要调整,或专门为这种用途设计。

插值圆柱型滤镜

这里我使用 '[Box](#box)' 滤镜,通过等价的 ResizeDistort 运算符,把单像素图像放大 30 倍。

  magick xc:  -bordercolor black -border 1 \
          -filter Box   -resize 3000%      dot_resize_box_black.png
  magick xc:  -bordercolor black -border 1 \
          -filter Box   +distort SRT 30,0  dot_distort_box_black.png

[IM Output]
Resize | [IM Output]
Distort
---|---

如你所见,当 '[Box](#box)' 滤镜作为圆柱型滤镜使用时,会得到一个圆(或三维中的圆柱)。不过由于滤镜处理方式的缘故,你会得到一些区域,其中两个像素被(等量)采样,从而产生完美的中间调灰色。你可以把圆柱型 box 滤镜理解为把源图像转换成一整组相互重叠的圆形像素,并将它们混合(不是相加)在一起。下面是使用“圆柱型 Box”滤镜放大图像时,一个更有颜色的结果示例…… |

  magick \( xc:red   xc:white xc:black +append \) \
          \( xc:blue  xc:lime  xc:white +append \) \
          \( xc:black xc:red   xc:blue  +append \) -append \
          -filter Box   +distort SRT 30,0  color_box_distort.gif

[IM Output]
在畸变后的图像中,这些圆形像素也会被畸变成一组相互重叠的椭圆。例如…… |

  magick \( xc:red   xc:white xc:black +append \) \
          \( xc:blue  xc:lime  xc:white +append \) \
          \( xc:black xc:red   xc:blue  +append \) -append \
          -alpha set -virtual-pixel transparent -filter Box \
          +distort Perspective '0,0 0,0  0,3 0,90 3,0 90,30 3,3 90,60' \
          color_box_distort.png

[IM Output]
| _圆柱型 'Box' 滤镜的 support “半径”会从 '0.5' 增加到 '0.707'(sqrt(2)/2)。这确保滤镜总能在圆形采样区域中(对角方向上)找到至少一个源像素。这是任何圆柱型滤镜的最小实用 support 大小。

没有其他滤镜存在这种覆盖问题,因此也不需要增加 support。_
---|---
| _如果 support 至少不是 '0.707',那么图像中可能会出现滤镜“错过”所有源像素的区域,从而产生 重采样失败

使用更大的 support 设置还会产生有趣的图案。随着“圆”变大,更多像素会被混合在一起。例如……_ | |

  magick \( xc:red   xc:white xc:black +append \) \
          \( xc:blue  xc:lime  xc:white +append \) \
          \( xc:black xc:red   xc:blue  +append \) -append \
          -filter Box -define filter:support=0.83 \
          +distort SRT 30,0  color_box_distort_overlap.png

[IM Output]
_结果是一种圆形形式的 Blend 插值

当 support 为 1.0 或更大时,每次重采样都会是至少两个像素的 “box” 或“平均”混合。

_

下面是若干插值滤镜的比较。这里使用灰色,以便看到过冲和欠冲。上面一行使用正交调整尺寸,下面一行使用圆柱型畸变。

  for filter in box triangle hermite lagrange catrom
  do
    magick xc:gray80  -bordercolor gray20 -border 2 \
            -filter $filter   -resize 2000%      dot_resize_$filter.png
    magick xc:gray80  -bordercolor gray20 -border 2 \
            -filter $filter   +distort SRT 20,0  dot_distort_$filter.png
  done

[IM Output]
[IM Output]
Box | [IM Output]
[IM Output]
Triangle | [IM Output]
[IM Output]
Hermite | [IM Output]
[IM Output]
Lagrange | [IM Output]
[IM Output]
Catrom
---|---|---|---|---

可以看到,两种应用滤镜的方式会生成相似但不同风格的 伪影,包括内部伪影和外部(振铃)伪影。内部伪影在 'Triangle' 滤镜中尤其明显。不过请记住,插值滤镜并不特别适合畸变图像的极端缩小,但非常适合放大。

圆柱型 Gaussian

在正交 “resize” 与圆柱型 “distort” 形式之间,唯一不会产生结果差异的滤镜,是特殊的 '[Gaussian](#gaussian)' 滤镜…… |

  magick xc:red -bordercolor yellow -border 1 \
          -filter Gaussian   +distort SRT 33,0  -normalize  dot_distort.jpg

[IM Output]
这实际上是该滤镜的一个特殊性质(称为可分离性),也是许多圆柱型重采样实现把它用作默认滤镜的原因之一。它是最初 EWA 论文中的默认选择,但其结果也非常模糊。ImageMagick 在最初实现 distorts 时也使用过它,但现在不再使用。与正交 resize 一样,'Gaussian' 滤镜在结果图像中绝不会产生任何 混叠伪影,即使应用到特殊的 'rings' 图像也是如此。但代价是结果模糊,即使实际上几乎没有或完全没有畸变。同样,正如 Sigma 专家控制 的讨论中所述,你也可以把这个滤镜用作一种插值滤镜。 | _自 IM v6.6.5-0 起,IM 不再默认把这个滤镜用于 图像畸变。取而代之的是另一个专门设计用于产生更锐利结果的滤镜 '[Robidoux](#robidoux)'。

无论如何,在这个版本之前,由于实现中的一个错误,畸变也非常模糊。如果你使用旧版本并想使用 图像畸变,请升级。

_
---|---
| _在 IM v6.6.7-6 之前,IM 对圆柱型 Gaussian 使用稍大的 'sigma' 值,即 1/sqrt(2) 或约 0.707,而不是 1/2。这会产生稍微更模糊的结果,用于减少可能的 混叠伪影

这是一个错误,由于遵循了一篇研究论文的建议,把 圆柱型 Box 滤镜 的更大 support 传入 Gaussian 滤镜而产生。提出的理由是 Gaussian 本质上是模糊 box。并不是。Gaussian 是模糊冲激,而不是模糊 box。这个版本移除了该错误,也意味着在使用 gaussian 滤镜时,无论 resize 还是 distort,都应该得到等价结果。

我个人确实发现,使用这个稍大的 sigma 值时,在放大线稿时会平滑掉混叠对角边缘上的任何“分块”伪影。但那是一个特殊情况。

_
---|---

加窗 Jinc 圆柱型滤镜

[IM Output] Jinc() 函数(有时被不准确地称为 'Bessel' 滤镜)是用于圆柱型过滤操作的 'Sinc' 等价物。虽然它与 Sinc() 非常相似且密切相关,但它设计用于通过径向或圆柱型距离,而不是仅在正交(轴对齐)方向上,过滤一个矩形数值数组。如果查看所提供的 Jinc() 函数图,会发现它的第一个“零交叉点”(表示第一圈近邻)落在 1.0(正交近邻)和 2 的平方根之间。也就是说,零交叉点大约为 '1.2196699'。Jinc() 函数的工作方式是:如果采样点等于一个实际像素值,Jinc() 函数会给稍近的正交相邻像素分配正值,然后给稍远的对角相邻像素分配类似的负值,并在二维数值数组中继续向外移动。结果是,当没有执行缩放(畸变)时,近邻的贡献理论上应彼此抵消。这就是为什么 Jinc 滤镜在数学上是方形数组圆柱型重采样的首选解,也因此是 Distort 椭圆重采样方法(EWA)的“理想”滤镜。这并不是说从人的角度看它是“完美”滤镜。正因如此,选择任何 加窗滤镜 并与 Distort 运算符 一起使用时,都会用等价的 'Jinc()' 函数替换普通的 'Sinc()' 函数。由于 Jinc() 函数的零交叉点在非整数位置,因此非常重要的一点是,要用特殊的 Lobes Support 设置 来指定滤镜 support;这个设置是上面为 加窗 Sinc 滤镜 引入的。使用“加窗 Jinc”滤镜的最大问题,是源图像包含像素级网纹图案时(例如 "pattern:gray50" 提供的图案,见 内置图案)。在这种情况下,所有正交近邻都不同于对角近邻,结果图像会被 'Jinc()' 函数严重模糊。不过几乎任何其他图案,如线条、边缘、角,在使用“加窗 Jinc”滤镜时都会保持相当锐利清晰,因此它仍然是一个好用的函数。这个“问题”也可以是好事,因为这意味着二维圆柱型 Jinc 派生滤镜可以作为从图像中去除强像素网纹类图案的方法,例如由 减色抖动 生成的图案,而不会大幅影响图像其余部分的锐利度。也就是说,它可以用作“抖动去除方法”(见下文)。

No-Op 情况下的 Distort 与滤镜

理想情况下,no-op 畸变应该返回完全相同的图像。但正如前面示例所见,实际未必如此。resize(2 遍一维)滤镜:Lanczos(Sinc-Sinc)、Lanczos2、Catrom、Hermite、Triangle 以及许多其他 resize 滤镜都有这个性质。如果图像没有缩放,像素图案会被精确保留。另一方面,Gaussian、Cubic 和 Quadratic 这类平滑或模糊滤镜,在接近 no-op 的情况下应用时会模糊图像。注意,即使默认 resize 滤镜 Mitchell-Netravali 也包含一些模糊,因为它基本是 B-spline “Cubic” 平滑滤镜和 Cubic 的 2 瓣 sinc 等价 Catmull-Rom 滤镜的混合。 | _resize 运算符默认会对 no-op 情况短路,因而什么都不做。因此,除非明确指定滤镜,否则无法生成一次 “noop” resize。

Distort 在 no-op 情况下绝不会短路,这是为了保证动画中的一致性,因为畸变缩放可能会穿过 “no-op” 情况。这通常不是 resize 需要关心的问题。

_
---|---
虽然许多 resize 滤镜会在 no-op 情况下保留图像,圆柱型(distort)方法基本上永远不会产生完美的 no-op 畸变。任何 no-op distort 至少都会轻微扭曲图像颜色,即使图像本身并未畸变。发生的情况是,使用圆柱型滤镜时,正交邻域像素的贡献会不同于对角邻域像素的贡献。它们本质上与查找点(在 no-op 情况下位于实际像素中心)的距离不同。'Jinc' 函数试图通过用对角近邻的贡献抵消正交近邻的贡献,减少这种颜色扭曲。事实上,这正是其数学定义的一部分。在最坏情况下,也就是“像素级网纹”中,每个对角相邻像素都不同于每个正交相邻像素。这时滤镜权重会增强贡献,而不是抵消贡献。结果,这类图像在对任何包含“像素级网纹”的图像执行 no-op 畸变时,往往会产生非常严重的颜色扭曲。这里例如我实际使用这种特殊性质,从图像中移除一个网纹图案。不使用缩放,只是在图像上应用二维“卷积”的畸变。

  magick -size 100x100 pattern:gray50  hash.png
  magick hash.png -filter Lanczos -distort resize 100% hash_removed.png

| [IM Output] | | [IM Output]
---|---|---|---

| _网纹图案被感知到的灰度级比网纹整体灰度级暗得多,原因在于 人类颜色感知 的工作方式。

修正方法是在上面的命令中加入 '-set colorspace RGB',告诉 IM 我们正在 linear-RGB 色彩空间中调整尺寸。见 带色彩空间校正的调整尺寸

_
---|---
上面的操作实际上等价于使用类 Jinc 核函数的 卷积。但如你所见,Jinc 函数的特殊性质(本例中是 EWA Lanczos,也就是 Jinc 加窗 Jinc)完全移除了原图中强烈存在的网纹图案。现在唯一残留的部分是在边缘处,因为包围图像本体的 “abyss”(没有虚拟像素贡献)会影响结果。加窗 Jinc 滤镜的实际瓣数也对结果有巨大影响。使用 2 个瓣时,“像素级网纹”倾向于被保留,尽管会变钝或模糊。 |

  magick hash.png -filter Lanczos2 -distort resize 100% hash_2_lobes.png

应用到 Jinc 函数上的加窗方法贡献,也会对这个效果产生重大影响。有些情况下甚至会进一步增强网纹图案。[IM Output]
于是问题变成:如何调节 distort 滤镜,以尽量减少滤镜在 no-op 畸变中生成的颜色扭曲。Nicolas Robidoux 决定采用的方式,是选择一种 blur(对滤镜核 support 的重新缩放),它倾向于尽可能保留正交边缘。

圆柱型 Lanczos 滤镜

如上面讨论,"Lanczos" 通常定义为一个同时用于滤镜加权和加窗的 'Sinc()' 函数。但当作为 EWA 圆柱型滤镜使用时,这两个加权函数都会被 'Jinc()' 函数替换。也就是说,不仅加权函数被替换(就像其他线性加窗滤镜那样),窗函数也被替换,从而产生 Jinc 加窗 Jinc 的加权函数。因此,“圆柱型 Lanczos”会选择一个具有相同瓣数(默认 3)的 “Jinc windowed Jinc”。这项技术最早由 Andreas Gustafsson 在 Interactive (Local) Image Warping 论文(第 24 页)中提倡。他具体使用了一个 2 瓣圆柱型 Lanczos(Jinc 加窗 Jinc)滤镜,并将其命名为 'Lanczos2D'(见下一节)。这只是平面(EWA)情形下的一个明显扩展,因此沿用了同样的名称。更多信息见 BC-splines 讨论中的这篇帖子

Lanczos2 - 2 瓣 Lanczos

为了方便,这个 2 瓣版本被简单命名为 '**Lanczos2**',并在 IM v6.6.4-10 中加入,专门用于畸变。它实际上只是一个带有 'filter:lobes=2 专家设置的圆柱型 'Lanczos'(Jinc-Jinc)滤镜。见 上面的图,并且由于 IM 滤镜会在适当时自动在 Sinc()Jinc() 函数之间切换,它并不只是用于 “2D”(圆柱型)用途。它也可以用于 resize(作为 Sinc-Sinc 函数),不过我不推荐,因为它可能有点太小,实际上几乎等价于各种其他 cubic 函数。

LanczosSharp - 略微锐化的 Lanczos

观察发现,对 Jinc() 函数加窗会导致 EWA distort 结果比正交 resize 结果中类似的加窗 Sinc() 函数模糊得多(尤其是细线)。这种情况在轻微畸变时尤其明显。基本上,Jinc() 函数有一些特殊性质,而对 Jinc() 函数加窗会破坏这些特定且有用的性质。经过一些计算,Laurentian University 的数学教授 Nicolas Robidoux 得出了一个略微更锐利的 3 瓣圆柱型 Lanczos 版本,现在作为 '**LanczosSharp**' 提供,在一定程度上修正了图像畸变的问题。不过所得滤镜仍具有 加窗 Jinc 圆柱型滤镜 对低层“像素网纹”图案的强模糊。

Lanczos2 锐化

[IM Output] 同样的问题在 'Lanczos2' 滤镜中更严重,所以 Nicolas 也使用稍大的 Blur 专家控制 生成了更锐利的 '**Lanczos2Sharp**' 滤镜。结果是在 “no distort” 情况下,对垂直或水平线只有最小模糊的滤镜。这个锐化滤镜会让零点略微移动,现在大约位于 '1.1684'。这看似不多,但对几乎没有畸变或完全没有畸变的图像而言,它会极大改变滤镜产生的模糊量。

Lanczos Radius

[IM Output] 这是一个 EWA Lanczos 滤镜,它经过模糊(锐化),使所用瓣数(默认 3)正好装入整数 support 半径。也就是说,3 瓣 EWA Lanczos(基于加窗 Jinc)被锐化为 support 半径正好为 3。你可以使用 Lobes 专家控制 达到相同结果,但它涉及基于 Jinc 函数已知零交叉点的调整,并不容易计算。Nicolas 建议加入这个滤镜,这样你就不必做那项计算,并能测试这个非常具体的锐化滤镜。未来:到 Jinc 加窗 Jinc 滤镜的 blur 因子表。
包含瓣数作为参考。

Robidoux 圆柱型滤镜

[IM Output] 奇怪的是,实验显示,把 Mitchell-Netravali 滤镜作为圆柱型滤镜使用,在 “no distort” 情况下会产生几乎等价的“锐利”结果。然而该滤镜与它作为圆柱型滤镜的用途没有关系,因为它是为正交(resize)过滤通过“社会研究”选择出来的。'Mitchell' 滤镜特别擅长保留低层“像素网纹”图案,而普通 加窗 Jinc 滤镜 会在圆柱型过滤的图像中破坏这些图案。Nicolas 随后发现,奇妙的巧合是 'Mitchell' 与上面讨论的“锐化”形式 'Lanczos2' 滤镜极为接近。这进一步促使他开发了一个能完美保留垂直(和水平)线的 Keys Cubic 滤镜。此外,这个新滤镜的计算成本更低,因为 cubic 函数比 Jinc 函数便宜得多。自 IM v6.6.5-0 起,这个 cubic 滤镜已作为 '**Robidoux**' 滤镜加入 IM,并且也成为 Distort 及其 椭圆加权重采样 方法使用的默认滤镜,尤其是因为它对只有最小畸变的图像具有最小模糊性质。这并不是说它是“最好”的滤镜,甚至 Nicolas 也喜欢使用其他滤镜,但它是一个非常好的折中,就像 'Mitchell' 对正交(张量)调整尺寸而言是一个很好的折中一样。我已把这个滤镜标在 "Cubics Map" 上,这张图由 Mitchell-Netravali 调查 生成,因此你可以看到它与 '[Mitchell](#mitchell)' 滤镜有多么接近。事实上,它对正交调整尺寸图像或圆柱型畸变图像都可以是一个合理的滤镜。

Robidoux Sharp 圆柱型滤镜

'**RobidouxSharp**' 滤镜是 '[Robidoux](#robidoux)' 滤镜的略微更锐利版本,尽管有些人觉得结果太锐利。它专门设计用于在 “no-distort” 情况下,以最小误差保留包含纯黑和纯白像素的图像。具体来说,正交相邻像素的权重会与 “no-distort” 情况下对角相邻像素的负权重精确匹配。巧合的是,'[Mitchell](#mitchell)' 滤镜几乎正好落在 '[Robidoux](#robidoux)' 滤镜和 '[RobidouxSharp](#robidoux_sharp)' 滤镜之间,并且它们都属于 Cubic Keys 滤镜族。因此,用户可以从这三个滤镜中选择任意一个,来控制接近 “no-distort” 情况下结果的模糊-锐利程度。关于该滤镜的细节,见 IM 论坛上的 BC-splines 讨论。

Robidoux Soft 圆柱型滤镜

这是很久以后才加入的,并且与前面看到的其他圆柱型滤镜非常不同。没错,它模糊得多,以便更适合图像放大或增大尺寸,这使它能在砖楼照片上避免一些阶梯效果。更多信息见 BC-splines 讨论中的这篇帖子,以及 摄影处理论坛讨论 中的这段讨论。

圆柱型滤镜总结

Nicolas Robidoux 在关于 EWA 中 Jinc 滤镜的正确缩放 的漫长且仍在继续的论坛讨论中,对圆柱型滤镜做了如下总结…… 如果 Robidoux 太软而 RobidouxSharp 混叠太重,我建议你试试 Mitchell(配合 distort Resize),它差不多正好位于中间。

由于 JPEG 涉及(离散)余弦变换,我并不惊讶于基于傅里叶考虑的滤镜(Lanczos 系列等,无论是用 Sinc resize,还是用 Jinc distort)通常比基于“平滑函数良好近似”的滤镜(基于 Keys cubics 的滤镜:Robidoux、Mitchell、RobidouxSharp、CatRom,无论 resize 还是 distort)表现更好。对于 PNG(不会通过傅里叶域破坏信息)来说,这种优势似乎较小。


Nicolas 还有更多话要说。多到他有自己的章节 Nicolas Robidoux 的重采样,如今这已经是一页独立且内容丰富的页面。

Magic Kernel Sharp 2013 + 2021

Magic Kernel Sharp 是 John Costella 开发的一种图像调整尺寸算法,最初于 2013 年为 Facebook 的一个项目创建。它包含一个三抽头锐化步骤,可在调整尺寸时增强图像清晰度,使其既快速又高效。自开发以来,这个版本一直被 Facebook 用于服务器端图像调整尺寸。2021 年,Costella 改进了 Magic Kernel Sharp 以提高精度,提供至少 9 位精度,并更好地满足锐化要求。这个更新版本仍被 Facebook、Instagram 以及 pica 调整尺寸引擎和 RedKetchup 图像压缩器等其他应用采用,以出色的保真度确保高质量的图像调整尺寸。


专家滤镜控制

在上面的各个小节中,我介绍了大量特殊“专家”控制,可让你以不同方式修改各种滤镜。你可以使用 全局 Define 设置(或等价的 Set 选项)定义这些专家设置。所有专家选项的完整摘要见 "[-filter](https://imagemagick.org/command-line-options/#filter)" 的 IM 命令行选项参考页面。事实上,"[-filter](https://imagemagick.org/command-line-options/#filter)" 设置只是用于查找并适当设置专家控制,以定义给定的“命名”调整尺寸滤镜。在为具体调整尺寸或畸变图像处理操作设置滤镜时,这些设置会覆盖上面指定的默认值。 "[-filter](https://imagemagick.org/command-line-options/#filter)" 设置 'Point' 会完全绕过上述所有滤镜设置,并退化为未缩放的“最近邻”直接查找(resize)或插值查找(distort)。因此,这个命名滤镜设置实际上完全关闭了缩放图像查找滤镜。
现在,虽然这些设置可用,我还想最后强调一点。

除非你是专家(或者只是想试着玩)-- 最好不要使用它们!

图像处理专家很少,除非你确切知道滤镜做什么,以及改变它们会如何影响过滤方法,否则你最可能做的只是破坏图像处理的有效性,并产生难看的结果。尤其是在你的测试用例之外的图像上。也就是说,并不是说用户不该使用它们,许多 IM 示例确实会用到它们,但通常是为了提供某种特殊效果。当使用特殊选项时,也会解释其使用原因,你应当遵循为该效果给出的配方。当然,欢迎你使用它们,而且利用这些选项可以生成一些非常有趣、非常不寻常的效果。

'verbose' 滤镜控制

"filter:verbose" 设置也许是弄清和理解其他滤镜控制时最好的朋友。例如,你可以验证 Lanczos 滤镜是以 Sinc 加窗 Sinc support 3 的形式定义的。

  magick null: -filter Lanczos -define filter:verbose=1 \
          -resize 2    null:    | grep '^#'

[IM Text]

注意,在内部 Lanczos 滤镜是用快速多项式等价的 'SincFast'(4 瓣)函数定义的,而不是用完整的 'Sinc' 函数定义;完整 'Sinc' 函数要使用计算量大得多的三角函数库函数。这里我们看到,当 Lanczos 滤镜作为圆柱型(EWA 算法)"-distort" 滤镜使用时,它被定义为 Jinc 加窗 Jinc 滤镜。

  magick null: -filter Lanczos -define filter:verbose=1 \
          -distort SRT 0   null:   | grep '^#'

[IM Text]

'filter:verbose' 设置是用户检查由于使用各种专家设置而得到的最终结果滤镜究竟是什么的唯一方法。在以 '#' 注释的滤镜设置头之后,会返回由滤镜生成的一组数据点。这些点专门用于绘制滤镜数据图,并让你无需根据测试图像结果猜测,就能进一步验证和检查滤镜实际产生了什么。例如,提取 Welch 加窗 Sinc 滤镜的数据……

  magick null: -filter Welch -define filter:verbose=1 \
          -resize 2 null:  > filter_welch.dat

或者提取上面使用的原始 Welch 窗函数,并把窗函数缩放到 0 到 1 的 support 范围。

  magick null: -define filter:filter=Box \
                -define filter:window=Welch \
                -define filter:support=1.0 \
                -define filter:verbose=1 \
           -resize 2 null:  > window_welch.dat

然后可以用 "gnuplot" 命令绘制这些数据(就像我在上面的 加窗 Sinc 滤镜 中所做的那样)……

  gnuplot
    set grid
    plot "window_welch.dat" with lines

专家滤镜控制的其他示例

可以这样设置一个“原始 8 瓣 Sinc”滤镜……

  -define filter:filter=Sinc
  -define filter:lobes=8

直接把 Blackman 窗函数用作滤镜(就像 IM 在 v6.3.6-3 之前错误地做的那样)。

  -define filter:filter=Blackman
  -define filter:support=4.0

未定义时,窗函数默认是 'Box'。'Box' 窗函数会导致基滤镜函数不被加窗。例如,'Gaussian' 滤镜默认具有 'Box' 窗函数。box 窗函数唯一的效果,是对函数的加窗区域进行截断。见上方 Filter Support 专家控制。使用下面的设置强制使用原始 Jinc 函数(显式设置 'Box' 加窗)……

  -define filter:filter=Jinc
  -define filter:window=Box
  -define filter:lobes=3

一个 12 瓣的 'Lanczos' 加窗滤镜,只截断到所得加窗滤镜的前 8 个瓣……

  -filter Lanczos
  -define filter:win-support=12
  -define filter:support=8

这会忽略(support 截断在 8)所得加窗 Sinc 滤镜的窗口调制“尾部”(到 12),从而使它大约快四倍。不过,由于 support 截断,这可能产生一些额外但轻微的伪影。使用 Gaussian 来“模糊”图像!这相当于一次 -gaussian 5x2 操作,但通过 no-op distort 实现!

  -filter Gaussian
  -define filter:sigma=2
  -define filter:support=5
  -distort SRT 0

注意:你不能用 -resize 做这个,因为它可能短路该操作,导致操作根本不执行。从 'Mitchell-Netravali' 调查中创建一个不同的滤镜。

  -filter Cubic
  -define filter:b=0.5
  -define filter:c=0.5

用 α 值 0.4 创建你自己的 'Keys Cubic' 滤镜……

  -filter Cubic
  -define filter:c=0.4

Nicholas Robidoux 在探索 'Interpolating EWA Filters' 时创建的这个古怪滤镜

  -define filter:blur=.7071067811865475
  -define filter:c=.49257366
  -define filter:b=2.089813051319261
  -filter Cubic

用于放大图像时,像素会被转换成类似菱形的图案,这种方案类似 Blend,但使用菱形而不是方块。任何专家选项的使用都由你自行承担风险。它们不是为了生产用途,而是作为探索或生成棘手、否则不可能实现的调整尺寸函数的方法。请谨慎使用!

调整尺寸滤镜总结

以下是我在研究、重写并记录 ImageMagick 中可用的上述所有滤镜之后的个人看法。如果你认为我可能错了,或想表达自己的意见,欢迎你在 IM 论坛表达观点,并邀请我回应。插值滤镜,例如 'Hermite',非常适合大幅放大图像,在最终结果中产生最少模糊,不过输出通常还可以在后处理中再人为锐化。类 Gaussian 模糊滤镜,例如 'Mitchell',最适合基本由线稿和卡通类图像组成的图像。你可以控制滤镜对图像产生的 模糊混叠 效果,方法是使用特殊的 滤镜 Blur 设置加窗 Sinc/Jinc 滤镜 以及等价的 Lagrange,是用于真实世界图像,尤其是缩小图像时的最佳滤镜。它们在基本结果上都非常相似。更大的 support,或者更好的是设置瓣数,通常会产生更好的结果,不过也可能带来更多 振铃 效果,并增加计算成本。Cubic 滤镜 是一组快速简单、固定 support(通常为 2.0)的滤镜,从 'Hermite' 平滑插值滤镜,到定性评估得出的用于图像放大的 'Mitchell',到非常模糊的类 Gaussian 'Spline' 滤镜,或使用 'Catrom' 的锐利加窗 Sinc 类滤镜,什么都能产生。一般来说,如果调整尺寸结果原样可以接受,就不要动它,因为你更可能把事情弄坏,而不是弄好。

滤镜比较

放大…… 作为最后的比较,这里我展示 12 个代表性调整尺寸滤镜的选择。图像是在深灰背景上、一条单像素宽线条中存在混叠阶梯的放大图。原图本身就是“混叠”的,因此你应该能看到各种滤镜能多好地去除已有混叠效果。

  magick -size 10x6 xc:grey20 +antialias -draw 'fill white line 4,0 5,5' \
          -filter {_filter_type_} -resize 100x   {_result_}

[IM Output]

上图从 插值滤镜 开始,然后是 Gaussian 模糊滤镜,显示这些滤镜会产生多少模糊,并借此去除原图中的“混叠”。这些滤镜不会产生振铃。第二行从三个 加窗 Sinc 滤镜 开始,显示它们可能产生的强振铃效果。请记住,这些滤镜真正设计用于缩小图像,而不是放大。接着是使用默认“插值”设置的 'Lagrange',以及 'Catrom' 插值 cubic 滤镜。最后一张图是 'Mitchell' 滤镜,展示“专家”主观上同意用于图像放大的最佳“理想”滤镜,最终结果中四种 重采样伪影 都只有最少量存在。我自己也同意他们的发现,但仅限于放大。这就是 'Mitchell' 是 IM 默认“放大”滤镜的原因。缩小…… 为了了解 混叠 效果,这里我缩小之前做出的 大环形图像 裁剪区域(大小为 105x105 像素),看看同样的 12 个代表性滤镜各自会生成什么样的摩尔纹效果。

  magick rings_crop.png -filter {_filter_type_} -resize 100x {_result_}

[IM Output]

如你所见,插值滤镜 滤镜会产生非常严重的混叠摩尔纹效果,这是它们生成的分块伪影带来的副作用。另一方面,Gaussian 模糊滤镜 的模糊伪影从结果图像中去除了所有这类分块摩尔纹效果,但结果图像整体会模糊(线条不清晰)。'[Gaussian](#gaussian)' 滤镜本身确实显示出由其无限(IIR)滤镜被 Filter Support 设置 截断造成的几乎不可察觉的混叠效果,但这非常轻微。另一方面,加窗 Sinc 滤镜 会生成非常锐利的图像,并在三个代表性滤镜中产生强度大致相同的圆形摩尔纹效果。这是这些滤镜产生的振铃伪影生成干涉图案造成的。最后,cubic 滤镜也显示出一些非常轻微的摩尔纹效果,但这只是由于负瓣振铃。'[Mitchell](#mitchell)' 滤镜产生的振铃效果最少。注意,'Mitchell' 确实会从几乎所有调整尺寸伪影中产生非常轻微的效果。也就是:网格状摩尔纹 - 混叠/分块,圆形摩尔纹 - 振铃,以及线条模糊。不过所有伪影都处在非常低的水平,这也是它成为优秀通用滤镜的原因。下面是另一个比较,这次是把 较小环形图像 进一步强烈缩小。

  magick rings_sm_orig.gif -filter {_filter_type_} -resize 100x {_result_}

[IM Output]

如你所见,插值滤镜 会产生大量 混叠伪影,而 Gaussian 模糊滤镜 倾向于比其他滤镜模糊掉更多线条。但所有其他滤镜通常都能做得还算合理。

最好的滤镜?

这需要你自己找出答案。不过通常它取决于你处理的图像类型以及你正在做的调整尺寸类型。放大图像时,'Mitchell' 可能是你能使用的几乎最好的滤镜;而基本上任何 加窗滤镜(默认是 'Lanczos')都适合缩小图像,尤其是在涉及某种低层图案时。不过,如果没有图案,但有大量直边(例如 GIF 透明度),你可能最好使用锐化的 Gaussian 滤镜,或者同样使用 'Mitchell',以避免强振铃效果。'Lagrange' 滤镜也相当不错,特别是在带有较大 Filter Support 设置 时,用于缩小图像效果很好。感兴趣的话,我建议查看 IM 用户讨论主题 a way to compare image quality after a resize?,它基本说明无法定量判断“最好的滤镜”,只有定性或主观的“最佳滤镜”。选择权在你,而选择正是 ImageMagick 的关键特性。

IM 的默认滤镜……

正因为这些原因,'Mitchell' 是放大图像,以及缩小涉及透明度的图像或包含调色板(或 colormap)的图像时的默认滤镜。不过在其他所有情况下,也就是缩小普通图像(通常是照片)时,会使用 'Lanczos'。对于 Distort,滤镜设置默认是 'Robidoux' 滤镜,它专门设计用于在没有实际畸变发生时尽量减少图像模糊。当然,你可以覆盖这些选择。

Nicolas Robidoux

Nicolas Robidoux 是一位图像处理专家,对于如何从图像调整尺寸中获得绝对最佳结果,他还有更多内容要说和推荐。多到他有自己的章节……
Nicolas Robidoux 的重采样