1. ホーム
  2. パイソン

[解決済み】2つの画像の違いを数値化するには?

2022-04-11 10:28:55

質問

こんなことをしたいのですが。

ウェブカメラで一定時間ごとに撮影しています。 タイムラプスのようなものです。 しかし、本当に何も変化していない場合、つまり、写真がかなり 見える を保存する必要はありません。

違いを数値化する方法があるのでしょうが、経験的に閾値を決めるしかないですね。

完璧さよりもシンプルさを求めています。 pythonを使っています。

どのように解決するのですか?

一般的な考え方

オプション 1: 両方の画像を配列として読み込む ( scipy.misc.imread ) を行い、要素毎 (ピクセル毎) の差分を計算する。差分のノルムを計算する。

オプション2:両方の画像を読み込む。それぞれについて何らかの特徴ベクトルを計算する(ヒストグラムのようなもの)。画像ではなく、特徴ベクトル間の距離を計算する。

しかし、その前に決めておかなければならないことがあります。

質問事項

まず、これらの質問に答えてください。

  • 画像の形や大きさは同じですか?

    そうでない場合は、リサイズやトリミングが必要かもしれません。PILライブラリは、Pythonでそれを行うのに役立ちます。

    同じ設定、同じデバイスで撮影したものであれば、おそらく同じものだと思います。

  • 画像はきれいに並んでいますか?

    そうでない場合は、まず相互相関を実行し、最適なアライメントを最初に見つけるとよいでしょう。SciPyにはそれを行うための関数があります。

    カメラとシーンが静止している場合は、画像の位置が合っている可能性が高いです。

  • 画像の露出は常に同じか?(明るさ・コントラストは同じか?)

    そうでない場合は を正規化する の画像が表示されます。

    しかし、状況によっては、良いことよりも悪いことの方が多いかもしれないので、注意が必要です。例えば、暗い背景の上に明るいピクセルが1つあると、正規化された画像は大きく異なってしまいます。

  • 色情報は重要か?

    色の変化を認識したい場合、グレースケール画像のようなスカラー値ではなく、1点あたりの色値のベクトルを持つことになります。このようなコードを書く場合は、より注意が必要です。

  • 画像にはっきりとしたエッジがあるか?それらは動きそうですか?

    もしそうなら、まずエッジ検出アルゴリズムを適用し(例えば、SobelやPrewitt変換で勾配を計算し、ある閾値を適用する)、最初の画像のエッジと2番目の画像のエッジを比較することができます。

  • 画像にノイズは入っていませんか?

    すべてのセンサーは、ある程度のノイズで画像を汚染しています。低価格のセンサーでは、より多くのノイズが発生します。画像を比較する前に、何らかのノイズリダクションをかけるとよいでしょう。ぼかしは最もシンプルな方法です(ただし、ベストではありません)。

  • どのような変化に気づきたいですか?

    これは、画像間の差分に使用する規範の選択に影響を与える可能性があります。

    画像がどれだけ変化したかを測定するために、マンハッタンノルム(絶対値の合計)またはゼロノルム(ゼロに等しくない要素の数)の使用を検討してください。前者は画像がどれだけずれているかがわかり、後者は何ピクセル違うかだけがわかる。

画像はよく整列され、同じサイズと形状で、おそらく露出が異なるものと仮定します。簡単のために、カラー(RGB)画像であってもグレースケールに変換しています。

これらのインポートが必要です。

import sys

from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average

メイン関数、2つの画像を読み込み、グレースケールに変換し、比較し、結果を印刷する。

def main():
    file1, file2 = sys.argv[1:1+2]
    # read images as 2D arrays (convert to grayscale for simplicity)
    img1 = to_grayscale(imread(file1).astype(float))
    img2 = to_grayscale(imread(file2).astype(float))
    # compare
    n_m, n_0 = compare_images(img1, img2)
    print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
    print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size

比較の仕方 img1img2 はここでは2次元の SciPy 配列です。

def compare_images(img1, img2):
    # normalize to compensate for exposure difference, this may be unnecessary
    # consider disabling it
    img1 = normalize(img1)
    img2 = normalize(img2)
    # calculate the difference and its norms
    diff = img1 - img2  # elementwise for scipy arrays
    m_norm = sum(abs(diff))  # Manhattan norm
    z_norm = norm(diff.ravel(), 0)  # Zero norm
    return (m_norm, z_norm)

ファイルがカラー画像の場合 imread は 3 次元配列を返し、RGB チャンネル(配列の最後の軸)を平均して強度を求めます。グレースケール画像の場合は不要です(たとえば .pgm ):

def to_grayscale(arr):
    "If arr is a color image (3D array), convert it to grayscale (2D array)."
    if len(arr.shape) == 3:
        return average(arr, -1)  # average over the last axis (color channels)
    else:
        return arr

正規化は簡単で、[0,255]の代わりに[0,1]に正規化することができます。 arr はここではSciPyの配列なので、すべての演算は要素単位で行われます。

def normalize(arr):
    rng = arr.max()-arr.min()
    amin = arr.min()
    return (arr-amin)*255/rng

を実行します。 main 関数を使用します。

if __name__ == "__main__":
    main()

さて、これをすべてスクリプトにまとめ、2枚の画像に対して実行します。画像同士を比較すると、違いはありません。

$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0

画像をぼかし、オリジナルと比較すると、若干の違いがあることがわかります。

$ python compare.py one.jpg one-blurred.jpg 
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0

追伸:全体 比較.py スクリプトを使用します。

アップデート:関連技術

この質問はビデオシーケンスに関するもので、フレームはほとんど同じである可能性が高く、何か異常なものを探すことになるので、関連する可能性のある別のアプローチをいくつか挙げておきたいと思います。

  • 背景減算とセグメンテーション(前景の物体を検出するため)
  • スパースオプティカルフロー (動き検出)
  • 画像ではなく、ヒストグラムなどの統計量を比較する。

Learning OpenCV」の第9章(Image parts and segmentation)と第10章(Tracking and motion)に目を通すことを強くお勧めします。前者はBackground subtractionの使い方を、後者はオプティカルフローの方法を教えてくれています。いずれの手法もOpenCVのライブラリで実装されています。Python を利用している場合は,OpenCV ≥ 2.3 とその cv2 Pythonモジュール

背景減算の最もシンプルなバージョンです。

  • 背景の各画素の平均値μと標準偏差σを学習する。
  • 現在の画素値を(μ-2σ,μ+2σ)または(μ-σ,μ+σ)の範囲と比較する。

より高度なバージョンでは、各ピクセルの時系列を考慮し、非静的なシーン(動く木や草など)を処理することができます。

オプティカルフローの考え方は、2つ以上のフレームを取得し、各画素に速度ベクトルを割り当てる(密なオプティカルフロー)、またはその一部に割り当てる(疎なオプティカルフロー)ことである。疎なオプティカルフローを推定するには、次のようにします。 ルーカス・カネード法 (OpenCVにも実装されています)。明らかに、流れが多い(速度場の最大値に対する平均値が高い)場合、フレーム内で何かが動いていることになり、その後の画像はより異なったものになります。

ヒストグラムを比較することで、連続したフレーム間の急激な変化を検出することができる場合があります。この方法は Courbon et al, 2010 :

<ブロッククオート

連続したフレームの類似性。 連続する2つのフレーム間の距離を測定します。これが高すぎる場合、2番目のフレームが破損していることを意味するため、画像が消去されます。その カルバック・ライブラー距離 または相互エントロピーのことで、2つのフレームのヒストグラムのことです。

ここで p q はフレームのヒストグラムを使用します.閾値は 0.2 に固定されている.