AnyMotionを使って2つの画像の骨格位置を比較する

# はじめに
AIを用いた姿勢推定による動作解析APIプラットフォームである[AnyMotion](https://dm.nttpc.co.jp/lp/anymotion)に2つの画像/動画間の動作比較機能が実装されました。

この記事では2つの画像を用いて比較機能を試してみたいと思います。

# AnyMotionの比較機能について
[公式ドキュメント](https://docs.anymotion.jp/comparison.html)によれば、キーポイント抽出した部位に対して以下のような計算を行っているようです。

- 2点がどの方向(degree)に差異があるか
- 2点がどれくらい距離(distance)があるか

比較する人物の大きさが異なっている場合でも同じ大きさになるように正規化を行っているため、被写体の写り方を気にする必要はないようです。

# 用意するもの
- AnyMotion APIのトークン
    - [AnyMotion ポータル](https://portal.anymotion.jp/)から取得できます

# やってみる
## AnyMotion CLIのインストール
[以前の記事](https://qiita.com/staybuzz/items/68997a2c3999483dae1b)はSDKを用いてPythonで実装しましたが、今回は手軽にAnyMotionを試せるCLIを使用します。本記事執筆時点での最新版は1.1.0です。

```shell
pip install anymotion-cli
```

Macの場合はhomebrewを使ってもインストールできます。

```shell
brew install nttpc/tap/anymotion-cli
```

## AnyMotion CLIへトークン情報の設定
```shell
$ amcli configure
AnyMotion Client ID: XXXXCLIENTIDXXXX (入力しても表示されない)
AnyMotion Client Secret: XXXXCLIENTSECRETXXXX (入力しても表示されない)
```

トークンが無事登録できればamcliを使ってAnyMotion APIにアクセスできます。
ここでは試しに画像一覧取得APIを実行します。AnyMotionに登録した直後は空の配列が返ってくるはずです。

```
$ amcli image list

[]
```

## 画像のアップロード
ここでは比較に使用する2枚の画像を1枚ずつアップロードします。
ここでは次の2枚の画像をアップロードしてみます。
image1.jpg
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53819/6b1364d6-d8cb-eec0-1506-befdd5cf711f.jpeg" width=50%>
image2.jpg
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53819/adfe6b5f-902c-5b5a-f2b1-89abb6397b4e.jpeg" width=50%>

```shell
$ ls
image1.jpg  image2.jpg

$ amcli upload image1.jpg
Success: Uploaded image1.jpg to the cloud storage. (image id: 16346)

$ amcli upload image2.jpg
Success: Uploaded image2.jpg to the cloud storage. (image id: 16347)
```

## キーポイント抽出
先ほどアップロードした画像に対してキーポイント抽出をかけます。
uploadコマンド実行時に表示される`image id`を使用します。

```shell
$ amcli extract --image-id 16346
Keypoint extraction started. (keypoint id: 25769)
Success: Keypoint extraction is complete.

$ amcli extract --image-id 16347
Keypoint extraction started. (keypoint id: 25770)
Success: Keypoint extraction is complete.
```

## 比較
抽出したキーポイントをもとに比較を行います。
extractコマンド実行時に表示される`keypoint id`を使用します。

キーポイントIDを指定するとき、先に指定するキーポイントが比較基準(source)、後に指定するキーポイントが比較対象(target)になります。

またここでは引数に `-d / --with-drawing` オプションを追加します。これにより比較処理と合わせて比較結果が描画されたファイルをダウンロードすることができます。

```shell
$ amcli compare -d 25769 25770
Comparison started. (comparison id: 38)
Success: Comparison is complete.

Drawing started. (drawing id: 25658)
Success: Drawing is complete.

Downloaded the file to image2_image1.jpg.
```

ダウンロードされたファイルを開いてみると、。抽出された灰色のキーポイントおよびそれらを結ぶ灰色の線が描画され、キーポイントの位置に大きく差がある右肘および右手首のキーポイントは赤くなっているのが確認できます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53819/86decb0f-f005-b569-79e4-120fc9091cd4.jpeg" width=50%>
比較基準としてimage1.jpgを使用しているため、ダウンロードされたファイルもimage1.jpgが使用されています。引数に指定したキーポイントIDの位置を入れ替えることで描画に使用されるファイルも以下のように入れ替わります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53819/e017481b-b980-db58-60a3-fd0d3a07f495.jpeg" width=50%>
### 比較機能の詳細取得
比較したキーポイントがどの方向にどれくらい離れているか、という情報はjson形式で取得することができます。

```
$ amcli comparison show 38

{
  "id": 38,
  "target": 25770,
  "source": 25769,
  "difference": [
    {
      "leftEar": {
        "distance": 0.0849754856212557,
        "direction": 203.08475544393698
      },
      "leftShoulder": {
        "distance": 0.06794792920664146,
        "direction": 202.95930768122653
      },
      "rightShoulder": {
        "distance": 0.04741214355763907,
        "direction": 228.66692586956376
      },
      "leftElbow": {
        "distance": 0.04866278725325595,
        "direction": 194.89279875931024
      },
      "rightElbow": {
        "distance": 0.21899947129386607,
        "direction": 357.703329183744
      },
      "leftWrist": {
        "distance": 0.015746550849744665,
        "direction": 191.1641311241438
      },
      "rightWrist": {
        "distance": 0.4218261496619992,
        "direction": 0.3992279749799625
      },
      "leftHip": {
        "distance": 0.03687588672417605,
        "direction": 244.6251848528287
      },
      "rightHip": {
        "distance": 0.03451332524341227,
        "direction": 242.75005929427078
      },
      "leftKnee": {
        "distance": 0.031044976542986987,
        "direction": 270.05760597221814
      },
      "rightKnee": {
        "distance": 0.032956247407511546,
        "direction": 270.0542651595068
      },
      "leftAnkle": {
        "distance": 0.05013280578456332,
        "direction": 288.0030704990386
      },
      "rightAnkle": {
        "distance": 0.04057149983586865,
        "direction": 292.4517105064375
      }
    }
  ],
  "execStatus": "SUCCESS",
  "failureDetail": "",
  "createdAt": "2020-09-08T09:19:04.804187Z",
  "updatedAt": "2020-09-08T09:19:05.173775Z"
}
```

比較結果を見てみると"rightElbow"と"rightWrist"の距離(distance)が0.2を超えています。
比較結果を描画するとき、デフォルトでは距離が0.2を超えるとキーポイントが赤く描画されるようです。
これらのしきい値や描画色は個別に設定することができます。詳しくは[ドキュメント](https://docs.anymotion.jp/drawing.html#%E6%AF%94%E8%BC%83%E7%B5%90%E6%9E%9C%E3%81%AE%E6%8F%8F%E7%94%BB)を参照してください。

# おわりに
2つの画像を使ってAnyMotionの比較機能を試してみました。
今回は画像を使用しましたが、画像と動画、動画と動画の比較も可能です。
スポーツやダンスなど様々なシーンで活用できそうだなと思いました。