にゃみかんてっくろぐ

猫になりたい

同じ構図で何枚も撮って,最も手ブレしていない 1 枚だけを残す

結論

  • ImageMagickcompare コマンドで, Perceptual Hash (pHash) により同一構図かチェックする.
  • ImageMagickconvertidentify コマンドで, Canny 法によりエッジ検出し同一構図の n 枚から最も鮮明な 1 枚を残す.
  • ソースはここに置いた: GitHub - typewriter/unblurred-photo-picker

背景

手ブレしたくないが, ISO 感度もあまり上げたくない(綺麗に撮りたい).その場合,ギリギリのシャッタースピードで何枚も撮る,ということをよくやります.しかし,撮影後の写真の選別が極めて面倒なうえ,かなり機械的な作業です.

  1. 同一構図で撮られた写真を探し出す
  2. そのうち最も鮮明と思われる写真 1 枚を残し,それ以外を重複とする.
  3. (重複写真は Flickr 上で非公開に設定する*1

機械的な作業… ということは機械で出来るのではないでしょうか.やってみました.

同一構図の判定

同一構図の判定は,画像の類似度が高いかどうかで行うこととします.ただし,画像処理はさっぱり分からないため, ImageMagick に全力で甘えます.

ImageMagick には compare コマンドがあり,お手軽に画像比較を行うことが可能です. 画像比較に使用できるメトリクスの一覧は ImageMagick - Command-line Options#-metric type にありますが,今回は PHASH (Perceptual Hash) を用います.

# ImageMagick 7 系.小さいほど類似度が高い.
$ magick compare -metric PHASH P9240031.JPG P9240035.JPG NULL:
13.7601

Perceptual Hash ではハミング距離を取って類似度とする例を見かけましたが, ImageMagick の数値はそうではないようです.まあ気にせずいくつかの画像で試してみます.

画像1 画像2 備考 出力値
f:id:no_clock:20191014202721j:plain f:id:no_clock:20191014202732j:plain 同じ構図 0.501766
f:id:no_clock:20191014202721j:plain f:id:no_clock:20191014202751j:plain 少し下に向けた 8.26181
f:id:no_clock:20191014202721j:plain f:id:no_clock:20191014202816j:plain 別構図 39.5355

同一構図では数値が小さく,異なる構図では数値が大きくなりました.使えそうです.

「最も鮮明な」写真の判定

やはり画像処理はさっぱり分からないため,こちらも ImageMagick に頼ります.

当初は「標準偏差 (Standard deviation) が大きければ値のバラつきが大きい→鮮明」と考えていましたが,手ブレした写真のほうが標準偏差が高いケースが複数枚でみられたため不採用です.

$ magick identify -format "{ \"Kurtosis\": %[kurtosis], \"StandardDeviation\": %[standard-deviation], \"Skewness\": %[skewness], \"Entropy\": %[entropy] }"  20171104_PB040552.JPG
{ "Kurtosis": 3.04856, "StandardDeviation": 11783.4, "Skewness": 1.91352, "Entropy": 0.760502 }
画像(切り抜き) 標準偏差
f:id:no_clock:20191014203238j:plain 11783.4
f:id:no_clock:20191014203249j:plain 11899.3

代わりに, Canny Edge Detection でエッジ検出した結果の標準偏差を用いることにします.

$ magick convert 20171104_PB040552.JPG -canny 0x1+10%+30% edge.png
$ magick identify -format "{ \"Kurtosis\": %[kurtosis], \"StandardDeviation\": %[standard-deviation], \"Skewness\": %[skewness], \"Entropy\": %[entropy] }"  edge.png
{ "Kurtosis": 13.5456, "StandardDeviation": 14823.4, "Skewness": 3.94279, "Entropy": 0.303514 }
画像(切り抜き) エッジ検出後(同左) 標準偏差
f:id:no_clock:20191014203238j:plain f:id:no_clock:20191014203811p:plain 14823.4
f:id:no_clock:20191014203249j:plain f:id:no_clock:20191014203853p:plain 11678.3

良さげな感じになりました.

スクリプト

Rubyで書きました。裏でImageMagickのコマンドガンガン実行します。

参考

*1:バックアップも兼ねているのでアップロードはしている