⚠️ これは 非公式の翻訳サイトです。ImageMagick Studio LLC とは無関係です。正確な情報は 原文(https://usage.imagemagick.org/compare/index.html) を参照してください。

ImageMagick 使用例 -- 画像の比較

ImageMagick 使用例 前書きと目次
画像を比較する方法 -- 何が違うのか?

画像を比較する方法

Compare プログラム

magick compare」プログラムは、二枚の似た画像を比較し、画像同士がどれくらい「違う」かを簡単に判定する手段を提供するために用意されています。たとえばここでは、アニメーションする「バッグ」の二つのフレームがあり、これを「magick compare」に渡して、変化した部分を強調表示させています。

  magick compare bag_frame1.gif bag_frame2.gif  compare.gif

[IM Output] [IM Output] [IM Output]

ご覧のとおり、白と赤の画像が得られ、その中に二枚目の画像の「影」が含まれています。二枚の画像の間で変化した三つの領域がはっきりと示されています。この「compare」画像を保存するのではなく、もちろん直接表示することもできます。私としてはそのほうが便利だと感じています。特別な「[x:](files.html#x)」出力フォーマットへ出力するか、「[display](basics.html#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  compare_color.gif

[IM Output]
IM v6.4.2-8 以降では、もう一方の色も指定できます。 |

  magick compare bag_frame1.gif bag_frame2.gif \
          -highlight-color  SeaGreen  -lowlight-color PaleGreen \
          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 \
          compare_mask.gif

[IM Output]
ただしこのマスクは、どんな差分であっても、最も小さな差分まで含めて表しています。たとえば、画像を非可逆 JPEG フォーマットに保存することで生じる小さな差分すべてを見ることができます……

  magick bag_frame1.gif  bag_frame1.jpg
  magick compare bag_frame1.gif bag_frame1.jpg   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   compare_fuzz.gif

[IM Text]

[IM Output]
これは、実際の差分のほとんどが小さなものに過ぎないことを示しています。「[-metric](https://imagemagick.org/command-line-options/#metric)」設定の特別な値「AE」(「Absolute Error」(絶対誤差)カウントの略)は、現在のファズ係数でマスクされたピクセルの実際の数を(標準エラー出力へ)報告します。

差分画像

画像がどれくらい違うかをより正確に把握するには、より厳密な「[difference](compose.html#difference)」合成画像を取得するほうがおそらく良いでしょう…… |

  magick composite bag_frame1.gif bag_frame1.jpg \
            -compose difference  difference_jpeg.gif

[IM Output]
ご覧のとおり、「magick compare」は JPEG が画像間に多くの差分を生じさせたことを示しましたが、「[difference](compose.html#difference)」合成はかなり暗く、差分はどれも比較的小さいものであることを示しています。結果の画像が黒すぎて差分が見えにくい場合は、結果を強調するために画像を正規化するとよいでしょう(より数学的に正しい「[-auto-level](https://imagemagick.org/command-line-options/#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]
なお、「[difference](compose.html#difference)」合成メソッドは結合的なので、上記の例で二枚の画像の順序は問題になりません。ただし「magick compare」とは異なり、サイズの異なる画像を比較でき、その場合は出力先の画像が差分画像の最終的なサイズを決めます。difference メソッドは「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」のほうが良い方法であり、一方「difference」画像は画像をさらに処理するにはより良い方法です。しかし差分画像をグレースケール化すると、単純に RGB 距離を平均(実際には加重平均)するだけになります。その結果、わずか 1 ビットの色差は量子丸め効果によって失われる可能性があります。画像間の最も小さな差分すら重要なのであれば、より良い方法は、差分画像の各カラーチャンネルを別々に加算して、最も小さな差分を含むすべての差分を確実に捉えることです。 |

  magick bag_frame1.gif bag_frame2.gif -compose difference -composite \
          -separate -evaluate-sequence add   difference_add.gif

[IM Output]
上記で生成される差分値は「マンハッタン距離」メトリックとして知られています。すなわち、直交(または軸方向)の移動に制限された場合の、各画像の二色間の距離です。ただし注意してほしいのですが、大きな差分はクリップ(または焼き付き)してしまうことがあります。HDRI 版の IM を使っていない限り、ピクセルデータの「Quantum Range」つまり整数の限界を超え得るからです。これをさらに進めて、二乗と平方根を使ってピタゴラス的(ユークリッド的)距離を実装することで、色ベクトルの距離を取得できます。 |

  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]
これは実際、「fuzz」係数がそのしきい値処理の一部として測定しているものと似ています(透明度が関与しない場合)。ただし「fuzz」は、結果が画像の色範囲の限界を超えないようにするため、加算する前に二乗値を 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」の処理を省くこともでき、その場合は二乗差分画像が得られます。色距離のメトリックは他にもあり、Color Difference, Wikipedia のページで読むことができます。これらのほとんどは(最後の例のように)ベクトル差分を生成しますが、LAB や LUV のような別の色空間を使います。ただしこれは、実世界の色差(例:人間の視覚による差の尺度)を比較する場合により重要になるでしょう。上記のような差分画像を使って背景除去を行う背景除去も参照してください。その実用例として、この外部ページ Change Detection も見てみるとよいでしょう。

フリッカー比較

画像間の差分を見るための「magick compare」プログラムの代替手段として、似た画像同士を適度に速いレートでフリッカー(ちらつき)比較する方法があります。 |

  magick -delay 50 bag_frame1.gif bag_frame2.gif -loop 0 flicker_cmp.gif

[IM Output]
これを簡単にするため、上記の例のように二枚の画像を交互に切り替えてアニメーション表示するスクリプト「**[flicker_cmp](../static/img/scripts/flicker_cmp)**」を書きました。これは表示画像の下部にラベルも追加し、任意の瞬間にどちらの画像を見ているかを示してくれます。

アニメーションの比較

特別な「フィルムストリップ」技法を使って、coalesce 処理した二つのアニメーションの差分を比較することもできます。並べて Append するで似た「append」技法を参照してください。基本的に、すべてのアニメーションフレームを append でつなげて、一枚の大きく長い画像を作ります。次にその二枚の画像を比較し、アニメーションを再び個別のフレームに分割することで新しいアニメーションを作成します。たとえば……

    magick \( anim1.gif -coalesce -append \) \
            \( anim2.gif -coalesce -append \) miff:- | \
      magick compare - miff:- |\
        magick - -crop 160x120 +repage anim_compare.gif

結果は「compare」画像のアニメーションで、二つ目のアニメーションの「薄暗くした」版に、違っている部分を示すハイライトが重なったものになります。なお、これがうまく動作するには「[-crop](https://imagemagick.org/command-line-options/#crop)」のサイズがアニメーションの元のサイズと一致している必要があります。また、アニメーションが持っていたかもしれない可変の時間遅延は失われ、元のアニメーションの最初のフレームに基づく一定の時間遅延が使われます。アニメーションに有用なもう一つの画像比較技法は、アニメーションが変化するすべての領域を特定し、アニメーションのつながっていない部分を分割するために使われます。こうすることで、大きなアニメーションを複数の小さなアニメーションに分けることができます。アニメーションの分割を参照してください。


比較統計

二枚の画像はどれくらい違うのか?

作成中

差分画像からの統計……

  以下は冗長な情報を出力し画像のチャンネル統計を含む
  セクションだけを抽出します……

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

  括弧内の数値は(存在する場合)0 から 1 の間に正規化された値で
  お使いの IM  Q レベルに依存しないようになっています
  これらの数値がない場合はIM のアップグレードを検討するとよいでしょう

  平均(mean)グレーレベルをパーセンテージとして取得するにはこの
  コマンドを使えます……

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

  パーセンテージでない場合はもっと単純な以下が使えます……

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


Compare プログラムの統計……

   -metric を使えば実際の平均差分値を取得できます

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

   -verbose を追加すると個々のチャンネルごとのより詳しい情報が得られます

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

      Image: rose.jpg
      Channel distortion: MAE
        red: 1884 (0.028748)
        green: 1532.34 (0.023382)
        blue: 1691.25 (0.0258068)
        all: 1702.53 (0.025979)

   選べるメトリックは何種類もあります
   同じテスト画像のセット(ほぼ同じもの)を使って

   ピクセル数
      AE ...... Absolute Error  異なるピクセル数の絶対誤差カウント(0=等しい)

                この値は -fuzz 設定でしきい値処理でき
                しきい値より大きいピクセルだけをカウントできます

                IM v6.4.3 以降-metric AE のカウントは -fuzz の影響を受けます
                そのため小さな差分をこのカウントから除外できます

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

                どのピクセルが異なるかは出力画像で確認できます
                (上記のコマンドでは無視しています)

                これがfuzzの影響を受ける唯一のメトリックです

   最大誤差(いずれか 1 ピクセルの)
      PAE ..... Peak Absolute Error   (3D 色空間で1 チャンネル内の)
      PSNR .... Peak Signal to noise ratio  (画像圧縮の論文で使われる)
                平均二乗差を任意の二枚の画像間に存在し得る最大平均二乗に
                対する比としてデシベル値で表したもの

                PSNR が高いほど画像が近いことを意味し差が最大のときは
                1 になりますPSNR  20 なら差分は最大の 1/100 です

   平均誤差(全ピクセルにわたる)
      MAE ..... Mean absolute error    (平均チャンネル誤差距離)
      MSE ..... Mean squared error     (平均二乗誤差距離)
      RMSE .... (平方)二乗平均平方根誤差 -- すなわち:  sqrt(MSE)


   特殊なメトリック
      MEPP .... 正規化平均誤差 AND 正規化最大誤差
                透明度のない画像ではこれらは-fuzz係数に
                直接関係するはずです

                透明度があるとこれが難しくなりますマスクは比較される
                ピクセル数に影響を与えそれゆえmeanにも影響するはず
                ですがこれは現状では行われていません

      FUZZ      透明度を考慮した fuzz 係数差分

      NCC       正規化相互相関 (1 = 類似)

   私のテスト画像で以下の結果が得られました……

    _メトリック_|__低 Q jpeg__|__黒 vs 白__
     PSNR   | 29.6504      | 0
     PAE    | 63479        | 65535
     MAE    | 137.478      | 65535
     MSE    | 4.65489e+06  | 4.29484e+09
     RMSE   | 2157.52      | 65535


   数値の 1 列目は低品質 JPEG による差分を持つ画像の比較で
   テスト画像を読み込んで非常に低い -quality 設定で保存し直したものです

   2 列目の vs ベタ塗りの黒画像とベタ塗りの白画像の比較です
   比較で画像の平均色が無視されるなら結果の値は非常に小さくなる
   はずですこれは PSNR メトリックでのみ当てはまるようで他はすべて
   最大差分値を生成しました

   e+06 は科学的記数法で小数点を何桁ずらすかを示します
   :   4.65489e+06  -->  4,654,890.0
   これは約 400 万に等しく2157.52 の二乗です

   警告:数値はコンパイル時に設定された IM  Quality (Q) レベルに依存します
   品質が高いほど数値は大きくなりますPSNR だけはこの影響を受けないはず
   ですこのため IM コンパイル時の品質設定に影響されない正規化結果
   も提供しますただしそれでもなお小さな量子または整数丸め効果が
   残ることがあります

   既存の-defineオプションのうちcompare機能で使えるものがあるか
   どうかはまだ把握できていません


   :不透明な色の場合AE -fuzz  RMSE の距離は等価です
   しかし透明な色が関与する場合AE のファズ係数テストは二つの異なる
   完全に透明な色を同じものとして扱う一方RMSE はそれらを異なるものと
   して扱います!

   たとえば……
   AE にとって完全に透明な白と完全に透明な黒は同じものです

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

   RMSE にとってもそれらは完全に透明なので同じ色です

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

Dissimilarity-threshold (非類似度しきい値)

  too different(違いすぎ)エラーが出た場合はこれで無効化できます……
      -dissimilarity-threshold 1.0

  しかしこのしきい値とは何でしょうか?

詳しくは、私の非常に古い生テキストのメモを参照してください…… Image Comparing, Tower of Computational Sorcery


サブイメージと形状の一致

作成中

compare -subimage-searchオプションを使う……

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

  これは二枚の画像を生成します
    results-0.png
        一致する位置を表示します
    results-1.png
        サブイメージがその位置でどれくらいよく一致するかを示す
        左上隅の可能性のある位置のマップです

  なお二枚目の画像はより小さく左上隅の位置だけだからです
  そのためサイズは   large_image - small_image + 1   になります

  ただしこの探索は色ベクトルの差分に基づいているので
  非常に正確な色比較を生成します

  この探索は基本的により大きな画像の中で可能なすべての位置において
  小さな画像の比較を行いますそのため遅いです!**とてもとても遅い**

  最善の考え方は非常に小さなサブイメージを比較して可能性のある位置を
  見つけそれを使って各候補位置で difference 比較を行いより正確に
  一致させることです

  スクリプトを見てみてください
    https://usage.imagemagick.org/scripts/overlap
  および関連する議論
    [Overlapped Images](https://magick.imagemagick.org/viewtopic.php?f=1&t=22526&p=95286)
  これはある画像の高エントロピーなサブイメージを特定して二枚目の
  画像の中で一致候補を探し二枚の画像間の重なりオフセットを発見して
  画像をより大きな一枚にマージできるようにするものです

  別の議論ではサブイメージ探索を使ってより大きな画像の中のタイリング
  パターンを見つけタイル可能な画像を生成することを目指しています
    [Stitching image over a canvas](https://magick.imagemagick.org/viewtopic.php?f=1&t=22860)


  RMSE と新しい -grayscale 関数を使って別々の色差分チャンネルの結果を
  最終画像にマージする例

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


類似度しきい値 (Similarity Threshold)

  多くの場合人は一致する最初の一つだけに関心があります
  この良い一致が見つかったらすぐに別の一致を探し続ける必要は
  ありません-similarity-metric 何を良い一致とみなすかを定義します

  -similarity-threshold 0.0最初に見つかった完全な一致で
  中断します一方-similarity-threshold 1.0(デフォルト)は決して
  一致せず可能なすべての点を探索しますその間の値は許容できる一致と
  みなす色だけのfuzz係数を設定します

  なおサブイメージ探索が中断された場合二枚目のマップ画像は部分的な
  結果しか含まず比較が探索を中断するまでの結果しか示しません


基本的なサブイメージ探索の例……

  端末ウィンドウのスクリーンショット(screen.png)を取得し
  一文字または一単語の画像(letter.png)を切り出します

  最初の一致だけを報告…… 速度のため
  その最初の一致が見つかったらすぐに中断します
  不完全な画像結果は出力しません

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

  なお速度はその最初の一致が画像のどこで見つかるかに大きく依存します

  その画像とまったく同じものの出現箇所をすべて見つけ
  画像として出力(一致箇所は白い点それ以外は黒)

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

  一致するすべての文字(白い点)の座標のリストを抽出
  (列挙されたピクセルリストとして黒いものはすべて無視)

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

  座標リストだけ

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



ImageMagick 以外のサブイメージ探索の解決策……

  xautomationパッケージのvisgrep」。

    これははるかに単純なサブイメージ探索プログラムで一致した箇所
    (あるいは複数のサブイメージの一致)の座標のリストを出力するだけです
    はるかに単純(ほぼ完全一致向け)さらなる研究のための結果画像
    生成しようとしないためはるかに高速でもあります

    たとえば……

      visgrep screen.png letter.png

    計測した結果
      compareで最初の一致だけを取得        0.21 
      compare結果画像を取得           1.56 
        同上ただし座標リストを抽出            1.76 
      visgrepで一致するすべての座標を取得    0.09 



サブイメージ探索の他の手法……

HitAndMiss モルフォロジー

  これは本質的にバイナリの一致でどのピクセルが背景どのピクセルが
  前景でなければならないかを定義しますただし結果が前景でも背景でも
  気にしない領域を定義することもできます

  基本的にはバイナリのパターン探索手法です

Correlate (Convolve の変種)

  これは Hit and Miss に似ていますがグレースケール値を使います前景には
  正の値背景には負の値気にしない部分にはゼロを使いますただし
  グレースケール画像に限定されます

  [相関と形状探索](convolve.html#correlate_search)を参照してください

  これらはどちらも基本的に前述のサブイメージ比較と同じくらい遅いですが
  色に関しては精度が落ちますしかしサブイメージに形状(気にしない領域)
  指定できる能力があるため探索手法として有用です

  ただしサブイメージを実際の画像としてではなく、「カーネル」、つまり
  浮動小数点値の配列に変換する必要があります


FFT Convolve (NCC)

  高速フーリエ変換は遅い演算子ですが通常は前述の二つの手法より何桁も
  高速ですその理由は周波数領域での畳み込みがピクセルごとの直接の
  乗算に過ぎないからです

  Convolve手法は探索対象のサブイメージを 180 度回転するだけで
  Correlateに変換できます
  [Correlate](convolve.html#correlate)を参照してください

  基本的に画像を周波数領域に変換することで前述の手法と比べて
  非常に高速にサブイメージ探索ができます特に元の画像と同じサイズに
  なり得るような大きなサブイメージの場合に有効です!

  これは NCC  compare メトリックとして追加されたと思います


<a id="peak_finding"></a>
ピーク発見と抽出(近い部分一致のため)……

  画像を比較すると通常一致がどれくらい完璧だったかを定義する
  何らかの確率マップが得られます

  ここでやりたいのは最良の一致あるいは画像内の複数の一致を見つける
  ことですつまり結果マップ内の主要なピークを特定し実際の位置を
  抽出したいのです

  * ラプラシアン畳み込みカーネルを使う

    結果を得るには画像内のピークを見つける必要があり必ずしも最も
    明るい点とは限りませんこれは中心ピクセルから周囲のピクセルの平均
    を引くように画像を畳み込むことで得られます正の結果だけが欲しいので
    バイアスで負の結果を取り除きます

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

    しきい値処理してマスクとして使えばそれらのピクセルだけを抽出できます

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

    問題はピークで明確な一ピクセルではなく点のクラスタが得られる
    ことがある点です特に非常に低い値に囲まれた二つのピークピクセルの
    場合です

  * Peaks Hit and Miss モルフォロジーカーネルを使う

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

    問題はまったく同じ値の二つのピークピクセルが得られた場合(前景と
    背景の間に隙間がない)結果が出ないことがある点です

    しかしそのようなピーククラスタでも位置を特定できる他のpeak
    カーネルもあります

  * Dilate して比較

    画像を 3  Dilate(最大値を拡張)それを元の画像と比較します
    Dilate のカーネルサイズ(7 ピクセル四方)の領域内のピークはすべて
    同じ値のままになります差分を示すすべてのピクセルをゼロに設定します

    HugoRune による手法 (IM 議論トピック 14491)

  * 一致と除去のループ

    基本的に最も高いピクセル値を見つけそれを記録します次にその
    ピーク周辺の領域のすべてのピクセルをマスクし何らかの限界(点の数
    またはしきい値)に達するまで繰り返します

    この手法のシェルスクリプト実装はFred Weinhaus のスクリプト
    [maxima](http://www.fmwconcepts.com/imagemagick/maxima/)」を参照
    してください

    これはほぼ等しい値のピクセルの大きなクラスタの中心を見つけること
    は考慮していませんが実際の画像ではそれは非常にまれでしょう

  * サブピクセルの位置特定

    ピークが正確な一ピクセルではなくサブピクセルの位置(ピクセルとピクセル
    の間)であり得る場合はピーク周辺の領域で何らかのパターンマッチ
    (ガウス曲線フィッティング)を行うことでピークをサブピクセル座標で
    特定できるかもしれません

    これはパノラマスティッチングのための画像レジストレーションでより重要
    になるかもしれません特に透視重ね合わせの最適近似平均を得るために
    多数の点を使っていない場合です

  * 画像内のタイルパターンを見つける

    すべての点が得られたら繰り返しパターン(複数のピーク間の似たベクトル
    距離)を探すことで何らかのタイリング構造を指し示せるはずです


サブイメージの一致を改善する……

  Correlate(または同じことをする高速 FFT correlate)の大きな問題は
  色をまったく理解しないことです

  Correlation(または convolve)は純粋に数学的な技法で値の集合に対して
  使われます画像でこれが意味するのは画像の個々のチャンネルに対してのみ
  適用されベクトル色距離に対しては適用されないということです


  一方 compare 色ベクトルの実際の比較を行いますこれは correlate
  よりもうまく形状を見つけますがはるかにはるかに遅いです

  そのため correlate をきちんと活用するには画像を(速度のため事前に
  あるいは結果に対して後から)処理して画像内の色差をグレースケールの
  相関画像として強調しようとするとよいでしょう

  余談:-channel を使って演算を一つのグレースケールチャンネルに限定すると
  速度が向上しますIMv7 ではグレースケール化が画像を一チャンネルに減らす
  ので自動的に速度向上が得られます

  たとえば輝度の代わりに画像の Hue を抽出すると前景/背景の区別が
  よりうまくいくかもしれませんただし探索対象のサブイメージに赤が多い
  場合は色相を回転させる必要があるかもしれません

  この問題を見るにはHSL  HSB のチャンネル分離の例を参照してください
    https://usage.imagemagick.org/color_basics/#separate

  非常にうまくいくはずの別のグレースケール化手法は二枚の画像にエッジ
  検出を行うことですこれは境界と形状を強調しますがこれは画像内の
  滑らかなグラデーションや色の変化よりも通常はるかに重要です

  エッジ検出手法の例については以下を参照してください
    https://usage.imagemagick.org/convolve/#edgedet

  方向性のあるつまりコンパス型のエッジ検出も見てみるとよいでしょう

  基本的にあなたの特定のケースで形状を強調するものなら何でも良い考えです
  相関を取る前に両方の画像にそれを適用するだけです


スケールと回転に不変なマッチング……

  * 位置非依存……
  * 回転したサブイメージの一致(角度非依存)
  * リサイズされたサブイメージの一致(サイズ非依存)
  * サイズと角度の両方に非依存


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

より特定的な他の画像マッチング……

直線のマッチング……

  Hough アルゴリズム

円のマッチング……

  Hough アルゴリズムの変種

顔のマッチング

  上記の組み合わせ

重複画像を探す

同一のファイル

ファイルがバイナリレベルで同一かどうか、つまりまったく同じファイルであり、おそらく互いの正確なコピーに過ぎないかどうか。ImageMagick は不要です。これを軽視しないでください。この方法では、たくさんのファイルを非常に、非常に速く比較できます。私が見つけた最良の方法は、MD5 チェックサムを使うことです。

  md5sum * | sort | awk {'print $2 " " $1'}  | uniq -Df 1

これで、同一の画像の md5 が一覧表示されます。この技法を使って、ファイルの md5sum リストを生成・比較し、md5 が同一のファイルを返すスクリプトを作りました。ただし、直接のコピー以外の画像ファイルへの変更は、たとえ画像データ自体が同じであっても、これによって異なるものとして分類されます。日付の変更やその他の小さなメタデータの違いがあるだけで、画像が異なるものになってしまうのです。

IM 画像シグネチャ

IM に各画像の「シグネチャ」を生成させることができます……

  magick identify -quiet -format "%#" images...

これは MD5 や SHA256 と同じようなハッシュ文字列を生成します。ただし後者と異なり、シグネチャの生成には画像のメタデータではなく実際の画像データを使います。そのため、作成/変更タイムスタンプの異なる同じ画像のコピーが二つある場合、両方のファイルで同じシグネチャが得られるはずです。一方 MD5 や SHA256 は、画像自体が同じであっても二つのシグネチャを生成します。警告:JPEG 画像の読み書きは、異なる画像データを生成し、それゆえ異なるシグネチャを生成します。これは単に JPEG 画像フォーマットが使う非可逆圧縮によるものです。

直接比較

二枚の画像が同じサイズであれば、(「magick compare」プログラムを使って)直接比較し、どれくらいよく一致するかを見ることができます。(上記参照)これは非常に遅く、フルサイズの画像に対して使うと、あまりに遅いため私の経験ではあまり有用ではありません。しかし、二枚の画像がどれくらい似ているかを把握するには、おそらく最良の方法です。

画像の分類

画像を比較しようとする試みの中で、私はカラー、カートゥーン風、そしてスケッチが、互いに非常に異なる比較結果になることに気づきました。線画やグレースケール画像は特に、ほぼすべての比較手法において、カラー画像よりも差分が小さくなる傾向があります。基本的に、色がすべて一直線上にあるため、どんな色のメトリックでも、そのような画像は 3 倍近くに配置される傾向があります(1 次元の色空間 vs 3 次元の色空間)。基本的にこれが意味するのは、画像を少なくともこの二つのグループに分けることが、重複や非常に似た画像を見つける本格的な試みにおいて、非常に重要な最初のステップになり得るということです。他の主要な分類、つまり画像タイプも、比較対象の画像数を減らすだけで、画像の比較を容易にしてくれます。後述の「画像の分類」を参照してください。

サムネイル比較

プログラムが(メモリ内に)比較対象の画像の小さなサムネイル(たとえば 64x64 ピクセル)をたくさん作成し、それを直接比較することで重複を探します。これは通常、人(私も含めて)が最初に試みることであり、実際これはほとんどの画像比較プログラム(写真管理ソフトウェアなど)が行っている技法です。実際これはうまく機能し、完全に一致する画像を見つけます。また、少しぼかして差分しきい値を緩めれば、わずかにトリミングやリサイズされた画像でさえ見つけられます。しかし、10,000 枚ものサムネイルをメモリに格納しようとすると、しばしば通常のコンピュータがスラッシングを起こし、非常に遅くなります。あるいは、(ユーザー閲覧のためにプログラムがそうするのでない限り)それらすべてのサムネイルを格納すると、大量のディスク容量を使います。ディスクスラッシング問題を改善する一つの方法は、メモリ内の画像数を少なくすることです。つまり、一枚の画像を他のすべての画像と比較するのではなく、グループごとに画像を比較するのです。自然なグループ化はディレクトリ単位で、各ディレクトリの画像を他のディレクトリの画像と比較します。実際これはかなり良い方法です。画像はまとめてグループ化される傾向があり、この画像のグループは似たグループと一致することが多いからです。一致した画像をディレクトリのペアごとに出力できるのは、おまけの利点です。また、二枚の画像がどれくらい許容できる程度に似ているかは、画像タイプに依存します。二つの線画の比較では、違っている画像を除外するために非常に小さな「しきい値」が必要な一方、大きな色の領域を持つ画像の比較では、トリミングされた似た画像を捉えるために、しばしばはるかに大きなしきい値が必要です。実写画像にはより大きな問題があります。テクスチャは、ごくわずかにオフセットがあるだけで、画像間に非常に深刻な加算的差分を生じさせ得るのです。このため、メディアンフィルタ、ぼかし、減色、あるいはカラーセグメンテーションを使って、そのような画像を一般的な色の領域へと単純化する必要があるかもしれません。そのような処理の後では、実写画像は一般にカートゥーンと同じような方法で比較できます。

画像メトリック

各画像について小さなメトリックを作ることは、線形の順序(O)の操作です。一方、すべての画像を他のすべての画像と比較することは、二乗の順序(O^2)の操作です。メトリックは、実際に一致する画像を見つけるためのものではなく、似た(一致しそうな)画像を、より小さなグループに対してより集中的な比較を行えるようにグループ化するためのものです。そのため、どんなメトリック比較も寛容であるべきで、一致の確率は低い(それでも確率はある)画像を受け入れるべきです。しかし、誤った一致を多く含めてしまうほど寛容であってはいけません。また、複数のメトリックを検討するとよいでしょう。あるメトリックが「ぎりぎり見逃した」(しきい値の不一致で)画像を、別のメトリックが一致させるかもしれないからです。次のセクション(メトリック)では、私が実験した、あるいは理論的に考えた、さまざまな IM 生成メトリックを紹介します。これには、平均色、主要色、前景背景、エッジ色、色の行列などが含まれます。Günter Bachelier 氏は、画像比較のためにもっと風変わりなメトリックを使う可能性についても報告しています。たとえば、フーリエ記述子、フラクタル次元、凸面積、長軸/短軸の長さと角度、円形度、凸性、カール、充実度、形状分散、方向、オイラー数、境界記述子、曲率、曲げエネルギー、総絶対曲率、面積、幾何学的重心、質量中心、コンパクトさ、離心率、中心まわりのモーメントなど、いろいろです。私の現在の取り組みは、画像を表現するために色平均の単純な 3x3 行列を生成して使うことです(後述の色行列メトリックを参照)。これらが生成される(または要求される)と、メトリックは(他のファイル情報とともに)各ディレクトリ内の特別なファイルにキャッシュされます。こうすることで、キャッシュされたメトリックが利用できないか、画像が変わった場合にのみ、特定のメトリックを再生成すればよくなります。

類似度または距離

二枚の画像(あるいは実際の画像)のメトリックは、いくつかの異なる方法で比較でき、一般に「似た」画像をクラスタリングするために使える単一の距離尺度、つまり「類似度メトリック」を生成します。

  • 直接しきい値、または最大差分(チェビシェフ距離)
    いずれか一つのメトリックの最大差分で画像を比較するだけ。
    このしきい値は、多次元のメトリック空間内で、似た画像の超立方体を生成します。もちろん、この画像差分は一つのメトリックだけに基づいており、すべてのメトリックにわたるものではありません。
  • 平均差分(平均距離、平均マンハッタン距離)
    すべての差分を合計し、必要に応じてメトリックの数で割る。
    これは二つのメトリック間のマンハッタン距離としても知られています。都市の格子状の道を移動する際にカバーする必要のある距離に相当するからです。すべてのメトリックが等しく寄与し、その結果、ものが予想より「近く」見えることになります。空間内では、このメトリックのしきい値はダイヤモンドのような形を生成します。
  • ユークリッド(ピタゴラス)差分
    あるいは、メトリック空間内のメトリック間の直接のベクトル距離。
    この値は、より多くのメトリックが関与すると大きくなる傾向があります。ただし、一つのメトリックが大きな差分を生成すると、それが他のメトリックよりも大きく寄与する傾向があります。しきい値はメトリック空間内に球状の体積を生成します。
  • 数学的誤差/データフィッティング、または(慣性モーメント???)
    すべての差分の二乗を合計し、それから平方根を取る
    これは、数学的な曲線が特定のデータ集合にどれくらいよく合うかを計算するためにより典型的に使われますが、画像メトリックの比較にも使えます。
    これは、ベクトルでない距離尺度として最良のものを提供しているようです。
  • ベクトル角
    画像のメトリックが作るベクトル空間の中心から伸びる二つの直線の間の角を見つける。これは、二枚の画像に適用されたかもしれないコントラストや画像強調の効果を取り除くはずです。
    まだ未検証
  • ベクトル距離
    線画やグレースケール画像のように、メトリック内の個々の色ベクトルがすべて同じ方向を向いている画像では、画像の平均色からのメトリックの相対距離のほうがおそらく重要です。最大距離に対して距離を正規化すると、コントラストの影響を減らせるかもしれません。
    つまり、これは線画画像の比較手法です。
    まだ未検証
  • クラスタ分析
    すべてのメトリックがプロットされ、多次元空間内で似たクラスタにグループ化されます。良いクラスタリングパッケージなら、クラスタリングを生み出さないメトリックを発見して除外できるかもしれません。
    まだ未検証

現時点では、後述の単純な 3x3 平均「色行列メトリック」を使って、グレースケールと色の両方のメトリックに対して「数学的誤差」技法がうまく機能するようです。

人間による検証

コンピュータが一致する画像を見つける試みを終えたら、画像が実際に一致するかを確認するのはユーザーの仕事です。一致をユーザーに提示することもまた難しい作業です。ユーザーはおそらく次のようなことができる能力を求めるからです……

  • 画像を並べて見る
  • 二枚の画像を、元のサイズ、そして任意で共通の「スケーリングされた」サイズで、非常に、非常に速く切り替える。
  • 異なるスケールと平行移動の画像を切り替えたり重ねたりして、画像を一致させようとする。
  • 一致する画像と同じディレクトリ(ソース)、あるいはおそらく同じクラスタ(他の近い一致)にある他の画像を見て、各画像を個別にではなくグループ全体として扱えるようにする。
  • 画像を二つ(以上)のディレクトリ間で名前変更、移動、置換、削除、コピーして、画像を整理し、他を除外する。
  • など……

。現在私は、一致をセットにグループ化し、ユーザーの制御のもとでそれらを扱うためにプログラムの組み合わせを使っています。これらのプログラムには、IM の「magick display」と「magick montage」、それに画像ビューア「XV」と「GQview」が含まれます。しかし、二つ以上のディレクトリを同時に開き、複数のディレクトリからの画像コレクションやグループを表示できる他のプログラムの提案も歓迎します。リモートまたは他のプログラムやスクリプトによる制御は、画像グループをユーザーが見て扱うのに最適な方法でセットアップ・提示できるため、不可欠になり得ます。私のニーズを満たすプログラムはまだありません。たとえば「gqview」にはコレクションと単一ディレクトリビューがありますが、複数ディレクトリビューや、提示のリモート/コマンドライン制御はできません。しかも、コレクションは各画像がどのディレクトリから来たかを表示せず、単一ディレクトリビューを別のディレクトリに切り替えることもできません。リモートプログラム制御もありません。一方、非常に古い「xv」は複数ディレクトリビュー(複数の「visual schnauzer」ウィンドウを使う)と、その制御ウィンドウのコレクションリストを許可しますが、一度に一枚の画像しか見られず、コマンドラインから開いて位置を指定できるのは一つのディレクトリだけです。もちろんリモート制御もありません。これらが私が見つけた最良の人間検証プログラムで、画像グループ、一致ペア、あるいはすべてのグループ一致画像ごとにセットアップして起動するスクリプトを使っています。しかし、どれもあまり満足のいくものではありません。ライトテーブルと関連ソフトウェアが、画像を整理するにはより良い方法だと私には思えますが、そのためにはより大きなタッチ感応スクリーンが必要で、そこに大きな出費が伴います。

異なるタイプ間の画像比較

私がやりたいことの中でもより難しいものの一つは、別の画像から作られた画像を見つけることです。たとえば、誰かが色を塗ったり、絵の具で描いたりしてカートゥーンや超リアルな画像を作った線画を、元の線画と一致させたいのです。背景が追加されているかもしれません。これらは非常に難しく、エッジ検出技法を使った私の実験はこれまでのところ決定的な結果が出ていません。ここで正しいメトリックを見つけることが鍵です。人間は「類似」のつながりをはるかにうまく作れますが、それでもユーザーに提示する可能性のある一致を見つけ出さなければならないからです。

重複画像を探すことのまとめ

要するに、重複画像を見つけて扱う私の現在の手順は、「似た」画像を見つけて整理するためのプログラムのパイプラインです。

   画像タイプとメトリックを生成/キャッシュ
     -> メトリックを比較して画像をクラスタリング。
       -> クラスタ内の画像を比較して一致を探す
         -> 一致する画像のセットにグループ化(ソースディレクトリ別)
           -> 人間による検証

ご覧のとおり、私は高度に段階分けされたアプローチを検討しています。あなたのアイデアをメールで送ってください!!!


画像をタイプ別に分類する

どのタイプの画像かを判定することは重要です。画像を比較するほとんどの手法は、特定のタイプの画像でしか機能しないからです。たとえば、テキストの画像をアーティストのスケッチと比較しても意味がありません。また、ほぼ純白の画像(スケッチ)にカラー画像の比較手法を使っても役に立ちません。通常、画像を比較する際に最初にすべきことは、どのタイプの画像か、つまり画像がどの「色空間」を使っているかを判定することです。画像の基本的な分類には次のようなものがあります……

  • 白黒の線画またはテキスト画像(ほぼすべてが一色)
  • 二つの基本色から成る画像 - 均等に(パターン画像?)。
  • グレースケールのアーティストの絵(多くの陰影)
  • 線形カラー画像(色がグラデーションを成すが黒から白ではない)
  • 大きなベタ塗りの色の領域を持つカートゥーン風カラー画像。
  • 陰影のある色の領域を持つ実写画像
  • 画像に注釈テキストやロゴのオーバーレイが含まれる。(色の単一のスパイク)

基本的なカテゴリ分けの後、さまざまな画像メトリックを使って画像をさらに分類しようとすることもできます。たとえば…… * 画像全体の平均色 * 画像内の主要色 * 画像の前景/背景色。

さらに厄介なことに、JPEG やリサイズされた画像はしばしば色も歪んでおり、色が本来あるべきものとは少し違うため、こうした分類がはるかに難しくなります。グレーは純粋なグレーにならず、線は鋭く明瞭でなくなります。画像をタイプ別に分類することに関する長期にわたる議論が、IM ユーザーフォーラムにあります…… How to check image color or black and white

グレースケール画像

画像がグレースケールかどうかを確認する最も簡単な方法は、画像の彩度レベルを見ることです。これは、画像を「Hue」画像色空間に変換し、色(通常は緑)チャンネルの平均値と最大値を取得することで簡単にできます。たとえば……

  magick rose: granite: -colorspace HCL \
          -format '%M  avg=%[fx:mean.g] peak=%[fx:maxima.g]\n' info:

[IM Text]

数値は 0 から 1 の範囲に正規化されています。ご覧のとおり「rose」は非常に色鮮やか(平均 30%)で、強いピーク(1 に近い)があります。一方「granite」画像は彩度が非常に低く(2% ほど)、ピーク値も低いです。純粋なグレースケールではありませんが、それに非常に近いです。低い平均と高いピークは、強い色の小さなパッチがあることを示します。同じチャンネルをしきい値処理すれば、画像の色鮮やかな領域のマスクを生成できます。問題:上記は色が線形な画像を見つけられません。つまり、黄ばんだ(セピア調)写真や青写真のような、線形の色グラデーションを成す色しか含まない画像です。これらは本質的に色鮮やかなグレースケール画像です。次の画像タイプを参照してください。

画像は線形カラーか

別の技法は、画像内のすべての色(あるいはメトリックの簡略化した色行列)に対して、3 次元の直線の直接の「最適フィット」を行うことです。フィットの誤差(一般に誤差の二乗の平均)は、その画像がその直線にどれくらいよく合うかについて、非常に良い指標を与えてくれます。3 次元画像への直線のフィッティングには、一般に何らかのベクトル数学が伴います。結果は、画像がほぼ「線形」な色の集合を使っているかどうかを教えてくれるだけでなく、明から暗だけでなく、黄ばんだ紙の上のオフグレーの線も含め、あらゆるスケールの色に対して機能します。結果はまた、より単純な比較とより良い一致探索のために、画像をより単純な「グレースケール」画像へと変換する(あるいは色メトリックの集合をグレースケールメトリックへと変換する)ためにも使えます。私の試作テストプログラムは、この判定を行うのに画像全体すら使わず、後述の単純な 9 色(27 値)の色行列メトリックを使って画像を表現します。ただし注意してほしいのですが、このテストは一般に、陰影のない線画をあまりうまく区別できません。そのような画像はほぼ完全に単一の背景色(通常は白)であり、そのため色の線形グラデーションをまったく示さないかもしれません。これらは別のテストを使って先に分離すべきです(次を参照。実際こちらのほうがはるかに簡単です)。興味があれば、そして何を試したか、メールで教えてください。

純粋な白黒画像

画像が、(アンチエイリアスによる)色やグレーすらほとんど含まない、ほぼ純粋な白黒画像かどうかを見るには、「[-solarize](https://imagemagick.org/command-line-options/#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]

上記の統計を見ると、色の「mean」(平均)が純粋な黒(「0」)に非常に近い一方、「standard deviation」(標準偏差)も非常に小さいものの、「mean」よりは大きいことが分かります。したがってこの画像は、色や中間調のグレーがほとんどなく、ほぼ純粋に白黒であるに違いありません。一般的なグレースケール画像やカラー画像では、「mean」ははるかに大きくなり、一般に「standard deviation」は mean より小さくなります。そうなった場合、ソラリゼーションされた画像にはほぼ純粋な黒がほとんど含まれていないことを意味します。つまり、純粋な黒や白の色がほとんど存在しないということです。組み込みの granite 画像を使ってこのテストを繰り返してみましょう。

   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]

「mean」が今や色範囲の中央に向かってはるかに大きくなり、「standard deviation」が「mean」の大きさよりもはるかに小さくなっていることに注目してください。IM v6.4.8-3 以降では、画像のタイプを判定するのに役立ち得る他の二つの統計値も見られます。「尖度(Kurtosis)」と「歪度(Skewness)」はどちらも、最初の白黒画像では比較的大きく(かつ正)、グレー画像と比べてグレーがほとんど関与していないという事実も反映しています。ただし、比較の目的には「mean」対「standard deviation」のほうがおそらく良い指標です。なお、この比較は「白地に黒」か「黒地に白」かを区別しませんが、本当はグレースケール画像でないと分かれば、画像の通常の mean を単純に確認することで、背景色が実際には何かを教えてくれます。

スポットカラー画像

これらの画像は上記のグレースケールテストには失敗しますが、それでも白黒であり、ただし小さな領域や色のパッチを含んでいます。色の小さなパッチは、大きな画像の全体平均に容易に飲み込まれてしまい、グレースケールと誤って分類されかねません。私たちが関心があるのは、ビットエラーである可能性が高い、たった一ピクセルの色を持つ画像や、画像全体にそのようなピクセルが散らばっているものではありません。そうではなく、色のついた矢印や小さな色のついたオブジェクトを持つ画像です。言い換えれば、集中した色のスポットです。IM フォーラムの議論 False positive for greyscale images using the "saturation test" で、画像をより小さなセクションに分割し、そのいずれかの領域で高い彩度を探すことが考えられました。これが以下の手法につながりました。

  • 画像を Saturation または Chroma チャンネルを持つ色空間に変換する
  • 画像を 1:50 (2%) の比率で小さくリサイズする(例:色の「スポットサイズ」)
  • 最大の彩度/クロマ値を取得するためにしきい値処理する

個々の、あるいは非常に小さなスポットは除去されますが、より大きな色のスポットは、リサイズされた画像の中に少なくとも一つの色鮮やかなピクセルを持つことになります。

中間調の着色画像

[IM Output] セピア調の画像や、中間調のグレーが何らかのハイライト色に着色された画像(たとえば右の画像)は、区別するのがはるかに難しいことがあります。そのような画像を生成するのは、中間調の色付けで示すように簡単ですが、あまり一般的ではありません。色は依然として色空間内で色のグラデーション(直線)を成しますが、そのグラデーションは、平面内で典型的には何らかの放物線のような、曲がった経路に沿って落ちます。しかし、そのような画像を区別するのは非常に難しいことがあります。一つの技法は、極端に小さい彩度を持たない色相の標準偏差を取得することです。中間調の着色画像内のすべての色相は、たとえ数が多くなくても、非常に似ているはずです。この技法は、How to check image color or back and white の特定の投稿で提示されました。念のためですが、Hue は循環的な値で、色「赤」のところで折り返します。適切にテストするには、色相を 180 度ずらして二度行う必要があるかもしれません。また、Hue は彩度が非常に低い色(グレー)に対しては実質的な意味を持たないので、色相の標準偏差をテストする際には、そのような色は無視すべきです。

テキスト vs 線画

ほぼ純粋に単一の色(通常は白)である画像があるなら、その画像の内容がテキストか線画のどちらに分類できるかを見てみるとよいでしょう。テキストには小さな分離したオブジェクトがたくさんあり、一般に水平な行にまとめられています。一方、線画はほとんどすべてが全体としてつながっており、多くの異なる角度が関与しているはずです。なお、カートゥーン風のカラー画像も、より単純な画像比較のために線画に変換できるので、線画の比較手法があれば有用でしょう。誰かやってくれませんか?テキストについてより詳しく知るための多くの技法が、IM フォーラムで議論されています。Check if image contains text

実写 vs カートゥーン風

基本的に、カートゥーンは非常に明確な色のブロックと鋭い境界の領域を持ち、しばしば分離用の黒い線でより鋭くされています。また通常、グラデーションや陰影効果は最小限です。一方、実写画像には柔らかなエッジ効果、色のグラデーション、テクスチャがたくさんあり、多くの異なる色を使います。もちろんこれは常に正しいわけではありません。実写画像が非常にカートゥーン風の質を持つこともあり、特に非常に高いコントラストが使われている場合がそうです。また、一部の現代のカートゥーンは非常にリアルなため、カートゥーンと分類するのが難しいことがあります。一般に、実写画像とカートゥーンの主な違いは、テクスチャとグラデーションです。そのため、どのタイプの画像かを判定するには、その画像を、細かいスケールのテクスチャを取り除いた同じ画像と比較する必要があります。大きな差分は、画像が「カートゥーン的」または「平坦」というより、より「リアル」で「実世界」的であることを意味します。また、線画、アーティストのスケッチ、テキストもスタイルとしては非常にカートゥーン風になり得ますが、上記の手法が画像を実世界的と考えてしまうほど細かいテクスチャと細部を持つことがあります。そのため、線画とスケッチは事前に分離しておくべきです。
Jim Van Zandt はこの解決策を提案しています……

  • すべてのピクセルの色を書き出す
  • 色でソートする
  • 各色のピクセル数を書き出す
  • ピクセル数でソートする
  • 画像内のピクセルの半分を占めるまで、リストを順に進む。
  • もし #pixels が #colors よりはるかに大きければ、カートゥーン風です。

最初の部分はヒストグラムとして分類できます。「[histogram:](files.html#histogram)」の例を参照してください。
何らかの画像分類のスキームを作ったなら…… たとえおおまかなものでも、結果を教えてください。他の人々(私を含めて)が恩恵を受けられるように。


特定の画像タイプの扱い

ここでは、より特定的な画像判定技法についてのメモと情報を紹介します。

不良スキャンやプリントアウト

実世界では、物事は望むほど完璧にはいきません。スキャナにはセンサの故障があり、プリンタのドラムには傷があります。これらの問題はどちらも、一般にスキャンやプリントアウトに長い縦線が含まれる結果になります。ただし、画像にこれらの縦線があるかを判定するのはかなり簡単です。考え方は、画像のすべての行のピクセルを一緒に平均することです。どんな「不良」も、最終的なピクセル行に鋭いブリップとして現れ、その数はピクセル行の「しきい値ヒストグラム」を使って数えられます。

将来 -- テスト用の画像例が必要
    magick bad_printout.png -crop 0x1+0+0 -evaluate-sequence mean \
            -threshold 50% -format %c histogram:info:-

より速い方法だが画像の高さが必要(1024 と仮定)
    magick bad_printout.png -scale 1024x1 \
            -threshold 50% -format %c histogram:info:-

ファクス、プリントアウト、スキャンからそのような「不良な線」を判定して取り除いたら、この種の実世界の不良を気にせずに他のテストを続けられます。

白紙ファクス

まず、ファクスがページに追加したかもしれないヘッダーとフッターを「[-shave](https://imagemagick.org/command-line-options/#shave)」で削り取る必要があります。それから「しきい値ヒストグラム」(前述参照)を行って、個々の黒いピクセルがいくつあるかを見ることができます。

将来 -- テスト用の画像例が必要
    magick blank_fax.png -threshold 50% -format %c histogram:info:-

あるいは、ノイジートリムを行って、画像に実際に注目に値するベタ塗りの領域やオブジェクトがもっと含まれているかを見ることもできます。

将来 -- テスト用の画像例が必要

スパム画像

スパム画像は一般に、画像の色ヒストグラムに主要な純色のスパイクを示します。画像内のその色を確認すると、通常それは画像の隅のいずれかにあることが分かります。ただし、これはカートゥーン風の画像ではうまくいきません。

メールスパム画像

これらは、さまざまなスパムフィルタをすり抜けるように設計された画像です。基本的に、広告のテキストがさまざまな色を使って画像内に隠され、検出しにくくするために余分な「ゴミ」やその他のノイズが追加されています。これらは、たとえば会社のメールヘッダーのロゴと区別するのが難しいのですが、通常は典型的なメールロゴよりもはるかに大きいです。一つの発見技法は、画像に大きなメディアンフィルタを使うことです。メールスパムのテキストは一般に消えますが、ロゴや画像は依然として非常に色鮮やかなままです。


画像メトリック、比較する画像を素早く見つける

メトリックは、画像を非常に少ないメモリ量で表現する一種の「指紋」です。似た画像は似たメトリックになるはずです。ただし、メトリックは実際に一致する画像を見つけるために設計されたものではなく、確実に一致しない画像を除外しようとするためのものであることに注意してください。つまり、良いメトリックは、ほとんどの画像をさらなる比較から除外させてくれるので、すべての画像を検索するのに必要な時間を減らせます。

画像の平均色

-scale を使って画像の平均色を取得できますが、画像の周りに追加されたかも
しれない「ふわふわした」ものの影響を減らすため、画像の外側の境界を
取り除くことも提案します。

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

あるいは、平均ではなく色のクラスタリングに基づく「加重重心」色を取得する
には、-colors を使えます

    magick rose: -colors 1 -crop 1x1+0+0 -depth 8 -format '%[pixel:s]' info:-
    rgb(146,89,80)

これは一般に、リサイズ、軽くトリミング、回転、平行移動された画像を一致させます。しかし、密接に関連していない画像も多く一致させてしまいます。最大の問題は、このメトリックが一般に、明るくされたり、暗くされたり、全体の色相が変えられたりした画像を除外してしまうことです。また、これは色と実世界の画像にとっては素晴らしいメトリックですが、グレースケールの画像にはまったく役立ちません。そのような画像はすべて、タイプ内でさらなるクラスタリングが行われずに、一般にひとまとめにされてしまいます。これは逆に、なぜ画像タイプの何らかの初期分類が、良い画像のソートと一致において不可欠になり得るかを示しています。

画像の主要色

画像の主要色は少し違います。背景色と前景を融合する平均ではなく、最も一般的な前景色を見つけ、おそらく画像のどれくらいの割合がその主要色から成るかも見つけたいのです。そのため、画像のヒストグラムを取るだけではうまくいきません。画像は特定の色ではなく、多くの個々の色の陰影を使っているかもしれないからです。これは低レベルの量子化関数 -segment を使い、それからヒストグラムを取ることで行えます。これは -colors を直接使うより有利です。(色的に)遠い色のクラスタをマージしようとしないからです。ただし、結果は判定しにくいかもしれません。

 将来の例

その後、ヒストグラムが各主要色の量を教えてくれます。ただし、通常、カートゥーンや線画の主要色は画像の背景色です。そのため、実写画像でしか本当には役立ちません。一方、これを画像の平均境界色と比較することで、画像に真の背景があるかどうかを発見するのに使えるかもしれません。なお、画像の主要色は、関心の対象であるオブジェクトよりも、画像の背景色によってより強く影響される可能性が高い点に注意してください。つまり、通常は画像の中心またはその近くにあるものです。

境界色

画像の四つの端をそれぞれ繰り返しトリミング(最大でも 2 〜 3 ピクセル)し、境界の平均色を計算することで、画像に枠があるか、そしてどれくらいの深さかを判定できます。画像に明確な背景があるかどうか。あるいは、画像全体に何らかの空/陸、または近景/遠景の色の分離があるかどうか。平均した辺の色を画像の平均中心色と比較することで、画像が、空っぽの風景の写真のように、中心的なテーマや主題なしに均一かどうかを発見できます。

ヒストグラム - 一般的な色のマッチング

画像内に見られる色のタイプに関するメトリックには、何らかのヒストグラムが使われます。これは「カラービン」の配列を作り、色が見つかるたびに各「ビン」のカウントを増やすことで行われます。さて、すべての画像について大きなヒストグラムを格納するのはとても考えられません!ですから、ヒストグラム内の最も主要な色だけを格納するか、はるかに少ない数のビン(各ビンにより多くのピクセル)を使うことになります。「カラービン」の通常のヒストグラムは、あまりうまく機能しません。その理由は、各色が常に一つのビンに入るからです。つまり、各ピクセルは、その色がビンの端にどれくらい近いかをまったく考慮せずに、オールオアナッシングで各ビンに追加されます。これは逆に、良いメトリックにはなりません。一つの解決策は、重なり合うビンを持つヒストグラムを作ることです。つまり、すべての色(おそらく黒や白を除いて)が二つのカラービンに入ります。すると、後で画像を比較する際に、近い色が少なくともそれらのビンの一つに一致します。別の代替策は、各色がビンの中心にどれくらい近いかに応じて、各「ビン」に寄与することでヒストグラムを作ることです。つまり、一つのビンの端にある色は、実際に二つのビンにまたがって自身を共有します。これは一種のファジーな、つまり補間されたヒストグラムを生成しますが、特にごく少数のカラー「ビン」しか使われない場合に、画像をより正確に表現するものです。また、ヒストグラムは伝統的に、画像のグレースケール成分だけか、三つの別々の RGB 成分のどちらかです。しかしこれはあまり良い表現ではありません。代わりに、画像をより良く表現するために、色相、彩度、輝度のヒストグラムを試せるでしょう。あるいは、なぜ自分を 1 次元のヒストグラムに限定するのでしょうか。色を色空間全体にわたる実際の色の集合にマッピングするのはどうでしょう!つまり、ただ「赤」の値をビン分けするのではなく、なぜそれを 3 次元のカラービン(どの色空間が最もうまく機能しても)で数えないのでしょうか。それは、画像内に見られる色を真に表現するヒストグラムを生成するでしょう。そのような 3 次元ヒストグラムメトリックは、たとえば 8x8x8、つまり 2048 ビンの単純な配列であり得ます。つまり、2K バイトのメトリックです。色の検索は、その後、近くのビンの正しい数を特定し、近くのビンの補間されたカウントを取得します。これは、画像内のその色に「近い」色の数を表すでしょう!

前景/背景の色の分離

-colors を使えば、画像を 2 色だけに減らすことで、画像を前景と背景の部分に分離しようとできます。先に -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:-

これは、赤い「rose」の色が主要な前景色であることを示します。なお、風景画像は異なる分離になるかもしれません。下に地面の色、上に空の色が得られるからです。そのため、色がどう分離されたかをおおまかに見ることは、画像タイプの判定に非常に役立ち得ます。また、「スパム」テキストのある画像は、しばしば一つの隅に、画像の残りよりもはるかに目立つ色の塊を示します。見つかった場合は、3 色でやり直し、最終テストを行う前に、見つかった最も一般的な「背景」色でその領域を消去します。この技法はおそらく、画像を「肌の色」「緑」「風景」などのクラスに分離する良い方法です。

平均色行列

3 行 3 列の行列の色スキーム(「-scale 3x3\!」)は、妥当な色分類スキームです。これは、似た画像を非常にうまく分離し、グループ化します。たとえば、スケッチ(すべてほぼ白)、グレースケール、風景、海景、部屋、顔などが、すべて基本的で似たグループに分離されます(理論上は)。これは、フォトモザイクを生成するために画像をインデックス化するのにも妥当なメトリックです。NetPBM 画像フォーマットの出力は、ピクセル値だけをテキストの数値として出力できるので、そのようなメトリックを生成するのに特に適しています。なお、これは 27 次元の結果(3x3 の色、各 3 値)を生成するので、多次元のクラスタリングアルゴリズムが必要かもしれません。良い 3 次元クラスタリングプログラム/アルゴリズムをご存知ですか? たとえば、これは IM ロゴの 3 x 3 の RGB 色(depth 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

なお、負の色の値は画像に保存できないので、差分に .5 を加えています。また、9 ピクセルしか処理されないので、遅い「[-fx](https://imagemagick.org/command-line-options/#fx)」演算子の使用も許容できます。なお、中心ピクセル(上記で二行目の先頭の「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 行列を使い、各セルの中心ピクセルだけを一緒に平均しています。また、画像のグレースケール版に限定しています。この技法は、ポストスクリプトの論文 Image Signature for Any Kind of Image で完全に定義されています。この論文は、そのシグネチャをデータベースに格納する方法や、似た(必ずしも同じではない)シグネチャを持つ画像を見つけるためにルックアップを実際に実行する方法についても踏み込んでいます。これは、その実行方法について実際に詳しく踏み込んだものとして、私が見つけた最初の論文です。:-)

知覚ハッシュ

画像を 8x8 に減らし、平均強度を計算します。64 ビットハッシュの各ビットは、そのピクセルが平均より上なら 1、平均より下なら 0 になります。二枚の画像の類似度を比較するには、ビット単位のハッシュをビットごとに単純に比較し、ハミング距離を返します。ハミング距離が近いほど、画像は似ています。64 分の 21 を超えるものはすべて、似ていないとみなされます。pHash は YCbCr エンコーディングを使っているようです。JPEG の DCT を直接扱う話もあり、最も有望なのは振幅/位相を扱い、それを対数極座標系にマッピングするものです。


画像をよりうまく一致させる

より大きな画像をより正確に一致させるために比較する際に、私が試していない、あるいはあまりうまく機能しなかった、雑多なメモと技法です。

セグメンテーションカラー

ご覧のとおり、上記のメトリックの多くは、ぼかし/メディアンフィルタの後に減色技法を使い、画像を単純化してより分類しやすくしようとする基本的な試みです。しかし、色量子化演算子は本当はこの目的のために設計されたものではありません。その仕事は、画像の重要な細部を強調するために色を減らすことです。しかし画像比較では、私たちは本当はこれらの特徴を強調したいのではなく、比較上関心のある領域を強調したいのです。これは、セグメンテーションとして知られる関連した色技法の仕事です…… 余談:Leptonica より:画像のセグメンテーションとは、画像を異なる特性を持つ領域に分割することです。この演算子は、似た色の領域をブロックして、それらの領域から細部を取り除きます。すると、二枚の画像を比較するとき、画像内の低レベルの細部ではなく、領域を比較していることになります。IM はセグメンテーションアルゴリズム「[-segment](https://imagemagick.org/command-line-options/#segment)」を実装しています。その実装の詳細については SegmentImage() を参照してください。例:

  magick logo: -median 10 -segment 1x1 \
          +dither -scale 100x100\! segment_image.gif

一つの問題は、-segment が非常に遅く、より大きな画像でしか機能しないように見えることです。小さな画像(rose: や 100x100 にスケーリングされた logo: のような)は、単一の色が生成される結果になるようです。これはバグかもしれません。もちろん、上記でやったように、セグメンテーションした後に画像をスケーリングすることはできます。そうすれば、互いに比較するためにより多くの画像をメモリに格納できます。また、結果のセグメンテーションは、Leptonica が提供する画像セグメンテーションアルゴリズムと比べると、あまりうまく機能しないようです。Leptonica: Color Segmentation を参照してください。しかし、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 の報告…… 私が取り組んでいるプロジェクトは、監視カメラが動きを検知したことに応じて送られてくる 20 枚一組の画像を処理することに関わっています。これらのカメラは遠隔地にあり、動きを検知すると、画像はローカルサーバに送られます。ローカルサーバに届いたら、イベントを引き起こしたものを含まない画像を「フィルタ」で除外できるようにしたいのです。私は PerlMagick を使って、シリーズの最初の画像(これは常に通常の背景以外のものを含みません)を残りの画像と比較します。すべての画像について「平均」差分を取得し、個々の差分が平均差分より大きければ、その画像には何かが含まれているとしてその画像を保持します。このアプローチは、昼でも夜でも、どんな照明条件でも、素晴らしく機能します。当初は最初の画像を上回る差分のパーセンテージだけを使おうとしていましたが、それはあまり信頼できず、照明条件に大きく依存していました。この比較に基づいて、どの画像が「内容」を持ち、どの画像が動きを含まず空っぽかを判定します。「動き」を含む画像だけを取得したら。