ImageMagick 示例 --
图像变换

索引
ImageMagick 示例前言和索引
艺术化变换
计算机视觉变换
阴影 3D 高亮
使用 FX,DIY 图像操作符
Evaluate 和 Function,快速 FX 操作符
渐变上的数学运算
这些操作会对图像的整体外观产生重大变化,无论是为了视觉效果还是艺术效果。但是,虽然图像的整体外观发生了变化,通常是戏剧性的变化,但原始图像本身通常仍然在结果中可见。

艺术化变换

凸起或凹陷边框

"-raise" 操作符是一个非常简单的图像变换,几乎算不上变换。它所做的只是为现有图像添加一个矩形斜角高亮。

  magick rose: -raise 5  rose_raise.gif
[IM Output]
可以使用操作符的“加号”形式生成反向的凹陷效果...

  magick rose: +raise 5  rose_sunken.gif
[IM Output]
此操作符有点像 框架 图像,但它不是添加额外的像素作为边框,而是 "-raise" 操作符重新着色图像的边缘像素。这使得它成为一个图像变换。
实际上,图像框架 是通过添加边框,然后凸起边框来实现的!
该操作符仅适用于矩形图像,对于具有透明背景的图像将失败,因为颜色修改也将是透明的。基本上,它是一个相当愚蠢的操作符!

添加内边框

用户希望添加一个覆盖图像边缘的边框,而不是在图像外部添加边框。解决方案是在图像周围绘制一个矩形。由于内置的 rose in 是 70x46 像素,因此这是结果。

  magick rose: -fill none -stroke navy -strokewidth 11  \
          -draw 'rectangle 0,0 69,45'   inside_border.jpg
[IM Output]
添加的边框宽度由矩形的 "-strokewidth" 控制。也就是说
{stroke width}  =  {border width} * 2 - 1
因此,上述 6 像素边框需要 "-strokewidth" 为 11。如果您不知道图像的大小,则可以 修剪 图像,然后像往常一样添加 边框。这可能更容易,尽管可能不如通用。

  magick rose: -bordercolor green -shave 6x6 -border 6x6 inside_border2.jpg
[IM Output]

随机像素扩散

"-spread" 将用源图像中随机的附近颜色的颜色替换每个像素。此随机选择是根据 像素插值虚拟像素设置 的使用情况进行的。
例如...

  magick -size 80x40 xc:red xc:blue -append -spread 5 spread_interpolated.png
[IM Output]
如果您要检查像素图像,您会发现某些像素可能混合了红色和蓝色。也就是说,它们是插值的,而不仅仅是扩散或交换。对于较小的距离值,这更为明显。
另请注意,"-spread" 还会使用 虚拟像素设置

  magick -size 80x80 xc: -virtual-pixel black -spread 10 spread_virtual.png
[IM Output]
如您所见,您获得了一个随机的边框,大部分是纯黑色的虚拟像素,尽管还有一些灰色的像素是从图像的真实像素和虚拟像素之间的边框插值而来。为了获得更传统的扩散像素效果,您可以通过强制使用 "-interpolate Nearest" 来强制特定像素的颜色查找,从而防止这种颜色混合。为了避免虚拟像素和可能的“边缘颜色偏差”问题,我建议您使用 "-virtual-pixel Mirror"。因此,这是一种更传统的随机“扩散”像素...

  magick rose: -interpolate nearest -virtual-pixel mirror \
                -spread 5   spread_rose.png
[IM Output]

建设中
上述的主要问题是您可能会丢失图像中的一些像素数据。也就是说,像素不是“交换”的,而是随机复制的,这意味着图像中的特定像素可能会被复制或丢失。从 IM v6.9.2-2 开始,您可以使用 "+spread" 来实际交换图像内的像素,这意味着图像中的任何像素都不会被复制或丢失。原始图像中的每个像素仍然存在,只是被移到了新的位置。但是,由于像素的处理方式,像素可能会被“双重交换”。也就是说,一个特定的像素可能会被交换,但随后会被选中再次与后面的像素交换。这意味着特定像素的漂移可能比扩散参数请求的更远。这种双重交换还意味着像素更有可能向右下角扩散。当然,这种运动是平衡的,但大量像素向左上角的漂移较小。
例如,这里我扩散了像素,并在前面添加了参考。

  magick -size 40x40 xc:red xc:blue -append \
          \( +clone +spread 5 \) +append spread_bias.png
[IM Output]
请注意,一些红色像素向下扩散得更多,但您也会看到一些蓝色像素向上扩散得超过预期(尽管朝向图像的左侧)。当您使用较小的距离参数进行扩散时,此问题更为明显。解决这种双重交换问题并不容易,我们正在寻找一种“有限区域洗牌”算法来解决它。但与此同时,您至少可以通过两次进行扩散来减轻方向偏差,并在 横向(左上到右下对角线镜像)扭曲时使用。

  magick -size 40x40 xc:red xc:blue -append \
          \( +clone +spread 5 -transverse -spread 5 -transverse \) \
          +append spread_no_bias.png
[IM Output]
当然,这确实使扩散更加明显,并且线性度降低,但至少它没有方向偏差或像素重复/丢失。上述添加内容源自论坛讨论:t=28043 IM 论坛讨论 重新排列垂直像素行

暗角照片变换

一个特殊的操作符,用于使图像呈圆形并具有柔和模糊的轮廓。

  magick rose: -background black -vignette 0x5  rose_vignette.gif
[IM Output]
通过使用零(或非常小的)sigma,您可以去除模糊,并生成椭圆或椭圆形框架。但是请注意,它实际上并没有使用最大的可能椭圆,因此您可能需要自己动手制作。

  magick rose: -background black -vignette 0x0  rose_vignette_0.gif
[IM Output]
您可以将其与透明度(和 PNG 格式)一起使用...

  magick rose: -alpha Set -background none -vignette 0x3  rose_vignette.png
[IM Output]
另一种参数方法是为第二个sigma组件使用一个非常大的数字,然后使用第一个radius来定义模糊的扩散范围。这会产生“线性”分布,而不是更常见的暗角模糊的高斯分布。

  magick rose: -background black -vignette 5x65000  rose_vignette_linear.gif
[IM Output]
带有柔和边缘的缩略图 中演示了另一种更矩形暗角的技术,该技术为图像产生了柔和的边缘。

复杂的拍立得变换

感谢 Timothy Hunter(RMagick 名人)完成的工作,"-polaroid" 变换操作符已添加到 IM v6.3.2 中。
Polaroid® 是 Polaroid Corporation 的注册商标。
例如,这里我给照片缩略图一个拍立得外观。图像正在查看 凯旋门内(向下)的螺旋楼梯,巴黎。这是一个非常长的楼梯!。

  magick spiral_stairs_sm.jpg -thumbnail 120x120 \
          -bordercolor white -background black  +polaroid  poloroid.png
[IM Output]
请注意,生成的图像具有半透明阴影,因此您要么必须使用 PNG 格式的图像,要么 "-flatten" 将结果展平到 GIF 或 JPG 格式的固定背景颜色上。
此操作符非常复杂,因为它添加了边框(根据 "-bordercolor" 设置),“卷曲”纸张,并在阴影上添加反向卷曲。阴影颜色可以通过 "-background" 颜色设置来控制。如您在上面看到的,操作符的加号形式将以随机量旋转结果。此操作符使 照片索引 比您原本获得的更加有趣且不那么静态。
操作符的减号形式允许您控制图像的旋转角度。

  magick spiral_stairs_sm.jpg -thumbnail 120x120 \
          -bordercolor AliceBlue -background SteelBlue4 -polaroid 5 \
          poloroid_5.png
[IM Output]
如果图像具有 "-caption" 元数据,则该文本也将通过 "caption:" 图像创建操作符添加到拍立得框架的下边框中。也就是说,它将换行到照片的宽度。

  magick -caption '%c %f\n%wx%h' spiral_stairs_sm.jpg -thumbnail 120x120 \
          -bordercolor Lavender  -background gray40  +polaroid \
          poloroid_captioned.png
[IM Output]
其他标准文本设置(根据 "caption:"),允许您控制添加的标题的外观。

  magick spiral_stairs_sm.jpg -thumbnail 120x120 -font Candice -pointsize 18 \
          -bordercolor Snow -background black -fill dodgerblue -stroke navy \
          -gravity center  -set caption "Spiral Stairs\!"  -polaroid 10 \
          poloroid_controls.png
[IM Output]
"-caption" 图像元数据属性之所以使用,是因为内部使用了 "caption:" 文本到图像生成器。

另一方面,IM 命令 "montage" 使用 "-label",因为它使用非换行的 "label:" 文本到图像生成器。
变换使用 旋转波浪 剪切扭曲为照片图像添加一点“卷曲”,这往往会在生成的图像的文本中产生水平模糊线。这是一个众所周知的 图像扭曲 问题(请参阅 旋转细线),可以通过使用 超级采样 技术来解决。基本上,我们将拍立得生成到我们真正想要的的两倍大小,然后我们将图像调整为最终的正常大小。图像大小的减小有效地锐化了生成的图像,更重要的是标题文本。但是,为了使此方法有效,我们不仅需要一个至少为最终大小两倍的图像,而且还需要为图像添加更大的边框,并以其正常 "-density" 的两倍绘制文本。不要增加字体的 "-pointsize",因为那样不会以相同的方式放大文本。


  magick -caption 'Spiral Staircase, Arc de Triumph, Paris, April 2006' \
          spiral_stairs_sm.jpg  -thumbnail 240x240 \
          -bordercolor Lavender -border 5x5   -density 144  \
          -gravity center  -pointsize 8   -background black \
          -polaroid -15     -resize 50%     poloroid_modified.png
[IM Output]
如您所见,即使我们使用了更小的字体大小,字幕文本仍然非常清晰锐利且易读。原始图像中可能存在的任何其他精细细节也是如此。唯一的缺点是生成的图像阴影会更小,并且模糊度降低。为了完全控制拍立得转换,您可以自己完成所有步骤。Tim Hunter 页面上记录的原始技术,RMagick 拍立得效果。步骤包括:创建和追加字幕、添加边框、用波浪卷曲照片、添加反向卷曲阴影,最后旋转图像。有关更多示例和其他 DIY 方法,请参阅拍立得缩略图示例拍立得照片蒙太奇。您可能还会对RubbleWeb IM 示例,其他中的一些拍立得示例感兴趣。

油画,彩色斑点

-paint”运算符旨在将图片转换为绘画,方法是在画布上应用厚厚的“斑点”颜料。结果是将邻域颜色合并成更大的单色区域。

  magick rose: -paint 1   rose_paint_1.gif
  magick rose: -paint 3   rose_paint_3.gif
  magick rose: -paint 5   rose_paint_5.gif
  magick rose: -paint 10  rose_paint_10.gif
  magick rose: -blur 0x3 -paint 10  rose_blur_paint_10.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] ==> [IM Output]
请注意,在颜料斑点的半径较大时,斑点开始呈现方形外观。可以通过在预处理时稍微模糊图像来稍微平滑此效果,如上图中的最后一个图像所示。这是一种有趣的效果,可用于制作一些奇特而奇妙的背景图像。例如,请参阅其在背景示例中的用法。最后警告。虽然“-paint”应该生成单一纯色区域,但在较大的半径值下,它往往会在某些区域产生垂直渐变。这非常令人讨厌,可能是错误。有人知道吗?可以使用“-paint”的替代方案。一种是使用“-statistic Mode”代替,它为每个像素分配给定矩形邻域内的“主要颜色”,并且可以产生更好的结果。

  magick rose: -statistic Mode 10 rose_paint_mode.gif
[IM Output]
另一种是使用一些形态学方法,更具体地说,是彩色图像的强度变体。例如,以下是玫瑰上的“OpenIntensity”形态。

  magick rose: -morphology OpenI Disk rose_paint_open.gif
[IM Output]
这里我使用“CloseIntensity”和稍小的“Disk”。

  magick rose: -morphology CloseI Disk:2.5 rose_paint_close.gif
[IM Output]
您不必使用“磁盘”,而是可以为其创建的斑点设计自己的“画笔”形状内核。例如,使用对角线画笔怎么样?

炭笔画,场景的艺术家素描

炭笔效果旨在模拟艺术家对给定图像的炭笔素描。运算符“-charcoal”在某些方面类似于计算机视觉使用的边缘检测变换。基本上,它试图将图像中物体的主要边界和边缘转换为铅笔和炭笔阴影。一个参数应该表示边缘线的粗细。

  magick rose: -charcoal 1   rose_charcoal_1.gif
  magick rose: -charcoal 3   rose_charcoal_3.gif
  magick rose: -charcoal 5   rose_charcoal_5.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]
有关在真实图像上使用炭笔变换的更好示例,请参阅照片的炭笔素描
从技术上讲,“-charcoal”运算符是“-edge”运算符,并对原始图像的灰度转换应用了一些阈值处理。

铅笔素描变换

-sketch”运算符基本上将线条笔触模式应用于图像,以生成看起来像艺术铅笔素描的效果。参数控制笔触的长度和角度。但是,最好将其应用于具有明显阴影的较大图像。请参阅铅笔素描,了解此运算符的完整示例及其内部工作原理。

浮雕,创建金属质感

-emboss”运算符试图生成灰度图像在金属板上进行酸性压印的效果。在许多方面,它与我们将在下面看到的“-shade”运算符非常相似,但没有 3D 外观边缘。其参数是半径/sigma,只有 sigma 重要。我发现该参数用处不大,实际上可能存在错误。该参数在最近版本的 IM 中也发生了变化。我只是不知道发生了什么事。如果您能理解,请帮助我理解。

  magick rose: -emboss 0x.5  rose_emboss_0x05.gif
  magick rose: -emboss 0x.9  rose_emboss_0x09.gif
  magick rose: -emboss 0x1   rose_emboss_0x10.gif
  magick rose: -emboss 0x1.1 rose_emboss_0x11.gif
  magick rose: -emboss 0x1.2 rose_emboss_0x12.gif
  magick rose: -emboss 0x2   rose_emboss_0x20.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
