PythonとOpenCVを用いた顔の類似度判定についての話
ハッカソンで使用したOpenCVを用いた顔の類似度判定について話をしようと思います。
環境
Python 3.5.2 OpenCV 3.1.0
やりかた
どうやって顔の類似度の判定を行うのかというと、特徴点のマッチングをします。簡単にいうと、判定したい2画像の特徴点を抽出し、それらの距離を比較します。
今回は、ジェフ・ベゾスの顔写真をターゲットとして、ビル・ゲイツとスティーブ・ジョブズの顔写真と比べてみようと思います。
01.png
02.png
target.png
コード
imagesというフォルダに比較したい顔写真とターゲットとなる写真を入れてください。
##!/usr/bin/env python # -*- coding: UTF-8 -*- import cv2 import os TARGET_FILE = 'target.png' IMG_DIR = os.path.abspath(os.path.dirname(__file__)) + '/images/' IMG_SIZE = (200, 200) target_img_path = IMG_DIR + TARGET_FILE target_img = cv2.imread(target_img_path, cv2.IMREAD_GRAYSCALE) target_img = cv2.resize(target_img, IMG_SIZE) bf = cv2.BFMatcher(cv2.NORM_HAMMING) # ORBとAKAZEは特徴点や特徴量を抽出するアルゴリズム # コメントアウトを調節することによりどちらでも行える # detector = cv2.ORB_create() detector = cv2.AKAZE_create() # ターゲットの写真の特徴点を取得する (target_kp, target_des) = detector.detectAndCompute(target_img, None) print('TARGET_FILE: %s' % (TARGET_FILE)) files = os.listdir(IMG_DIR) for file in files: if file == '.DS_Store' or file == TARGET_FILE: continue comparing_img_path = IMG_DIR + file try: comparing_img = cv2.imread(comparing_img_path, cv2.IMREAD_GRAYSCALE) comparing_img = cv2.resize(comparing_img, IMG_SIZE) # 比較する写真の特徴点を取得する (comparing_kp, comparing_des) = detector.detectAndCompute(comparing_img, None) # BFMatcherで総当たりマッチングを行う matches = bf.match(target_des, comparing_des) #特徴量の距離を出し、平均を取る dist = [m.distance for m in matches] ret = sum(dist) / len(dist) except cv2.error: # cv2がエラーを吐いた場合の処理 ret = 100000 print(file, ret)
実行結果
ジェフ・ベゾスの顔写真を用いて、ビル・ゲイツとスティーブ・ジョブズの顔写真と比べた結果が以下になります。 01.pngがビルゲイツで、02.pngがスティーブ・ジョブズです。
TARGET_FILE: target.png 01.png 128.7171717171717 02.png 123.4949494949495
距離の平均が近い方が似ているということなので、今回は02.pngつまりジョブズの写真の方が若干類似度が高いという感じになりました。
あとがき
今回は拾い物の画像で検証したため、写真の顔の位置などが違い、あまり高い類似度は出せませんでしたが、これを顔の位置がほぼ同じ場所で撮影した場合にはかなり高い類似度が出ると思います。(R-Stack Hack Dayで使用した写真ではもっと高かったので...)
画像の類似度判定といえば、機械化学習で行うイメージですが、このように機械化学習を行わなくても、簡単な類似度チェックは行えるということは覚えておいて欲しいですね。