ImageMagick 示例 --
图像比较

索引
ImageMagick 示例前言和索引
图像比较方法 -- 哪里不同?
比较统计 -- 差异程度?
子图像匹配和定位 在更大的图像中查找较小的图像。
查找重复图像 -- 查找两个相同的图像
按类型排序图像 -- 用于比较的图像分类
处理特定图像类型
图像度量 -- 用于比较的图像指纹
网络摄像头 -- 查找固定摄像机中发生的变化
比较两个或多个图像,或在一个大型集合中查找重复图像,是一个非常棘手的问题。在这些示例中,我们研究比较图像以确定它们的相似程度以及它们的不同之处。这可能涉及将图像分类或分组到各种类型中以进行更好的处理。发现一些度量来简化和分组类似的图像。以及根据此类度量聚类类似的图像。然而,这些比较或研究虽然困难,但却是值得的,因为它能够查找图像重复项、副本,甚至可以从图像中删除“垃圾邮件”或其他文本或通知。

图像比较方法

Compare 程序

提供了“magick compare”程序,以便您可以轻松地比较两个相似的图像,以确定图像的“差异”程度。例如,这里我有动画“包”的两帧,然后我将其提供给“magick compare”,以突出显示其发生变化的区域。

  magick compare bag_frame1.gif bag_frame2.gif  magick compare.gif
[IM Output] [IM Output] ==> [IM Output]
如您所见,您将获得一个白色和红色的图像,其中包含第二个图像的“阴影”。它清楚地表明了两个图像之间发生变化的三个区域。您当然可以直接查看“比较”图像,而无需保存它,我发现更方便,可以通过输出到特殊的“x:”输出格式,或使用“display”程序。例如..

  magick compare bag_frame1.gif bag_frame2.gif  x:
  magick compare bag_frame1.gif bag_frame2.gif  miff:- | display
从 IM v6.4 开始,您可以将差异的颜色从红色更改为其他更有趣的颜色...

  magick compare bag_frame1.gif bag_frame2.gif \
          -highlight-color  SeaGreen  magick compare_color.gif
[IM Output]
从 IM v6.4.2-8 开始,您还可以指定其他颜色。

  magick compare bag_frame1.gif bag_frame2.gif \
          -highlight-color  SeaGreen  -lowlight-color PaleGreen \
          magick compare_colors.gif
[IM Output]
如果您不希望第二个图像出现该“阴影”,则从 IM v6.4.2-8 开始,您可以向选项添加“-compose src”将其删除。

  magick compare bag_frame1.gif bag_frame2.gif \
          -compose Src compare_src.gif
[IM Output]
通过使用所有三个额外的设置,我们可以生成已更改像素的灰度蒙版...

  magick compare bag_frame1.gif bag_frame2.gif \
          -compose Src -highlight-color White -lowlight-color Black \
          magick compare_mask.gif
[IM Output]
但是请注意,此蒙版是针对任何差异,即使是最小的差异。例如,您可以看到将图像保存到有损 JPEG 格式会产生的所有细微差异...

  magick bag_frame1.gif  bag_frame1.jpg
  magick compare bag_frame1.gif bag_frame1.jpg   magick compare_lossy_jpeg.gif
[IM Output] [IM Output] ==> [IM Output]
如您所见,即使您实际上看不到 GIF 和 JPEG 版本图像之间的任何差异,“magick compare”也会报告很多差异。通过使用小的模糊因子,您可以要求 IM 忽略这两个图像之间的这些细微差异。

  magick compare -metric AE -fuzz 5% \
          bag_frame1.gif bag_frame1.jpg   magick compare_fuzz.gif
[IM Text]
[IM Output]
这表明大多数实际差异都只是微不足道的。特殊的“-metric”设置“AE”(“绝对误差”计数的缩写)将在当前模糊因子下报告(到标准错误)被屏蔽的像素的实际数量。

差异图像

为了更好地了解图像之间究竟有多大差异,您可能最好获得更精确的“差异”合成图像....

  magick composite bag_frame1.gif bag_frame1.jpg \
            -compose difference  difference_jpeg.gif