该运算符是灰度运算符,这意味着它将分别应用于三个颜色通道。因此,应仅应用于灰度图像。如您在上面看到的,彩色图像可能会产生一些奇怪的效果。

  magick rose: -colorspace Gray  -emboss 0x.5  rose_g_emboss_0x05.gif
  magick rose: -colorspace Gray  -emboss 0x.9  rose_g_emboss_0x09.gif
  magick rose: -colorspace Gray  -emboss 0x1   rose_g_emboss_0x10.gif
  magick rose: -colorspace Gray  -emboss 0x1.1 rose_g_emboss_0x11.gif
  magick rose: -colorspace Gray  -emboss 0x1.2 rose_g_emboss_0x12.gif
  magick rose: -colorspace Gray  -emboss 0x2   rose_g_emboss_0x20.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
 If anyone knows exactly what the emboss algorithm is supposed to do,
please let me know.

隐写术,将秘密图像隐藏在图像中

-stegano”运算符实际上更像是一个“有趣”的运算符。例如,间谍可以使用它将信息隐藏在随机图像的“混乱”中。首先警告...
不要将 JPEG、GIF 或任何其他“有损”图像编码与隐写术一起使用
例如,让我们生成一条您想发送给同伴间谍的密码信息(图像)...

  magick -gravity center -size 50x40 label:"Watch\nthe\nPidgeon" message.gif
  magick identify message.gif
[IM Output]
[IM Text]
请注意,我们还需要消息图像的大小(36x43 像素),因此在上面进行识别。接下来将其放入某个图像中并进行偏移。使用的偏移量(和消息大小)是隐藏消息的加密“密钥”。

  magick composite message.gif rose: -stegano +15+2  rose_message.png
[IM Output]
现在您可以将该图像发送给您的同胞,他们可能已经知道消息的大小和偏移量。我们可以恢复隐藏在图像中的消息...

  magick -size 50x40+15+2 stegano:rose_message.png message_recovered.gif
[IM Output]
包含图像越大,恢复的图像质量越好,因此将小图像隐藏在大图像中比上面显示的示例更好。为了向您展示隐藏消息是如何分布在整个容器图像中的,让我们将组合图像与原始图像进行比较。

  magick compare -metric PAE rose: rose_message.png   rose_difference.png
[IM Output]
[IM Text]
这显示了消息图像是如何加密并分布到整个容器图像以隐藏它。此外,上面返回的“PAE”度量表明最大差异仅是此图像使用的 8 位颜色值中的一个颜色值。也就是说,微不足道。微不足道到图像的细微更改或修改都会破坏隐藏在其中的消息。差异如此之小,您甚至无法使用 JPEG 及其有损压缩作为图像格式,或任何其他有损图像格式(包括 GIF)作为容器图像。此外,如果您使用错误的“偏移密钥”,您将无法获取消息...

  magick -size 50x40+14+2 stegano:rose_message.png message_bad.gif
[IM Output]
您还可以使用区域设置来限制要隐藏消息的图像区域。尝试恢复消息时也需要相同的设置。这可能会使在大型图像中查找和解码隐藏的消息变得更加困难,尤其是在限制在“繁忙”区域时,难度将成倍增加。但是请注意,这不是一种非常安全的加密技术。特别是如果原始源图像也可用。图像的频率分析通常会让攻击者知道存在隐藏的消息。作为图像版权保护的一种方法,“隐写术运算符”也是无用的,因为对图像的最小更改都会破坏消息,从而降低其有效性。作为间谍工具,它也不是很好,对于合理大小的图像,它只有少量“组合”。任何大致了解您在做什么的人都可以很快破解它。最好坚持使用众所周知且经过时间考验的加密方法。它唯一真正实用的用途是作为一种有趣的工具,或者作为向现有图像添加极少量噪声的方法。

加密图像数据

运算符“-encipher”和“-decipher”基本上会将图像数据加密成乱码。也就是说,图像内容本身在图像稍后解密之前根本无法识别。例如,这可以用于保护公共服务上的敏感图像,以便只有拥有秘密密码的其他人才能稍后查看它。但首先警告...
不要将 JPEG、GIF 或任何其他“有损”图像编码与加密一起使用
例如,让我们使用保存在不太“秘密”的文件“pass_phrase.txt”中的密码来加密上面创建的秘密消息图像。

  magick message.gif    -encipher pass_phrase.txt  \
          -depth 8 png24:message_hidden.png
[IM Output] ==> [IM Output]
加密图像假定它使用 8 位图像文件格式保存。因此,建议通过在最终保存到输出文件之前设置“-depth 8”来强制执行此限制。

上面也需要“png24”以确保输出不是调色板或颜色映射的“png8:”图像,这也不起作用。
如您所见,生成的图像看起来像是完全的垃圾,没有图像真实内容的任何指示。现在您可以将该图像发布到网络上,只有知道确切原始密码的人才能恢复图像数据...

  magick message_hidden.png -decipher pass_phrase.txt message_restored.gif
[IM Output]
但是请注意,如果图像数据以某种方式损坏,您将无法恢复它。这包括如果 PNG 使用灰度图像格式类型保存。因此,只能使用无损图像格式,例如 PNG、MIFF、TIFF,甚至像素枚举文本。但是,使用有损图像格式,例如 JPEG、PNG8 和 GIF,会损坏图像数据,从而破坏最终的加密。请注意,可能描述图像的任何元数据仍然是明文。这意味着,您可以使用图像自己的“注释”字符串作为密码来加密图像,或使用使用较小密码加密的注释。这是一个简单的想法,可以使密码更加多变。加密图像可能只是一个步骤。将结果再进一步就可以生成一个图像,如果没有一些额外的处理,它就不会简单地解密。例如,这里我使用一些简单的非破坏性扭曲来迷惑任何试图以正常方式解密图像的人。

  echo "password" | magick message.gif -encipher - \
                      -transpose  -depth 8   png24:message_obfuscate.png
  echo "password" | magick message_obfuscate.png -transpose \
                      -decipher -  message_restored_2.png
[IM Output] ==> [IM Output] ==> [IM Output]
如果您没有在上面的解密命令中包含“-transpose”,则图像将无法正确解密。另请注意,由于使用了流密码(请参阅下面的专家说明),因此仅使用某种“-roll”将无法防止图像被解密,至少部分如此。请注意,在上面我没有使用文件来保存“密码”,而是使用标准输入将短语馈送到“magick”命令中,这允许您使用其他程序或命令从用户那里获取短语,生成它,或其他方法,而不是使用包含明文密码的文本文件。密码也可以从其他免费下载的文件和图像中生成。例如,您可以使用众所周知、免费下载的参考图像的签名或注释字符串来解密图像。例如,这里我使用“rose.gif”图像的签名来加密,然后解密“message.gif”图像。

  magick identify -format %# rose.gif |\
    magick message.gif  -encipher - -depth 8    png24:message_signed.png
  magick identify -format %# rose.gif |\
    magick message_signed.png   -decipher -   message_restored_3.png
[IM Output]  + [IM Output] ==> [IM Output]  + [IM Output] ==> [IM Output]
从 IM v6.4.8-0 开始,“-encipher”和“-decipher”使用的文件可以是二进制文件。因此,您甚至可以直接使用图像本身作为密码。

  magick message.gif   -encipher rose.gif  -depth 8  png24:message_binary.png
  magick message_binary.png   -decipher rose.gif   message_restored_4.png
[IM Output]  + [IM Output] ==> [IM Output]  + [IM Output] ==> [IM Output]
在 IM v6.4.8-0 之前,二进制文件会在找到的第一个“NULL”字符处停止。如果使用 PNG 图像,则这种情况会很早发生。
此技术是精确的(除非某些数据在传输过程中被破坏)。因此,您可以使用它来加密包含其他隐藏信息的图像,例如隐写术图像。这意味着即使当局解密了图像,或强迫您泄露密码,他们也会看到实际的图像,但该图像可能不是最终的隐藏图像。

IM v6.3.8-6 版本中添加了“-encipher”和“-decipher”操作符,但需要在构建配置中包含“--enable-cipher”选项。然而,到了 IM v6.4.6 版本(具体时间不详),这个配置项不再需要,它变成了标准的配置设置。因此,您现在很可能可以直接使用它。
加密的实现是使用基于分组密码的自同步流密码。

这意味着即使图像的部分下载内容因传输错误而损坏,您仍然可以对其进行解密。即使图像的某些部分被破坏,您也可以解密并检查成功下载的部分。您不需要下载整个图像才能解密并检查成功下载的部分。

但是,您确实需要密码才能有机会成功解密图像,因为它是一种非常强大的加密方式。

像素化图像

像素化图像基本上是将图像转换为一系列较大的彩色“像素”,这些像素只能显示原始图像的模糊轮廓。这两种技术都涉及缩小图像(以生成更少的像素),然后以某种方式放大它们,以便使用缩放操作符采样操作符创建“像素块”来生成颜色块。正是图像的缩减方式决定了将使用哪种颜色。单个像素样本或合并的平均颜色。

  magick rose: -sample 25%  -scale 70x46\!  rose_pixelate_sampled.gif
  magick rose: -scale  25%  -scale 70x46\!  rose_pixelate_scaled.gif
  magick rose: -resize 25%  -scale 70x46\!  rose_pixelate_resized.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]
如您所见,“采样”区域将具有更明显的(锯齿状)“像素”,而其他两种方法则使用合并或平均颜色,这往往会为每个“像素”产生更柔和但更准确的颜色表示。另请参阅保护某人的匿名性,了解如何在图像的较小蒙版区域(例如人脸)上使用此方法的示例。

像素网格

图像网格化与图像像素化非常相似。在这种情况下,我们只想放大图像,以生成图像细节的清晰像素级视图。通常是一个非常小的图像。最简单的方法就像前面的示例一样,只需缩放一个小图像,以放大像素。

  magick rose: -crop 10x10+12+20 +resize  grid_input.png
  magick grid_input.png  -scale  1000%  grid_scale.png
[IM Output] ==> [IM Output]
简单缩放的问题在于,在像素颜色相似的区域,您可能难以看到单个“像素块”。我们需要在像素周围添加边框以将其分隔开。为此,我们需要覆盖一个生成的图块蒙版。请参阅使用内存中已有的图像进行平铺,了解使用生成平铺图像的各种方法,在一个命令中。
在这里,我们生成一个黑白“网格”,并使用屏幕合成进行叠加(叠加白色,同时保持黑色区域不变)。

  magick -size 10x10 xc: -draw 'rectangle 1,1 9,9' -write mpr:block +delete \
          grid_input.png -scale 1000% -size 101x101 tile:mpr:block \
          +swap -compose screen -composite grid_blocks.png
[IM Output]
请注意,用于生成图块的大小为scale*image_size+gap_size(在本例中为 10*10+1 => 101)。我还交换了这两个图像,以便最终图像大小来自图块图像,而不是来自缩放图像(缩放图像的大小少了一个像素)。但是,这可能会丢失原始图像中的任何图像元数据,因为我使用了图块图像作为目标。
在这里,我生成圆形的彩色“斑点”,但这次使用了乘法合成(叠加黑色,同时保持白色区域不变)。

  magick -size 10x10 xc: -draw 'circle 5,5 1,3' -negate \
               -write mpr:spot +delete \
          grid_input.png -scale 1000% -size 101x101 tile:mpr:spot \
          +swap -compose multiply -composite grid_spots.png
[IM Output]
您也可以通过对图块叠加进行反转(黑色区域变为透明)并使用复制不透明度合成而不是乘法来使网格边框透明。也可以添加其他颜色,但要使此方法有效,您必须使用包含真实透明度的图块图像。为此,您需要将黑白图块图像转换为形状蒙版
例如,这里我使用基本形态学操作符在彩色叠加层上生成菱形“孔”。为此,绘制单个“种子”像素并使用菱形形态学内核进行扩展。

  magick -size 10x10 xc: -draw 'point 5,5' -morphology Erode:4 Diamond \
          -background Navy -alpha shape -write mpr:diamond +delete \
          grid_input.png -scale 1000% -splice 1x1+0+0 \
          -size 101x101 -background none tile:mpr:diamond \
          -alpha set -compose Over -composite grid_diamonds.png
[IM Output]
请注意,“tile:”编码器会将图像中的任何透明度替换为当前背景颜色。如果您想保留平铺图像的透明度,请设置“-background none”或“-compose Src”。前者更容易。
请注意,从技术上讲,alpha 形状可以在保存图块图像之前或在平铺图块图像之后(在将其叠加之前)进行。选择权在您手中。最后一种技术是使用错误的重采样滤镜来产生重采样失败,以生成每个像素的锯齿状圆圈。这不是一个好方法(滥用图像处理失败),但它确实形成了像素网格。

图块间距

类似的问题是在图像中分隔图块网格。这不仅仅是将单个像素缩放成“像素块”,而是将图像的矩形区域之间插入空间。也就是说,在图像的规则间隔处拼接额外的像素。目前,最佳解决方案是将图像分解成行和列,并在拼接额外间距到每个图块上,然后再附加图块以重新组合在一起。例如……

  magick rose: -background SkyBlue \
          -crop 10x0 +repage -splice 3x0 +append \
          -crop 0x10 +repage -splice 0x3 -append \
          grid_tile.png
[IM Output] ==> [IM Output]
这是另一种方法,它也分离原始图像中的图块,但随后使用一些DIY FX 表达式根据图块的旧位置计算其新位置。

  magick rose: -crop 10x10 \
          -set page '+%[fx:page.x+3*page.x/10]+%[fx:page.y+3*page.y/10]' \
          -background skyblue -layers merge +repage  grid_tile_fx.png
[IM Output]
上面的数字“3”是要添加的间隙宽度,“10”是图块大小。您只需要在结果中添加边框或其他边缘即可。稍微多做一些工作,您甚至可以为上述网格中每个图块的放置添加一些随机的“抖动”,以获得不太规则的效果。这两种方法的问题在于,生成大量的小图像,然后再将它们拼接在一起确实会产生大量的工作。特别是对于非常小的图块尺寸。IM 论坛讨论中提议了一种更好的方法,即对拼接操作符进行特殊扩展拼接(添加图块网格间隙)

计算机视觉变换

边缘检测

-edge”操作符突出显示图像中颜色渐变的区域。它是一个灰度操作符,因此分别应用于三个颜色通道中的每一个。

  magick mask.gif -edge 1   mask_edge_1.gif
  magick mask.gif -edge 2   mask_edge_2.gif
  magick mask.gif -edge 3   mask_edge_3.gif
  magick mask.gif -edge 10  mask_edge_10.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]
