【AI】画像認識で顔診断!”そっくりポケモン診断”をつくってみた!【機械学習】

こんにちは。堤 真聖です。
この間ショッピングモールに出かけたらみんなポケモンGOをやっていて驚きました。
ポケモンGO、1週間だけやって辞めたけど、まだ結構流行っているんですね。

せっかくだしポケモンの懐かしさに浸りつつ「自分に似てるポケモンを抽出してくれる解析プログラム」でも作ってみようかな!

  • openCVで画像を取得
  • openCVで画像を調整
  • openCVで特微量計算
  • openCVで類似度判定

思いっきりopenCVの力を借りて実装して行きます!

使用画像

今回810種類のポケモンと闘わせる画像はコチラ。

田舎のヤンキーみたいな写真しかなくてごめんなさい。

まずは特微量を算出。
コードはGitHubにアップしているので要所をかいつまんで行きます。

import cv2
import os

def calc_feature(img_path: str, detector: cv2.ORB_create()):

    IMG_SIZE = (100, 100)
    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
    img = cv2.resize(img, IMG_SIZE)
    
    return detector.detectAndCompute(img, None)

次に、810もある画像一つ一つを比較し特微量の差を計算します

target_image = 'me.jpg'
image_directory = '../../blog/material_images/'

# マッチング
bf = cv2.BFMatcher(cv2.NORM_HAMMING)

# 特微量算出
# detector = cv2.ORB_create()
detector = cv2.AKAZE_create()
(target_kp, target_des) = calc_feature(image_directory + target_image, detector)

min_value = 1000
min_path = ''

files = os.listdir(image_directory)
for file in files:
    if file == '.DS_Store' or file == target_image:
        continue

    comparing_img_path = image_directory + file
    try:
        (comparing_kp, comparing_des) = calc_feature(
            comparing_img_path, detector)
        #画像同士をマッチング
        matches = bf.match(target_des, comparing_des)
        dist = [m.distance for m in matches]
        #類似度計算
        ret = sum(dist) / len(dist)
    except cv2.error:
        ret = 1000
        
    if min_value > ret:
        min_value = ret
        min_path = file

こうなります。

結果

target: me.jpg
parasect.png 165.36363636363637
lumineon.png 157.27272727272728
.
.
.
latios.png 151.63636363636363
mew.png 170.36363636363637
ekans.png 173.9090909090909

今回計算しているのは「特微量の差」なので数値が低いほど類似度が高いということになります。
どれも少し値が大きすぎますね。もしかして俺はポケモンには似てないってことかな(笑)。

もう少し詰めて行きます。
アルゴリズムをORBに変えてみます。

出力結果

target: me.jpg
parasect.png 87.61702127659575
lumineon.png 81.08510638297872
.
.
.
latios.png 71.34042553191489
mew.png 86.91489361702128
ekans.png 86.68085106382979

AKAZEの半分ほどの値になりましたね。
今思ったけど自分からポケモンに似せていくってなんかシュール。
それでは結果を可視化して行きます。

def show_imgs_match(file):
    img1 = cv2.imread('../../blog/material_images/me.jpg')
    img2 = cv2.imread('../../blog/material_images/' + file)
    gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    akaze = cv2.ORB_create()
    kp1, des1 = akaze.detectAndCompute(gray1, None)
    kp2, des2 = akaze.detectAndCompute(gray2, None)

    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    matches = bf.match(des1, des2)
    matches = sorted(matches, key = lambda x:x.distance)
    img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)
    plt.imshow(cv2.cvtColor(img3, cv2.COLOR_BGR2RGB))
    plt.show()

さて、ここで問題です。俺はどのポケモンに似ているでしょうか?(810択クイズ)

正解は、、、

デンヂムシ!

参考:デンヂムシ ポケットモンスターサン・ムーン公式サイト

確かになんか似ている。。

値が62程度まで落ち着きました。

ちなみにAKAZEでは

カプ・レヒレ!

参考:カプ・レヒレ ポケットモンスターサン・ムーン公式サイト

ちなみにこちらの場合、値は100前後になりました。

AKAZEとは、要は画素の応答値を閾値と比較し最大値であればと特微点とする方法。なので出っ張った鼻やズボンの角などのエッジ部分が特に紐づいています。
詳しい非線形拡散方程式の計算方法は以下より。

Qlita-KAZE理論を読んでみた

対してORBは、輝度値やエッジを特微点として判定するため、同じような色合いを紐付けます。

つまり、ポケモンは「絵」なので、凹凸よりも輝度やエッジによる特徴が特微点として検出されやすいということ。
なので今回はAKAZEよりもORB方が類似度が高かったんですね。

要するに、AKAZEの場合、同じような形のポケモンが、ORBの場合、同じような色彩のポケモンが高い類似度だと判定されるということなんですね。

今後の展望

  • 画像の処理の精度を高める
  • 特微量算出アルゴリズムの工夫

さらに精度を高めてデプロイするので楽しみにしていてください!

参照

ソースコード:Github-masatsch/find-similar-pokemon 
参考:特徴点のマッチング

今回の記事では画像認識の技術を利用して似ているポケモンを探しました。AI、機械学習それからディープラーニングの経験はないけど、「AIをどのように活用するのだろう?」や「Aidemy Premium Planを受講して、私でもきちんと続けられるだろうか?」など、少しでも気になることがございましたら、ぜひ一度気軽に無料相談会にお越しいただき、お悩みをお聞かせください!
最後までご覧くださりありがとうございました。

プログラミング未経験からでもAIスキルが身につくAidemy Premium Plan

PythonやAIプログラミングを学ぶなら、オンライン制スクールのAidemy Premium Planがおすすめです。
「機械学習・ディープラーニングに興味がある」
「AIをどのように活用するのだろう?」
「文系の私でもプログラミング学習を続けられるだろうか?」
少しでも気になることがございましたら、ぜひお気軽にAidemy Premium Planの【オンライン無料相談会】にご参加いただき、お悩みをお聞かせください!