如果我正确理解了要求,我们需要:
- 查找文件夹gray/中名为 XYZ的每个灰度图像...
- ...文件夹color/中名为 ABC的匹配彩色图像和...
- ...以新名称 XYZ将 ABC 复制到文件夹results/
所以我建议的基本算法是这样的:
将文件夹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
,这确实允许在比较 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
警告:不要盲目依赖这些构建块。它们未经测试。我没有可用于测试的多个合适图像的目录,并且我不想自己创建一个只是为了这个练习。谨慎行事!