如您所见,边缘仅添加到颜色渐变超过 50% 白色的区域!我不知道这是错误还是故意的,但这意味着上述边缘几乎完全位于原始蒙版图像的白色部分。在使用“-edge”操作符的结果时,这一事实可能极其重要。例如,如果您要对包含黑色轮廓的图像进行边缘检测,“-edge”操作符会“加倍”黑色线条,产生奇怪的结果。

  magick piglet.gif  -colorspace Gray  -edge 1 -negate  piglet_edge.gif
[IM Output] ==> [IM Output]
但是,在进行边缘检测之前对图像进行反转,加倍的线条会向内移动并合并在一起,从而消除“加倍线条”效果。

  magick piglet.gif -colorspace Gray \
                 -negate -edge 1 -negate    piglet_edge_neg.gif
[IM Output]
我发现边缘往往过于锐利,导致生成的图像边缘不平滑。因此,我发现对结果进行非常轻微的模糊处理可以改善外观。

  magick piglet_edge_neg.gif  -blur 0x.5  piglet_edge_blur.gif
[IM Output]
在这里,我将边缘检测应用于彩色图像和灰度版本,以向您展示其对照片类图像的影响。

  magick rose:                  -edge 1  rose_edge.gif
  magick rose: -colorspace Gray  -edge 1  rose_edge_grey.gif
[IM Output] [IM Output]
如您所见,在不将图像转换为灰度的情况下,不同颜色通道的边缘是完全独立生成的。

Canny 边缘检测器

在 IM v6.8.9-0 版本及更高版本中,IM 现在支持 Canny 边缘检测器。(请参阅 IM 论坛上的公告示例)。这是一种非常先进的边缘检测算法,它在所有锐利边缘处生成非常强(二进制)的单像素宽线条,并且干扰噪声非常少。例如,这里我们将其应用于上面使用的测试图像。

  magick mask.gif           -canny 0x1+10%+30%  mask_canny.gif
  magick piglet.gif         -canny 0x1+10%+30%  piglet_canny.gif
  magick piglet.gif -negate -canny 0x1+10%+30%  piglet_canny_neg.gif
  magick rose:             -canny 0x1+10%+30%  rose_canny.gif
[IM Output] ==> [IM Output]
[IM Output] [IM Output] [IM Output]
如您所见,它产生的结果比上面的边缘操作符更锐利。模糊的反锯齿边缘对结果几乎没有影响,产生了细的位图线条。此外,如小猪图像所示,它不像之前的边缘操作符那样放置在特定的一侧。因此,对输入图像进行反转没有影响。但与所有边缘检测器一样,它在具有“繁忙”背景的真实世界图像(例如内置的玫瑰图像)中可能会遇到问题。这个干净的结果在后面的霍夫线检测中非常重要。

来自抗锯齿形状的边缘轮廓

