michimani.net

Amazon Rekognition を使ってスマブラ SP のキャプチャ画像から世界戦闘力を抜き出す

2020-08-22

みなさんスマブラやってますか?今回は、スマブラ SP の強さをはかる指標である 世界戦闘力 の値を Amazon Rekognition のテキスト抽出機能で抜き出してみます。

概要

Nintendo Switch のゲーム 大乱闘スマッシュブラザーズ SPECIAL の世界戦闘力を、 Amazon Rekognition のテキスト抽出機能を使って、ゲーム内で撮影したキャプチャ画像から抜き出します。

スマブラ SP オンライン対戦のキャラ選択画面で、任意のキャラを選択した状態でスクリーンキャプチャを撮ります。例えば下記のようなもの。

Smash Bros SP capture 1

右下に 3 つの戦闘力が表示されていますが、今回抜き出すのは一番上の戦闘力の値です。

Amazon Rekognition

Amazon Rekognition (以下、Rekognition) は、 AWS で提供されているディープラーニングベースの視覚分析サービスです。静止画や動画から物体やシーンの検出、顔分析、テキストの抽出などを行うことができます。

今回はその中から テキスト抽出 - Detect Text の機能を使います。

マネジメントコンソールで試す

Rekognition の各機能はマネジメント今ソースから簡単に試すことができるので、まずはそれで試してみます。

Rekognition Management console 1
Rekognition Management console 2

この様に、画像内のテキストが抽出されます。 プレビュー内の青枠をホバーすると、右側の 結果 に表示されている文字列を確認することができます。

また、 レスポンス では実際の API レスポンスを JSON 形式で確認することができます。例えば、今回抜き出したい戦闘力部分のオブジェクトは次のようになっています。

{
    "DetectedText": "7,816,946",
    "Type": "WORD",
    "Id": 55,
    "ParentId": 9,
    "Confidence": 98.4032974243164,
    "Geometry": {
        "BoundingBox": {
            "Width": 0.11172738671302795,
            "Height": 0.04027777910232544,
            "Left": 0.8187500238418579,
            "Top": 0.6694444417953491
        },
        "Polygon": [
            {
                "X": 0.8187500238418579,
                "Y": 0.6694444417953491
            },
            {
                "X": 0.930468738079071,
                "Y": 0.668055534362793
            },
            {
                "X": 0.930468738079071,
                "Y": 0.7083333134651184
            },
            {
                "X": 0.8187500238418579,
                "Y": 0.7097222208976746
            }
        ]
    }
}

DetectedText が抽出された文字列、 Geometry にはその文字列が画像のどの位置にあるかを示しています。 Geometry.Polygon では、その文字列が存在するエリア (長方形) の四角の座標を、画像のサイズに対する割合で示されています。

一点注意が必要なのは、 日本語には対応していない ため日本語の文字列については正しく抽出することができないという点です。

Python で実装

続いては、 boto3 (AWS SDK for Python) を使って戦闘力を抽出してみます。

使うのは boto3 の Client.detect_text です。

Rekognition — Boto3 Docs 1.14.47 documentation | Client.detect_text

テキスト抽出する対象の画像ファイルは S3 またはバイト文字列で指定します。今回はローカルにある画像ファイルを使うので、バイト文字列で指定します。

対象となる戦闘力のエリアを確認

先ほどのマネジメントコンソールでの例を見てもらうとわかるように、抽出されたテキストから戦闘力の部分を判定する必要があります。レスポンスにはテキストが存在するエリアの四角の座標が含まれているので、この座標をもとにして目的の戦闘力を抜き出したいと思います。

目的の戦闘力が存在するエリアは、だいたいこのあたりです。

Smash Bros SP capture 1

スマブラ SP のキャプチャ画像のサイズは 1260 x 720 (px) で、上の画像内に示した長方形 ABCD の各頂点の座標 (X, Y の始点は画像の左上) はだいたい下記の値でした。

A : (1004.85, 460.33)
B : (1216.26, 460.33)
C : (1216.26, 530.83)
D : (1004.85, 530.83)

これを画像サイズに対する割合で表すと

A : (0.785039062, 0.639347222)
B : (0.950203125, 0.639347222)
C : (0.950203125, 0.737263889)
D : (0.785039062, 0.737263889)

となります。

レスポンス内の Geometry.Polygon に含まれるオブジェクトは、この ABCD の順番で対応しているので、各頂点が上で用意した範囲内に入っているものを、目的の戦闘力とすることができそうです。

実装

実際のスクリプトは次のようになります。

import boto3
import sys


reko = boto3.client('rekognition')
target_area = {
    'A': {'X': 0.785039062, 'Y': 0.639347222},
    'B': {'X': 0.950203125, 'Y': 0.639347222},
    'C': {'X': 0.950203125, 'Y': 0.737263889},
    'D': {'X': 0.785039062, 'Y': 0.737263889},
}


def get_bytes_of_image(image_path):
    with open(image_path, mode='rb') as img:
        image_bytes = img.read()

    return image_bytes


def detect_text(image_path):
    image_bytes = get_bytes_of_image(image_path)
    return reko.detect_text(
        Image={
            'Bytes': image_bytes
        }
    )


def get_smash_power(image_path):
    smash_power = '0'
    detect_res = detect_text(image_path)

    for detected in detect_res['TextDetections']:
        polygon = detected['Geometry']['Polygon']
        if polygon[0]['X'] > target_area['A']['X'] and polygon[0]['Y'] > target_area['A']['Y'] \
                and polygon[1]['X'] < target_area['B']['X'] and polygon[1]['Y'] > target_area['B']['Y'] \
                and polygon[2]['X'] < target_area['C']['X'] and polygon[2]['Y'] < target_area['C']['Y'] \
                and polygon[3]['X'] > target_area['D']['X'] and polygon[3]['Y'] < target_area['D']['Y']:
            smash_power = detected['DetectedText']

    return smash_power


if __name__ == '__main__':
    image_path = sys.argv[1]
    smash_power = get_smash_power(image_path)
    print(smash_power)

実行してみます。

$ python detect_smash_power.py 2020082121055400-0E7DF678130F4F0FA2C88AE72B47AFDF.jpg
7,816,946

取れました。

Use Amazon Rekognition to detect world strength from captured images of Smash Bros SPECIAL.

まとめ

Amazon Rekognition を使ってスマブラ SP の世界戦闘力を抜き出してみました。キャプチャ画像にはキャプチャした日時が含まれているので、その値も含めれば世界戦闘力の推移がグラフ化できそうです。


comments powered by Disqus