我有两个目录,里面有很多图像,比如:color/和gray/。在color/中,图像被命名为:image1.png image2.png等
我知道gray/包含相同的图像,但灰度不同,文件名和文件顺序不同(例如:file_01.png,但这与image1.png不是同一张图像)。
是否可以比较两个目录中的图像,并将color/文件复制到文件名为gray/的results/目录?
示例:
directory | directory | directory
"color/" | "gray/" | "results/"
(color images) | (grayscale images) | (color images with gray-scale names)
-----------------+---------------------+----------------------------------------
color/image1.png | gray/file324.png | results/file324.png (in color: ==>
| this and image1.png are the same image)
我希望这不是很令人困惑,但我不知道如何更好地解释它。
我尝试过使用imagemagick,compare选项似乎可以实现这一点,但我无法制作一个bash脚本或其他能很好地实现它的东西。
另一种说法是:我希望使用正确匹配的gray/*.jpg
名称将所有color/*.jpg
复制到results/*.jpg
文件夹中。
编辑(一些注意事项):1。这三张图片的大小和内容相同。唯一的区别是两个是彩色的,一个是灰度的。当然还有文件的名称。2.我上传了一个zip文件,其中包含一个带有当前名称的示例图像(文件夹"img1">是颜色文件夹,文件夹imm2">是灰度文件夹)和预期结果(img3">为结果),此处:http://www.mediafire.com/?9ug944v6h7t3ya8
如果我正确理解了需求,我们需要:
- 查找文件夹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有一个方便的命令,可以逐像素比较两个(相似的)图像,并将结果写入"delta"图像:
compare reference.png test.png -compose src delta.png
如果比较是针对彩色图像,则在delta图像中。。。
- 。。。每个相等的像素都显示为白色,而
- 。。。每个不同的像素都显示为高亮显示颜色(默认为红色)
另请参阅我的回答"ImageMagick:‘Diff’an Image",以获取此技术的示例
如果我们直接逐像素比较灰色图像和彩色图像,我们当然会发现几乎每个像素都不同(导致全红色的"delta"图片)。因此,我在上面的步骤1中建议首先将彩色图像转换为灰度。
如果我们比较两个灰度图像,则生成的delta图像也是灰度图像。因此,默认的高亮颜色不能是红色。我们最好将其设置为"黑色",以便更好地看到它。
现在,如果我们目前对颜色的灰度转换会导致与现有灰度图像"不同"的灰度(由于应用了不同的颜色配置文件,我们目前产生的灰度可能比现有灰度图像略浅或略暗),那么我们的delta图片可能仍然是"红色",或者更确切地说是全部高亮颜色。然而,我用你的样本图像进行了测试,结果很好:
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万像素减少到245000像素,比例为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/'目录中的图像,并将结果保存在'referencegray/'文件夹中:
# 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
注意:不要盲目依赖这些构建块。它们未经测试。我没有一个包含多个合适图像的目录来测试这一点,我也不想只为这个练习创建一个。小心操作!
您应该尝试一下感知哈希技术(如pHash)是否能在具体数据上产生一些好的结果。
感知哈希将为您提供可靠的相似性度量,因为底层算法足够强大,可以考虑对比度调整或不同压缩/格式等变化/转换,而MD5等标准加密哈希函数则不然。
此外,您可以通过在自己的图像上使用其方便的基于网络的演示界面来验证pHash是否有效。
Kurt的解决方案在对-fuzz选项进行了一些调整和篡改之后,效果非常好!.:)最终运行良好的-fuzz的最终值是50%!我尝试了3、10、19、20、24、25、30和40%,但都没有成功。可能是因为以前用不同的方法生成的灰度图像,所以灰度不同。此外,所有图像都有不同的大小,其中一些图像相对较小,因此按百分比缩放的方法会产生糟糕的结果。我使用了-resize 200x
,所以所有的参考图像大小都差不多,最后这就是我使用的bash脚本:
# this bash assumes the existence of two dirs: color/ and gray/
# each one with images to compare
echo Starting...
echo Checking directories...
if [ ! -d color ]; then
echo Error: the directory color does not exist!
exit 1;
fi
if [ ! -d gray ]; then
echo Error: the directory gray does not exist!
exit 1;
fi
echo Directories exist. Proceeding...
mkdir reference-color
echo creating reference-color...
for i in color/*.png; do
convert "${i}" -colorspace gray -resize 200x reference-color/$(basename "${i}")
done
echo reference-color created...
mkdir reference-gray
echo creating reference-gray...
for i in gray/*.png; do
convert "${i}" -resize 200x reference-gray/$(basename "${i}")
done
echo reference-gray created...
mkdir results
echo created results directory...
echo ...ready.
echo "-------------------------"
echo "| starting comparison |"
echo "-------------------------"
for i in reference-gray/*.png; do
echo comparing image $i
for j in reference-color/*.png; do
# compare the two grayscale reference images
if [ "x0" == "x$(compare -metric AE "${i}" "${j}" -fuzz 50% null: 2>&1)" ]; then
# if we found a match, then create the copy under the required name
echo Founded a similar one. Copying and renaming it...
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)
echo Deleting references...
rm -rf "${i}"
rm -rf "${j}"
echo "--------------------------------------------------------------"
# if we found a match, break from within this loop and start the next one
break ;
fi
done
done
echo Cleaning...
rm -rf reference-color
rm -rf reference-gray
echo Finished!
时间度量是(对于180个图像,在cygwin中使用imagemagik,所以在原生linux imagemagik中可能更好,我还不知道):
real 5m29.308s
user 2m25.481s
sys 3m1.573s
如果有人感兴趣的话,我上传了一个包含脚本和一组测试图像的文件。http://www.mediafire.com/?1ez0gs6bw3rqbe4(用7z格式压缩)
再次感谢!