[IM Output]
如您所见,虽然“magick compare”显示 JPEG 在图像之间创建了很多差异,但“差异”合成非常暗,表明所有差异都相对较小。如果生成的图像看起来太黑而无法看到差异,您可能希望规范化图像(使用更数学上正确的“-auto-level”,以便增强结果。

  magick difference_jpeg.gif  -auto-level  difference_norm.gif
[IM Output]
这仍然表明大多数差异仍然非常小,最大的差异出现在图像的锐利边缘,JPEG 图像文件格式无法很好地处理这些边缘。另一方面,在动画的两个原始帧之间获取差异图像显示了两个图像之间非常明显的差异,即使没有任何增强。

  magick composite bag_frame1.gif bag_frame2.gif \
            -compose difference  difference_frames.gif
[IM Output]
请注意,由于“差异”合成方法是关联性的,因此上述示例中两个图像的顺序无关紧要,尽管与“magick compare”不同,您可以比较不同大小的图像,目标图像决定差异图像的最终大小。不同的方法在与“magick”程序一起使用时更有用,因为您可以在保存或显示结果之前进一步处理生成的图像。例如,您可以对每个颜色通道进行阈值处理和合并,以生成任何在两个图像之间颜色发生变化的像素的蒙版。

  magick bag_frame1.gif bag_frame2.gif -compose difference -composite \
          -threhold 0 -separate -evaluate-sequence Add \
          difference_mask.gif
[IM Output]
这基本上是“magick compare”程序所做的,但对颜色和输出样式有更多控制。但是,如您所见,它往往会发现两个图像之间即使是最小的微小变化。如果图像来自有损图像文件格式(例如 JPEG)或需要颜色减少和抖动(颜色量化)的 GIF 图像,那么这可能会匹配图像中的所有内容。因此,它通常不是很有用。为了获得更好的结果,您可以尝试找出像素颜色究竟有多大差异。例如,我们可以将结果灰度化,以便获得比彩色图像更好的比较图像。

  magick bag_frame1.gif bag_frame2.gif -compose difference -composite \
          -colorspace Gray   difference_gray.gif
[IM Output]
现在,与“magick compare”不同,差异图像显示了最终结果中组合的两个图像的混合。例如,看看猫的前额上出现的奇怪的“护身符”。这最初是第一个图像中包的把手。这种合并可能会让人难以理解您正在看到的差异,并且您会看到图像中添加和删除内容的混合。由于这种细节混淆,“magick compare”通常是人类查看的更好方法,而“差异”图像是进一步处理图像的更好方法。但是,灰度化差异图像只会将 RGB 距离取平均值(实际上是加权平均值)。结果,单个位颜色差异可能会丢失,尽管存在量子舍入效应。如果图像之间即使是最小的差异也很重要,则更好的方法是添加差异图像的单独颜色通道,以确保您捕获所有差异,包括最小的差异。

  magick bag_frame1.gif bag_frame2.gif -compose difference -composite \
          -separate -evaluate-sequence add   difference_add.gif
[IM Output]
上面产生的差异值被称为“曼哈顿距离”度量。也就是说,当您仅限于正交(或轴向)移动时,两个图像的每个颜色的距离。但是请注意,较大的差异可能会被裁剪(或烧毁),因为它可能超过像素数据“量子范围”或整数限制,除非使用 IM 的 HDRI 版本。要进一步了解这一点,您可以获得颜色向量距离,方法是使用一些平方和平方根来实现毕达哥拉斯或欧几里得距离。

  magick bag_frame1.gif bag_frame2.gif -compose difference -composite \
           -evaluate Pow 2 -separate -evaluate-sequence Add -evaluate Pow 0.5 \
           difference_vector.gif
[IM Output]
这实际上类似于“模糊”因子作为其阈值处理的一部分实际测量的内容(当不涉及透明度时)。但是,“模糊”还会将平方值除以 3,然后再相加,以确保结果不会超过图像颜色范围限制。这样做意味着您只会获得结果中纯“白色”像素,用于相反的原色和二次色之间的差异,例如蓝色和黄色像素之间的差异。所以让我们也进行这种缩放...

  magick bag_frame1.gif bag_frame2.gif -compose difference -composite \
          -evaluate Pow 2 -evaluate divide 3 -separate \
          -evaluate-sequence Add -evaluate Pow 0.5 \
          difference_vector_scaled.gif
[IM Output]
这实际上与您为“-colorspace Gray”差异图像(如上)获得的结果非常相似,但它是颜色差异的更准确表示。您可以省略第二个“Pow 0.5”修改,在这种情况下,您将获得平方差图像。还有其他颜色距离度量,您可以在颜色差异,维基百科页面上阅读。大多数这些都涉及生成向量差异(见最后),但使用不同的颜色空间,例如 LAB 或 LUV。然而,这在比较现实世界的颜色差异(例如:人类视觉差异测量)方面会更重要。另请参阅背景移除,其中使用上述差异图像来执行背景移除。您可能还想查看此外部页面变化检测作为其使用的一个实际示例。

闪烁比较

除了“magick compare”程序之外,另一种查看图像之间差异的方法是以相当快的速度对类似图像进行闪烁比较。

  magick -delay 50 bag_frame1.gif bag_frame2.gif -loop 0 flicker_cmp.gif
[IM Output]
为了使这更容易,我编写了一个脚本来显示两个给定图像的动画,称为“flicker_cmp”,它在两个图像之间切换,就像上面的示例一样。它还在显示图像的底部添加了一个标签,以便详细说明您在任何特定时刻看到的图像。

比较动画

您还可以使用特殊的“胶片带”技术比较两个合并动画的差异。在并排追加中查看类似的“追加”技术。基本上,我们将所有动画帧追加在一起,形成一个大型且长的图像。然后比较这两个图像,并通过再次将动画拆分为单独的帧来创建一个新的动画。例如...

    magick \( anim1.gif -coalesce -append \) \
            \( anim2.gif -coalesce -append \) miff:- | \
      magick compare - miff:- |\
        magick - -crop 160x120 +repage anim_compare.gif
结果是“比较”图像的动画,生成第二个动画的“调暗”版本,并叠加突出显示不同的部分。请注意,为了使此方法有效,“-crop”大小必须与动画的原始大小匹配。此外,动画将丢失它可能具有的任何可变时间延迟,使用基于原始动画第一帧的恒定时间延迟。另一种对动画有用的图像比较技术用于定位动画发生变化的所有区域,以便划分动画的未连接部分。这样,您可以将大型动画分成多个较小的动画。请参阅拆分动画

比较统计
两个图像究竟有多大差异?

正在建设中
Statistics from difference image...

  The following outputs verbose information and extracts just the
  section containing the channel statistics of the image....

    magick image1 image2 -compose Difference -composite \
            -colorspace gray -verbose  info: |\
       sed -n '/statistics:/,/^  [^ ]/ p'

  The numbers in parenthesis (if present) are normalized values between
  zero and one, so that it is independent of the Q level of your IM.
  If you don't have these numbers, you should think of upgrading your IM.

  To get the average (mean) grey level as a percentage you can use this
  command...

     magick image1 image2 -compose Difference -composite \
           -colorspace gray -format '%[fx:mean*100]' info:

  For non-percentage you can use the even simplier..

     magick image1 image2 -compose Difference -composite \
           -colorspace gray -format '%[mean]' info:


Compare  Program  Statistics...

   You can get an actual average difference value using the -metric

     magick compare -metric MAE image1 image2 null: 2>&1

   Adding -verbose will provide more specific information about each separate
   channel.

      magick compare -verbose -metric MAE rose.jpg reconstruct.jpg null: 2>&1

      Image: rose.jpg
      Channel distortion: MAE
        red: 2282.91 (0.034835)
        green: 1853.99 (0.0282901)
        blue: 2008.67 (0.0306503)
        all: 1536.39 (0.0234439)

   Their are a number of different metrics to chose from.
   With the same set of test images (mostly the same)

   Number of pixels
      AE ...... Absolute Error count of the number of different pixels (0=equal)

                This value can be thresholded using a -fuzz setting to
                only count pixels that have a larger then the threshold.

                As of IM v6.4.3  the  -metric AE  count is -fuzz effected.
                so you can discount 'minor' differences from this count.

                magick -metric AE -fuzz 10% image1.png image2.png null:

                Which pixels are different can be seen using the output
                image (ignored in the above command).

                This is the ONLY metric which is 'fuzz' effected.

   Maximum Error (of any one pixel)
      PAE ..... Peak Absolute Error   (within a channel, for 3D color space)
      PSNR .... Peak Signal to noise ratio (used in image compression papers)
                The ratio of mean square difference to the maximum mean square
                that can exist between any two images, expressed as a decibel
                value.

                The higher the PSNR the closer the closer the images are, with
                a maximum difference occurring at 1.  A PSNR of 20 means
                differences are 1/100 of maximum.

   Average Error (over all pixels)
      MAE ..... Mean absolute error    (average channel error distance)
      MSE ..... Mean squared error     (averaged squared error distance)
      RMSE .... (sq)root mean squared error -- IE:  sqrt(MSE)


   Specialized metrics
      MEPP .... Normalized Mean Error AND Normalized Maximum Error
                These should directly related to the '-fuzz' factor,
                for images without transparency.

                With transparency, makes this difficult the mask should
                effect the number of pixels compared, and thus the 'mean'
                but this is currently not done.

      FUZZ      fuzz factor difference taking transparency into account

      NCC       normalized cross correlation (1 = similar)

   I produced the following results on my test images...

    _metric_|__low_Q_jpeg__|__black_vs_white__
     PSNR   | 29.6504      | 0
     PAE    | 63479        | 65535
     MAE    | 137.478      | 65535
     MSE    | 4.65489e+06  | 4.29484e+09
     RMSE   | 2157.52      | 65535


   The first column of numbers is a compare of images with low-quality JPEG
   differences, where the test image was read in and saved with a very low
   -quality setting.

   The second "black vs white", is a compare of a solid black image verses
   a solid white image.  If the 'average color' of the image is ignored
   by the comparision then the resulting value will be very small.  This
   seems only to be the case with the PSNR metric, as all others produced
   a maximum difference value.

   The e+06 is scientific notation, on how many places to shift the
   decimal point.  EG:   4.65489e+06  -->  4,654,890.0
   Thus is equal to about 4 million, and is the square of 2157.52

   WARNING: numbers are dependant on the IM Quality (Q) levels set at compile
   time. The higher the quality the larger the numbers. Only PSNR should be
   unaffected by this.  For this reason IM also gives you a 'normalized'
   result that is uneffected by the compile time quality setting, though may
   still have minor 'quantum' or 'interger rounding' effects.

   I have NOT figured out if there are any of the existing "-define" options
   usable the "compare" function.


   NOTE for opaque colors AE -fuzz  and RMSE distances are equivelent.
   HOWEVER,  when transparent colors are involved AE fuzz factor testing
   will treat two different fully-transparent colors as being the same
   while RMSE will treate them as being different!

   For example...
   To AE fully-transparent white and fully-transparent black are the same.

     magick compare -metric AE xc:#0000 xc:#FFF0 null:
     0

   But to RMSE they are VERY different

     magick compare -metric RMSE xc:#0000 xc:#FFF0 null:
     56755 (0.866025)

Dissimilarity-threshold

  If you get a 'too different' error,  you can disable that using...
      -dissimilarity-threshold 1.0

  But what is this threshold?

有关更多信息,请参阅我非常旧的原始文本注释... 图像比较,计算巫术塔

匹配子图像和形状

正在建设中
Using "compare -subimage-search" option...

  magick compare -subimage-search  large_image.png  sub-image.png  results-%d.png

  This produces two images
    results-0.png
        which displays the matching location
    results-1.png
        which is a map of possible top-left corner locations showing how well
        the sub-image matches at that location.

  Note the second image is smaller, as it is only top-left corner locations.
  As such its size is   large_image - small_image + 1

  The search however is based on a difference of color vectors, so produces
  a very accurate color comparison.

  The search basically does a compare of the small image at EVERY possible
  location in the larger image.  As such it is is slow! very very slow..

  The best idea is to compare a very very SMALL sub-image to find possible
  locations, than use that to then do a difference compare at each possible
  location for a more accurate match.

  Have a look at the script
    https://imagemagick.org.cn/Usage/scripts/overlap
  and associated discussion
    Overlapped Images
  Which looks at locating 'high entropy' sub-images of one image to search
  for posible matches in a second image so the overlap offset between the
  two images can be discovered, and the images merged into a larger image.

  Another discussion uses sub-image searches to find tiling patterns in
  larger images, with the goal of generating tilable images
    Stitching image over a canvas


  Example using RMSE and the new -grayscale function to merge the
  separate color difference channel results into a final image

    magick large_image.png small_image.png miff:- |
      magick compare -metric RMSE -subimage-search - miff:- |
        magick - -delete 0 -grayscale MS show:


Similarity Threshold

  As many time people are only interested in the first match that matches.
  As soon at this 'good' match is found, there is no need to continue
  searching for another match.  The -similarity-metric defines what you
  would regard as a good match.

  A "-similarity-threshold 0.0" will abort on the very first 'perfect' match
  found, while "-similarity-threshold 1.0"  (the default) will never match and
  will search every posible point.  A value between will set a color only
  'fuzz' factor on what you would find an acceptable match.

  Note that if the sub-image search is aborted, the second 'map' image will
  only contain a partial result, only showing the results up until the comapre
  aborted its search).


