概要
AIを用いた姿勢推定による動作解析APIサービスであるAnyMotionを用いて、人物の動きの違いを可視化してみました。
AnyMotionとは
AnyMotionは、AIを用いた姿勢推定による動作解析APIサービスです。
人物の関節などの座標を推定して、様々な身体動作を可視化/定量化してくれます。
今回やること
- 動画に映る人物の関節などの座標を描画して、動きの違いを可視化する
アクセストークンの取得
AnyMotionポータルで発行された、Client ID
とClient 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")
結果
おわりに
今回は、AnyMotionを用いて動きの違いを可視化してみました。
1つの動画に2人の関節などの座標を描画することで動きの違いが明らかになりました。