如果我正确理解了要求,我们需要:
- 查找文件夹 gray/ 中名为 XYZ 的每个 灰度 图像...
- ...文件夹color/中名为ABC的匹配color图像和...
- ...将 ABC 复制到文件夹 results/ 下,新名称为 XYZ
所以我建议的基本算法是这样的:
-
将文件夹 color/ 中的所有图像转换为灰度并将结果存储在文件夹 gray-reference/ 中。保留原名:
mkdir gray-reference
convert color/img123.jpg -colorspace gray gray-reference/img123.jpg
-
对于 reference/ 中的每个灰度图像,与文件夹 gray/ 中的每个灰度图像进行比较。如果找到匹配项,请将相同名称的相应图像从 color/ 复制到 results/。创建差异的视觉表示的一种可能的比较命令是:
compare gray-reference/img123.jpg gray/imgABC.jpg -compose src delta.jpg
真正的诀窍是比较两个灰度图像(如第 2 步)。 ImageMagick 有一个方便的命令来逐像素比较两个(相似)图像并将结果写入“增量”图像:
compare reference.png test.png -compose src delta.png
如果比较是针对彩色图像,则在增量图像中...
- ...每个相等的像素显示为白色,而...
- ...每个不同的像素都以高亮颜色显示(默认为红色)。
另请参阅我的回答 "ImageMagick: 'Diff' an Image",了解该技术的示例。
如果我们直接逐个像素地比较灰色图像和彩色图像,我们当然会发现几乎每个像素都是不同的(导致全红色的“delta”图片)。因此,我在上面的步骤 1 中建议首先将彩色图像转换为灰度图像。
如果我们比较两张灰度图像,得到的增量图像也是灰度的。因此默认的高亮颜色不能是红色。我们最好将其设置为“黑色”以便更好地查看。
现在,如果我们当前对颜色的灰度转换会导致与现有灰度图像具有“不同”的灰度(我们当前生成的灰度可能只是比现有灰度图像稍亮或稍暗,因为已应用不同的颜色配置文件),可能仍然我们的增量图片是全“红色”,或者更确切地说是全高亮颜色。但是,我用您的示例图像对此进行了测试,结果很好:
convert color/image1.jpg -colorspace gray image1-gray.jpg
compare \
gray/file324.jpg \
image1-gray.jpg \
-highlight-color black \
-compose src \
delta.jpg
delta.jpg 由 98% 的白色像素组成。我不确定您的数千张灰度图像中的所有其他图像在源自彩色原件时是否使用相同的设置。因此,我们在运行 compare 命令时添加了一个小的 fuzz 因素,这确实允许在比较 2 个像素时出现一些颜色偏差:
compare -fuzz 3% reference.png test.png -compose src delta.png
由于该算法要执行数千次(可能是数百万次,考虑到您所说的图像数量),我们应该考虑一些性能因素,我们应该对compare 命令的持续时间进行计时。这尤其令人担忧,因为您的示例图像相当大(3072x2048 像素 - 6 兆像素),并且比较可能需要一段时间。
我在 MacBook Pro 上的计时结果如下:
time (convert color/image1.jpg -colorspace gray image1-gray.jpg ;
compare \
gray/file324.jpg \
image1-gray.jpg \
-highlight-color black \
-fuzz 3% \
-compose src \
delta100-fuzz.jpg)
real 0m6.085s
user 0m2.616s
sys 0m0.598s
6 秒时间:1 次将大型彩色图像转换为灰度,外加 1 次比较两个大型灰度图像。
您谈到了“数千张图片”。假设有 3000 张图像,基于这个时间,所有图像的处理将需要(3000*3000)/2 比较(450 万)和(3000*3000*6)/2 秒(2700 万秒)。完成所有比较总共需要 312 天。太长了,如果你问我的话。
我们可以做些什么来提高性能?
嗯,我的第一个想法是减小图像的大小。如果我们比较较小的图像而不是 3072x2048 大小的图像,则比较应该更快地返回结果。 (但是,我们还将花费额外的时间来首次缩小测试图像 - 但希望比我们以后在比较较小的图像时节省的时间要少得多:
time (convert color/image1.jpg -colorspace gray -scale 6.25% image1-gray.jpg ;
convert gray/file324.jpg -scale 6.25% file324-gray.jpg ;
compare \
file324-gray.jpg \
image1-gray.jpg \
-highlight-color black \
-fuzz 3% \
-compose src \
delta6.25-fuzz.jpg)
real 0m0.670s
user 0m0.584s
sys 0m0.074s
这样好多了!我们缩短了近 90% 的处理时间,如果您使用 MacBook Pro,这让您有希望在 35 天内完成工作。
改进是合乎逻辑的:通过将图像尺寸减小到原始图像的 6.25%,生成的图像只有 192x128 像素——从 600 万像素减少到 24500 像素,比例为 256:1。
(注意:-thumbnail 和 -resize 参数的运行速度会比 -scale 快一点。但是,这种速度提高是对质量损失的权衡。质量损失可能会使比较不那么可靠...)
我们可以告诉 ImageMagick 打印一些统计数据,而不是从比较图像中创建视觉可检查的 delta 图像。要获取不同像素的数量,我们可以使用AE 指标。命令及其结果如下:
time (convert color/image1.jpg -colorspace gray -scale 6.25% image1-gray.jpg ;
convert gray/file324.jpg -scale 6.25% file324-gray.jpg ;
compare -metric AE file324-gray.jpg image1-gray.jpg -fuzz 3% null: 2>&1 )
0
real 0m0.640s
user 0m0.574s
sys 0m0.073s
这意味着我们有 0 不同的像素——我们可以直接在 shell 脚本中使用这个结果!
Shell 脚本的构建块
以下是用于执行自动比较的 shell 脚本的构建块:
-
将彩色图像从'color/'目录转换为灰度图像,将它们缩小到6.25%并将结果保存在'reference-color/'目录中:
# Estimated time required to convert 1000 images of size 3072x2048:
# 500 seconds
mkdir reference-color
for i in color/*.jpg; do
convert "${i}" -colorspace gray -scale 6.25% reference-color/$(basename "${i}")
done
-
缩小“gray/”目录中的图像并将结果保存在“reference-gray/”目录中:
# Estimated time required to convert 1000 images of size 3072x2048:
# 250 seconds
mkdir reference-gray
for i in gray/*.jpg; do
convert "${i}" -scale 6.25% reference-gray/$(basename "${i}")
done
-
将“reference-gray/”目录中的每个图像与“reference-color”目录中的图像进行比较,直到找到匹配项:
# Estimated time required to compare 1 image with 1000 images:
# 300 seconds
# If we have 1000 images, we need to conduct a total of 1000*1000/2
# comparisons to find all matches;
# that is, we need about 2 days to accomplish all.
# If we have 3000 images, we need a total of 3000*3000/2 comparisons
# to find all matches;
# this requires about 20 days.
#
for i in reference-gray/*.jpg ; do
for i in reference-color/*.jpg ; do
# compare the two grayscale reference images
if [ "x0" == "x$(compare -metric AE "${i}" "${j}" -fuzz 3% null: 2>&1)" ]; then
# if we found a match, then create the copy under the required name
cp color/$(basename "${j}" results/$(basename "${i}") ;
# if we found a match, then remove the respective reference image (we do not want to compare again with this one)
rm -rf "${i}"
# if we found a match, break from within this loop and start the next one
break ;
fi
done
done
警告:不要盲目依赖这些构建块。它们未经测试。我没有可用于测试的多个合适图像的目录,并且我不想自己创建一个只是为了这个练习。谨慎行事!