Some Basic Sub-Image Search Examples....

  Grab a screen shot of a terminal window ("screen.png"),
  and crop out an image of a single letter or word ("letter.png").

  Just report first match.... for speed,
  immeditally abort after finding that first match.
  Don't bother outputing the incomplete image results.

     magick compare -subimage-search -metric AE -similarity-threshold 1.0 \
                   screen.png letter.png null: 2>&1

  NOTE speed will be highly dependant on where in the image that first
  match is found.

  Find all occurances of exactly that image,
  as an image (white dots on matches, black elsewhere)

     magick compare -subimage-search -metric AE \
                   screen.png letter.png miff:- 2>/dev/null |
       magick - -delete 0 show:

  Extract a list of the coordinates of all matching letters (white dots)
  (as an enumerated pixel list, ignoring anything black)

     magick compare -subimage-search -metric AE \
                   screen.png letter.png miff:-  2>/dev/null |
       magick - -delete 0 txt:- | grep -v '#000000'

  Just the coordinate list

     magick compare -subimage-search -metric AE \
                   screen.png letter.png miff:-  2>/dev/null |
       magick - -delete 0 txt:- | sed -n '/#FFFFFF/s/:.*//p'



NON-ImageMagick sub-image search solutions...

  "visgrep" from the "xautomation" package.

    This is much simpler sub-image search program, that only outputs a
    list of coordinates for the matches (or even multiple sub-image matches).
    Because it is so much simpler (for near exact matching) and not trying
    to generate 'result images' for further study, it is also a LOT FASTER.

    For example...
  
      visgrep screen.png letter.png

    Timed results
      using "compare" to get just the first match        0.21 seconds
      using "compare" to get a 'results image'           1.56 seconds
        ditto, but extracting the coordinate list        1.76 seconds
      using "visgrep" to get all matching coordinates    0.09 seconds



Other Methods of sub-image searching....

HitAndMiss Morphology

  This is essentually a binary match, where you define what pixels much be
  'background' and what must be forground.  However it also allows you to
  define areas where you don't care if the result is a foregorund or
  background.

  Basically a binary pattern search method.

