※ グーのポーズは5秒間維持すると画像が散らばるエフェクトが発動します(プログレスバー表示)
このドキュメントは、<script type="module"> 内で実装された主要機能の仕様と構造を説明するものです。
以下、各機能の概要と重要なポイントについて、図やフローチャートを用いて分かりやすく解説します。
この関数は、Webカメラ映像の表示、オーバーレイキャンバス、各種画像・動画エフェクト、時計キャンバス、さらに深度マップ表示のための各要素を動的に生成・構築します。
┌────────────────────────────┐
│ Wrapper (div) │
│ ┌────────────────────────┐ │
│ │ Video & Canvas Container │
│ │ ├─ video要素 │ │
│ │ ├─ オーバーレイcanvas │ │
│ │ ├─ poseImage (img) │ │
│ │ ├─ rockVideo (video) │ │
│ │ ├─ rockImage (img) │ │
│ │ ├─ particlesコンテナ │ │
│ │ └─ clock (canvas) │ │
│ └────────────────────────┘ │
│ ┌────────────────────────┐ │
│ │ Depth Map Container │ │
│ │ (canvas & ラベル) │ │
│ └────────────────────────┘ │
└────────────────────────────┘
重要なポイント:
・各UI要素はCSSのレスポンシブ設計(幅100%、自動高さ調整)により、画面サイズに合わせて柔軟にレイアウトされます。
・動画の実際サイズが確定すると、loadedmetadata イベントをトリガーとしてキャンバスやその他子要素のサイズが再設定されます。
画像を小さな粒子に分割し、ランダムな方向へアニメーションさせることで「散らばり」エフェクトを実現します。
各粒子は、オフスクリーンキャンバス上で生成された画像の断片を背景として持ち、一定時間後にフェードアウトし削除されます。
Webカメラ映像からMediaPipe Handsを利用して手のポーズ(例:グー、ピースサイン)を検出します。
特に、グーのポーズが一定時間継続すると以下の処理が実行されます:
アナログ時計は、以下の処理で描画されます:
ctx.save()) と復元 (ctx.restore()) を行う
深度推論:
scheduleDepthInference 関数では、Webカメラの映像をオフスクリーンキャンバスに描画し、ONNXモデルを用いて深度マップ推論を実行します。
推論結果はキャンバス上にレンダリングされ、深度範囲の情報がデバッグ用にコンソール出力されます。
AI推論の詳細:
この深度推論システムは、ディープラーニングに基づくONNXモデルを使用しており、入力されたRGB画像から各ピクセルの深度を推定します。
映像はまず適切な解像度にリサイズされ、正規化処理を通じてモデルに適した形式に変換されます。GPUアクセラレーションが利用可能な場合、高速なリアルタイム推論が実現され、CPU環境下でも十分なパフォーマンスが発揮されるよう最適化されています。
生成される深度マップは、シーン内のオブジェクト間の距離や位置関係を正確に把握するために利用され、後続のエフェクト処理やジェスチャー認識の判断材料として活用されます。さらに、推論プロセス中に得られたデバッグ情報は、システムの性能解析や最適化に役立つようコンソールへ出力されます。
カメラ映像処理:
Camera クラスを通じ、毎フレームMediaPipe Handsに映像を送信し、連続的な解析と描画処理がrequestAnimationFrameによって管理されます。
コード全体は、イベント駆動アーキテクチャと非同期処理により以下のように構成されています:
loadedmetadata イベントで実サイズ取得時にUI要素のサイズ再設定setTimeout を用いたエフェクト開始と削除のタイミング制御requestAnimationFrame による定期的な映像解析と深度推論スケジュール※ 特に重要なのは、リアルタイム性の確保と各UI要素の動的な切り替え処理、そしてレスポンシブなレイアウト実現です。
[初期化]
│
├─ initVideoCanvasContainer()
│ ├─ 動画、キャンバス、画像、動画、粒子、時計、深度マップの各UI要素生成
│ └─ レスポンシブ対応のためのサイズ調整処理 (loadedmetadataイベント)
│
├─ createScatterEffect()
│ └─ 指定画像を粒子に分解し、アニメーションで散らばらせる
│
├─ drawAnalogClock() & drawHand()
│ └─ アナログ時計の外枠、目盛、数字、針を描画
│
├─ カメラ映像取得 & MediaPipe Hands処理
│ └─ 毎フレーム映像を解析しポーズ検出 (requestAnimationFrameで実行)
│
└─ 深度推論処理
└─ オフスクリーンキャンバス経由で深度マップを生成・描画
上記の各処理が連携し、ユーザーの手のポーズによるインタラクション、エフェクトの実行、及び各種UIの動的表示を実現しています。
このセクションでは、各処理がどのようなシーケンスで実行され、条件分岐によって最終的な結果表示へどのように導かれるかを示します。
まず、初期化処理で各UI要素が組み立てられ、loadedmetadata イベントで各コンポーネントのサイズが確定されます。その後、requestAnimationFrame により
リアルタイム映像解析とジェスチャー検出が行われ、ユーザーの手の動作(例:グーのポーズ)が解析されます。
一定期間グーのポーズが検出されれば、左側のブランチでエフェクト実行が開始され、ロック画像や粒子エフェクトがトリガーされます。条件が満たされない場合は右側のブランチを通り、
エフェクトなしの状態となり、最終的にどちらの処理も結果表示へ統合されます。
この図は、初期化からUI構築、イベント検出、分岐処理、そして結果表示への統合までのシーケンスフローを視覚化しています。各段階は非同期イベントやユーザーインタラクションによりトリガーされ、 条件に応じた分岐処理が行われることで最終的な出力が決定されます。