1

我有 2 个目录,其中包含大量图像,例如:color/gray/。在颜色/图像中命名为: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 脚本或其他做得很好的东西。

另一种说法:我希望使用正确匹配的名称将所有内容color/*.jpg复制到文件夹中。results/*.jpggray/*.jpg

编辑(一些注释): 1. 这三个图像的大小和内容相同。唯一的区别是两个是彩色的,一个是灰度的。当然还有文件的名称。2. 我上传了一个带有当前名称的示例图像的 zip 文件(文件夹“img1”颜色文件夹,文件夹“img2”灰度文件夹)和预期结果(“img3”结果文件夹),这里:http://www.mediafire.com/?9ug944v6h7t3ya8

4

3 回答 3

4

如果我正确理解了要求,我们需要:

  • 查找文件夹gray/中名为 XYZ的每个灰度图像...
  • ...文件夹color/中名为 ABC的匹配彩色图像和...
  • ...以新名称 XYZ将 ABC 复制到文件夹results/

所以我建议的基本算法是这样的:

  1. 将文件夹color/中的所有图像转换为灰度并将结果存储在文件夹gray-reference/中。保留原始名称:

    mkdir gray-reference
    convert  color/img123.jpg  -colorspace gray  gray-reference/img123.jpg
    
  2. 对于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 脚本的构建块:

  1. 将 '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
    
  2. 从 '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
    
  3. 将目录“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
    

警告:不要盲目依赖这些构建块。它们未经测试。我没有可用于测试的多个合适图像的目录,并且我不想自己创建一个只是为了这个练习。谨慎行事!

于 2012-10-04T23:11:13.003 回答
2

如果诸如pHash 之类的感知散列技术对您的具体数据产生了一些好的结果,您应该尝试一下。

感知散列将为您提供可靠的相似性度量,因为底层算法足够强大,可以考虑对比度调整或不同压缩/格式等变化/转换 - 这与 MD5 等标准加密散列函数不同。

此外,您可以通过在您自己的图像上使用其方便的基于 Web 的演示界面来验证 pHash 是否有效。

于 2012-09-29T10:18:14.977 回答
1

在对 -fuzz 选项进行一些调整和摆弄之后,Kurt 的解决方案非常有效!:) 最终运行良好的 -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 中使用 imagemagick,所以在本机 linux imagemagick 中可能更好,我还不知道):

real    5m29.308s
user    2m25.481s
sys     3m1.573s

如果有人感兴趣,我上传了一个包含脚本和一组测试图像的文件。http://www.mediafire.com/?1ez0gs6bw3rqbe4(以7z格式压缩)

再次感谢!

于 2012-10-08T15:37:55.133 回答