Correlate (a Convolve variant)

  This is similar to Hit and Miss but using greyscale values.  Positive values
  for forground and negative values for background, and zero for don't care.
  It is however limited to grayscale images.

  See Correlation and Shape Searching.

  Both of these are basically just as slow as the previous sub-image compare,
  but less accurate with regards to colors.  However it's ability to specify
  specify a shape (don't care areas) to the sub-image makes then useful as
  a search method.

  However you need to magick the sub-image into a 'kernel', or array of
  floating point values, rather than as an actual image.


FFT Convolve (NCC)

  Fast Fourier Transforms is a slow operator, but usually many orders of
  magnitude faster than the previous two methods use.  The reason is that
  a convolution in the frequency domain is just a direct pixel by pixel
  multiplication.

  The 'Convolve' method, can be converted into a 'Correlate', simply by
  rotating the sub-image being searched for by 180 degrees.
  See Correlate.

  Basically by converting images into the 'frequency' domain, you can do
  a sub-image search, very very quickly, compared to the previous, especially
  with larger sub-images that can be the same size as the original image!

  This I believe has been added as a NCC compare metric.



Peak Finding and extracting (for near partial matches)...

  Once you have compared the image you will typically have a 'probably map'
  of some kind which defines how 'perfect' the match was.

  What you want to do now is to find the best match, or perhaps multiple
  matches in the image.  That is, you want to locate the major 'peaks'
  in the resulting map, and extract actual locations.

  * Using a Laplacian Convolution Kernel

    To get results you need to find the 'peaks' in the image, not
    necessarily the brightest points either. You can get this by convolving
    the image so as to subtract the average of the surrounding pixels from
    the central pixel.  As we only want positive results, a bias removes the
    negative results.

      magick mandril3_ncc1.png \
              -bias -100% -convolve Laplacian:0 result.png

    Thresholding and using it as a mask, and we can extract just those pixels.

      magick mandril3_ncc1.png \
              \( +clone -bias -100% -convolve Laplacian:0 -threshold 50% \) \
              -compose multiply -composite \
              txt:- | grep -v black

    The problem is you can get a cluster of points at a peak, rather than
    a definitive pixel, especially for two peak pixel surrounded by very low
    values.

  * Using a Peaks Hit and Miss Morphology Kernel

      magick mandril3_ncc1.png \
              -morphology HMT Peaks:1.5 result.png

    The problem is that this may produce no result if you get two peak pixels
    with exactly the same value (no gap between foreground and background)

    However there are other 'peak' kernels that will still locate such a peak
    cluster.

  * Dilate and compare

    Dilate (expand maximum values) the image 3 times then compare it to the
    original image.  Any peak within the area of dilated kernel size (7 pixel
    square) will remain the same value. Set all pixels that show a
    difference to pixels to zero.

    Method by HugoRune  (IM discussion topic 14491)

  * Looped match and remove.

    Basically find the highest pixel value, note it. Then mask all pixels in
    an area around that peak, and repeat until some limit (number points or
    threshold) is reached.

    See a shell script implementation of this in  Fred Weinhaus's script
    "maxima"

    This does not look at finding the center of large 'cluster' of near equal
    valued pixels, though this would be very rare in real images.

  * Sub-pixel locating

    If the peak is not an exact pixel, but could conceivably be a sub-pixel
    location (between pixels) then some form of pattern match (gaussian curve
    fit) in the area of the peak may let you locate the peak to a sub-pixel
    coordinate.

    This may be more important in image registration for parorama stitching,
    especially when you are not using a large number points to get a best-fit
    average of the perspective overlay.

  * Finding a tile pattern in an image

    When you have all the points, a search for a repeating pattern (similar
    vector distances between multiple peaks) should point out some form of
    tiling structure.


Improving the Sub-Image Matching...

  The major problem with Correlate, (or the fast  FFT correlate, which is the
  same thing) is that it has absolutely no understanding of color.

  Correlation (or convolve) is purely a mathematical technique that is used
  against a set of values.  With images that means it is only applied
  against the individual channels of an image, and NOT with vector color
  distances.


  While compare actually does real comparing of color vectors.  This will find
  shapes better than correlate but is much much slower.

  As such to make proper use of correlate you should magick your images
  (before hand for speed, or afterward against results) to try and highlight
  the color differences in the image as a greyscale 'correaltion' image.

  ASIDE: Use -channel to limit operations to one greyscale channel will
  improve speed.  In IMv7 greyscaling will reduce images to one channel so
  will gain speed improvements automatically.

  For example instead of intensity, you may get a better foreground
  / background differentiation, by extracting the  Hue of an image.
  Though you may need to color rotate the hue's if there is a lot of red
  in the sub-image being searched for.

  See the examples of HSL and HSB, channel separation, to see this problem.
    https://imagemagick.org.cn/Usage/color_basics/#separate

  Another greyscaling method that should work very well is to do edge
  detection on the two images.  This will highlight the boundaries and shape,
  which is typically much more important than any smooth gradient or color
  changes in the image.

  For examples of Edge detection methods see
    https://imagemagick.org.cn/Usage/convolve/#edgedet

  You may like to also look at directional or compass type edge detection.

  Basically Anything that will enhance the shape for your specific case is
  a good idea.  Just apply it to BOTH images before correlating them.


Scale and Rotation Invariant Matching...

  * position independence...
  * matching rotated sub-image (angle independent)
  * matching resized sub-images  (size independent)
  * Both size and angle independence


--------------

Other more specific image matching..

Matching Lines...

  Hough Algorithm

Matching Circles...

  Hough Algorithm Variant

Matching Faces

  A combination of the above.




查找重复图像

相同的文件

文件是否二进制相同,即它们是完全相同的文件,可能只是彼此的精确副本。不需要 ImageMagick。不要忽视这一点。您可以通过这种方式非常非常快地比较大量文件。我发现最好的方法是使用 MD5 校验和。


  md5sum * | sort | awk {'print $2 " " $1'}  | uniq -Df 1
这将列出完全相同的图像的MD5值。使用此技术,我创建了一些脚本,可以生成并比较文件的md5sum列表,并返回MD5值相同的那些文件。但是请注意,除了直接复制外,对图像文件的任何更改都将被视为不同,即使图像数据本身相同。仅仅是日期更改或文件中其他细微的元数据差异,都会使图像被视为不同。

ImageMagick 图像签名

您可以让ImageMagick为每个图像生成一个“签名”...

  magick identify -quiet -format "%#" images...
这会生成一个类似于MD5和SHA256的哈希字符串。但是,与后者不同,它使用实际的图像数据来生成签名,而不是图像的元数据。因此,如果您有两个相同图片的副本,但创建时间/修改时间戳不同,则这两个文件的签名应该相同,而MD5和SHA256即使图像本身相同,也会生成两个不同的签名。警告:读取和写入JPEG图像将生成不同的图像数据,从而产生不同的签名。这仅仅是由于JPEG图像格式使用的有损压缩造成的。

直接比较

如果两个图像大小相同,您可以直接比较它们(使用“magick compare”程序),以查看它们匹配程度。(见上文)这非常慢,根据我的经验,当针对全尺寸图像使用时,效果并不好,因为它太慢了。但是,这可能是了解两个图像相似程度的最佳方法。

图像分类

在我尝试比较图像的过程中,我发现颜色、卡通风格和素描彼此的比较结果差异很大。线条图和灰度图像,尤其是在几乎所有比较方法中,往往具有更小的差异。基本上,由于所有颜色都在一条线上,任何颜色指标都倾向于将此类图像的距离缩短3倍(一维颜色空间与三维颜色空间)。基本上,这意味着将图像至少分成这两组,可能是任何认真尝试查找重复或非常相似图像的重要第一步。其他主要的图像类型分类也可以通过减少比较的图像数量来简化图像比较。请参阅下面的图像分类。

缩略图比较

您可以让程序(在内存中)创建大量图像的缩略图(例如64x64像素)以进行比较,寻找重复项,然后通过直接比较进行处理。这通常是人们(包括我自己)首先尝试做的事情,事实上,这是大多数图像比较程序(如照片处理软件)所采用的技术。实际上,这种方法效果很好,并且确实可以找到完全匹配的图像。此外,稍微模糊一下,降低差异阈值,它甚至可以找到经过轻微裁剪和调整大小的图像。但是,尝试在内存中存储10,000个这样的缩略图,通常会导致普通计算机开始“抖动”,变得非常缓慢。或者,存储所有这些缩略图(除非程序出于用户查看目的这样做)会占用大量磁盘空间。改进磁盘抖动问题的一种方法是,只在内存中保留少量图像。也就是说,通过分组比较图像,而不是将一个图像与所有其他图像进行比较。一种自然的分组方式是按目录分组,并将每个图像目录与其他图像目录进行比较。实际上,这相当不错,因为图像往往会分组在一起,并且这组图像通常会与类似的组匹配。因此,按目录对输出匹配的图像是一个额外的好处。此外,两个图像的可接受相似程度取决于它们的图像类型。比较两张线条图需要非常小的“阈值”来剔除不同的图像,而比较具有大面积颜色的图像通常需要更大的阈值才能捕捉到被裁剪的相似图像。现实世界的图像有一个更大的问题,即纹理会在具有非常轻微偏移的图像之间产生非常严重的累加差异。因此,您可能需要将此类图像简化为一般的颜色区域,方法是使用中值滤波器、模糊、颜色减少或颜色分割。经过这样的处理后,现实世界的图像通常可以像卡通一样进行比较。

图像指标

为每个图像创建一个小指标是一个线性排序(O)操作。而将所有图像与所有其他图像进行比较是一个平方排序(O^2)操作。指标的目的不是实际查找匹配的图像,而是将相似的(可能匹配的)图像分组,以便您可以对较小的组进行更深入的比较。因此,任何指标比较都应该宽松,并接受可能匹配概率低(但仍然存在概率)的图像。但它不应该过于宽松以至于包含太多错误匹配。此外,您可能希望考虑多个指标,因为某些指标可能会匹配其他指标“略过”的图像,因为它们落在不同的相邻区域(阈值不匹配)。在下一节(指标)中,列出了一些我尝试过或理论上考虑过的不同的ImageMagick生成的指标,包括:平均颜色、主要颜色、前景背景、边缘颜色、颜色矩阵等。Günter Bachelier还报告了使用更奇特的指标进行图像比较的可能性,例如:傅里叶描述符、分形维数、凸区域、长/短轴长度和角度、圆度、凸度、卷曲度、实心度、形状变化、方向、欧拉数、边界描述符、曲率、弯曲能量、总绝对曲率、面积、几何中心、质量中心、紧凑性、偏心率、关于中心的矩等,等等。我目前的工作是生成和使用一个简单的3x3颜色平均矩阵来表示图像(见下面的颜色矩阵指标)。在生成(或请求)这些指标时,将指标(以及其他文件信息)缓存到每个目录中的特殊文件中。这样,我只需要在没有可用的缓存指标或图像发生更改时重新生成特定的指标。

相似性或距离

可以使用多种不同的方法比较两个图像的指标(或实际图像),通常会生成一个单一的距离度量或“相似性指标”,可用于将“相似”的图像聚类在一起。
  • 直接阈值或最大差异(切比雪夫距离)
    只需根据任何一个指标中的最大差异来比较图像。
    该阈值将在多维指标空间中生成一个类似超立方体的相似图像。当然,图像差异仅基于一个指标,而不是所有指标。
  • 平均差异(平均距离,平均曼哈顿距离)
    将所有差异相加,并可选地除以指标数量。
    这也被称为两个指标之间的曼哈顿距离,因为它等价于在城市网格中旅行需要覆盖的距离。所有指标的贡献相同,导致事物看起来比你预期的“更近”。在空间中,此指标的阈值将产生菱形。
  • 欧几里得(毕达哥拉斯)距离
    或指标空间中指标之间的直接向量距离。
    当涉及更多指标时,该值往往更大。但是,一个指标产生很大的差异,往往比其他指标贡献更大。阈值在指标空间中产生球形体积。
  • 数学误差/数据拟合或(惯性矩???)
    将所有差异的平方相加,然后取平方根。
    这更常用于计算数学曲线与特定数据集的拟合程度,但也可以用于比较图像指标。
    这似乎提供了最佳的非向量距离度量。
  • 向量角度
    找到由图像指标创建的向量空间中心到两条线的夹角。这应该消除可能应用于两个图像的对比度或图像增强效果。
    尚未测试
  • 向量距离
    对于线条图或灰度图像,其中指标中的所有单个颜色向量都指向相同的方向,指标相对于图像平均颜色的相对距离可能更重要。相对于最大距离标准化距离可以减少对比度影响。
    也就是说,这是一种线条图图像比较方法。
    尚未测试
  • 聚类分析
    将所有指标绘制并分组到多维空间内的相似聚类中。一个好的聚类包甚至能够发现并剔除没有产生聚类的指标。
    尚未测试
目前我发现“数学误差”技术对于灰度和彩色指标都适用,使用一个简单的3x3平均的“颜色矩阵指标”(见下文)。

人工验证

在计算机完成查找匹配图像的尝试后,接下来由用户实际验证图像是否匹配。向用户呈现匹配项也可能是一项困难的任务,因为他们可能希望能够...
  • 并排查看图像
  • 以原始大小和可选的公共“缩放”大小,在两个图像之间非常快速地切换。
  • 在不同缩放和平移的图像之间切换或叠加,以尝试匹配图像。
  • 查看同一目录(源)或可能与匹配图像相同的聚类(其他近似匹配)中的其他图像,以便处理整个组,而不是单独处理每个图像。
  • 在两个(或多个)目录之间重命名、移动、替换、删除、复制图像,以整理图像并拒绝其他图像。
  • 等等...
目前,我将匹配项分组到集中,并使用组合程序在用户的控制下处理它们。这些程序包括ImageMagick的“magick display”和“magick montage”,以及图像查看器“XV”和“GQview”。但是,我乐于接受其他可以同时打开两个或多个目录并显示来自多个目录的图像集合或图像组的程序建议。远程或其他程序或脚本的控制至关重要,因为它允许以最佳方式设置和呈现图像组,以便用户查看和处理。目前还没有哪个程序满足我的需求。例如,“gqview”有集合和单个目录视图,但不允许多个目录视图,也不允许远程/命令行控制演示。但是,这些集合没有显示每个图像来自哪个目录,也没有将单个目录视图翻转到其他目录。它也没有远程程序控制。另一方面,非常旧的“xv”允许多个目录视图(它使用多个“视觉雪纳瑞”窗口),以及在其控制窗口中的集合列表,但一次只能查看一个图像,并且只能从其命令行打开和定位一个目录。当然,它也没有远程控制。这些是我发现的最佳人工验证程序,我使用脚本为每个图像组、匹配对或所有组匹配图像设置和启动它们。但都没有令人满意。在我看来,光桌和相关的软件是整理图像的更好方法,但为此您需要更大的触摸敏感屏幕,而这会带来很大的成本。

跨类型图像比较

我想做的一件比较困难的事情是找到那些由其他图像创建的图像。例如,我想将其他人着色或绘制的线条图匹配起来,以生成卡通甚至超现实的图像。也可能添加了背景。这些事情非常困难,我使用边缘检测技术的实验到目前为止没有得出结论。找到合适的度量标准是关键,因为人类可以更好地建立“相似性”的联系,但您仍然需要找到可能的匹配项来呈现给用户。

查找重复图像的总结

总之,我目前查找和处理重复图像的过程是一个程序管道,用于查找和筛选“相似”的图像。
   Generate/Cache  Image Types and Metrics
     -> Compare metrics and cluster images.
       -> compare images in cluster for matches
         -> group into sets of matching images (by source directory)
           -> human verification
如您所见,我正在寻找一种高度分阶段的方法。请将您的想法邮件给我!!!

按类型排序图像

确定图像的类型很重要,因为大多数比较图像的方法只适用于特定类型的图像。例如,将文本图像与艺术家的草图进行比较是没有意义的。同样,在几乎纯白色的图像(草图)上使用彩色图像比较方法也没有用。通常,比较图像时要做的第一件事是确定图像的类型或图像使用的“颜色空间”。图像的基本分类可以包括……
  • 黑白线条图或文本图像(几乎都是一种颜色)
  • 包含两种基本颜色且颜色相等的图像(图案图像?)
  • 灰度艺术家绘画(大量阴影)
  • 线性彩色图像(颜色形成渐变,但不是从黑色和白色)
  • 卡通风格的彩色图像,具有大面积的纯色。
  • 具有阴影区域的真实图像
  • 图像包含一些带注释的文本或徽标叠加。(单一的颜色尖峰)
在您拥有基本类别后,您还可以尝试使用各种图像度量标准对图像进行排序,例如……
  • 整个图像的平均颜色
  • 图像中的主要颜色
  • 图像的前景/背景颜色。
更糟糕的是,JPEG 或调整大小的图像通常也会发生颜色失真,这使得此类分类变得更加困难,因为颜色不会完全如预期的那样。灰色不会是纯灰色,线条可能不会锐利清晰。关于按类型排序图像的持续长期讨论在 IM 用户论坛上…… 如何检查图像颜色或黑白

灰度图像

检查图像是否为灰度的最简单方法是查看图像的颜色饱和度水平。也就是说,可以通过将图像转换为“色相”图像颜色空间并获取颜色(通常为绿色)通道的平均值和最大值来轻松完成。例如..

  magick rose: granite: -colorspace HCL \
          -format '%M  avg=%[fx:mean.g] peak=%[fx:maxima.g]\n' info:
[IM Text]
数字被归一化为 0 到 1 的范围。如您所见,“玫瑰”色彩鲜艳(平均 30%),具有很强的峰值(接近 1)。然而,“花岗岩”图像的饱和度非常低(大约 2%)并且峰值也低。虽然它不是纯灰度,但非常接近它。低平均值和高峰值表示小块的强颜色。对同一通道进行阈值处理可以生成图像彩色区域的蒙版。问题:以上方法无法找到颜色呈线性的图像。也就是说,仅包含形成线性颜色渐变的颜色(例如泛黄的(棕褐色调)照片或蓝图)的图像。这些本质上是彩色的灰度图像。请参阅下一种图像类型。

图像是否为线性颜色

另一种技术是对图像中所有颜色(或简化的度量颜色矩阵)进行直接的“最佳拟合”三维线。拟合误差(通常是误差平方和的平均值)可以很好地指示图像与该线的拟合程度。将直线拟合到三维图像通常涉及一些向量数学。结果不仅会告诉您图像是否使用接近“线性”的颜色集,而且适用于任何颜色比例,不仅是明暗,还适用于黄色纸上的偏灰色线条。结果还可以用于将图像转换为更简单的“灰度”图像(或仅将一组颜色度量转换为灰度度量),以便进行更简单的比较和更好的匹配查找。我的试用测试程序甚至不使用完整图像来进行此确定,而是使用下面 9 种颜色(27 个值)的简单 颜色矩阵度量 来表示图像)。但是请注意,此测试通常无法很好地区分未着色的线条图。此类图像几乎完全是单一背景颜色(通常为白色),因此可能不会显示任何形式的线性颜色渐变。应首先使用不同的测试将其分离出来(请参阅下一项,实际上它更容易)。如有兴趣,请给我发邮件,并告诉我您尝试过什么。

