「カメラで撮った映像からAIが猫を見つけてくれるアプリ」を作りました。ここまでの道のりは、大きく3つの部分に分かれます。
1.カメラの映像をAIに渡せる形にする (MyImageAnalyzer の役割)
まず、スマホのカメラはリアルタイムでたくさんの映像(画像)をAIに見せます。しかし、AIは「写真」そのままの形では理解できません。AIが理解できる「データ」の形に変換する必要があります。
カメラからの映像を受け取る:
ImageAnalysis という機能を使って、カメラからどんどん送られてくる映像を受け取ります。受け取った映像は ImageProxy という一時的な形なので、これを普通の「画像データ」(Bitmap)に変換します。
AIが理解できる「数値」に変換:
この Bitmap の画像を、AI(今回のYOLOv8モデル)が処理できる「数値の羅列」(ByteBuffer)に変換します。このとき、画像のサイズをAIが期待する大きさ(例:640×640ピクセル)に調整したり、色をAIが理解しやすいように並べ替えたりする「前処理」を行います。ここで MyImageAnalyzer が大活躍します! MyImageAnalyzer はカメラから画像を受け取り、AIに渡すための変換を全て担当しています。
2.AIモデルで「これは猫だ!」と判断する (YoloV8Detector の役割)
AIモデルの準備:
事前に訓練しておいたAIモデル(.tflite ファイル)をアプリに組み込んでおきます。これは、何万枚もの猫の画像を学習して「猫とはこういう形だ!」と覚えた賢い先生のようなものです。YoloV8Detector がこのAIモデル(先生)を準備し、AIに「画像を分析して」と指示を出す役割を担っています。
「推論」と「結果の読み取り」:
AIに変換した画像データ(ByteBuffer)を渡すと、AIはそれを分析して「推論」を行います。推論の結果は、AI独自の「数値の羅列」で返ってきます。ここには、「このあたりに猫っぽいものがあるぞ、自信度はこれくらい、種類はこれだ」というような情報が隠されています。YoloV8Detector は、このAIの数値の羅列を人間が理解できる形(「座標」や「信頼度」、「クラスID」)に読み解きます。
不要な検出結果を整理する (NMS):
AIは「ちょっとでも猫っぽいもの」を見つけると、たくさんの候補を出してきます。しかし、同じ猫に何個も四角が表示されても困ります。「NMS (Non-Maximum Suppression)」という技術を使って、たくさんの候補の中から、最も自信度が高く、重なっていない「代表」の四角だけを選び出します。
クラスIDを名前に変換:
AIは「これはクラスIDが62番だ」と教えてくれますが、私たちはそれが「猫」であることを知りたいです。そこで、あらかじめ「62番は猫」というリストを用意しておき、AIの「62番」を「猫」という名前に変換して表示できるようにしました。
3.画面に「猫」の四角を表示する (OverlayView の役割)
AIが「猫だ!」と判断した情報(どこに、何の種類の猫が、どれくらいの自信度でいるか)を、カメラの映像の上に表示します。
透明なシートを重ねる:
カメラの映像が表示されている画面の上に、透明なシート(OverlayView)を重ねます。このシートには、好きなものを描くことができます。
四角とラベルを描く:
OverlayView は、YoloV8Detector から渡された猫の位置情報(座標)を受け取ります。その座標に合わせて、猫の周りに四角い枠を描き、その枠の近くに「猫 (自信度)」というラベルを表示します。最初はAIへの「前処理」や、AIからの「結果の読み取り」がうまくいきませんでした。AIが理解できる言葉と、私たちが理解できる言葉の間に通訳がいなかったような状態です。これを修正し、AIが意味のある結果を返すようになりました。
最初はバウンディングボックス(四角)が表示されなかった:
AIは結果を出しているのに、画面に四角が表示されませんでした。一番の原因は、カメラの映像を表示する PreviewView という部品を、画面のレイアウトに追加し忘れていたことでした。透明なシートがあっても、その下に映像がなければ何も見えません。また、四角を描く透明なシート(OverlayView)が、映像とピタッと合うように、サイズ情報を正しく渡せていない問題もありました。これらを修正し、四角が表示されるようになりました。
「Class 62」ではなく「猫」と表示したい:
これは、AIが数字で返す「クラスID」を、人間がわかる「ラベル名」(”cat”)に変換するリストを YoloV8Detector に追加することで解決しました。
「close()」「detect()」「saveImages」「getInputSize()」などのエラー:
これらは、それぞれの部品(クラス)が持つべき「機能(メソッド)」がまだ作られていなかったり、他の部品からその機能を使えるようにする「許可(public修飾子)」が設定されていなかったり、新しい機能(saveImages)を導入したときに、その情報を他の部品に伝える「引数」が足りなかったりしたことが原因でした。一つずつ足りない機能を追加したり、設定を修正したりして、エラーを解決していきました。
猫が検出された画像だけを保存したい:
これは、MyImageAnalyzer で「AIが猫だと判断した結果」が出たときだけ、元の画像を保存するように条件を追加することで解決しました。まとめると、このアプリは、カメラから画像を受け取り、それをAIが理解できる形に変換し(MyImageAnalyzer)、訓練済みのAIモデルで分析させ(YoloV8Detector)、その結果を人間が見てわかるように画面に描画する(OverlayView)という連携プレーで動いています。各部品がそれぞれの役割をきちんと果たし、情報が正しく連携されることで、最終的に「猫検出アプリ」が完成しました。
次は、CLASやRTKと連動し、どこで猫を発見したかという位置情報を追加します。