AKAZEを用いた特徴量マッチングによるCDジャケ買いアプリ

このブログはAidemyさんで受講した講座「AIアプリ開発」の課題である
オリジナルアプリ製作についての内容になります。あとは受講の経緯など…。
（若干追記・修正しております2021/12/05）

###**唐突な自分語りお許しください**
お世話になります、僕です。
製造業で技術職をしております。主に機械設備の設計、図面を描く、
客先へ納品した設備の試運転、設備の定期メンテナンス及びトラブル対応、
といったことを生業としております。

ちなみに技術職になるまえは同社内で営業職をしていました。
営業4年→技術5年という形です。
なんでもできる丈夫な子に育ってほしいという思いが伝わってきます。
プログラミングに全くと言えるほど縁がない僕が受講した理由は

このままこの仕事してても、近い将来食いっぱぐれんじゃね？

という恐怖があったからになります。

###**はじめに恐怖がありました**
しかしこのブログを書くにあたってもmarkdownとか急に言われてもなぁという程度の
知識レベルの私。

正直最初はAidemyさんのカリキュラムの説明文読んでも「ふむふむ。日本語でおk」
状態でしたので、そもそも基礎知識が足りなすぎると感じ、amazonでかえるの表紙の本を
買って読んだりしてました。

学習の進みが遅く、チューターさんからはよく心配をされていましたが、
ある時に「いいからやってみそ、最初から全部理解する必要はないっす」
という励ましをもらいなんとかやってきた形です。

なので今は2週目をやったりしています。
2週目はひらがなは読めるようになったかなというくらいの感じがします。

###**いっぱい質問しよう、とは思うんですけど…**
Aidemyさんには6か月コースでお世話になったのですが、いきなり全部わからんで良いと
言われつつもやはり「ンギギ…！」とか「ンゴゴ…！」という感じで頭を抱えていました。
新しい知識、しかも経験のない分野の学習は楽しい反面、しんどいです。

また急に生活が多忙になるなんてこともあるので、最終課題まで一通り完了してから
復習しましょう、ということはお伝えできるかと思います。

あとカウンセリングはどんどん受けた方がいいですね。私は相当な回数が余って
しまいました。
とはいえ、質問するには何が分からないかを理解できないとならないんですよね。
分からないことが分からない。ここを抜けてようやく初心者脱出でしょうか。

###**はい、初心者でございます**
僕はCDのジャケ買いが好きでした。唐突ですね。現職と関りも全然ないですね。

それはそれとして。今や音楽もデジタルがメインになって、フィジカルで買わなくなって
久しいですが、今でもジャケ買いにはロマンがあると思っています。

CDなので本体は収録されている楽曲になるわけですが、その前に手に取って貰えるように
デザインされていなくてはなりませんし、またCDは全て試聴できるわけでもないので、
ほぼ見た目だけで買ってもらうところまでいく必要があるわけです。

ロマンというよりギャンブルか…。

ビジュアル的に気に入る→中身の音楽も気に入るだろうというのが
（もちろん外れもありますが）ジャケ買いの楽しいところです。

というわけでそんな感じのアプリを制作してみました。

**[ジャケ買いしよう（提案）](https://jakegai.herokuapp.com/)**

送信された画像の特徴量と、登録された40枚のCDジャケット（私有のものを写真撮影）
の特徴量をマッチングし、送信された画像と一番似ているジャケットのCDのタイトル・
アーティスト名を表示するというものです。

ジャケ買い＝気に入ったデザインのCDを買うことと考えると、つまり気に入ってる画像と
似たCDを見つけることと同義なんじゃないかと…。

特徴量マッチングにはAKAZEを使用しています。参考としたのはこちらのサイトです↓

[OpenCVのAKAZEで顔写真の類似度判定をやってみた](https://www.pc-koubou.jp/magazine/43855)

特徴量マッチングではORBなどもありますが、こっちは古いとのこと。
新しいことはいいことです。性能がいいんらしいですよどうやら。

判定の流れとしては下記のとおりです。
・画像を200px×200pxに変換
```IMG_SIZE = (200, 200)```

・BFMatcherオブジェクトの生成
```bf = cv2.BFMatcher(cv2.NORM_HAMMING)```

・AKAZEオブジェクトの生成
```detector = cv2.AKAZE_create()```

・入力された画像を読み込み、特徴量を抽出
```input_img = cv2.imread(target_img_path, cv2.IMREAD_GRAYSCALE)
input_img = cv2.resize(input_img, IMG_SIZE)```

・AKAZEを適用、特徴点を検出
```(target_kp, target_des) = detector.detectAndCompute(input_img, None)```

・距離を記録するリストを作成
```sample_list = []
foloders = []```

・比較する画像を読み込み、特徴量を抽出
```for foloder, comparing_des in all_data.items():```

・matcherで入力された画像と比較する画像の距離を算出
```matches = bf.match(target_des, comparing_des)```

・距離の平均を算出・結果の表示
```dist = [m.distance for m in matches]
ret = sum(dist) / len(dist)
sample_list.append(ret)
foloders.append(foloder)
min_index = np.array(sample_list).argmin()
pred = foloders[min_index]
return "一番似ているジャケットは{}です。".format(pred)```

アプリ化するに当たってこの部分は軽量化のため関数化されています。
またCDジャケットという性質上、1タイトルにつき1枚です。
※これを書いていて、裏表紙も背表紙もあるやんけ、と気づきましたが…。

特徴量の質によって結果が決まるため、入力データの良し悪しが重要になりますが、
この点今回比較しているのはCDのジャケットのため、角度や陰影などの不安定要素がなく、
信頼度は高いものと考えています。

BFMatcherついては[こちら](http://whitewell.sakura.ne.jp/OpenCV/py_tutorials/py_feature2d/py_matcher/py_matcher.html)に直訳っぽい解説がありますが、良くわからない…。
つまりは1枚目の画像にある一つの特徴点と、2枚目の画像の全特徴点の距離を計算し、
距離が近いものをマッチング結果として出す、というものだと認識しています。

###**もうちょっと出来たことも…**
入力された画像に対してもっとも似ているものを見つけるということですが、
ある意味正解がないものになるため、結果に対しての評価が難しいなというのがあります。
ふーん、君はそう思うんだ？的な…。それはそれで面白いのかなとは思いますが。

比較結果に答えの文字だけでなく、画像も表示したかったなと思っています。
この辺りはスキル不足に加え、個人的理由による時間不足によるもののため、
ちょっと残念だったなと。

また単純に比較画像が40枚分というのが少ないなというのがあります。
本当はこの世のあらゆるCDジャケットと比較できればいいのですが、
イメージとしては通販サイトなどと連動してその膨大なCDジャケットの画像と比較できれば…。

###**これからどうしよう、どうしたい？**
最終目標は転職ですが、飯を食うレベルのスキルを着けるのは大変ですよね。
精進は引き続きするとして、なかなか年齢とスキルの壁は高いです。
現職のスキルと合わせ技でなんとかしたいところです。

###**終わりに**
まだまだプログラミングの世界をかすった程度と思いますが、実際に初めてみたら
ネットにいっぱいヒントが載ってるし、質問できる場があるということが知れたので、
今後も続けていけるなという実感はあります。
(Aidemy Gritもありますしね！）

以上、ありがとうございました。