纯黑白图像

要查看图像是否接近纯黑白图像,以及是否存在任何颜色甚至灰色(由于抗锯齿),我们可以巧妙地使用“-solarize”选项(请参阅 Solarize 上的 IM 示例)。将此操作应用于任何图像都会导致任何亮色变为暗色(被取反)。因此,任何接近白色的颜色都会变成接近黑色的颜色。从这样的图像中,对图像进行简单的统计分析将确定图像是否纯粹(或几乎纯粹)为黑白。

   magick wmark_dragon.jpg  -solarize 50% -colorspace Gray  wmark_bw_test.png
   magick identify -verbose -alpha off wmark_bw_test.png | \
       sed -n '/Histogram/q; /Colormap/q; /statistics:/,$ p'  > wmark_stats.txt
[IM Output] ==> [IM Output] ==>
[IM Text]
如果您查看上面的统计数据,您会发现颜色“均值”非常接近纯黑色(“0”),而“标准差”也很小,但大于“均值”。因此,此图像必须主要为纯黑白,颜色或中间色调灰色很少。对于一般的灰度和彩色图像,“均值”将大得多,并且通常“标准差”小于均值。发生这种情况时,这意味着太阳化图像中几乎没有纯黑色。也就是说,几乎不存在纯黑色或白色。让我们使用内置的花岗岩图像重复此测试。

   magick granite: granite.jpg
   magick granite.jpg -solarize 50% -colorspace Gray  granite_bw_test.png
   magick identify -verbose -alpha off granite_bw_test.png | \
     sed -n '/Histogram/q; /Colormap/q; /statistics:/,$ p' > granite_stats.txt
