使用ImageMagick对图像进行“差异”处理

219

如何获取两张图片之间的差异?我有原始图片。有人在完全复制的原始图像上写了字。现在,我需要比较原始图像和写在图像上的图像,并提取仅包含文字的图像。

例如:我有一张房子的照片。有人复制了它并在复制品上写下“你好!”。我希望以某种方式比较这两张图片,删除房子,并留下一个包含“你好!”字样的图像。

使用ImageMagick能否实现这一点?我知道有方法可以获取图像之间的统计差异,但那不是我想要的。


8
请查看ImageMagick使用指南中的此部分 - Benoit
1
我知道这个问题是关于ImageMagick的,但我不得不包含一个指向Resemble.js链接的原因是为了“随意”搜索者可能需要一个通用解决方案。 - brichins
有没有人知道一个工具,可以通过从第一张图片中减去第二张图片的像素来比较这两张图片?我不想自己编写代码。 - MarcusJ
@BReddy 我不知道,我从未使用过它。我只是重复了研究论文和ImageMagick文件的说法。我并不惊讶它在实践中不起作用,这是一个经典的做法,假装有什么不可思议的东西,然后它失败了。 - v.oddou
1
@v.oddou,谢谢您。我阅读了文档并进行了更多测试。它似乎在线条图像上表现不佳,这些图像非常稀疏且像素密度极低。看起来像素密度是PHASH识别相似性的关键。 - BReddy
显示剩余3条评论
3个回答

377

我自己的最爱是这两个:

 compare image1 image2 -compose src diff.png
 compare image1 image2 -compose src diff.pdf

上述两个命令唯一的区别是:第一个命令将两张图片的视觉差异作为PNG文件显示,而第二个命令则作为PDF显示。

生成的差异文件中所有不同像素都以红色显示,未更改的像素以白色显示。

简短明了。

注意,你的图像不需要是相同类型的。甚至可以混合使用JPEG、TIFF、PNG格式——但有一个条件:这些图像应该具有相同的尺寸(以像素为单位)。输出格式由输出文件名的扩展名确定。

如果您因某种原因需要比默认值(72 dpi)更高的分辨率,则只需添加适当的-density参数即可:

 compare -density 300 image1 image2 -compose src diff.jpeg

实例说明

这里是对以上命令的几个变化结果进行的示例说明。注意:比较的两个文件都是相同的PDF文件,所以它也可以使用在这些文件上(只要它们都是单页)!


左:带有文本的图像   中:原始图像   右:不同之处(=文本)以红色像素表示。 仅显示红色差异像素;相同的像素为白色

compare \
        porsche-with-scratch.pdf  porsche-original.pdf \
       -compose src \
        diff-compose-default.pdf

这是我之前建议的同一条命令。


左侧:带文本的图像      中心:原始图像      右侧:'seagreen'像素的差异。 仅包含'Seagreen'差异像素;相同的像素为白色

compare \
        porsche-with-scratch.pdf  porsche-original.pdf \
       -compose src \
       -highlight-color seagreen \
        diff-compose-default.pdf
此命令添加一个参数,使得不同的像素点“seagreen”而非默认的红色。

左:带文本的图像     中:原始图像     右:蓝色差异(但具有一些背景上下文)。 只有蓝色差异像素;第一张被比较的图片作为一个变亮的背景l

compare \
        porsche-with-scratch.pdf  porsche-original.pdf \
       -highlight-color blue \
        diff-compose-default.pdf

这个命令移除了 -compose src 部分 -- 结果是默认行为的 compare 命令,它保留了两个不同图片中第一个作为亮背景的图片。(这次加入了参数以使得不同像素出现蓝色。)


我无法理解这个比较cli是从哪里来的?它是Imagebrick的一部分吗?在Windows上可用吗? - Krishnom
3
@Krishnom: "imagebrick"这个词并不存在。您是指ImageMagick吗? - Kurt Pfeifle
5
这个问题明确要求提供一个ImageMagick的解决方案。ImageMagick v6.x软件套件中有一个单独的命令行工具叫做“compare”。而在ImageMagick v7.x中,你应该使用“magick compare”代替。 - Kurt Pfeifle
我的错。感谢您纠正了那个(imagebrick -> imageMagick)。我会尝试一下的。我还在寻找比较大量图像的工具。再次感谢您的帮助。 - Krishnom
@Krishnom:我不知道什么是“批量图像”。但我敢打赌,ImageMagick工具套件可以满足你的需求。 - Kurt Pfeifle
我之前不知道这个存在。太棒了!我正在使用 Puppeteer 进行一些视觉回归测试,但是对于某个页面,我总是无法得到相同的结果,感到困惑。现在有了这个工具,我可以轻松地找到差异!谢谢! - matchew

