[解決済み】2つの画像の違いを数値化するには?
質問
こんなことをしたいのですが。
ウェブカメラで一定時間ごとに撮影しています。 タイムラプスのようなものです。 しかし、本当に何も変化していない場合、つまり、写真がかなり 見える を保存する必要はありません。
違いを数値化する方法があるのでしょうが、経験的に閾値を決めるしかないですね。
完璧さよりもシンプルさを求めています。 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
比較の仕方
img1
と
img2
はここでは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 に固定されている.
関連
-
Python Pillow Image.save jpg画像圧縮問題
-
[解決済み] staticmethodとclassmethodの違いについて
-
[解決済み] Pythonで辞書に新しいキーを追加するにはどうすればよいですか?
-
[解決済み] Pythonで2つのリストを連結する方法は?
-
[解決済み] Pythonのリストメソッドであるappendとextendの違いは何ですか?
-
[解決済み] 2つのリストの差を取得する
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】__str__と__repr__の違いは何ですか?
-
[解決済み】画像処理。コカ・コーラ缶」認識のためのアルゴリズム改良
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Pythonコンテナのための組み込み汎用関数操作
-
PythonはWordの読み書きの変更操作を実装している
-
Python 可視化 big_screen ライブラリ サンプル 詳細
-
PythonによるExcelファイルの一括操作の説明
-
[解決済み】numpyの配列連結。"ValueError:すべての入力配列は同じ次元数でなければならない"
-
[解決済み】TypeErrorを取得しました。エントリを持つ子テーブルの後に親テーブルを追加しようとすると、 __init__() missing 1 required positional argument: 'on_delete'
-
[解決済み] builtins.TypeError: strでなければならない、bytesではない
-
[解決済み] 'DataFrame' オブジェクトに 'sort' 属性がない
-
[解決済み】 TypeError: += でサポートされていないオペランド型: 'int' および 'list' です。
-
[解決済み】画像の類似性を比較する簡単で高速な方法