[IM Output] ==> [IM Output] ==>
[IM Text]
请注意,“均值”现在大得多,接近颜色范围的中间,而“标准差”远小于“均值”的大小。从 IM v6.4.8-3 开始,您还将看到另外两个统计值,这些值可能有助于确定图像的类型。“峰度”和“偏度”在第一个黑白图像中都相对较大(且为正),这也反映了与灰色图像相比,涉及的灰色很少。但是“均值”与“标准差”仍然可能是更好的比较指标。请注意,此比较不会区分“黑底白字”或“白底黑字”,但是一旦您知道它不是真正的灰度图像,对图像正常均值进行简单的检查就会告诉您背景颜色是什么。

点彩色图像

这些图像未通过上述灰度测试,但仍然是黑白的,但其中包含一小块或一小块颜色。小块的颜色很容易被大图像的整体平均值淹没,可能会被错误地分类为灰度。我们不感兴趣的图像只是说一个像素的颜色,这可能是位错误,或者图像上散布着这样的斑点。但比如说一个带有彩色箭头或彩色小对象的图像。换句话说,是一个集中的彩色斑点。在 IM 论坛上的一篇讨论中 使用“饱和度测试”对灰度图像的误报 认为将图像分解成更小的部分,然后在其中任何一个区域中寻找高饱和度。这导致了以下方法。
  • 将图像转换为具有饱和度或色度通道的颜色空间
  • 将图像缩小 1:50(2%)的比例(例如,颜色的“斑点大小”)
  • 对获取的最大饱和度/色度值进行阈值处理
单个或非常小的斑点将被移除,但较大的彩色斑点在调整大小的图像中至少会包含一个彩色像素。

中间色调彩色图像

[IM 输出] 经过棕褐色处理或中间色调灰色着色为某种高光颜色的图像(例如右侧的图像)可能更难以区分。生成此类图像很容易,如 中间色调颜色着色 中所示,但并不常见。颜色仍然在颜色空间中形成颜色渐变(线条),但该渐变沿着曲线路径(通常是某种抛物线)在平面上下降。但是区分此类图像可能非常困难。一种技术是获取任何色相的标准差,该色相没有极小的饱和度。即使中间色调彩色图像中的色相不多,也应该非常相似。此技术在 如何检查图像颜色或黑白 中的特定帖子中进行了介绍。提醒一下,色相是一个循环值,并且围绕颜色“红色”循环。要正确测试,您可能需要执行两次,色相偏移 180 度。此外,对于饱和度非常低(灰色)的任何颜色,色相都没有实际意义,因此在测试色相的标准差时应忽略任何此类颜色。

文本与线图

如果您的图像几乎完全是单一颜色(通常为白色),那么您可以尝试查看图像内容是否可以分类为文本或线条图。文本将具有许多小的不连接的对象,通常分组为水平线。另一方面,线条图应将所有内容主要连接在一起作为一个整体,并包含许多不同的角度。请注意,卡通风格的彩色图像也可以转换为线条图以进行更简单的图像比较,因此线条图比较方法将是一件有用的工具。谁有这方面的想法?要了解更多关于文本的信息,IM 论坛上讨论了许多技术,检查图像是否包含文本

真实生活与卡通

基本上,卡通具有非常特定的色块和锐利的边界区域,通常通过使用分隔的黑色线条来使其更锐利。它们通常也具有最小的渐变或阴影效果。然而,真实图像具有大量的柔和边缘效果、颜色渐变和纹理,并使用大量不同的颜色。当然,这并不总是正确的。真实图像可能具有非常卡通的品质,尤其是在使用非常高的对比度时,而且一些现代卡通非常逼真,以至于很难将它们归类为卡通。通常,真实图像和卡通之间的主要区别在于纹理和渐变。因此,要确定图像的类型,需要将图像与相同图像(已去除精细纹理)进行比较。差异越大,图像就越“逼真”和“真实世界”般,而不是“卡通化”或“扁平化”。还要记住,线条图、艺术家草图和文本在风格上也可能非常像卡通,但具有如此精细的纹理和细节,以至于上述方法可能会将图像视为真实世界。因此,应事先分离出线条图和草图。
Jim Van Zandt 提供了以下解决方案……

  • 输出每个像素的颜色
  • 按颜色排序
  • 输出每种颜色的像素数量
  • 按像素数量排序
  • 遍历列表,直到统计完图像中一半的像素。
  • 如果像素数 >>> 颜色数,则图像类似卡通。
初始部分可以归类为直方图。请参阅“直方图:”示例。
如果您创建了某种图像分类方案……即使只是粗略的,也请告知您的结果,以便其他人(包括我自己)受益。

处理特定图像类型

以下是关于更具体的图像确定技术的注释和信息。

扫描或打印输出不良

在现实世界中,事情永远不会像您希望的那样完美。扫描仪有损坏的传感器,打印机滚筒有划痕。这两个问题通常会导致扫描和打印输出包含长垂直线。然而,确定图像是否具有这些垂直线相当容易。其思路是将图像中所有行的像素平均在一起。任何“故障”都将显示为最终像素行中的尖锐突起,您可以使用像素行的“阈值直方图”来计算其数量。
FUTURE -- image example needed for testing
    magick bad_printout.png -crop 0x1+0+0 -evaluate-sequence mean \
            -threshold 50% -format %c histogram:info:-

faster method but needs image height (assumed to be 1024)
    magick bad_printout.png -scale 1024x1 \
            -threshold 50% -format %c histogram:info:-
当您确定并从传真、打印输出或扫描中删除此类“不良线条”后,您可以继续进行其他测试,而无需担心这种现实世界中的故障。

空白传真

首先,您需要“-shave”删除传真可能添加到页面上的任何页眉和页脚。然后,您可以执行“阈值直方图”(参见上文)以查看有多少个单独的黑色像素。
FUTURE -- image example needed for testing
    magick blank_fax.png -threshold 50% -format %c histogram:info:-
或者,您可以进行噪声修剪以查看图像是否实际上包含任何更多值得您关注的实体区域或对象。
FUTURE -- image example needed for testing

垃圾邮件图像

垃圾邮件图像通常会在图像的色彩直方图中显示一个主要的纯色峰值。对图像中颜色的检查通常会显示它位于图像的一个角上。但是,这在卡通图像中不起作用。

电子邮件垃圾邮件图像

这些图像旨在绕过各种垃圾邮件过滤器。基本上,广告的文本隐藏在图像中,使用各种颜色和额外的“污垢”和其他噪声来使其更难以检测。虽然这些很难与公司电子邮件标题的徽标区分开来,但它们通常也比典型的电子邮件徽标大得多。一种发现技术是在图像上使用较大的中值滤波器。电子邮件垃圾邮件文本通常会消失,而徽标或图像仍然会保持色彩丰富。

图像度量,快速查找要比较的图像

度量代表一种“指纹”,以非常少的内存量来表示图像。相似的图像应该产生相似的度量。但是请注意,度量并非旨在实际查找匹配的图像,而是试图排除肯定不匹配的图像。也就是说,一个好的度量将使您可以忽略大多数图像的进一步比较,从而减少搜索所有图像所需的时间。

图像的平均颜色