79

虽然compare在许多应用中都表现良好,但我发现有时候我更喜欢采用另一种方法,特别是在比较主要为灰度的图像时:

convert '(' file1.png -flatten -grayscale Rec709Luminance ')' \
        '(' file2.png -flatten -grayscale Rec709Luminance ')' \
        '(' -clone 0-1 -compose darken -composite ')' \
        -channel RGB -combine diff.png
该想法如下:将file1.pngfile2.png都转换为灰度。然后将第一个文件视为结果图像的红色通道,将第二个文件视为绿色通道。使用darken合成运算符从这两个文件中形成蓝色通道,该运算符实际上意味着取最小值。
因此,在两个图像中均为白色的部分保持白色。在两个图像中均为黑色的部分保持黑色。在第一个图像中为白色但在第二个图像中为黑色的部分变成红色,而在第二个图像中为白色但在第一个图像中为黑色的部分则变成绿色。
结果给出了一个很好的彩色编码图像,您可以轻松地将绿色与第一个输入相关联,将红色与第二个输入相关联。以下是一个示例,我在其中使用它来比较LaTeX的输出与KaTeX的输出(在我修复了一些错误之前): enter image description here 您可以结合这些方法,使用compare查看某个地方的变化,然后使用上述方法更详细地查看其变化方式。

2
不错!我需要一些交互,所以我在Gimp中复制了你的方法。供参考:1)将图像作为图层加载,2)对两个图层进行颜色->去饱和度处理,3)在“图层”选项卡中删除两个图层的alpha通道,4)在一个图层上选择G + B通道,全选并用黑色清除通道,在第二个图层上也是同样的操作,选择R + B通道,4)在“图层”选项卡中设置上层的屏幕模式。 - Matěj Šmíd
1
@Palmstrom:谢谢!我最初是使用Gimp自己进行这些图像比较的,但我直接在输入图像上使用“颗粒提取”图层模式,因此共同区域会变成灰色,而差异则在一个方向上为黑色,在另一个方向上为白色。虽然更难读取,但生成速度更快,并且可以包含颜色信息。我想如果您使用“仅加深”而不是“屏幕”,并将未使用的通道涂成白色而不是黑色,那么您的命令可能会更加匹配。 - MvG
1
某些PDF输入在灰度转换后会因为某种原因导致图像翻转。使用-colorspace gray而不是-grayscale Rec709Luminance可以解决这个问题,但会破坏图像的构成。将-respect-parentheses作为convert的第一个选项添加进去,以解决这个问题。 - Brecht Machiels
1
以下是一个脚本,使用此方法逐页可视化比较两个PDF文件:https://gist.github.com/brechtm/891de9f72516c1b2cbc1。它会在“pdfdiff”目录中为每个PDF页面输出一个JPG,并额外打印出两个PDF文件之间不同的页面编号。 - Brecht Machiels
1
在ImageMagick v6.7.7-10中,似乎不支持“-grayscale”选项,我必须使用@BrechtMachiels建议的“-colorspace gray”。 - austinmarton
非常好!对我来说(ImageMagick 7.1.0-29),“-flatten”做了一些奇怪而无用的事情(它似乎恢复到我的源图像的未裁剪版本,这是没有意义的),但是在没有它的情况下完美地工作。如果您的png中有透明层,则可能仅有用?我还交换了输入文件的顺序,因此红色表示“在file2中删除”,绿色表示“在file2中添加”,这在我看来更直观。 - Heath Raftery

3
从ImageMagick 6.3.4开始,你可以使用-compose ChangeMask(另请参阅"Removing a Known Background"和后续部分)。 例如,使用IM7和这些图像stone.pngdiamond_ore.pngnetherrack.png
stone.png diamond_ore.png netherrack.png

magick diamond_ore.png stone.png -fuzz 15% -compose ChangeMask -composite diamond_ore_overlay.png 给出了:
diamond_ore_overlay.png

然后 magick netherrack.png diamond_ore_overlay.png -composite nether_diamond_ore.png 给出了:
nether_diamond_ore.png
(在一个命令中:magick netherrack.png \( diamond_ore.png stone.png -fuzz 15% -compose ChangeMask -composite +compose \) -composite nether_diamond_ore.png


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