推しアイデア
サブデバイスを使用した没入感!!
Flask
TypeScript
Azure
Python
JavaScript
サブデバイスを使用した没入感!!
サークル内でJust Danceが流行っていたので
mediapie pose類似度判定
画面左側に表示されるお手本動画に合わせて踊ろう! mediapipeの画像認識を用いてカメラからキャプチャしたダンスの類似度を算出&NintendoSwitchのJoyconで太鼓を叩く動作を検出し、スコア化! 極上の没入感を提供します
7曲のダンスゲームを収録!
画面のどの位置にいるかではなく、「頭に対して手がどこにあるか、足がどこにあるか」という各ランドマーク同士の相対的な位置が重要
姿勢推定から得られたランドマークのデータを入力することで12の点(右肩)からの相対座標を出力する
function getRelativeLandmarks(landmarks) { if (!landmarks || landmarks.length === 0) { console.error("ランドマークが正しく取得されていません"); return []; // エラー回避のために空の配列を返す } const baseLandmark = landmarks[12]; // 基準座標 return landmarks.map(landmark => ({ x: landmark.x - baseLandmark.x, y: landmark.y - baseLandmark.y, })); }
⇩ 2. ダンスの類似度をcos類似度(角度を用いた類似度)で算出
ダンスのポーズ検出において、ランドマーク同士の距離ではなく、角度が重要。同じ距離でも角度が違えば全く違うポーズになってしまう。
コサイン類似度はベクトル同士の向きの類似度であり角度が近いほど1になり遠いほど-1になる。ここでは、各ランドマーク毎にコサイン類似度を算出し、平均をとり、コサイン平均類似度を出している。
function calculateCosineSimilarity(landmarks1, landmarks2) { let dotProduct = 0; let norm1 = 0; let norm2 = 0; for (let i = 0; i < landmarks1.length; i++) { const x1 = landmarks1[i].x; const y1 = landmarks1[i].y; const x2 = landmarks2[i].x; const y2 = landmarks2[i].y; dotProduct += (x1 * x2) + (y1 * y2); norm1 += (x1 * x1) + (y1 * y1); norm2 += (x2 * x2) + (y2 * y2); } return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)); }
以上を毎フレーム繰り返してお手本との類似度をとります
動画を読み込ませ、fpsを指定するだけで各フレームのランドマーク座標を保存したJSONファイルを作成する。これによりゲームで踊れるダンスを簡単に増やせる汎用的なプログラムになった。
import cv2 import mediapipe as mp import json import os import time # Mediapipeのポーズモジュールを初期化 mp_pose = mp.solutions.pose pose = mp_pose.Pose() # 見本動画から骨格ランドマークを抽出し、保存 def extract_and_save_landmarks(video_path, save_path, target_fps=60): cap = cv2.VideoCapture(video_path) landmarks_data = [] frame_interval = 1.0 / target_fps prev_time = time.time() while cap.isOpened(): ret, frame = cap.read() if not ret: break current_time = time.time() if current_time - prev_time >= frame_interval: # mediapipeで骨格検出 frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = pose.process(frame_rgb) if results.pose_landmarks: frame_landmarks = [] for landmark in results.pose_landmarks.landmark: frame_landmarks.append({ 'x': landmark.x, 'y': landmark.y, 'z': landmark.z, 'visibility': landmark.visibility }) landmarks_data.append(frame_landmarks) prev_time = current_time cap.release() # JSONファイルとして保存 with open(save_path, 'w') as f: json.dump(landmarks_data, f) # 見本動画の骨格ランドマークを抽出して保存 extract_and_save_landmarks('app/static/video/sample.mp4', 'app/static/landmarks/sample_landmarks.json')
AzureのFunctions用
https://github.com/jyogi-web/yanabaru-Functions
使うのをやめた
将来的には使いそう
joyconの代わり用 https://github.com/jyogi-web/yanbaru-react-pwa
joycon https://github.com/jyogi-web/yanbaru-back-joycon
mediapipe https://github.com/jyogi-web/yanbaru-back-mediapipe
1. スタート・リセット・カメラ関係 2. 判定・スコア 3. プレイヤーランドマーク表示 4. お手本映像&ランドマーク表示
カメラ映像の上にランドマークが表示されたらスタートボタンを押してゲームスタート!
bluetooth接続して、楽しようとしたらデプロイしたら無理だと気づきました。 他のデバイス(ラズパイ)などを使ってAzure IoT HubやAzure IoT Centralなどのクラウドサービスと連携すれば、JoyconのBluetooth接続でも可能かなと....
使用技術
https://red-grass-08143c200.5.azurestaticapps.net/ ↑スマホで「リクエストを許可」をすると値が取れます。 スコアに関しては取れるのを確認したかっただけなのでめちゃくちゃな値が取れます 加速度は取れましたけど、連携が少し手間取ったので今後連携したいなと思います。
Xcodeと仲良くなれなかったのでWebで実装をしました...
今回の構成図
Azureの提供するリアルタイムプッシュ通信を提供するAzureSignalRを使ってみたかったですけど、時間がなくて断念... 今後挑戦してみてもおもしろいのかなと思ってます
元ネタ https://www.youtube.com/watch?v=DxpzZ96LxjE
毎日部室で部員がこんな激しいダンスを踊っていますw