You can use -scale to get an average color of an image, however I also suggest
you remove the outside borders of the image  to reduce the effect of
any 'fluff' that may have been added around the image.

    magick image.png  -gravity center -crop 70x70%+0+0 \
            -scale 1x1\! -depth 8 txt:-

Alternatively to get 'weighted centroid' color, based on color clustering,
rather than an average, you can use -colors

    magick rose: -colors 1 -crop 1x1+0+0 -depth 8 -format '%[pixel:s]' info:-
    rgb(146,89,80)
这通常会匹配已调整大小、轻微裁剪、旋转或平移的图像。但它也会匹配许多关系不密切的图像。最大的问题是,此度量通常会忽略已增亮、调暗或更改图像整体色调的图像。此外,虽然它是颜色和现实世界图像的绝佳度量,但对于灰度图像完全无用。所有此类图像通常都被归为一类,而无需在类型内进行进一步的聚类。这反过来表明了为什么对图像类型的初始分类对于良好的图像排序和匹配至关重要。

图像的主要颜色

图像的主要颜色略有不同,而不是合并背景颜色和前景的平均颜色,您需要找到最常见的前景颜色,以及图像中包含该主要颜色的百分比。因此,您不能只获取图像的直方图,因为图像可能使用许多单独的色调而不是特定的颜色。这可以使用低级量化函数 -segment 完成,然后获取直方图。这与直接使用 -colors 的优势在于,它不会尝试合并颜色上距离较远的颜色簇,尽管结果可能难以确定。
 FUTURE example 
之后,直方图将为您提供每种主要颜色的数量。但是,通常卡通或线稿的主要颜色是图像的背景颜色。因此,它仅对现实生活中的图像真正有用。另一方面,您可以通过将其与图像的平均边界颜色进行比较来发现图像是否具有真正的背景。请注意,图片的主要颜色更有可能受到图像的背景颜色的强烈影响,而不是感兴趣的对象。也就是说,通常在图像的中心或附近。

边界颜色

通过反复裁剪图像的四个边缘中的每一个(最多 2 到 3 个像素),并计算边界的平均颜色,您可以确定图像是否已加框,以及深度。图像是否有明确的背景。或者图像是否具有一些类型的空中/陆地或特写/远距离颜色分离。通过将平均侧面颜色与图像的平均中心颜色进行比较,您可以发现图像是否统一且没有中心主题或主体,例如空旷景观的照片。

直方图 - 通用颜色匹配

对于关于图像中要查找的颜色类型的度量,使用某种直方图。这是通过创建“颜色箱”数组并在找到颜色时递增每个“箱”的数量来完成的。现在我看不出您会为每个图像存储一个大型直方图!因此,您要么只存储直方图中最主要的颜色,要么使用更少的箱数(每个箱中有更多像素)。普通的“颜色箱”直方图实际上效果并不好。原因是每种颜色始终会落入一个箱中。也就是说,每个像素都是根据所有或没有的基础添加到每个箱中,而不管该颜色有多接近箱的边缘。这反过来不利于形成一个好的度量。一个解决方案是创建一个具有重叠箱的直方图。也就是说,每种颜色(可能除了黑色或白色之外)都会落入两个颜色箱中。然后,稍后在比较图像时,近似颜色将至少匹配其中一个箱。另一种选择是通过让每种颜色根据其与箱中心的接近程度来为每个“箱”做出贡献来创建直方图。也就是说,一个箱边缘的颜色实际上会在两个箱之间共享自身。这将生成一种模糊或插值的直方图,但它会更准确地表示图像,尤其是在仅使用非常少的颜色“箱”时。此外,直方图传统上只是图像的灰度分量或三个单独的 RGB 分量。但这并不是一个很好的表示。您可以尝试使用色相、饱和度和亮度直方图来更好地表示图像。或者,为什么要将自己限制在 1 维直方图中。如何将颜色映射到整个颜色空间中的一组真实颜色!也就是说,与其只对“红色”值进行分箱,为什么不在 3 维颜色箱中对其进行计数(无论哪种颜色空间最有效)。这将生成一个真正表示图像中发现的颜色的直方图。这样的 3 维直方图度量可以是简单的数组,例如 8x8x8 或 2048 个箱。也就是说,一个 2K 字节的度量。然后,颜色搜索将找到正确数量的附近箱,并获得附近箱的插值计数。这将表示图像中“接近”该颜色的颜色数量!

前景/背景颜色分离

使用 -colors,您可以尝试将图像分离为前景和背景部分,方法是将图像减少到两种颜色。首先使用 -median 滤波器将消除图像中可能存在的次要细节、线条边缘和噪声的影响。当然,这对于大部分是白色草图般的图像来说并不是很好。
  magick rose: -median 5 +dither -colors 2 \
          -depth 8 -format %c histogram:info:- 
这显示了红色和灰色作为图像中的主要颜色。然后,对图像中心进行修剪/裁剪应该确定什么是前景,什么是背景。
  magick rose: -median 5 +dither -colors 2 \
          -trim +repage  -gravity center -crop 50% \
          -depth 8 -format %c histogram:info:- 
这表明红色“玫瑰”色是主要的前景颜色。请注意,景观图像可能会以不同的方式分离,即您获得较低的底色和较高的天空颜色。因此,粗略了解颜色的分离方式对于图像类型确定非常有用。此外,包含一些文本“垃圾邮件”的图片通常会在一个角上显示一个颜色斑点,该斑点比图像的其余部分更为突出。如果发现,请使用 3 种颜色重新执行,然后使用之前找到的最常见的“背景”颜色擦除该区域,然后再进行最终测试。这种技术可能是将图像分离成“肤色”、“绿色植物”、“景观”等类别的好方法。

平均颜色矩阵

三乘三矩阵颜色方案(“-scale 3x3\!”)是一种合理的颜色分类方案。它将很好地分离和组合相似的图像。例如,草图(全部接近白色)、灰度、景观、海景、房间、面孔等都将被分离成基本且相似的组(理论上)。这也是用于索引图像以生成照片马赛克的合理度量。NetPBM 图像格式的输出特别适合生成此类度量,因为它可以仅将像素值输出为文本数字。请记住,这将产生 27 维的结果(3x3 种颜色的 3 个值),因此可能需要多维聚类算法。您是否了解良好的 3D 聚类程序/算法?例如,以下是 IM 徽标的 3 x 3 RGB 颜色(深度为 8)。
  magick logo: -scale 3x3\! -compress none -depth 8 ppm:- |\
    sed '/^#/d' | tail -n +4

  251 241 240 245 234 231 229 233 236 254 254 254
  192 196 204 231 231 231 255 255 255 211 221 231
  188 196 210
以上可以通过使用 16 位值以及可能裁剪 10% 的边框来改进,以删除可能添加的徽标和框架垃圾……
  magick logo: -gravity center -crop 80% -scale 3x3\! \
          -compress none -depth 16 ppm:- |   sed '/^#/d' | tail -n +4

  63999 59442 58776 62326 58785 58178 51740 54203 54965 65277 65262 65166
  45674 47023 49782 56375 55648 55601 65535 65535 65535 52406 55842 58941
  44635 48423 52881
当然,与之前的平均颜色度量一样,这也会在匹配已进行颜色修改(例如色调或亮度更改)的图像时遇到问题。(参见下一节)此外,此度量可以在其分组中分离线条图,尽管只是以非常通用的方式。此类绘图仍然会根据背景“纸张”的颜色而不是内容进行更多分组,并且通常需要比彩色图像更小的“阈值”相似度。

颜色差异矩阵

直接使用颜色作为度量最大的问题是,您将图像绑定到特定的通用颜色。这意味着任何已增亮或调暗或其色调已更改的图像都不会被组合在一起。对此的一个解决方案是以某种方式从度量中减去图像的主要或平均颜色,并且使用颜色矩阵可以实现这一点。例如,这里我从矩阵中所有周围的颜色中减去中间或中心平均颜色。
  magick logo: -gravity center -crop 80% -scale 3x3\! -fx '.5+u-p{1,1}' \
          -compress none -depth 16 ppm:- | sed '/^#/d' | tail -n +4

  51093 45187 41761 49419 44529 41163 38834 39947 37950 52371 51007 48152
  32767 32767 32767 43469 41393 38587 52629 51279 48521 39500 41587 41926
  31729 34168 35867