普通边缘检测方法的最大问题是结果高度锯齿化。也就是说,无论形状是平滑(反锯齿)还是锯齿化,它都会产生非常类似阶梯的像素效果。例如,这里是一个平滑的反锯齿语音气泡(“WebDings”字体字符“(”)。

  magick -size 80x80 -gravity center -font WebDings label:')' voice.gif
[IM Output]
以下是其边缘检测后的图像……

  magick voice.gif -edge 1 -negate   voice_edge.gif
[IM Output]
如您所见,它看起来很糟糕,边缘外部有一些轻微的反锯齿,线条内部则完全是锯齿状(阶梯状)外观。对图像进行反转会在图像外部生成类似的轮廓,但在线条外部也有很强的锯齿化。

  magick voice.gif -negate -edge 1 -negate   voice_edge_negate.gif
[IM Output]
当您已经有一个具有反锯齿边缘的图像时,另一种方法是生成原始形状的“抖动”克隆的差分图像。例如,这里我们找到原始图像和向右偏移(或抖动)1 个像素的图像之间的差分图像。

  magick voice.gif \( +clone -roll +1+0 \) -compose difference -composite \
          -negate   voice_jitter_horiz.gif
[IM Output]
请注意,这不会为水平倾斜的边缘产生良好的边缘。但是,通过组合水平和垂直抖动差分图像,我们可以获得形状非常好的反锯齿轮廓。

  magick voice.gif \
          \( -clone 0 -roll +1+0 -clone 0 -compose difference -composite \) \
          \( -clone 0 -roll +0+1 -clone 0 -compose difference -composite \) \
          -delete 0  -compose screen -composite -negate  voice_jitter_edge.gif
[IM Output]
此技术还具有无论蒙版是否反转都能起作用的优点。但是请注意,结果相对于原始图像有 1/2 像素的偏移,因此可能需要进一步的“变形”处理来重新对齐原始形状或轮廓,如果需要将两者组合以获得所需的结果。

来自位图形状的边缘轮廓

位图图像更难处理,因为它们没有任何可用于生成平滑轮廓的反锯齿像素。例如,这里是一个从“WebDings”字体(字符“Y”)中提取的花哨“心形”形状。但是我故意将其生成为锯齿状位图,以模拟从网络下载的糟糕位图图像。例如,包含透明度的 GIF 图像的轮廓。

  magick +antialias -size 80x80 -gravity center \
          -font WebDings label:Y   heart.gif
[IM Output]
所以我们有这张糟糕的图像,但我们想要找到图像的轮廓而不是其形状。直接使用边缘检测只会在线条的外部生成纯位图边缘。

  magick heart.gif -edge 1 -negate   heart_edge.gif
[IM Output]
反转边缘会生成边缘图像,但用于黑色区域的内部。

  magick heart.gif -negate -edge 1 -negate   heart_edge_negate.gif
[IM Output]
通过将上述两者相加,您可以在位图形状边缘上获得 2 像素的边缘。

  magick heart.gif \( +clone -negate \) -edge 1 \
          -compose add -composite  -negate  heart_edge_double.gif
[IM Output]
如您所见,生成的图像高度锯齿化,轮廓中存在“阶梯状”效果,即使原始图像在这方面本身也不算太糟糕。这不是一个好的解决方案。可以使用“EdgeIn”形态学方法或其他类似方法创建稍微更好的边缘。

  magick heart.gif  -negate -morphology EdgeIn Diamond -negate heart_edgein.gif
[IM Output]
类似的效果可以通过正确地使用调整大小模糊边缘,然后再使用太阳化提取形成边缘的中间灰色像素来实现。可以通过添加“-filter Cubic”设置或其他重采样滤镜来生成更厚的边缘。

  magick heart.gif -resize 400% -resize 25% \
          -solarize 50% -evaluate multiply 2 -negate heart_resize.gif
[IM Output]
或者,为了获得更可控的模糊效果,您可以只模糊形状并以类似的方式提取边缘。我发现“0.7”的模糊效果最好,并且将限制设置为 3 个像素以加快速度。


  magick heart.gif -blur 3x.7 -solarize 50% -level 50%,0 heart_blur.gif
[IM Output]
请注意使用了Level 运算符,它等同于前面示例中使用的“-evaluate multiply 2 -negate”。使用抗锯齿边框,如果只想平滑原始形状而不是获取其轮廓,则现在可以重新添加原始形状。只需记住,轮廓正好位于原始图像的边缘,因此尺寸将比前面的示例大半个像素。您是否知道从形状(抗锯齿或位图)生成抗锯齿轮廓的其他方法?如果是这样,请将其邮件发送给我或IM论坛。您将获得认可。

使用光栅到矢量转换器进行边缘化

最理想的解决方案之一是使用非IM的“光栅到矢量”转换程序将此位图形状转换为矢量轮廓。可以执行此操作的程序包括:“ScanFont”、“CorelTrace”、“Adobe的Streamline”以及“Vector Magic”。但是,大多数这些程序都需要您支付一定的费用。“VectorMagick”和另一个跟踪程序“AutoTracer”提供了免费使用的在线图像转换器。其他免费解决方案包括“AutoTrace”或“PoTrace”。欢迎提出更多建议。这些跟踪程序使用简单,但通常需要某种形式的图像预处理和后处理。它们具有有限数量的输入格式,并输出矢量图像,这将创建输入图像的“平滑”形式。我更喜欢“AutoTrace”,因为它不会缩放生成的SVG数据,从而产生标准的线宽,但是您不能在“管道”中使用它。为了获得最佳效果,最好确保我们只向其提供基本的位图图像,我们可以通过对输入图像进行阈值处理来确保这一点,同时将其转换为autotrace理解的图像格式。然后,我可以将该图像转换为SVG矢量图像。

  magick heart.gif -colorspace gray -threshold 50% heart_tmp.pbm
  autotrace -output-format svg -output-file heart.svg heart_tmp.pbm
  magick heart.svg heart_svg.gif
  rm -f heart_tmp.pbm
[IM Output] ==>
[IM Text]
==> [IM Output]
从IM v6.4.2-6开始,您可以使用“autotrace:”图像输入委托直接执行上述序列。这只需要安装“autotrace”命令即可。例如

  magick autotrace:heart.gif  heart_traced.gif
[IM Output]
如果您的IM使用“AutoTrace”委托库构建,则还可以让IM直接从内存中的图像生成SVG图像。有关此内容的详细信息,请参阅SVG输出处理。例如……

  magick heart.gif  heart_2.svg
[IM Text]
现在,SVG输出当然会表示原始图像的平滑版本,这实际上不是我们在此示例中想要的。但是,由于我们现在以矢量形式拥有了位图的形状,因此我们可以简单地调整SVG的“style”属性,以便“stroke”轮廓,而不是“fill”形状。然后,可以将修改后的SVG重新馈送到ImageMagick中,以重新创建干净的轮廓栅格图像。例如……

  cat heart.svg |
    sed 's/"fill:#000000[^"]*"/"fill:none; stroke:black;"/' |
      magick svg:- heart_outline.gif
[IM Output]
是的,这有点笨拙,但平滑的抗锯齿效果非常值得付出努力。如果轮廓或其他修改可以作为“autotrace”命令本身的选项来指定就好了,但这目前不是一个功能。您还可以进一步修改SVG输出以加厚边缘,或指定其他笔画或背景颜色,更改矢量边缘形状的填充颜色。例如,这里我们使用红色填充生成形状的更粗的轮廓,所有这些都是经过抗锯齿处理的。

  cat heart.svg |
    sed 's/"fill:#000000;[^"]*"/"fill:red; stroke:black; stroke-width:5;"/' |
        magick svg:- heart_outline_thick.gif
[IM Output]
如此完美的爱心无法通过任何其他方式从位图形状生成。我们还可以提取“d="..."”路径元素,以便在绘图命令中直接用作SVG路径字符串。然后,这将允许您使用任何其他IM绘图设置以及该矢量轮廓,从而完全控制最终结果。有关使用“AutoTrace”程序的另一个示例,请参阅使用Autotrace的骨架

霍夫线检测器

霍夫线检测器(IM v6.8.9-1中添加的“-hough-lines”)是一个非常复杂的变换,包含许多阶段(有关详细信息,请参阅维基百科,霍夫变换)。基本上,它旨在检查图像,查找黑色背景上的白色线条,并尝试返回图像中存在的任何线段(线性序列像素)的确切位置。这对于图像旋转移除或确定图像中的透视变换非常重要,因此可以重复或移除。以下是运算符的完整选项集

  -background {background} -stroke {line_color} -hough-lines {W}x{H}+{threshold}
颜色(背景线颜色)用于设置结果图像中线条的颜色(如果您实际绘制它们)。霍夫运算符的参数(W}x{H}+{阈值)用于定义用于在中间“搜索图像”中查找“峰值”的过滤器的大小和阈值。也就是说,它控制了它实际“查找”我们试图检测的线条的程度(请参见下文)。您可以调整这些帮助查找线检测。例如,让我们尝试在矩形形状的图像中查找线条。首先,我们需要将图像简化为线条,并且为了获得清晰的结果,建议使用Canny边缘检测器

  magick shape_rectangle.gif -canny 0x1+10%+30% rectangle.gif
[IM Output] ==> [IM Output]
现在让我们将霍夫线检测器应用于此图像。

  magick rectangle.gif -background black -stroke red \
          -hough-lines 5x5+20   rectangle_lines.gif
[IM Output]
如您所见,找到了5条线,其中2条非常靠近。出现额外的线的原因是图像中的矩形并不完美。现在,虽然我显示的是栅格(GIF)图像结果,但霍夫运算符实际上会生成Magick矢量图形格式中的矢量图像。这意味着您可以列出线条信息以进行进一步处理。

  magick rectangle.gif -background black -stroke red \
          -hough-lines 5x5+20   rectangle_lines.mvg
[IM Text]
请注意,线条是从一个边缘(具有浮点值)绘制到图像的另一个边缘。由此您可以看到第二条和第三条线是彼此靠近的两条线。MVG输出中的注释为您提供了线条在图像中“命中”的像素累积数,因此很好地指示了线条在图像中的强度。此值始终大于您提供给“-hough-line”运算符的阈值。由此您可以看到第一条和最后一条线(它们非常匹配)的强度大致相等,因此很难选择其中一条而不是另一条。如果发生这种情况,我建议您尝试改进边缘检测步骤。请注意,MVG图像未定义任何颜色。此示例中的颜色设置实际上未使用。仅当您在将上述结果转换为“栅格”图像时实际“绘制”矢量时才会使用颜色,就像我们之前所做的那样。
您还可以查看正在查找每个方向上白色像素的中间“搜索图像”或“累加器”,方法是使用特殊的define

  magick rectangle.gif \
          -define hough-lines:accumulator=true -hough-lines 5x5+20 \
          -delete 0 -contrast-stretch 0.1% rectangle_accumulator.gif
[IM Output]
该define只会将“搜索图像”附加到图像结果,在本例中我们将其删除。我们还对“累积值”应用了一些对比度,以使它们更清晰可见。这是霍夫检测器参数正在搜索的图像。图像始终为180像素宽(每度线角度1像素),而高度是图像对角线长度的两倍。因此,峰值的位置将直接定义线的角度,以及相对于输入图像中心点的线的垂直距离。也就是说,X坐标是角度(以度为单位),Y坐标是从-对角线距离到+对角线距离的中心距离。如果您仔细观察右下方的峰值,您就会明白为什么我们最终得到了两条线而不是一条线。此处的峰值与它们之间存在一个小间隙而“缠绕”。该算法基于Fred Wienhaus编写的脚本“houghlines”,但具有不同的“垂直距离”累积处理。

局部自适应阈值

建设中
-lat”运算符尝试根据周围窗口中像素的值自适应地对每个像素进行阈值处理。这通常用于对背景不均匀(即照明不均匀)的图像进行阈值处理。它基于以下假设:小窗口中的像素将具有大致相同的背景颜色和大致相同的前景颜色。
For example.
   magick input.png -lat 17 output.png
在上面,使用17像素正方形“窗口”来确定每个点处图像的平均颜色,如果像素比此平均值暗,则将其设为黑色,如果比此平均值亮,则将其设为白色。较小的窗口尺寸将使阈值对照明的小变化更敏感,计算速度更快,但会受到图像噪声的不利影响。
Example
较大的窗口尺寸将使阈值对照明的小变化不太敏感,计算速度较慢,受图像噪声的影响较小。这会使阈值选择对像素值的小变化或多或少敏感。
Example
The window does not need to be square.  for example...
  magick input.png -lat 15x25 output.png
您还可以提供一个偏移量,该偏移量将添加到计算出的平均颜色中,从而使每个像素的局部阈值变亮或变暗。例如,这可以用于减少噪声或像素值微小变化的影响。
  magick input.png -lat 15x25+2%
当使用扫描仪或数码相机获取图像时,通常会发生这些微小变化。使用正偏移值可使自适应阈值对像素值的微小变化不太敏感。使用负阈值可使自适应阈值对像素值的微小变化更敏感。或者,可以在使用“-lat”处理图像之前减少图像中的噪声。
In summary, each pixel is thresholded using the following logic:
  AVG = average value of each pixel in the window
  IF (input pixel is > AVG + OFFSET)
     Output pixel is BLACK
  else
     Output pixel is WHITE

---

An alternative is to subtract a blurred copy of the original image
using (Modulus) Subtraction, then thresholding.

   magick rose: -colorspace gray -lat 10x10+0% x:

is roughly equivalent to...

   magick rose: -colorspace gray \( +clone -blur 10x65535 \) \
           -compose subtract -composite -threshold 50%  x:

The special "-blur 10x65535"  is a linear averaging blur limiting itself to a
10x10 window.

The 'Subtract' composition being a mathematical modulus type of operation will
wrap the values that goes negative back round to a value greater than 50%.

If you want to include an offset you can do so by also subtracting a solid
color background image by using a -flatten...  for example

   magick rose: -colorspace gray -lat 10x10+10% x:

is roughly equivalent to...

   magick rose: -colorspace gray \( +clone -blur 10x65535 \) \
           -compose subtract -background gray10 -flatten -threshold 50%  x:

以上内容是从D Hobson <dhobson@yahoo.com>提供的初始注释中修改的。
   -adaptive-sharpen
        Sharpen images only around the edges of the images

   -segment cluster-threshold x smoothing-threshold
         Segmentation of the color space (not image objects)
         This can produce very verbose output.
         This applies the "fuzzy c-means algorithm" if you want to know more.

Also related is -despeckle. to remove single off color pixels.

Generate a 3d stereogram of two images (one for each eye)
This is also known as an anaglyph
  magick composite left.jpg right.jpg -stereo anaglyph.jpg


3D阴影高亮显示

阴影用法

我一直认为ImageMagick提供的“-shade”运算符是最有趣的运算符之一。该运算符的文档仅粗略地暗示了其功能。我花费了大量个人研究来理解该运算符,甚至找出如何最好地利用它可以为IM用户提供的强大功能。基本上,此运算符的作用是假设给定图像称为“高度场”。也就是说,表示某个对象或地形的表面的灰度图像。“白色”表示图像中的最高点,而“黑色”表示最低点。这种表示来自20世纪80年代的计算机视觉研究,其中使用了具有强“相机光”的照片,使近点变亮,远处点变暗。
由于“-shade”需要灰度图像,因此该运算符会自动删除输入图像中的任何颜色。同样,图像中可能存在的任何透明度对运算符来说完全无用且被忽略。
现在,“-shade”获取此灰度高度场并对其照射光线。结果是将由此产生的光照阴影的表示形式。请记住,您必须将输入图像视为输出的“表面”,才能使其有任何意义。为了进行演示,我们需要一个“高度场”图像,因此让我们绘制一个。


  magick -font Candice -pointsize 64 -background black -fill white \
          label:A  -trim +repage -bordercolor black -border 10x5 \
          shade_a_mask.gif
[IM Output]
此图像也等同于形状的“蒙版”,通常不仅用作“-shade”的输入,还用于蒙版图像,从阴影结果中剪切出相同的形状。请参见下面的蒙版阴影图像。对于“-shade”操作符,此图像看起来像一个平坦的黑色平面,上面有一个垂直向上升起的平坦白色平台。因此,只有此图像的边缘会产生有趣的效果。为此,这两个参数定义了光线照射的方向。第一个参数是光线照射的方向。因此,'0' 度角将来自东方(左侧),'90' 则为从北方(或顶部)逆时针方向,依此类推。例如...

  magick shade_a_mask.gif   -shade    0x45   shade_direction_0.gif
  magick shade_a_mask.gif   -shade   45x45   shade_direction_45.gif
  magick shade_a_mask.gif   -shade   90x45   shade_direction_90.gif
  magick shade_a_mask.gif   -shade  135x45   shade_direction_135.gif
  magick shade_a_mask.gif   -shade  180x45   shade_direction_180.gif
您明白了。光线可以来自任何方向。另一个参数是高度,表示光源与地面的夹角。您可以将其视为白天太阳的高度,因此'0' 为黎明,'90' 为正上方。
[diagram]

  magick shade_a_mask.gif   -shade  90x0    shade_elevation_0.gif
  magick shade_a_mask.gif   -shade  90x15   shade_elevation_15.gif
  magick shade_a_mask.gif   -shade  90x30   shade_elevation_30.gif
  magick shade_a_mask.gif   -shade  90x45   shade_elevation_45.gif
  magick shade_a_mask.gif   -shade  90x60   shade_elevation_60.gif
  magick shade_a_mask.gif   -shade  90x75   shade_elevation_75.gif
  magick shade_a_mask.gif   -shade  90x90   shade_elevation_90.gif
如您所见,当高度为'0' 时,形状仅在光线照射的一侧突出显示。其他所有部分都是黑色,因为没有光线照射到任何其他表面。我称之为“黎明高光”,它有其自身的特殊用途。这使我们想到了第一个值得注意的要点。“-shade”处理后的图像通常比高光区域具有更多的黑暗或阴影区域。阴影并不相等。随着光线在“高度场”图像上变得更高。图像的整体亮度将变得更白,直到“正午”或高度为'90' 时,任何平坦区域都将呈现出明亮的白色,并且只有斜坡和边缘被阴影处理成灰色,其中灰色为最大值,或“悬崖状”的斜坡变化。此“正午”图像是另一种特殊情况,有点类似于边缘检测系统,尽管对于锐利边缘,它的宽度在 2 到 4 个像素之间。我过去曾使用此图像生成“-shade”图像的斜角边缘的蒙版,以便使平坦区域透明。如果高度角超过'90' 度,则将获得与光线来自另一个方向相同的结果。因此,参数'0x135' 将产生与'180x45' 完全相同的结果。负高度角也将产生相同的结果,就像光线从下方照射到“半透明”表面一样。因此,'0x-45' 将与'0x45' 相同。换句话说,对于特定的阴影,通常还有其他 4 个参数也会产生相同的结果。从上面可以看出,我认为'120x45' 参数最适合直接使用阴影输出。例如,这里它创建了一些斜角文本...

  magick -size 320x100 xc:black \
          -font Candice -pointsize 72 -fill white \
          -draw "text 25,65 'Anthony'" \
          -shade 120x45  shade_anthony.jpg
[IM Output]
-shade”的主要问题之一是实际产生的斜角的厚度。我上面使用的此类锐利边缘始终会产生大约 4 个像素宽的斜角,既进入蒙版区域也超出蒙版区域。无法调整此厚度,除非在使用“-shade”操作符之前和之后调整图像大小。如果您想了解特定高度照明角度下“平坦区域”的亮度,则可以使用以下命令对平坦的纯色表面进行阴影处理。

  magick -size 50x50 xc:white -draw 'circle 25,25 20,10' \
          -blur 0x2  -shade 0x45   -gravity center -crop 1x1+0+0 txt:-
[IM Text]
如您所见,'45' 度的高度产生了大约 70% 灰度的相当明亮的纯色,对于一般观看来说,这是一个合理的灰色级别。但是,如果您计划使用阴影生成各种形状的 3D 高光,那么实际的灰色级别变得非常重要。我们将在创建叠加高光中介绍这一点。基本上,这就是“-shade”操作符。但是,有效地使用它呈现了一系列技术和可能性,我们将在接下来进行介绍。

蒙版阴影形状

如上所述,简单的“蒙版”形状通常与“-shade”一起使用,以从简单的形状生成复杂的三维效果。例如,让我们对直接阴影蒙版图像执行此操作。

  magick shade_direction_135.gif  shade_a_mask.gif \
          -alpha Off -compose CopyOpacity -composite   shade_beveled.png
[IM Output]  + [IM Output] ==> [IM Output]
请注意,“-shade”操作符生成的斜角大约有一半实际上超出了蒙版区域。换句话说,直斜角在蒙版时会减半。另一方面,垂直或“正午”阴影图像(使用'90' 度高度角)可用于仅提取斜角边缘,使图像中心为空心。

  magick shade_direction_135.gif \
          \( shade_elevation_90.gif -normalize -negate \) \
          -alpha Off -compose CopyOpacity -composite   shade_beveled_edge.png
[IM Output]  + [IM Output] ==> [IM Output]
但是请注意,“正午”阴影图像虽然提供了一种方法来蒙版“-shade”操作符效果的位置(和强度),但实际上并没有完全覆盖这些效果。通过将“正午”阴影图像与原始蒙版组合,您可以稍微增加该蒙版的大小,以生成更好的蒙版斜角图像。
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

  magick shade_direction_135.gif \
          \( shade_elevation_90.gif -normalize -negate \
             shade_a_mask.gif -compose screen -composite \) \
          -alpha Off -compose CopyOpacity -composite   shade_beveled_plus.png
[IM Output]
请记住,使用 IM v6,您可以在同一个命令中生成我之前生成的“阴影”图像。因此,上述内容可以完全从头生成。例如。

  magick -font Candice -pointsize 72 -background black -fill white \
          label:X  -trim +repage -bordercolor black -border 10x5 \
          \( -clone 0 -shade  135x45 \) \
          \( -clone 0 -shade  0x90  -normalize -negate \
             -clone 0 -compose screen -composite \) \
          -delete 0 -alpha Off -compose CopyOpacity -composite \
          shade_beveled_X.png
[IM Output]

阴影形状图像

Alpha Extract 操作符”不仅会将形状图像的 Alpha 通道提取为灰度蒙版,而且还会产生保留“关闭”Alpha 通道中形状的副作用。由于它是“关闭”的,因此许多图像处理操作符(包括“-shade”)将不会对其进行处理,从而保留其细节。这意味着对于形状图像,您可以提取形状,完成工作,然后在完成所有图像处理后,只需再次打开Alpha On即可恢复透明度!例如,这里我在透明背景上绘制一个“心形”,对图像进行一些模糊和阴影处理,然后恢复图像的原始形状轮廓。

  magick -size 100x100 -gravity center -background None \
          -font WebDings label:Y \
          -alpha Extract -blur 0x6 -shade 120x21 -alpha On \
          -normalize +level 15%  -fill Red -tint 100%    shade_heart.png
[IM Output]
我只能说哇,真是节省时间!比之前的命令及其所有额外的处理和图像克隆简单得多。

圆形阴影边缘

如您在上一个示例中看到的,通过模糊图像形状蒙版,“边缘悬崖”的“斜率”将被平滑,就像随着时间推移而磨损一样。这会为阴影图像产生不错的圆形效果。

  magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
          shade_circle_mask.gif
  magick shade_circle_mask.gif            -shade 120x45  shade_blur_0.gif
  magick shade_circle_mask.gif -blur 0x1  -shade 120x45  shade_blur_1.gif
  magick shade_circle_mask.gif -blur 0x2  -shade 120x45  shade_blur_2.gif
  magick shade_circle_mask.gif -blur 0x3  -shade 120x45  shade_blur_3.gif
  magick shade_circle_mask.gif -blur 0x4  -shade 120x45  shade_blur_4.gif
  magick shade_circle_mask.gif -blur 0x5  -shade 120x45  shade_blur_5.gif
如您所见,模糊不仅会圆化边缘,还会使灯光效果变暗。您可以通过规范化结果来最大化其对比度,以便将最亮和最暗的点分别恢复为纯白色和黑色。

  magick shade_blur_3.gif   -normalize  shade_blur_3n.gif
[IM Output] ==> [IM Output]
唯一的缺点是,这通常也会使阴影图像变暗。这是我们在创建叠加高光中需要考虑的事情。让我们通过直接蒙版此阴影图像来完成它。

  magick shade_blur_3n.gif shade_circle_mask.gif \
          -alpha Off -compose CopyOpacity -composite   shade_blur_3n_mask.png
[IM Output] ==> [IM Output]
如您所见,模糊蒙版图像会很好地圆化结果形状的边缘。

创建叠加高光

-shade”操作符的输出非常不错,但您实际上很少想要形状的普通灰度图像。它需要一些颜色。但是,这并不容易,因为添加颜色的两种主要方法,颜色着色中间色调仅重新着色灰度,或'叠加' Alpha 合成,以图像替换灰色区域,都依赖于灰度图像的特殊形式。也就是说,完美的中间色调灰色('grey50')被颜色或图像替换,而更白或更暗的灰色则相应地使颜色或图像变白或变暗。这些具有完美中间色调灰色的特殊灰度“叠加高光”图像,用于未修改的区域,使用“-shade”创建起来并不那么简单。但是,以下是我发现的一些更简单的方法。使用“-shade”的 30 度高度照明角,是一种为阴影形状的平坦区域生成完美中间色调灰色的方法。例如,这里我对图像进行阴影处理,然后提取左上角像素以检查“平坦”部分图像的结果颜色。
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

  magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
          -blur 0x2  -shade 120x30           shade_30.png
  magick shade_30.png   -gravity center -crop 1x1+0+0 txt:-
[IM Image]
[IM Text]
不幸的是,更改上述命令中“-blur”的圆形效果往往也会改变阴影图像的结果高光强度。也就是说,使用较大的模糊不仅会产生外观圆润的边缘,还会使高光变得非常暗淡,几乎不可见。这意味着您需要在生成的“-shade”图像的输出中添加更多对比度,以使高光作为叠加图像有效。为了解决这个问题,我们需要一种方法来消除圆形调整带来的这种对比度效果。通常的做法是“-normalize”图像,但是对 30 度阴影图像执行此操作会导致“平坦”区域不再是完美的灰色。例如...

  magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
          -blur 0x2  -shade 120x30 -normalize   shade_30_norm.png
  magick shade_30_norm.png   -gravity center -crop 1x1+0+0 txt:-
[IM Image]
[IM Text]
然而,经过进一步的实验,我发现使用 21.78 度阴影高度角,在经过规范化后,将产生所需的完美中间色调灰色级别以及良好的强高光效果。

  magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
          -blur 0x2  -shade 120x21.78 -normalize   shade_21_norm.png
  magick shade_21_norm.png   -gravity center -crop 1x1+0+0 txt:-
[IM Image]
[IM Text]
由于阴影图像现在已通过“-normalize”操作符运行,“-blur”用于“圆化边缘”的值将不再影响最终结果的强度。一种更好的方法。总之,“规范化”阴影图像会使中间色调偏离完美的灰色颜色。现在我们可以完全独立于其他调整来调整产生的高光的输出强度。通常,由于规范化结果是极端的,我们将需要受控的反规范化或反对比度控制,以将高光降低到所需的级别。调整结果高光的简单方法是使用完美的灰色颜色着色图像。这会将图像中的所有颜色级别都向中心的纯中间色调灰色颜色移动。例如...


  magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
          \( +clone -blur 0x2 -shade 120x21.78 -normalize  \) \
          +swap -alpha Off -compose CopyOpacity -composite  shade_tint_0.png
  magick shade_tint_0.png -fill grey50  -colorize 10%  shade_tint_10.png
  magick shade_tint_0.png -fill grey50  -colorize 30%  shade_tint_30.png
  magick shade_tint_0.png -fill grey50  -colorize 50%  shade_tint_50.png
  magick shade_tint_0.png -fill grey50  -colorize 80%  shade_tint_80.png
除了线性渐变高光之外,另一种方法是使用S型非线性对比度来减少高光的整体效果,同时保留高光中极亮/极暗的点。这应该可以让高光效果看起来更“自然”,并且可以使高光更亮,就像表面更具反射性一样。但是,为了使这种技术更有效,我们需要确保阴影结果中没有纯白色和黑色。这可以通过首先使用“-contrast-stretch”的'0%'而不是“-normalize”,以及像上面那样对结果进行少量反归一化来实现。这似乎只是增加了高光叠加图像生成的复杂性,但强调高光中的亮点使额外的处理值得付出努力。例如……

  magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
          \( +clone -blur 0x2 -shade 120x21.78 -contrast-stretch 0% \) \
          +swap -alpha Off -compose CopyOpacity -composite shade_sig_0.png

  magick shade_sig_0.png  -sigmoidal-contrast 10x50%  shade_sig-10.png
  magick shade_sig_0.png  -sigmoidal-contrast  5x50%  shade_sig-5.png
  magick shade_sig_0.png  -sigmoidal-contrast  2x50%  shade_sig-2.png

  magick shade_sig_0.png  +sigmoidal-contrast  2x50%  shade_sig+2.png
  magick shade_sig_0.png  +sigmoidal-contrast  5x50%  shade_sig+5.png
  magick shade_sig_0.png  +sigmoidal-contrast 10x50%  shade_sig+10.png
如您所见,整体高光强度降低了,但反射光产生的亮点仍然像以前一样亮,只是尺寸减小了。结果是形状看起来更自然的“有光泽”。这种技术的唯一缺点是也会生成阴影“斑点”,但这通常不那么明显。最后,我们可以将“高光点”与整体高光减少相结合,以生成一组高度可配置的高光叠加生成器控件……
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] <== [IM Output] ==> [IM Output] [IM Output] [IM Output]

  magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
          \( +clone -blur 0x4 -shade 120x21.78 -contrast-stretch 0% \
             +sigmoidal-contrast 7x50% -fill grey50 -colorize 10%  \) \
          +swap -alpha Off -compose CopyOpacity -composite shade_overlay.png
