いきなりですが、このふたりをご存知でしょうか。
左が乃木坂46の秋元真夏さん、右が銀シャリの鰻和弘さんです。
以前から、このふたりが似てるとネットで話題となっていました。
このふたりもブログやTwitterでコメントしています。

出典:鰻さんと真夏さんヽ(。・ω・。)ノ546 | 乃木坂46 秋元真夏 公式ブログ
確かに似てる感じしますね笑
そこで今回はOpenCVを用いて顔の類似点を調べ、どのくらい似ているのか調べたいと思います! 今回、プログラム書くにあたり参考とさせていただいたサイトは以下になります。 ありがとうございました。
参考:OpenCVを使って誰の顔なのかを推定する(Eigenface, Fisherface, LBPH) OpenCVを使った顔認識(Haar-like特徴分類器) Fisherfaces
使用するアルゴリズムと環境
今回、顔の類似度を調べるにあたり、使用したアルゴリズムは Fisherfacesです。これはEigenfaceの改良版で、照明や角度の違いに影響されにくいといった特徴があります。 使用する画像からHaar-like特徴分類器を使用し、顔領域を抽出します。
その抽出した顔画像をFisherfaceで学習させ、未学習の画像と比較し、類似度を調べます。
環境は
- Python 3.6.5
- opencv 3.3.1
秋元さん15枚の画像を学習データとし、未学習の画像である鰻さんの画像をテストデータとします。鰻さんの比較対象として乃木坂メンバー数人の画像もテストデータとして用意します。

プログラム
import cv2
import os
import numpy as np
from PIL import Image
train_path = './train_images'
test_path = './test_images'
cascadePath = "/Users/ユーザー名/Downloads/opencv-3.4.1/opencv-3.4.1/data/haarcascades/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)
recognizer = cv2.face_LBPHFaceRecognizer.create()
def get_images_and_labels(path):
images = []
labels = []
files = []
for f in os.listdir(path):
image_path = os.path.join(path, f)
image_pil = Image.open(image_path).convert('L')
image = np.array(image_pil, 'uint8')
faces = faceCascade.detectMultiScale(image)
for(x, y, w, h) in faces:
roi = cv2.resize(image[y: y + h, x: x + w], (200, 200), interpolation=cv2.INTER_LINEAR)
images.append(roi)
labels.append(int(f[7:9]))
files.append(f)
return images, labels, files
images, labels, files = get_images_and_labels(train_path)
recognizer.train(images, np.array(labels))
test_images, test_labels, test_files = get_images_and_labels(test_path)
i=0
while i < len(test_labels):
label, confidence = recognizer.predict(test_images[i])
print("Test Image: {}, Predicted Label: {}, Confidence: {}".format(test_files[i], label, confidence))
cv2.imshow("test image", test_images[i])
cv2.waitKey(300)
i += 1
cv2.destroyAllWindows()
Test Image: subject01.akimoto.png, Predicted Label: 1, Confidence: 48.77426502706794
Test Image: subject01.asuka.jpg, Predicted Label: 1, Confidence: 54.37620231697899
Test Image: subject01.hori.jpg, Predicted Label: 1, Confidence: 53.24049819391969
Test Image: subject01.ikuta.jpg, Predicted Label: 1, Confidence: 56.262042555618166
Test Image: subject01.nishino.png, Predicted Label: 1, Confidence: 50.30127169485847
Test Image: subject01.shiraishi.jpg, Predicted Label: 1, Confidence: 72.06184327769823
Test Image: subject01.unagi.png, Predicted Label: 1, Confidence: 63.37511081588498
subject01の「01」をラベルに設定し、学習しています。複数の画像を学習させる際は、この数値を変更してください。学習した画像は今回秋元さんのみなのでラベルも1のみです。 分散に基づいて計算されているため、Confidence(確度)は0に近い方が確度が高くなります。
学習に使用した画像をテストで使用すると特徴点が一致するため、Confidenceは0です。 未学習の秋元さんの画像は48.77、もちろんこの中で一番近い値です。 類似度順に並び替えると
白石 < 鰻 < 生田 < 齋藤 < 堀 < 西野 < 秋元
のようになりました。ちなみにニャンちゅうは顔認識されず対象外となってしまいました。
学習データを変更
こちらは秋元さんが番組で平野ノラさんのモノマネをしたときのものです。

この番組でのモノマネした秋元さんの画像をできるだけ集めて学習させます。あとは先ほどと同様です。 
実行結果
Test Image: subject01.akimoto.png, Predicted Label: 1, Confidence: 64.72162690757675
Test Image: subject01.asuka.jpg, Predicted Label: 1, Confidence: 70.898033127977
Test Image: subject01.hori.png, Predicted Label: 1, Confidence: 71.68987057398674
Test Image: subject01.ikuta.jpg, Predicted Label: 1, Confidence: 72.3624149846466
Test Image: subject01.nishino.png, Predicted Label: 1, Confidence: 71.81215441739869
Test Image: subject01.shiraishi.jpg, Predicted Label: 1, Confidence: 78.99918092527798
Test Image: subject01.unagi.png, Predicted Label: 1, Confidence: 65.89760962981548
白石 < 生田 < 西野 < 堀 < 齋藤 < 鰻 < 秋元
という結果になりました。 学習データを鰻さんに似ているモノマネした秋元さんの画像に変更することでより近い結果となりました。
学習データの追加
次は、先ほどの乃木坂メンバー白石、生田、西野、堀、齋藤の画像10枚学習させます。 もちろん、テストデータとは違うものです。
ラベルは01が秋元、02が齋藤、03が堀、04が生田、05が白石、06が西野、07が鰻です。
実行結果
Test Image: subject01.akimoto.jpg, Predicted Label: 1, Confidence: 21.786044627006834
Test Image: subject02.asuka.jpg, Predicted Label: 2, Confidence: 51.351808634017296
Test Image: subject03.hori.jpg, Predicted Label: 3, Confidence: 44.75424378786359
Test Image: subject04.ikuta.jpg, Predicted Label: 4, Confidence: 45.70965779143789
Test Image: subject05shiraishi.jpg, Predicted Label: 5, Confidence: 49.08969544979982
Test Image: subject06nishino.jpg, Predicted Label: 6, Confidence: 43.72499865726888
Test Image: subject07.unagi.png, Predicted Label: 1, Confidence: 63.37511081588498
各乃木坂メンバーはsubjectとPredicted Labelが同じであるため、自分の顔の学習データとテストデータが一致していることが分かります。 鰻さんは学習させていないですが、Predicted Labelが1となりました。これは学習データの中から秋元さんの顔に近いと判断され、ラベル1に振り分けられました。
考察と感想
今回は、Haar-like特徴分類器を使って顔領域を抽出、Fisherfaceで学習、テスト、結果表示という流れで類似度を調べました。ブログに載せた以外にもAKAZE特徴量を使用した特徴点マッチングで類似度を試みましたが上手くいきませんでした。 学習データを変更、追加することでより近い結果になったと思います。
今回は比較対象として乃木坂の数人を挙げましたが、少なくともこのメンバーの中では秋元さんが一番鰻さんに似ていることが分かりました。 Pythonにふれてまだ3週間で、まだまだ未熟ではありますがこれから自分で色々実装してみたいと思います。