同じ画像を自動的にまとめたい・・・
このような課題にたいしてPythonを利用した自動化手法をご紹介致します。
本記事では画像からhash値を求める方法とファイルからhash値を求める2つの方法をご紹介し、組み合わせることで精度向上が期待できる内容となっております。
同一画像検知
hashとは?
通信の暗号化や文章の改ざん防止を目的にその情報をユニークな固定長に置き換える技術です。
これにより、固定長の値を比較することで完全一致すれば同じ情報であることがわかるので同一画像を見つける手段として利用できます。
Pythonのhash変換ライブラリ
Pythonにはhash値に変換するライブラリがいくつかありますが画像検知でよく利用されるものは下記2つです。
①pHash(Perseptual Hash)
②aHash(Average Hash)
ロジックはそれぞれ異なりますが非常に似通っています。それぞれのロジックの説明をしても実際には両方を利用してみてどちらが精度が高いか作業内容によるので試さないとわからないでしょう。その為ここではロジックの細かい説明は省略します。
同一画像検知という観点であれば私の経験から①pHashの方が精度が高い経験がありますので迷いましたらpHashを利用していただければと思います。
ライブラリpHashのインストール方法
pHashのインストールもいくつかありますが利用しやすいと感じているImageHashからpHashを呼び出すかたちを今回選定しました。
ライブラリのインストールコマンドは下記
pip install ImageHash
画像を読み込むライブラリが必要になるので今回はPILをインストールします。pipをアップデートしないとインストールできないケースが多いのでアップデートコードも記載しています。
python -m pip install --upgrade pip
pip install Pillow
尚、pipでインストールできない方はセキュリティ環境の問題かもしれないので過去記事のPythonのpip installが使えない時のプロキシとSSL無視をご覧くださいませ。
同一画像検知のpythonコード全て
全コードを紹介します。
今回は画像ファイルが1つのディレクトリ内に複数入っていると想定しその中の画像ファイル名とhash値を一覧化したものです。
import glob
import os
from PIL import Image
import imagehash
import pandas as pd
user=os.getlogin()
#同一画像検知したい画像ファイルがあるディレクトリを指定
dir_ = targetのpathを指定してください
#pHashを算出する関数
def pHash(InputPath):
return imagehash.phash(Image.open(InputPath))
#画像ディレクトリからpHashの値を取得するコード
output=[[os.path.basename(dir_ + i),pHash(dir_ + i)] for i in os.listdir(dir_) if "Thumbs.db" not in i]
#結果を一覧で表示する
pd.DataFrame(output,columns=["画像ファイルPath","Hash値"])
画像ファイルPath | Hash値 | |
---|---|---|
0 | roze_marry_14 – コピー.png | e8e6337c1de31861 |
1 | roze_marry_14.png | e8e6337c1de31861 |
上記のような結果が出たと思います。
上記例では同じファイルをコピーしてhash値を算出したので値が同じになっています。
後はやりたいように加工いただければと思います。少ないコードで同一画像検知ができるのですからPythonって簡単ですね。
pHashのコード
pHashでHash値を抽出した関数です。
PILを利用して画像ファイルを開いた後にhash値を取得しています。
#pHashを算出する関数
def pHash(InputPath):
return imagehash.phash(Image.open(InputPath))
pHashの値ではうまく検知できない場合 hashlibの併用を検討
pHashは100%確実ではありません。画像への文字の有無などがあるのに同じと判定されてしまったということもあります。その場合どうしたらよいか考えますよね。
いくつか試したことがあるので結果を共有致します。
①aHash(Average Hash)と組み合わせる
→ただpHashの方が精度が高いイメージなのであまり効果は望めないと考えます
②画像の特徴量を抽出するモデルと組み合わせる(akazeやORB)
→やったことありますが同一画像検知ではあまり精度はよくありません。また結構重いので処理時間がかかります。
③hashlibを使う
→これが一番有効でphashと組み合わせるとある程度意図した値を得られますのでサンプルコードを載せておきます。
import hashlib
with open(pathをいれてください, 'rb') as f:
targetHash = hashlib.sha256(f.read()).hexdigest()
targetHash
phashとhashlibで出た数値の両方で比較することにより同一画像検知の精度を増すことができます。
hashlibの公式ページのリンクを貼っておきます。
最後に私がPythonの勉強をして入門者から中級者までにこの本1冊あれば習得できるおすすめ本記事も書いております【本1冊で】Python入門から中級までなれるおすすめ本ご興味がある方は御覧くださいませ。
コメント