[IM Output]
总之,上面的示例有四个单独的控件……
"blur":圆化形状边缘(0.001=斜角 2=平滑 10=圆角)
"shade":光线照射的方向(120=左上方 60=右上方)
"sigmoidal":表面反射控制高光点(1=平坦 5=良好 10=反射)
"colorize":高光的整体对比度(0%=明亮 10%=良好 50%=暗淡)
注意,虽然上面的例子已经形成原始的“圆形”形状,但透明度应该只在应用'Overlay'合成后恢复,而不是之前。此外,如果您计划对相同形状重复使用高光(在执行任何旋转后),您可以为计划使用的每个形状预先生成高光叠加,并将结果保存以供多次重复使用。在IM讨论论坛中,从平面源图像生成3D DVD封面就是这种阴影叠加重复使用的一个例子。我还强烈建议您尝试以上技术,因为它们是使您的平面形状图像看起来更逼真的关键。如果您想出其他突出显示的想法,请告诉我。
FUTURE:
   Color Tinting the Overlay image
   Overlay Alpha Composition with an Image

使用黎明阴影高亮

在上面蒙版阴影图像中,我们展示了“中午”或“正午”阴影图像(使用'90'的仰角)如何可以用于蒙版以及"-shade"产生的效果的位置和范围。但是,形状的水平或“黎明”阴影图像(使用'0'的仰角)也相当有用。例如,它可以用作白色或黑色图像的蒙版,以在形状上生成单独的高光和阴影效果。这还可以用于确保形状获得大致相等数量的明暗区域(甚至不相等的数量),因为我分别生成它们,但以完全受控的方式。
FUTURE: more detail here
请参阅第一个高级3D徽标,了解使用此技术的示例。

使用FX,DIY图像操作符

图像列表操作符"-fx"是一个通用的DIY操作符,它不属于任何特定类别的IM操作符,因为它可以用于创建几乎任何图像操作。在这些页面中可以看到其用法的示例,但在这里我们将专门关注其功能以及如何使用它们。该命令在其功能方面非常通用,它可以:
  • 创建画布、渐变、数学颜色映射。
  • 在图像和通道之间移动颜色值。
  • 以几乎所有可以想象的方式调整图像颜色。
  • 平移、翻转、镜像、旋转、缩放、剪切并通常扭曲图像。
  • 将多个图像合并或合成在一起。
  • 以奇特而奇妙的方式平铺图像。
  • 卷积或合并相邻像素。
  • 生成图像度量或“指纹”。
  • 以不寻常的方式比较图像。
当然,许多这些技术已经是IM的一部分,可以产生更快、更灵活的结果。但是,如果它不是内置的,"-fx"允许您生成所需操作的自己的版本。事实上,我以及其他人经常使用它来制作新操作的原型,这些操作后来被构建到IM的核心库中。例如,请参阅DIY新的有序抖动替换,我使用"-fx"开发了-ordered-dither"操作符的修订版本。该操作符本质上允许您对一个或多个图像执行自由形式的数学运算。有关该命令的官方摘要,请参阅FX,特殊效果图像操作符,网址为ImageMagick网站

FX 基本用法

该命令接受任意数量的输入图像的图像序列。通常是一个或两个图像,并将所有输入图像替换为第一个图像的副本,该副本已由"-fx"函数的结果修改。也就是说,第一个图像中的任何元数据都将保留在"-fx"操作符的结果中。为了便于数学使用,所有提供的颜色值都归一化为0.0到1.0的值范围。结果也应在此范围内。这包括透明度或alpha通道,它从0.0(表示完全透明)到1.0(表示完全不透明)。这些值表示“alpha透明度”,实际上是IM通常在内部存储透明度(作为遮罩值)的反值。然而,以这种形式在数学上更正确且更容易使用。"-channel"设置定义了第一个(也称为“第零”或“u”)图像中的哪个通道将被"-fx"操作符的结果替换。默认情况下,这仅限于原始图像的颜色通道('RGB')。除非更改"-channel"设置以包含alpha('A')通道,否则该图像中任何现有的透明度都不会被修改。对于每个像素执行一次表达式,以及对正在处理的像素中的每个颜色通道执行一次。此外,由于每次执行表达式时都会重新解析它,因此复杂的表达式在大型图像上可能需要一些时间才能处理。例如,这里我们定义了一个黑色图像,但随后将蓝色通道设置为一半亮度以形成“海军蓝”颜色。

  magick -size 64x64 xc:black -channel blue -fx '1/2' fx_navy.gif
[IM Output]
在这里,我们采用黑白渐变,然后将蓝色和绿色通道设置为零,因此它变成了黑色-红色渐变。

  magick -size 64x64 gradient:black-white \
           -channel blue,green    -fx '0'    fx_red.gif
[IM Output]
为了使"-channel"设置更像"-fx"操作符,它将接受字母'RGBA'的任何组合来指定操作符要限制其操作的通道。

这意味着要将"-fx"的输出限制为仅蓝色和绿色通道,您现在可以说"-channel BG"而不是更长的"-channel blue,green"。
我们本可以在不使用"-fx"的情况下生成上述示例,但能够对现有图像执行此操作使它成为一个强大的图像操作符。事实上,该函数可以读取和使用当前内存中图像序列中任何图像的任何像素或特定颜色。第一个“零”图像被赋予“u”的特殊名称。第二个图像“v”。内存中的其他图像可以通过索引引用。因此,“u[3]”是当前图像序列中的第四个图像,而“u[-1]”是序列中的最后一个图像。这与图像列表操作符使用的相同索引方案相同,因此您应该得心应手。如果没有给出其他限定符,则使用的颜色值与指定图像中使用的颜色值相同。也就是说,除非您明确表示要使用红色,否则它将使用命令在该时间处理的颜色通道的颜色值。也就是说,在处理蓝色通道时,它将应用蓝色颜色值的表达式。除非另有说明,否则它将处理图像中每个像素的每个RGB颜色值(由默认的"-channel"设置设置)。也就是说,3*w*h个计算,这些计算通过给定的表达式修改图像中的所有值。例如,这里我们采用IM内置的“rose:”图像并将所有像素值乘以50%。

  magick rose: -fx 'u*1.5'    fx_rose_brighten.gif
[IM Output]
在上面的示例中,每个单独的红色、绿色和蓝色值都乘以1.5。如果结果值超出0到1的范围,它将被限制在适当的边界(在本例中为1.0),除非您使用默认的ImageMagick的HDRI版本。在数学颜色调整直方图曲线中探讨了许多其他“-fx”公式来重新着色图像。由于我们还可以将当前图像序列中的任何图像作为修改第一个图像的表达式的一部分进行引用,因此我们可以以几乎任何我们想要的方式合并两个或更多图像。在这里,我们通过将黑色-蓝色渐变(旋转)中的蓝色通道复制到上面生成的以前的黑色-红色渐变中,生成一个黑色-红色-蓝色颜色图表图像。

  magick -size 64x64 gradient:black-blue -rotate -90  fx_blue.gif
  magick fx_red.gif  fx_blue.gif \
          -channel B  -fx 'v'    fx_combine.gif
[IM Output]  + [IM Output] ==> [IM Output]
当然,我们可以使用通道复制合成方法,这会快得多。但这不是重点。

虽然反之亦然。几乎所有IM图像操作都可以用FX等效函数替换。

现在上面的第二个图像仅用作源图像。真正发生的是"-fx"首先只创建第一个图像的副本。然后它根据公式修改该图像,使用所有其他给定的图像。最后,它放弃所有输入图像,并用第一个图像的修改副本替换它们。您还可以根据图像中每个像素的位置计算值。值'i,j'是正在处理的像素的当前位置,而'w,h'给出图像的大小(第一个图像,除非给出了特定图像限定符)。例如,这里我们生成一个DIY渐变图像

  magick rose: -channel G -fx 'sin(pi*i/w)' -separate   fx_sine_gradient.gif
[IM Output]
或者使用'i,j'位置值的其他更复杂的东西。


  magick -size 80x80 xc: -channel G -fx  'sin((i-w/2)*(j-h/2)/w)/2+.5'\
          -separate fx_2d_gradient.gif
[IM Output]
在生成灰度渐变时,只需要求它只处理一个颜色通道(例如上面示例中的“G”或绿色通道),就可以使 -fx 运算符的速度提高约 3 倍。然后可以将此通道分离以生成最终的灰度图像。这可以带来非常大的速度提升,尤其是在使用非常复杂的“-fx”公式时。有关更多 FX 生成的渐变,请参见示例自定义渐变您可以使用位置信息使用“p{x,y}”语法从源图像中查找特定像素。例如,您可以轻松地创建自己的“镜像”类型函数(如“-flop”图像运算符),该函数用原始源的“镜像”位置的颜色值替换每个像素。

  magick rose: -fx  'p{w-i-1,j}'  fx_rose_mirror.gif
[IM Output]
这种类型的“图像扭曲”通过创建扭曲图像映射或其他类型的以图像形式的值查找表而变得更加强大。在DIY 抖动图案和阈值映射中提供了执行此操作的示例,其中 FX 用于将特定颜色替换为其他图像中的图案。现在,FX 表达式生成的最终图像的大小与给定的第一个图像相同,因此要生成更大的图像,您需要将第一个图像设置为所需的大小。在这种情况下,第二个图像(甚至第三个图像)可以用作颜色源(因此在下一个示例中交换)。例如,这里我们调整 rose 图像的大小(使用插值缩放或调整大小)以生成更大的图像。

  magick rose:  -size 120x80 xc: +swap  \
           -fx 'v.p{  (i+.5)*v.w/w-.5, (j+.5)*v.h/h-.5  }' \
           fx_scaled.png
