1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AnyMotionを利用して動きの違いを可視化してみた

Last updated at Posted at 2022-01-28

概要

AIを用いた姿勢推定による動作解析APIサービスであるAnyMotionを用いて、人物の動きの違いを可視化してみました。

AnyMotionとは

AnyMotionは、AIを用いた姿勢推定による動作解析APIサービスです。
人物の関節などの座標を推定して、様々な身体動作を可視化/定量化してくれます。

今回やること

  • 動画に映る人物の関節などの座標を描画して、動きの違いを可視化する

アクセストークンの取得

AnyMotionポータルで発行された、Client IDClient Secretを用いて、AnyMotionにアクセスするためのトークンを取得します。

from urllib.parse import urljoin

import requests

CLIENT_ID = "<your_client_id>"
CLIENT_SECRET = "<your_client_secret>"
BASE_URL = "https://api.customer.jp/"
AUTH_URL = urljoin(BASE_URL, "v1/oauth/accesstokens")


def authenticate() -> str:
    headers = {"Content-Type": "application/json"}
    body = {
        "grantType": "client_credentials",
        "clientId": CLIENT_ID,
        "clientSecret": CLIENT_SECRET,
    }
    res = requests.post(AUTH_URL, json=body, headers=headers)
    token = res.json()["accessToken"]
    result = f"Bearer {token}"
    return result


token = authenticate()

姿勢推定

取得したトークンを用いて人物の関節などの座標データを取得します。
今回用いる2つの動画をアップロードします。アップロード完了後、2つの動画それぞれに対して、座標データを取得します。
処理完了後、動画の各フレームごとに検出した17点の座標データを取得できます。

実装

import base64
import hashlib
import time
from pathlib import Path

ANYMOTION_URL = urljoin(BASE_URL, "anymotion/v1/")
CURRENT_DIR = Path(__file__).parent
MEDIA_DIR = CURRENT_DIR / "media"
WAIT_TIME = 1


def calc_content_md5(path: Path) -> str:
    alg = hashlib.md5()
    with open(path, "rb") as f:
        alg.update(f.read())
    result = base64.b64encode(alg.digest()).decode()
    return result


def create_movie(token: str, content_md5: str) -> tuple[int, str]:
    headers = {"Content-Type": "application/json", "Authorization": token}
    body = {"contentMd5": content_md5}
    url = urljoin(ANYMOTION_URL, "movies/")
    res = requests.post(url, json=body, headers=headers)
    movie_id, upload_url = res.json()["id"], res.json()["uploadUrl"]
    return movie_id, upload_url


def upload(path: Path, upload_url: str, content_md5: str) -> None:
    with open(path, "rb") as f:
        headers = {"Content-MD5": content_md5}
        requests.put(upload_url, data=f, headers=headers)


def create_keypoint(token: str, movie_id: int) -> int:
    headers = {"Content-Type": "application/json", "Authorization": token}
    body = {
        "movieId": movie_id,
    }
    url = urljoin(ANYMOTION_URL, "keypoints/")
    res = requests.post(url, json=body, headers=headers)
    keypoint_id = res.json()["id"]
    return keypoint_id


def wait_for(token: str, resource: str, resource_id: int) -> None:
    headers = {"Authorization": token}
    url = urljoin(ANYMOTION_URL, f"{resource}/{resource_id}/")
    while True:
        res = requests.get(url, headers=headers)
        status = res.json()["execStatus"]
        if status == "SUCCESS":
            break

        time.sleep(WAIT_TIME)
        
# もう1つの動画に対しても同様の処理を実施
student_path = MEDIA_DIR / "student.mp4"
content_md5 = calc_content_md5(student_path)
movie_id, upload_url = create_movie(token, content_md5)
upload(student_path, upload_url, content_md5)
source_keypoint_id = create_keypoint(token, movie_id)
wait_for(token, "keypoints", source_keypoint_id)

2つの姿勢の比較描画

最後に、座標データを動画に描画します。
今回は1つの動画に座標データの描画ともう1つの動画の座標データを描画して、動きの違いを可視化します。
処理完了後、描画処理された動画のダウンロードURLが取得できるので、動画をダウンロードします。

実装

def create_drawing(token: str, source_keypoint_id: int, target_keypoint_id: int) -> int:
    headers = {"Content-Type": "application/json", "Authorization": token}
    body = {
        "keypointId": source_keypoint_id,
        "rule": [
            {
                "drawingType": "merge",
                "overlap": {
                    "targetId": target_keypoint_id,
                    "pivot": "leftAnkle",
                },
            }
        ],
    }
    url = urljoin(ANYMOTION_URL, "drawings/")
    res = requests.post(url, json=body, headers=headers)
    drawing_id = res.json()["id"]
    return drawing_id


def get_download_url(token: str, drawing_id: int) -> str:
    headers = {"Authorization": token}
    url = urljoin(ANYMOTION_URL, f"drawings/{drawing_id}/")
    res = requests.get(url, headers=headers)
    download_url = res.json()["drawingUrl"]
    return download_url


def download(download_url: str, filename: str, path: Path = MEDIA_DIR) -> None:
    res = requests.get(download_url)
    dest_path = path / filename
    with open(dest_path, "wb") as f:
        f.write(res.content)


drawing_id = create_drawing(token, source_keypoint_id, target_keypoint_id)
wait_for(token, "drawings", drawing_id)
download_url = get_download_url(token, drawing_id)
download(download_url, "output.mp4")

結果

out.gif

おわりに

今回は、AnyMotionを用いて動きの違いを可視化してみました。
1つの動画に2人の関節などの座標を描画することで動きの違いが明らかになりました。

参考サイト

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?