見出し画像

Google Cloud AutoML Visionでボンゴレちゃんを検知、Slackに通知する

やりたいこと

ラズベリーパイで撮影した画像に、特定の何かが認識された場合にSlackで通知されるようにする。
前回に引き続き、機械学習での認識にGoogle Cloud AutoML Visionを使用していきます。

必要なもの

ラズベリーパイ(ラズベリーパイ3 Model B+を使用)
カメラモジュール
認識対象(今回は人形 ← キャンドゥで入手 )
ボンゴレちゃんと名付けます。

データセットを用意する

ボンゴレちゃんを色んな角度から撮りまくります。
1ラベルにつき100枚以上推奨ですが、今回は61枚となりました。
この枚数でもまあまあの精度は出ると思います。

さて、学習にはラベルが最低2つは必要です。
今回はImageNetからその他の人形画像を取得します。
- キーワードは 'Doll, dolly'
ImageNetのIDリストからIDを特定
- 下記のパラメータにIDを指定することでURLリストが取得できます

http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n03219135

100枚取得、有効なものは73枚となりました。
こうして見るとボンゴレちゃんがいかに可愛いらしいことか(笑)

ラベリング

さて、ボンゴレちゃんには「vongole」ラベルを、その他には 「None_of_the_above」ラベルを付けます。

「None_of_the_above」については下記のとおりです。
Cloud AutoML Vision
 トレーニング データの準備

定義されたラベルのいずれとも一致しない画像を含めることを検討してください。たとえば、花のデータセットの場合、ラベルが付けられた品種以外の花の画像を含め、それらに None_of_the_above のラベルを付けます。そうすることで、モデルの精度が向上します。ラベル名は何でも構いませんが、None_of_the_above はシステムによって特別に扱われるため、常に UI のラベルリストの最後に表示されます。

トレーニング

データが揃えばコンソール上でトレーニング開始ボタンを押すだけです。
終わり次第、メールで通知が送られてきます。
学習結果をみると精度100% ですね。。
何かがうまくいっていない気がします。
ボンゴレちゃん画像が一様なので過学習となっているのでしょうか。

予測してみる

雑なボンゴレちゃん画像を予測してみます。
vongole 100%です。

同系色のDollを。
None_of_the_above 99.9%

None_of_the_above 95.9%

家に転がってたクマ
vongole 99.6%
背景が似ているからか誤検知がひどいです。
とりあえず今回は精度は置いておいて、次に行きましょう。

Slack 通知の設定

このへんが参考になるでしょうか。
SlackのWebhook URL取得手順
名前とアイコンぐらいは設定しておきます。

簡単に実装してみる

下記を入力することで任意のタイミングでAutoMLに画像を投げています。
1: 撮影
2: 画像認識。結果により、Slackへ通知する。
3: 終了
n秒おきに自動撮影 → 認識させることで監視カメラや定点観測に使えるかと思います。

import os
import sys
import requests
import configparser
from picamera import PiCamera


def main(conf):
    while True:
        with PiCamera() as camera:
            camera.resolution = (600, 480)
            # 検証用プレビュー画面
            camera.start_preview(fullscreen=False, window=(50, 50, 200, 300))
            while True:
                input_ = input('1:撮影 2:解析 3:終了 input: ')
                if input_ == '1':
                    camera.capture('image.jpg')
                elif input_ == '2':
                    break
                elif input_ == '3':
                    sys.exit()
                else:
                    print('1から3の整数を指定してください')

        # キャプチャ画像を取得
        with open('image.jpg', 'rb') as f:
            content = f.read()

        # AutoMLで予測
        response = get_prediction(conf, content)
        print(response)

        results = response.payload
        if len(results) != 0:
            labels = ['vongole']
            # 認識したいラベルに一致する結果を抽出
            matched_labels = [result for result in results if result.display_name in labels]
            for label in matched_labels:
                if label.classification.score >= 0.9:
                    # 90%以上の予測結果ならSlack通知
                    slackPost(conf, label.display_name)
        else:
            print('認識情報なし')


if __name__ == '__main__':
    conf = configparser.ConfigParser()
    ini_path = os.path.join(os.path.dirname(__file__), 'automl.ini')

    if not os.path.exists(ini_path):
        sys.stderr.write('{} 設定ファイルが見つかりません'.format(ini_path))
        sys.exit(2)

    conf.read(ini_path)
    main(conf)

AutoMLの呼び出し

あらかじめ、下記をインストールしておきます。

pip install google-cloud-automl

さらに、下記が必要となります。
iniファイルから読み込みます 。
- プロジェクトID
- モデルID
- KEYファイル

from google.cloud import automl_v1beta1


def get_prediction(conf, content):
    project_id = conf.get('AutoML', 'PROJECT_ID')
    model_id = conf.get('AutoML', 'MODEL_ID')
    key_file = conf.get('AutoML', 'KEY_FILE')

    service_client = automl_v1beta1.PredictionServiceClient()
    prediction_client = service_client.from_service_account_json(key_file)

    name = 'projects/{}/locations/us-central1/models/{}'.format(project_id, model_id)
    payload = {'image': {'image_bytes': content}}
    params = {}
    request = prediction_client.predict(name, payload, params)
    return request

Slack通知の部分

import json
import random


def slackPost(conf, display_name):
    comment = ['ボンゴレチャン ヲ ケンシュツ シマシタ', 'ボンゴレちゃん発見!']
    webhook_url = conf.get('Slack', 'webhook_url')
    text = '[{}] {}'.format(display_name, random.choice(comment))
    payload = {'text': text}
    requests.post(webhook_url, data=json.dumps(payload))

撮ってみる

予測結果

結果がコンソール出力されます。

payload {
  classification {
    score: 0.9923621416091919
  }
  display_name: "vongole"
}

通知

無事に通知されていることを確認!
ここでキャプチャ画像まで出したいところですが、今回はここまでとしたいと思います。

この記事が気に入ったらサポートをしてみませんか?