[IM Output]
请注意如何执行像素查找,它可能看起来很复杂,但它是缩放(扭曲)图像的正确方法。基本上,添加到表达式中的所有额外的“0.5”值都需要在用于输入坐标“i,j”的像素坐标和位置查找“v.p{...}”之间正确地进行映射,而更数学上正确的图像坐标则需要用于实际的数学计算(缩放)。上面实际上是任何形式的图像扭曲所使用的确切方法。您可以通过打开详细扭曲摘要来查看大多数扭曲的 FX 等效项。这报告了大多数图像扭曲的 FX 等效项,作为一种双重检查扭曲是否按预期执行的方式。使用FX DIY 运算符进行图像扭曲,显示了该运算符的强大功能。如果不是因为这个运算符,我怀疑许多新的操作,例如扭曲、稀疏颜色或有序抖动,是否会添加到 ImageMagick 核心库中。这里有一些更简单的东西,交换 rose 图像的红色和蓝色通道。看看你是否能弄清楚它是如何工作的。

  magick rose: \( +clone -channel R -fx B \) \
          +swap -channel B -fx v.R     fx_rb_swap.gif
[IM Output]
执行相同操作更快更好的方法是使用“-separate”和“-combine”)。请参见组合 RGB 通道图像。或者,您还可以使用“-color-matrix”以更快地执行相同操作。

你在这里看到趋势了吗?
作为默认的“-channel”设置,它将“-fx”运算符的输出限制为三个颜色通道。这意味着如果您想影响 alpha 或透明度通道,则必须通过更改通道设置来显式指定它。例如,让我们通过将所有 alpha 通道值设置为一半来创建一个半透明的“rose:”图像。

  magick rose: -alpha set  -channel A  -fx '0.5'    fx_rose_trans.png
[IM Output]
请注意,为了使上述操作正常工作,我需要确保“rose:”实际上有一个 alpha 通道,以便“-fx”可以处理它。我是用Alpha 通道控制运算符来实现的。“-fx”运算符能够操作图像的 RGBA 通道,这使得它非常适合操作通道和蒙版。
从 IM 6.2.10 开始,您可以向“-fx”表达式添加变量赋值,这使您可以减少某些表达式的复杂性,否则这些表达式基本上是不可能的。例如,这里我根据距特定点(分配给变量“xx”和“yy”)的距离创建渐变。如果没有使用变量,这个公式可能会变得非常难以阅读。

  magick -size 100x100 xc:  -channel G \
          -fx 'xx=i-w/2; yy=j-h/2; rr=hypot(xx,yy); (.5-rr/70)*1.2+.5' \
          -separate  fx_radial_gradient.png
[IM Output]
由于“-fx”使用的简单标记化处理,变量名只能包含字母,并且不能包含数字。此外,由于许多单个字母用于访问图像信息的内部变量,因此建议变量名至少为两个字母长。因此,我使用“xx”和“yy”而不是“x”或“y”。
-fx”函数 'rr=hypot(xx,yy)' 已添加到 IM v6.3.6 中,以加快非常常用的表达式 'rr=sqrt(xx*xx+yy*yy)' 的速度。

当然,如果您需要距离的平方,则应避免使用 'hypot()' 函数及其隐含的 sqrt() 函数。
有关一些真正复杂表达式的更多示例,请参见更复杂的 DIY 渐变,如果没有多语句赋值,这些表达式将是不可能的。对于透视扭曲的 FX 形式也是如此。从 IM 版本 6.3.0-1 开始,“-fx”表达式的复杂性开始需要外部文件,因此标准的“@filename”现在可以用于从文件中读取表达式。

   echo "u*2" | magick rose: -fx "@-"  fx_file.png
[IM Output]
这也意味着您可以使用更复杂的脚本为特定作业生成特定的 FX 表达式。在内部,文件只是简单地读入一个字符串并像往常一样解释。对“-fx”很重要的其他设置是“-virtual-pixel”和“-interpolate”。虚拟像素设置允许人们设置当查找坐标超出输入图像覆盖的区域时应返回的颜色或图像结果。这允许人们为模糊等内容设置边缘效果,以及在更大区域上平铺图像。插值设置允许人们指定当查找坐标(浮点值)落在输入图像中像素的整数坐标之间时,IM 应该如何混合相邻像素的颜色。有关更多信息,请参见插值像素查找
在不同的时间添加了一些更多功能
IM v6.3.6:hypot()
IM v6.7.3-4:while()、not()、guass()、squish()

FX 调试

'debug(expr)' 本质上是一种打印浮点值的方法,每次计算 FX 表达式时都会打印一次。这反过来提供了一种调试表达式的办法。但是,您可以通过使用三元 if-else 表达式来限制“debug()”的输出。例如,这将打印内置“rose:”图像中像素 10,10 的浮点颜色值。通过使用 'NULL:' 图像处理程序来忽略实际的图像结果。

  magick rose: -fx 'i==10&&j==10?debug(u):1; u' null:
[IM Output]
请记住,输出在标准错误上,而不是正常的标准输出,这样您就可以在命令管道中使用它,而不会出现问题。请注意 FX 表达式是如何执行三次的,一次针对每个通道,仅针对该一个像素。将此乘以像素数,您可以想象如果“debug()”不限于单个像素,即使对于这张小图像,输出的长度也会有多长。

类似 FX 的内置操作

-fx 运算符表示一种开发以前在 ImageMagick 中不存在的新图像处理函数的方法。用户进行此类开发的结果使 ImageMagick 能够扩展,并具有新的功能和方法,例如颜色查找表(“-clut”)。但是,通常一旦使用“-fx”稳定了新方法,该表达式就会转换为更快的内置操作,通常作为一组类似运算符的一部分添加。这些包括以下通用图像运算符及其方法...
-evaluate 直接像素、颜色值、通道修改函数。
(见下面的Evaluate)。
-function 更复杂的像素、颜色值、通道修改函数。
(见下面的Function)。
-evaluate-sequence 以数学方式合并多图像序列的图像
(见下面的Evaluate-Sequence)。
-sparse-color 通用图像重新着色运算符。
(见稀疏颜色渐变)
-compose 通用多图像组合和叠加方法。
(见Alpha 合成)。
-distort 通用图像扭曲运算符,使用反向像素映射。
(见扭曲运算符)
-morphology 通用区域效果卷积/形态学函数。
(见形态学运算符卷积运算符)
当人们开发新型图像操作时,他们通常首先使用“-fx”运算符对其进行原型设计。当他们完成了该“方法”的制定后,该方法将转换为 ImageMagick 核心库中的新超快速内置运算符。欢迎用户贡献他们认为对 IM 有用的自己的“-fx”表达式(或其他已定义的函数),但这些函数尚未被其他图像运算符涵盖,如果它们可以由上述通用运算符之一处理,则应该很容易添加它。例如,我自己需要一种“如果颜色相似则屏蔽”类型的操作来比较两张图像。这已作为新的“-compose”方法“ChangeMask”添加。这反过来让我能够为 GIF 动画添加更复杂的透明度优化。“-fx”的速度和复杂性开始成为问题,那么最好转向 API 脚本语言(如 PerlMagick)。使用 PerlMagick 的一个示例“pixel_fx.pl”是该 API 发行版的一部分。

FX 表达式作为格式和注释转义

从 IM 版本 6.2.10 开始,您现在可以在图像属性转义字符串(例如“-format”和“-annotate”参数使用)中使用FX 表达式。转义序列“%[fx:...]”被替换为一个数字作为浮点值,在当前图像序列中的每个图像上计算一次。FX 表达式在处理期间会稍作修改。具体来说...
  • 当前像素坐标“i”、“j”固定为值 0,因此,除非使用“p{}”索引,否则图像变量本身仅返回像素 0,0 的值。
  • 除非选择颜色通道,否则仅返回红色通道值。
  • 默认图像引用“s”设置为当前图像,正在对其进行注释或识别。
  • 索引“t”返回由“s”引用的图像的索引。
在 IM v6.6.8-6 之前,"t" 图像索引和 "n" 图像总数的 FX 表达式值都存在问题,并且对于所有图像都只分别返回 0 和 1 的值。 '%p' 和 '%n' 的百分比转义符也存在相同的问题。
例如,这里我使用 "-annotate" 命令在每个图像上标注了其左上角像素的颜色。

  magick -size 150x25 xc:DarkRed xc:Green xc:Blue \
          -fill white -gravity center \
          -annotate 0 '%[fx:t] / %[fx:n] : %[fx:r],%[fx:g],%[fx:b]' \
          annotate_fx_%d.gif
[IM Output] [IM Output] [IM Output]
注意,每个图像上写入的文本都不同,因为 'r' 实际上等价于 's.p{0,0}.r'。'g' 和 'b' 颜色通道值也是如此。当然,每个值都返回 0.0 到 1.0 范围内的归一化值。为了使特定像素颜色值的输出更容易,在 IM v6.3.0 中也添加了一个 '%[pixel:...]' 转义符。此运算符对每个图像的每个通道调用一次给定的 FX 表达式,并将返回值格式化为 IM 可以处理的颜色参数。

  magick -size 300x100 gradient:yellow-limegreen \
          -gravity NorthWest  -annotate 0 '%[pixel:s.p{0,0}]' \
          -gravity Center     -annotate 0 '%[pixel:s.p{0,50}]' \
          -gravity SouthEast  -annotate 0 '%[pixel:s.p{0,99}]' \
          annotate_pixel.gif
[IM Output]
您可以使用 "-format" 选项与 "identify" 命令直接输出结果。

  magick identify -format '%[fx:atan(1)*4]' null:
[IM Output]
这将数学计算并返回 PI 的值,尽管此值可作为内置变量 'pi' 使用。您可以生成随机数。例如,要生成一个介于 -5 到 10(包含 -5 和 10)之间的整数。这里我使用 "info:",它等价于 "magick identify" 命令。

  magick xc: -format '%[fx:int(rand()*16)-5]' info:
[IM Output]
有关更多方法,请参阅 识别替代方案:文本输出选项。另请参阅 带圆角的边框,它使用 FX 表达式 根据图像宽度和高度信息生成绘制字符串。您可以 使用 FX 公式计算图像位置,甚至可以使用其他图像的大小和位置进行定位(请参阅 增量计算的位置)。您还可以在 文件名百分比转义符 中使用 FX 转义符 来根据计算值生成新文件。有关示例,请参阅 平铺裁剪 中的最后一个示例。
以上所有操作实际上都会对当前图像序列中的每个图像运行 "-format" 命令,以及任何包含的 FX 表达式。 "-print" 运算符的工作方式与 "-identify" 类似,但它只运行一次,并且可以访问当前图像序列中的所有图像。使用此运算符,您可以使用 'u[{i}]' 访问任何图像的值,这与上面提到的不同。
Fx 表达式可以应用于其他颜色空间的图像,因此我可以例如找出三种不同颜色的 '色相' 值(在 '红色' 通道中)。

  magick xc:red xc:green xc:blue -colorspace HSL \
          -format '%[fx: s.r ]\n' info:
[IM Output]
您还可以使用 IM 进行一些直接的颜色数学运算,例如找出 'gold'、'yellow' 和 'khaki' 的平均颜色。

  magick xc: -format '%[pixel:(gold+yellow+khaki)/3]' info:
[IM Output]
虽然这显示了颜色与三个源颜色相比的样子,但...

  magick xc:gold xc:yellow xc:khaki +append \
          \( xc: -fx '(gold+yellow+khaki)/3' \) \
          -scale 90x30\! -append fx_hues.png
[IM Output]
您还可以使用 "-print" 打印信息。这仅对整个图像序列应用一次。这意味着您可以使用此运算符计算涉及多个图像的更复杂的 '%[fx:...]' 表达式。

访问其他图像中的数据

然而,使用 FX 转义表达式存在一个严重的问题。当您创建图像时,IM 无法直接访问当前图像序列中的其他图像。在典型的图像创建过程中,通常不需要这样做,因为新图像通常不依赖于以前内存中的图像。基本上,如果您想获取不同图像中特定像素的颜色(如上所示),或者正在创建新图像,那么 IM 核心函数与所需信息没有直接关联。例如,如果您尝试使用内置 "rose:" 图像像素 12,26(一个蓝色的像素)的颜色创建标签,则直接方法将失败!

  magick rose: label:'%[pixel:p{12,26}]' -delete 0 label_fx_direct.gif
[IM Output]
好吧,rose 图像实际上不包含任何黑色像素,因此以上结果是错误的。解决此问题的办法是提取所需的信息并将其保存到全局 IM 元数据中。此信息将传递给库核心中的所有子例程,包括图像创建的子例程。

  magick rose: -set option:mylabel '%[pixel:u.p{12,26}]' -delete 0 \
          label:'%[mylabel]'    label_fx_indirect.gif
[IM Output]
这并不直观,但我们现在得到了正确的结果。特殊的 'option:' 标签告诉 "-set" 选项,您希望将给定的设置保存为全局 工件,而不是作为图像 '属性' 或 '特性' 字符串,就像 "-define" 一样。但是,"-set" 形式允许您在设置 工件 时扩展 百分比转义符,而 "-define" 则不允许。当 "label:" 运算符扩展其百分比转义符时,首先会查找给定的 '键' 作为每个图像的 '属性' 或 '特性',但如果找不到任何内容,则会查找全局 工件 设置中的 '键'。因此,即使在创建 工件 时该图像不再存在,也会使用我们从前一个图像创建的全局 '工件'。基本上,'工件' 设置在 "magick" 命令的生命周期内是全局的,因此可用于将信息从一个图像传递到另一个图像。对于编程 API,可以避免这种情况,因为您可以直接从图像中读取所需的数据并自己生成标签字符串,而无需 IM 以如此复杂的方式存储这些信息。

评估和函数,自由形式通道修改器

因为 FX 运算符 是一个解释型表达式处理器,所以添加了 "-evaluate" 运算符,以便您可以更快地进行简单的图像修改。后来,在 IM v6.4.8-8 中添加了一个更复杂的 "-function" 运算符,以允许在复杂的图像调整中具有更大的灵活性。这两个运算符以及其他 图像级别调整运算符(例如 "-negate"、"-level")可能最适用于对灰度图像进行微调,然后再应用这些图像。尤其是在用于 背景去除高光和阴影叠加 以及 图像映射 生成和微调的灰度图像中。

Evaluate,简单的数学运算

"-evaluate" 运算符基本上是 "-fx" 运算符的快速但非常简单的版本(实际上比它添加到 IM 中早了几个月)。但是,它仅限于使用单个用户提供的常数值进行一项简单操作。您可以使用以下命令找出哪些函数已内置到 evaluate 中:

  magick -list evaluate