请注意,我添加了 0.5 到差值,因为您无法在图像中保存负颜色值。此外,使用缓慢的“-fx”运算符是可以接受的,因为它仅处理 9 个像素。请注意,中心像素(在上述第二行开头处的“32767 32767 32767”)不会发生太大变化(任何变化仅是由于轻微的舍入误差),并且可以从结果中删除,从而将度量减少到 24 维(值)。或者,您可以从所有 9 个颜色值中减去图像的平均颜色。

  magick logo: -scale 3x3\! \( +clone -scale 1x1 \) -fx '.5+u-v.p{0,0}' \
          -compress none ppm:- | sed '/^#/d' | tail -n +4

  38604 35917 34642 37011 33949 32441 32839 33841 33649 39447 39259 38369
  23358 24377 25436 33538 33174 32426 39612 39434 38605 28225 30576 32319
  22271 24381 27021
这也可以由度量比较器而不是度量生成器来完成。该度量仍然可以很好地分离和聚类彩色图像,将相似的图像放置得非常靠近,而不管任何一般的颜色或亮度变化如何。但它仍然对对比度变化敏感。实际上,可以在比较过程中完成此度量修改,因此原始的颜色矩阵度量仍然可以用作要收集、缓存和比较的标准图像度量。我现在正在进行大规模图像比较时就是这么做的。与简单的颜色平均值不同,您可以使用此度量来区分不同的线条图图像。但是,由于线条图使用线性颜色比例(所有颜色在度量空间中都位于一条线上),因此图像之间的差异大约是彩色图像的 1/3。因此,在比较线条图时需要一个非常不同的阈值。因此,仍然最好将线条图和灰度图像与彩色图像分开。换句话说,这是我迄今为止发现的用于彩色图像的最佳度量之一。只需确保首先确定哪些图像是线条图,并使用更低的阈值单独比较它们即可。幸运的是,度量本身可以用于将图像分离成灰度线性彩色图像。欢迎提出建议。

邻居差异

上面生成一个 3x3 矩阵,其中减去了中心像素,并将所有值偏移到完美的灰色。但是,更好的方法是,而不是尝试保存各个单元格的颜色,而是生成每个单元格与其邻居(8 个邻居)之间的差异。也就是说,不要保存左上角的颜色,而是保存该角与顶部中间、中心和左侧中间之间的差异。当然,即使对于一个小的 3x3 数组,最终也会得到一个包含 12 个差异的签名,尽管您不需要编码完整的差异,只需要一个一般的差异级别,例如相等或大/小正/负差异值。这更有可能找到即使在包含颜色差异很大的图像之间匹配的图像,因为实际颜色在签名中根本不起作用。图像比较库 'libpuzzle' 正是这样做的,尽管它使用的是 9x9 矩阵,并且仅将每个单元格的中心像素平均在一起。它还将自身限制在图像的灰度版本。该技术在 Postscript 论文任何类型图像的图像签名中完整定义。本文还介绍了如何在数据库中存储该签名以及如何实际执行查找以查找具有相似(不一定是相同)签名的图像的方法。这是我发现的第一篇真正详细介绍如何做到这一点的论文。:-)

感知哈希

将图像缩减为 8x8 并计算平均强度。然后,如果像素高于平均值,则 64 位哈希的每个位为 1,如果低于平均值,则为 0。要比较两个图像之间的相似性,只需逐位比较按位哈希,并返回汉明距离即可。汉明距离越近,图像越相似。任何超过 21/64 的都被认为是不相似的。pHash 似乎使用 YCbCr 编码。有些人谈论直接使用 JPEG 中的 DCT,最有希望的工作使用幅度/相位并将其映射到对数极坐标系。

更好地匹配图像

我尚未尝试或对比较更大图像以进行更精确的图像匹配效果不佳的各种注释和技术。

分割颜色

如您所见,上述许多度量都使用了模糊/中值滤波器,然后是颜色缩减技术,这些都是简化图像以更好地对其进行分类的基本尝试。但是,颜色量化运算符并非真正为此目的而设计的。它的作用是减少颜色,以便突出显示图像的重要细节。但是,对于图像比较,我们并不真正想突出显示这些特征,而是突出显示比较感兴趣的区域。这是一项相关的颜色技术,称为分割... 附注:来自 Leptonica:图像分割是将图像划分为具有不同属性的区域。此运算符屏蔽掉颜色相似的区域,从而去除这些区域的细节。然后,当您比较两幅图像时,您是在比较区域而不是图像中的低级细节。IM 为其实现细节实现了分割算法“-segment”,请参阅SegmentImage()。示例
  magick logo: -median 10 -segment 1x1 \
          +dither -scale 100x100\! segment_image.gif
一个问题是 -segment 非常慢,并且似乎仅适用于较大的图像。小图像(如玫瑰:或 100x100 的缩放徽标:)似乎只会产生单一颜色。这可能是错误。当然,您仍然可以在分割图像后对其进行缩放,就像我们在上面所做的那样。这样,您可以在内存中存储更多图像以相互比较。此外,与 Leptonica 提供的图像分割算法相比,生成的分割似乎效果不佳。请参阅Leptonica:颜色分割。但是,IM 分割的替代方法是误用颜色量化功能来查找颜色相似的区域。示例
  magick logo: -scale 100x100\! -median 3 \
          -quantize YIQ +dither -colors 3 segment_image.gif
-color 的缺点是它限制了图像中可能存在的颜色区域的数量,而 segment 则尝试保留相似的区域,而不管图像中实际存在多少区域(或者至少它应该这样做)。

无色边缘比较

图像颜色非常不可靠,特别是对于卡通图像。不同的用户可以很容易地重新着色此类图像,添加不同的颜色背景,甚至取一个草图并将其着色。匹配此类图像的一种方法是对其进行一些基本的颜色缩减,如上所述,但随后不是根据生成的颜色比较图像,而是执行边缘检测,并进行进一步处理,以便仅使用最重要的颜色变化的轮廓进行度量和图像比较。例如...
  magick logo: -scale 100x100\! -median 3 \
          -quantize YIQ +dither -colors 3 -edge 1 \
          -colorspace gray -blur 0x1   outline_image.gif
另一种方法可能是使用 -lat(局部区域阈值)进行边缘检测,这可能会为您提供更好的控制...
  magick logo: -scale 100x100\! -median 3 \
          -quantize YIQ +dither -colors 3 \
          -lat 3x3-5% -negate \
          -colorspace gray -blur 0x1  outline_image.gif
当然,对于比较,您将使用线条图比较方法。
???您将如何以可行的方式比较线条图???
将图像乘在一起,看看生成的图像是否增加了或减少了线条的强度。不匹配的线条将变为黑色。

网络摄像头
固定摄像头发生了什么变化

正在建设中
Walter Perry <gatorus13_AT_earthlink.net> 报告... 我正在从事的项目涉及处理来自监控摄像头的 20 组图像,这些图像是在摄像头感应到运动时发送的。这些摄像头位于远程位置,一旦检测到运动,图像就会发送到本地服务器。在本地服务器上,我希望能够“过滤”掉那些不包含导致事件发生内容的图像。我使用 PerlMagick 将系列中的第一张图像(始终不包含除正常背景之外的任何内容)与其余图像进行比较。我正在获取所有图像的“平均”差异,然后如果单个差异大于平均差异,则保留该图像,因为它其中包含某些内容。无论白天或黑夜或照明条件如何,这种方法都非常有效。我最初试图仅使用第一张图像以上百分比的差异,但这不太可靠,并且确实取决于照明条件。根据此比较,我将确定哪些图像具有“内容”,哪些图像为空白且没有任何运动。一旦我获得了那些包含“运动”的图像。