这包括典型的数学函数 'add'、'subtract'、'multiply' 和 'divide'。针对常数值。与 -fx 运算符不同,这些值不会规范化为 0 到 1 的范围,而是保持图像的真实颜色值。因此,在 Q8 IM 中减去 50 的值(请参阅 质量和深度 将导致大幅减小,但对于 Q16 版本的 IM,它只会是一个很小的、几乎不可察觉的变化。但是,如果您在参数中添加了 '%',则该参数将表示最大颜色值的百分比(称为 'QuantumRange',等于 ('2quality-1')。这意味着您可以通过适当使用百分比来使 "-evaluate" 参数与 IM 质量级别无关,适用于相应的 evaluate 方法。 例如,只需简单地将图像中的所有颜色值替换为 50% 的灰色级别非常简单且快速,使用 'Set'

  magick rose: -evaluate set 50%  rose_set_gray.gif
[IM Output]
"-evaluate" 运算符还包括典型的数学函数 'add'、'subtract'、'multiply' 和 'divide'。 例如,要将图像的对比度减半,您可以将其 'divide' 除以 '2',然后 'add' 加 '25%' 以将其重新居中到完美的灰色。

  magick rose: -evaluate divide 2 -evaluate add 25%  rose_de-constrast.gif
[IM Output]
这比直接使用带有 'u/2+.25' 的 "-fx" 运算符快几个数量级。因此,如果可能,您应该优先使用此运算符而不是 "-fx"。 "-evaluate" 的主要问题是所有结果都被剪裁到 0 到 'QuantumRange' 的限制内(除非您使用的是 HDRI 版本的 ImageMagick),因为每个修改后的值都会保存回图像数据中。这意味着在任何单独的 "-evaluate" 操作之后,值可能会被 'QuantumRange' 剪裁。 因此,如果您尝试直接应用对比度增强函数(相当于 "-fx '2*u-.25'"),您将无法获得正确的结果,因为在进行减法之前,加倍的值将被剪裁。

  magick rose: -evaluate multiply 2  -evaluate subtract 25% \
          rose_contrast.gif
[IM Output]
首先,'multiply' 将所有较大的颜色值剪裁到最大值,然后 'subtract' 将剪裁下限值。结果是对上限的错误剪裁,产生暗淡和颜色失真的结果。 直接解决方案是首先 'subtract' 减去适当的常数(对下限进行最终但正确的剪裁),然后再进行乘法,有效地使用等效公式 '(u-.125)*2'

  magick rose: -evaluate subtract 12.5%  -evaluate multiply 2 \
          rose_contrast2.gif
[IM Output]
但是,此“剪裁”问题有很多替代方案。第一个合乎逻辑的方案是较新的 多项式函数方法(见下文)。其他替代方案还包括使用 级别调整运算符 甚至 按颜色进行级别调整,只需指定您想要拉伸以填充整个颜色范围的原始颜色值即可。基本上,在使用多个 "-evaluate" 方法时,请注意颜色值剪裁。
"-evaluate" 运算符与 "-fx"(以及大多数其他低级 IM 运算符)一样受 "-channel" 影响。这允许您分别控制图像的 alpha 透明度与颜色通道。是的,与 "-fx" 一样,透明度被视为 'alpha 值',而不是 '蒙版' 值。例如,要使图像透明 50%,作为 溶解 类型操作的一部分。

  magick rose: -alpha set  -channel A -evaluate divide 2   rose_transparent.png
[IM Output]
结果是一个半透明的图像,这意味着在显示时,您看到的颜色有一半是网页的背景颜色。因此,显示的图像会朝向背景颜色变暗。通常,我还发现,在将各个通道分离成单独的图像以用于特定目的之前(请参阅 分离通道),在各个颜色通道上使用 "-evaluate" 通常更容易。例如,这里我使用它来进行快速但不寻常的灰度化。基本上,我将每个通道乘以适当的数量,然后将这些通道分离并加在一起,以生成使用特定颜色比例进行灰度化的图像。


  magick test.png -channel R -evaluate multiply .2 \
                   -channel G -evaluate multiply .5 \
                   -channel B -evaluate multiply .3 \
                   -channel RGB -separate -background black -compose plus -flatten gray_253.png
[IM Output]

Evaluate 数学函数

除了评估操作,ImageMagick 还包含一组特殊用途的数学函数。这些函数通常使用归一化的颜色值(0 到 1 的范围),输出结果也进行归一化,以适应图像的完整颜色范围。 S形对比度 函数也是这种数学函数拟合的一个例子。

幂运算

例如,“Pow” 函数(从 IM v6.4.1-9 版本开始添加)使用归一化的颜色值,允许用户修改图像亮度。它与 C 函数 pow() 完全等效,(使用 0 到 1 范围内的归一化颜色值)。
    value = pow(value, constant) 
因此,要创建“抛物线”渐变,可以使用参数“2”。或者使用值“0.5”来创建“平方根”渐变。例如……

  magick -size 20x600  gradient: -rotate 90  gradient.png
  magick gradient.png  -evaluate Pow  2   eval_pow_parabola.png
  magick gradient.png  -evaluate Pow 0.5  eval_pow_sq_root.png
[IM Output] [IM Output] [IM Output]
[IM Output] ==> [IM Output] [IM Output]
下面三个图像显示了生成的渐变的曲线图和原始图像本身。这使得更容易看出一个渐变图像是如何修改成另一个的。它是使用 Gnuplot 图形绘制程序生成的,通过 IM 示例中的脚本“im_profile”,位于 Scripts 目录。
这实际上等同于 伽马校正 操作符,但参数反转了。例如,“-gamma 2” 操作相当于“-evaluate pow 0.5” 或“平方根”操作函数。类似地,“-gamma 0.5” 等于使用“-evaluate pow 2”进行平方。通过一些特殊的渐变操作,您可以使用此方法将线性渐变转换为复杂的圆弧。

  magick -size 20x300  gradient: -rotate 90 \
          -evaluate Pow 2 -negate -evaluate Pow 0.5 \
          -flop \( +clone -flop \) +append  eval_circle_arc.png
[IM Output]
[IM Output]
对于想要弄清楚这一点的人来说,上面代码的第二行等同于 FX 表达式 'sqrt(1-u^2)'。这生成一个四分之一圆弧,然后进行 翻转拼接,以生成一个半圆弧。它也比使用 FX 表达式 快得多,即使它需要更多单独的(更小的)步骤。另请参阅更高级的 多项式函数

对数运算

Log” 函数(从 IM v6.4.2-1 版本开始添加)也使用归一化值(添加 1.0 以避免无穷大),其中给定的常数用作对数底数。实际公式(使用归一化值)如下……
    value = log(value*constant+1.0)/log(constant+1.0) 
例如...

  magick gradient.png -evaluate Log 10  eval_log.png
[IM Output]
[IM Output]
这看起来可能与之前的 Pow 评估方法 非常相似,但并不完全相同。“Log” 在接近“0” 时会产生明显的斜率,而“Pow” 会产生垂直斜率。该值控制斜率。对数函数也与指数函数密切相关,指数函数目前仅作为 S形对比度调整 操作符实现。它包含与上面对数曲线中相同的斜率特征。这解释了为什么“-sigmoidal-contrast” 是一种比 伽马校正 或“幂运算”曲线更适合增强低光照条件下图像的技术。

正弦和余弦运算

从 IM v6.4.8-8 版本开始添加了“sin” 和“cos” 方法。这些方法获取图像中给定的值并将其归一化为角度,因此完整范围将覆盖一个完整的圆形角度。结果给出一个 50% 的偏差并缩放以再次适应正常的值范围。常数用作值的乘数(以及角度),因此“N” 表示该函数将在整个值范围内绕圆旋转“N” 次。具体来说,它定义了这些函数(使用归一化值)如下……
   value = 0.5 * sin( constant*value*2*PI ) + 0.5
   value = 0.5 * cos( constant*value*2*PI ) + 0.5 
从本质上讲,这些函数的作用是将图像值(通常是灰度值)重新映射到正弦/余弦曲线。例如,这里我取一个渐变图像并使用这些评估方法对其进行修改。

  magick gradient.png  -evaluate sin 1  eval_sin_1.png
  magick gradient.png  -evaluate cos 1  eval_cos_1.png
[IM Output] [IM Output]
[IM Output] ==> [IM Output] [IM Output]
现在,由于常数参数是角度乘数,因此提供给评估方法的值将在图像中整个渐变范围内创建这么多峰值。

  magick gradient.png -evaluate cos 5  -negate  eval_cos_5.png
[IM Output]
[IM Output]
这对于许多任务都非常完美,从生成波纹或色散效果到生成波纹状位移曲线。通过使用“0.5” 的乘数常数,您可以简单地将线性渐变转换为正弦曲线渐变,它仍然具有与原始渐变相同的斜率。通过对结果取反,可以确保渐变也具有正确的斜率。

  magick gradient.png -evaluate cos 0.5  -negate  eval_cos.5.png
[IM Output]
[IM Output]
这对于生成用于重叠照片的平滑渐变非常有用。但是,最后两个“-evaluate” 方法很少使用,因为它们已被更通用的 正弦函数(见下文)所取代,该函数提供了更多控制选项,超越了简单的频率选项。

Function,多参数 Evaluate

上述波形生成器被证明非常有用,尤其是在 图像扭曲映射 中。但人们发现需要对函数进行更精细的控制,需要多个参数。因此,在 IM v6.4.8-9 版本中添加了“-function” 操作符。基本上,“-function” 是“-evaluate” 的多参数形式。但是,与 评估操作符 不同,这些操作符与数学操作符一样,所有上述函数仅作用于图像的归一化通道值(0.0 到 1.0 范围),这在大多数情况下使它们更容易使用。

多项式函数

polynomial” 方法将接受任意数量的值,并根据给定的精确表达式修改图像中的颜色值,速度比 FX 操作符 快得多。
-function   Polynomial   a,b,c,...
每个值将用作从最高阶到最低阶的系数,以生成具有给定项数的多项式。例如,参数“4,-4,1” 将生成等效于“-fx” 表达式“4*u^2 - 4*u + 1” 的多项式表达式。如果您了解高中数学,那么您应该知道此多项式函数会生成一个抛物线曲线,在输入('u')颜色范围 0.0 到 1.0 内从 1.0 到 0.0 再回到 1.0。也就是说,它将使黑色和白色颜色变为“白色”,并将完美的灰色变为“黑色”。

  magick gradient.png -function Polynomial 4,-4,1  func_parabola.png
[IM Output]
[IM Output]
您甚至可以创建更复杂的渐变,例如四次多项式,它是使用一组“级别控制点”生成 曲线级别调整 的结果。这通常用于调整图像的颜色以赋予其各种阴影效果。

  magick gradient.png -function Polynomial '-25, 53, -36, 8.3, 0.2' \
          func_quartic.png
[IM Output]
[IM Output]
当然,简单的线性修改也是可能的,就像您使用 级别操作符 时获得的一样……

  magick gradient.png -function Polynomial '4, -1.5' func_linear.png
[IM Output]
[IM Output]
但是请注意,您不能使用“Polynomial” 执行完整的 阈值 操作,因为需要无限个系数才能执行此操作,尽管您可以非常接近。单个值自然只是一个常数,并导致直接分配该值。换句话说,它就像“-evaluate Set” 方法一样,在这种情况下为 33% 的灰色值。

  magick gradient.png -function Polynomial 0.33 func_constant.png
[IM Output]
[IM Output]
通过将“Polynomial” 与其他数学函数结合使用,您可以创建更复杂的渐变修改。例如,通过取多项式的平方根,我可以在一个线性渐变上创建一个真正的圆弧。等效的“-fx” 表达式“sqrt( -4*u^2 + 4*u + 0 )”……

  magick gradient.png -function Polynomial -4,4,0 -evaluate Pow 0.5 \
          func_circle_arc.png
[IM Output]
[IM Output]
另请参阅 Pow 评估方法 以了解上述方法的替代方案。

正弦函数

Sinusoid” 函数方法是“-evaluate” 方法“sin” 和“cos” 的更高级版本,实际上可以复制这些函数,但您可以更好地控制它如何修改图像中的颜色值。
-function   Sinusoid   frequency,phase,amplitude,bias
并且使用以下公式实现……
  value = ampl * sin(2*PI( freq*value + phase/360 ) ) + bias
这看起来可能很复杂,但它确保了函数易于使用。只需要第一个值“频率”,其工作方式与上面完全相同,所有其他参数都是可选的。默认情况下,它将生成一个正弦曲线。

  magick gradient.png -function Sinusoid 1    func_sine.png
[IM Output]
[IM Output]
通过添加一个以度为单位的“相位” 参数,您可以指定曲线的起始角度。允许您将默认正弦曲线转换为余弦曲线。

  magick gradient.png -function Sinusoid 1,90   func_cosine.png
[IM Output]
[IM Output]
通过调整“频率”和“相位”,我可以直接将线性渐变转换为一个从黑色到白色(沿正弦曲线从最小到最大)的平滑正弦渐变。有关不太直接的方法,请参阅 评估余弦方法

  magick gradient.png -function Sinusoid 0.5,-90 func_sine_grad.png
[IM Output]
[IM Output]
接下来的两个可选值“幅度”和“偏差”控制正弦曲线的比例和中心线。例如,这里我制作了一个波形(反余弦曲线),它在白色和灰色之间振荡(值范围为0.75 ±0.250.5 到 1.0),从白色开始并以白色结束。

  magick gradient.png -function Sinusoid 5,90,.25,.75  func_sine_bias.png
[IM Output]
[IM Output]
小心使用这些最后的参数,因为它们很容易导致波形超出颜色值范围的界限,从而被剪裁(除非您使用 ImageMagick 的 HDRI 版本)。

反正弦函数

反正弦函数“Arcsin” 已添加到 IM v6.5.3-0 版本中。这是一种特殊的曲线,需要用于生成 圆柱体位移图。它的参数是……
-function   Arcsin   width,center,range,bias
并且使用以下公式实现……
  value = range/PI * asin(2/width*( value - center ) ) + bias
默认值(如果未定义)“1, 0.5, 1, 0.5” 确保该函数居中,以便覆盖从0,01,1 的整个颜色范围。

  magick gradient.png -function Arcsin 1    func_arcsin.png
[IM Output]
[IM Output]
通过将所得曲线的“宽度” 减半,您将得到……

  magick gradient.png -function Arcsin 0.5    func_arcsin_width.png
[IM Output]
[IM Output]
中心” 将允许您根据输入灰度值重新定位曲线。

  magick gradient.png -function Arcsin 0.4,0.7 func_arcsin_center.png
[IM Output]
[IM Output]
范围” 参数允许减小颜色值的输出范围,“偏差” 将调整该范围的中心。

  magick gradient.png -function Arcsin 0.5,0.5,0.5,0.5  func_arcsin_range.png
[IM Output]
[IM Output]
请注意如何处理由于函数导致的无效值。这使得在位移中使用该函数时可以更好地控制,并提供清理它们的方法。使用的实际值是“偏差 ±范围/2”,正如您所期望的那样。请注意,如果“宽度” 或“范围” 为负数,则由于该负值,函数的斜率将被翻转。

  magick gradient.png -function Arcsin -1    func_arcsin_neg.png
[IM Output]
[IM Output]

反正切函数

Arctan” 方法已添加到 IM v6.5.3-1 版本中。它的参数是……
-function   Arctan   slope,center,range,bias
并且使用以下公式实现……
  value = range/PI * atan(slope*PI*( value - center ) ) + bias
如您所见,它与“Arcsin” 函数几乎完全相同,只是做了一些小的改动以使其更有用。它甚至具有相同的默认值集(如果未定义)“1, 0.5, 1.0, 0.5”。这意味着,如果您指定“1.0” 的斜率值,则直方图变化的斜率将在纯灰色周围产生 1:1 的变化(无缩放),同时使白色和黑色变为更灰色的值。例如

  magick gradient.png -function Arctan 1 func_arctan.png
[IM Output]
[IM Output]
也就是说,渐变的中间部分实际上保持不变,只有黑色和白色端变得对比度降低。随着曲线的“斜率” 变大,中间的渐变将变得更强(中间更压缩),增加的量与斜率成正比。

  magick gradient.png -function Arctan 10 func_arctan_10.png
[IM Output]
[IM Output]
在很多方面,这与 S形对比度 颜色修改操作符非常相似。但是,“Arctan” 函数永远不会真正达到纯黑色和白色的输出范围限制。它将接近这些限制,但永远不会越过它们。与前面的函数(以及 S形对比度)类似,第二个参数将调整曲线相对于输入渐变值的位置。

  magick gradient.png -function Arctan 10,.7 func_arctan_center.png
[IM Output]
[IM Output]
最后两个参数“范围” 将允许您调整将生成的值的输出范围。例如,通过稍微扩展此值,您可以确保它将完全覆盖所有可能的值范围。


  magick gradient.png -function Arctan 5,0.7,1.2 func_arctan_range.png
[IM Output]
[IM Output]
但是,如果您确实想要生成曲线以这种方式修改整个图像的对比度,则更典型的方法是使用S形对比度运算符,该运算符专为此目的而设计。更典型的是使用“Arctan”渐变函数来创建一条曲线,该曲线将非常快地接近特定值,但不会超过该值。正是这些限制值由“range”和“bias”参数控制。例如,此曲线将修改图像中的渐变,以在 0.7 的输入灰度级周围产生非常锐利的阈值,但值在 0.5 和 1.0 的范围限制之间变化。

  magick gradient.png -function Arctan 15,0.7,0.5,0.75 func_arctan_typ.png
[IM Output]
[IM Output]
这是S形对比度无法生成的。

渐变图像上的数学运算

现在,上述函数为渐变图像提供了一些非常基本的变换。但是,如果您想对两个或多个渐变图像进行一些数学运算怎么办?也就是说,使用另一个图像的渐变修改一个渐变。为此,您需要使用特殊的数学合成方法(例如“Plus”和“Divide”)。但是,在我们开始之前,我想给您一个警告。如果您的渐变图像是纯灰度图像,没有 Alpha 通道,那么您可以直接使用数学合成方法。但是,如果您想将这些方法限制在特定通道,或将其应用于 Alpha(透明度)通道,则需要确保设置了适当的“-channel”设置,并且没有特殊的“Sync”通道标志。有关更多详细信息,请参阅使用图像合成进行图像数学运算。通常,使用数学合成方法并不是那么困难。当您具有也包含“偏差”的渐变时,就会出现复杂情况。也就是说,渐变应在“50% 灰色”处表示“零”值,并在 -1(黑色)到 +1(白色)之间覆盖一个范围。此类图像通常用于失真图像映射。因此,对“带偏差的渐变”进行数学运算才是真正的问题,我们将在本文中更具体地讨论这个问题。

衰减带偏差的渐变

例如,这里我想创建一个正弦波,但它最初很小,然后幅度变大。这称为“衰减”带偏差的渐变。或者换句话说,将带偏差的渐变乘以另一个绝对渐变。这也是诸如调幅广播中的“幅度调制”的工作原理!因此,我们首先需要一个正弦波,我们可以简单地从线性渐变中生成它……

  magick -size 5x300 gradient: -rotate 90   math_linear.png
  magick math_linear.png  -evaluate sine 12  math_sine.png
[IM Output] ==> [IM Output]
现在,为了衰减它,我们使用乘法 Alpha 合成将正弦波与线性渐变相乘……

  magick math_sine.png  math_linear.png  \
          -compose Multiply -composite  math_sine_2.png
[IM Output] X [IM Output] ==> [IM Output]
但是,为了在例如水波纹、位移映射中使用它,波浪必须保持围绕完美的灰色居中。为此,我们需要向原始图像添加偏差。碰巧这是我们用于将原始图像相乘的相同函数,取反并除以二……

  magick math_linear.png -negate -evaluate divide 2  math_bias.png
  magick math_sine_2.png  math_bias.png \
          -compose Plus -composite  math_attenuated.png
[IM Output] X [IM Output] ==> [IM Output]
因此,我们得到了一个线性衰减的正弦波渐变,适用于位移映射。

当然,您可以将整个过程都放在一个命令中,并且它也不必是简单的线性衰减。例如,这里我使用取反的余弦波而不是线性渐变来衰减高频正弦波。


  magick math_linear.png  -evaluate cos 1 -negate  math_cosine_peak.png
  magick math_sine.png  math_cosine_peak.png \
          \( -clone 0,1 -compose multiply -composite \) \
          \( -clone  1  +level 50%,0 \
             -clone  2  -compose plus -composite \) \
          -delete 0--2  math_cosine_atten.png
[IM 输出] 衰减 [IM 输出] ==> [IM 输出]
从 IM v6.5.4-3 开始,现在可以在一个合成方法中完成上述所有步骤,使用特殊的数学合成方法。基本上,通过认识到衰减运算的公式为Sc*Dc-.5*Sc+.5或参数“1,-.5,0,.5”。

  magick math_sine.png  math_cosine_peak.png \
          -compose Mathematics -set option:compose:args 1,-.5,0,.5 \
          -composite  math_attenuate.png
[IM Output]
也可以通过首先使用多项式函数调整衰减渐变,然后使用排除合成运算符来合并图像来实现相同的结果。

  magick math_sine.png \( math_cosine_peak.png -function polynomial -.5,.5 \) \
          -compose Exclusion -composite  math_poly_excl.png
[IM Output]

乘以有偏渐变

但是如果两个函数都存在偏差,因此完美的灰色表示零,黑色和白色表示 -1 到 +1 的范围呢?好吧,这有点复杂,因为您不能只是将它们相乘并期望得到正确的结果,因为乘法可能包含负值。这需要小心,以确保您最终不会裁剪值并获得结果图像中曲线的正确取反。诀窍是将乘法分解成多个步骤。也就是说   A × B   也可以写成   A × abs(B) × sign(B)。通过这样做,您避免了乘以负值,这无法存储在正常的渐变图像中。因此,我们需要做的就是取其中一个偏差渐变并将其分成两部分,以便它们可以适当地应用于另一个渐变。“sign()”带偏差的渐变,或获取哪些部分为负的掩码,可以通过在偏差级别对渐变使用阈值来提取。您可以稍后使用合成差和该阈值图像选择性地取反另一个渐变。“abs()”带偏差的渐变可以使用Solarize轻松提取,然后取反并加倍(使用Level)以获得从 0.0 到 1.0 的渐变的绝对值。由于我们还需要将偏差偏移作为乘法的一部分(如上所述衰减),因此您可以在将其转换为渐变的绝对值之前,直接使用取反且缩放一半的 Solarize 输出。因此,让我们将一个渐变转换为这三个组成部分。

  magick math_cosine_peak.png  -threshold 50% -negate  math_m_sign.png
  magick math_cosine_peak.png     -solarize 50%        math_m_bias.png
  magick math_m_bias.png          -level 50%,0         math_m_abs.png
[IM Output] 渐变的符号
白色 = 负数
[IM Output] ==> [IM Output] 偏差偏移
[IM Output] 绝对值
现在我们有了其中一个渐变图像的这三个部分,我们可以将它们与另一个渐变合并。为此,我们乘以绝对值,重新添加偏差,然后取反应取反的部分。

  magick math_sine.png   math_m_abs.png \
          -compose Multiply -composite    math_m_1.png
  magick math_m_1.png   math_m_bias.png \
          -compose Plus -composite        math_m_2.png
  magick math_m_2.png   math_m_sign.png \
          -compose Difference -composite  math_multiply.png
[IM Output] X [IM Output] ==> [IM Output]
+ [IM Output] ==> [IM Output]
符号 [IM Output] ==> [IM Output]
这就是两个偏差渐变图像的完美乘法!这里再次显示所有内容,但都在一个命令中……

  magick math_sine.png  math_cosine_peak.png \
          \( -clone  1  -threshold 50% -negate \) \
          \( -clone  1      -solarize 50%      \) \
          \( -clone  3      -level 50%,0       \) \
          \( -clone 0,4 -compose multiply   -composite \
             -clone  3  -compose plus       -composite \
             -clone  2  -compose difference -composite \) \
          -delete 0--2    math_multiply_2.png
[IM Output] X [IM Output] ==> [IM Output]
最后一点,与衰减不同,偏差渐变的这种乘法是可交换的。也就是说,交换输入图像不会影响最终结果。由于以上等价于公式2*Sc*Dc-Sc-Dc+1,因此从 IM v6.5.4-3 开始,您可以使用参数“2,-1,-1,1”将上述复杂步骤实现为单个“Mathematics”合成方法。

  magick math_sine.png  math_cosine_peak.png \
          -compose Mathematics -set option:compose:args 2,-1,-1,1 \
          -composite  math_bias_multiply.png
[IM Output]
也就是说,与没有此参数化合成方法所需的十几步相比,这是一种简单得多的方法。碰巧的是,一旦我看到了那个公式,我就意识到这恰好是“Exclusion”合成方法的否定。奇怪但真实。因此,以下内容也将生成相同的零偏差乘法。

  magick math_sine.png  math_cosine_peak.png \
          -compose exclusion -composite -negate  math_excl_neg.png
[IM Output]

添加有偏渐变

随着“Mathematics”合成方法的出现,添加偏差渐变也相对容易。等效的 FX 公式为“u+v-0.5”或合成参数“0,1,1,-.5”。例如,以下是傅里叶变换示例,我手动生成了它,需要添加 3 个带偏差的正弦波和一个常数直流值。

  magick math_linear.png -function sinusoid 3.5,0,.25     wave_1.png
  magick math_linear.png -function sinusoid 1.5,-90,.13   wave_2.png
  magick math_linear.png -function sinusoid 0.6,-90,.07   wave_3.png

  magick wave_1.png wave_2.png wave_3.png -background gray40 \
          -compose Mathematics -set option:compose:args 0,1,1,-.5 \
          -flatten  added_waves.png
[IM Output]  + [IM Output]  + [IM Output] ==> [IM Output]
请注意,在上面我如何使用“-flatten”运算符和“-background”设置来实现多图像合成。或者在这种情况下,所有给定图像加上背景常数的“带偏差的总和”。

频率调制

通过将函数直接应用于另一个函数的输出,您不会产生简单结果。原因是所有这些数学函数都应用于各个像素的渐变“值”,而不是针对渐变中像素的 x 值。例如……

  magick gradient.png  -evaluate sin 0.5 -normalize \
                        -evaluate cos  8  math_cos_var.png
[IM Output]
[IM Output]
这会生成一个非常复杂的函数,基本上等效于
cos( 8 * sin( {value}/2 ) )
换句话说,这是一个可变频率,其中频率随第一个正弦曲线的渐变而变化。基本上,原始图像中渐变变化越快,峰值之间的距离就越小。但是峰值的高度(幅度)不会变化。这实际上是“频率调制”的工作原理,其中一个看似简单的函数会产生非常复杂的结果。
建设中
Miscellaneous Image Transformation Techniques.

These have not been exampled yet, but are some basic IM developed transforms
that may provide useful.  If you have an interesting effect please contribute.

   pixelize an image
      resize an image down 10 then scale the image 10 to produce blocks
      of roughly averaged color.
      For example...
         magick input.jpg -resize 10% -sample 1000% output.jpg

  De-skew slightly rotated images

    -deskew {threshold}
       straighten an image. A threshold of 40% works for most images.

    Use -set option:deskew:auto-crop {width} to auto crop the image. The set
    argument is the pixel width of the image background (e.g 40).

    Programmically we auto crop by running a median filter across the image
    to eliminate salt-n-pepper noise.  Next we get the image bounds of the
    median filter image with a fuzz factor (e.g. -fuzz 5%).  Finally we
    crop the original image by the bounds.  The code looks like this:

      median_image=MedianFilterImage(image,0.0,exception);
      geometry=GetImageBoundingBox(median_image,exception);
      median_image-DestoryImage(median_image);

      print("  Auto-crop geometry: %lux%lu%+ld%+ld",
                geometry.width,geometry.height, geometry.x,geometry.y);
      crop_image=CropImage(rotate_image,&geometry,exception);

    See Trimming 'Noisy' Images

  Segmentation
    look at scripts
       divide_vert
       segment_image
    for some simple scripts I wrote to segment well defined images into
    smaller parts.   I hope to get simple segmentation functions like this
    into the core library, to allow for things like automatic sub-division of
    GIF animations, and seperating images and diagrams from scanned documents.