# RGB Camera Viewer — スマホ検知・推定視線 v0.2

スマホの検出枠・クラス・信頼度と、カメラ方向への推定視線を表示する独立HTML5デモです。OCR・年齢性別・領域分割は実装しません。Headspaceとは別アプリです。

- 公開パス: `/experiments/webgl/rgb-camera-viewer/`
- ローカル一覧: http://127.0.0.1:8019/
- ローカルビューア: http://127.0.0.1:8019/experiments/webgl/rgb-camera-viewer/
- 分析: ビューアの「記録・分析」リンク。公開版に記録APIはありません。カメラ検知自体はHTTPS上で動きます。

## 操作

1. カメラを選び「カメラ開始」。開いただけでは映像・音声を取得しません。音声は常に無効です。
2. スマホ枠と顔枠を表示。スマホ信頼度の下限は50%が初期値で、顔の追跡・校正には影響しません。ミラー・枠表示を切替可能です。
3. 目が明確に見える人が実際のレンズを3秒見て校正。最大4顔。校正できない別の顔がいても、品質を満たす顔だけ校正します。
4. 緑＝校正したレンズ方向らしい、橙＝外れている、灰＝不明。未校正・閉眼・小さい顔・目の画像情報不足等は不明です。眼鏡反射や目の遮蔽がある場合は申告チェックで判定を止めてください。
5. 停止・タブ非表示・切断・モデルエラーで映像と両Workerを解放。再開始できます。見失った顔は再校正が必要です。

「合成プレビュー」は固定検出値による操作デモで、実際のAI検出ではありません。映像FPS、顔更新Hz、スマホ更新Hz、スマホ処理msはカメラ入力時の実測値だけを表示します。

## v0.2の修正

- SSDのクラス共通NMSを使わず、personとcell phoneのスコアを個別に読み、クラスごとに重複除去。IoU 0.45と表示信頼度を分離。人物枠がスマホを消す問題を修正しました。
- 全画面入力の正規化座標を元映像へ戻し、表示時だけ左右反転。切り出しによる部分枠の二重計数を避けるため、通常処理ではタイル分割を行いません。
- 視線側はFaceLandmarkerの顔を直接追跡。SSD人物枠の成否から独立。身体の検出や人物との所有関係は主UIで扱いません。
- 顔とスマホは別Worker・別時刻・各1枚だけ処理。待ち行列なし。顔は最低100ms、スマホは最低250ms間隔で実行し、実速度は端末次第です。
- 目の形・虹彩だけでなく、眼領域の画像コントラストも確認。ランドマークが遮蔽物上に補完されても、平坦な領域なら不明にします。万能な遮蔽・反射検出ではありません。
- 顔1.5秒、スマホ3秒より古い結果は無効。記録は両方が新鮮なときだけ有効観測とし、それ以外は欠測です。

## 判定と限界

眼の開き、顔幅80px・目幅14px以上、画面端・極端な傾き、虹彩位置・左右整合、眼領域の輝度標準偏差6以上を品質条件として使います。値は実験的です。顔と虹彩の4特徴を3秒・8サンプル以上で校正し、EMAで平滑化。校正値との差が許容幅内かを見て、同じ状態が400ms続いて確定します。

顔の向き＝視線ではありません。正確な視線座標、注意力、集中、感情、広告の実視聴を判定しません。画面注視とレンズ注視は別です。表示する解析対象数は**検出された顔の数**で、画面内の全人数ではありません。顔未検出の人の視線も不明人数も算出できません。

小さいスマホ・強い遮蔽・遠距離の小さい顔は取りこぼします。複数人の交差・入替では短時間の位置追跡が誤対応し得ます。顔認証・恒久ID・スマホ保持者推定はありません。詳細な実測と未検証範囲は [REBUILD_RESULTS.md](REBUILD_RESULTS.md)。実ユーザーのカメラ、実スマホ、Safari/iOS、自然な視線移動の精度は未検証です。

## 起動とビルド

Node.js 22.22.3で検証。ランタイム・モデルは同梱し、公開先でビルド不要です。

```powershell
cd experiments/webgl/rgb-camera-viewer
npm ci
npm run build
npm run verify:assets
npm run dev
# Windowsでターミナル終了後も動かす場合、devの代わりに:
./scripts/start-background.ps1
```

非表示の独立Nodeプロセスを127.0.0.1:8019で起動。PIDとログはgit対象外のdata/。OS自動起動・ファイアウォール設定は変更しません。PC再起動後は再実行。停止前は記録の保存完了と対象PIDを確認してください。静的検証のみなら `npm run dev:static`（8018）。

## 固定技術・通信

SSD MobileNet V2（coco-ssd 2.2.3、base=mobilenet_v2）、TF.js/WASM 4.22.0、MediaPipe Tasks Vision 1.0.1 / FaceLandmarker float16 v1。コード・重みのApache-2.0根拠とモデルカードは [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) と licenses/。モデルとWASM等36ファイルはasset-manifest.jsonでSHA-256固定。YOLO・独自の許諾不明モデルは追加していません。

モデル・JS・WASMは同一オリジンで配信。映像は端末内処理し、画像送信・録画機能はありません。MediaPipe READMEのPrivacy Noticeは利用/性能metricsに言及するため、無条件にSDK全体の完全無通信を保証しません。同一オリジンCSPと実行時ネットワークを検証しています。配信設定やSDKを変えた場合は再検証してください。

## ローカル記録

「記録開始」を別途押した場合だけ、数値・UTC時刻・一時IDと状態をSQLiteへ保存。顔画像・特徴・座標・名前・映像は保存しません。詳細は [ANALYTICS_SPEC.md](ANALYTICS_SPEC.md)。DB/APIはlocalhost専用で、Cloudflare Pagesへの配置だけでは有効になりません。

v0.2のpeopleは解析対象顔数です。旧版の全身検出人数とは定義が異なるため、旧記録と同じ人数指標として比較しないでください。既存DBを改変・リセットせず、分析画面に定義変更を明記しています。

## 検証

背面スマホの追加改善は現在ローカルのみです。弱い候補を最大2件だけ拡大し、必要時は回転して再確認します。表示閾値は50%のままです。比較結果と残課題はリポジトリ内の `PHONE_DETECTION_RESULTS.md` を参照してください。スマホ検出を撮影行為として数える機能は追加していません。

```powershell
npm test
npm run test:analytics
npm run test:analytics-browser
node scripts/fetch-test-inputs.mjs
# 別端末で npm run dev:static
npm run test:browser
npm run test:video
npm run test:lifecycle
node tests/independent-pipeline.mjs
node tests/real-inputs.mjs revised
```

実画像は明示したテストでだけ取得し、Gitや公開物に含めません。出典とハッシュは tests/fixtures/README.md。結果・画面画像はgit対象外のtests/results/。個別サンプルの改善を一般的な検出精度の保証とは扱いません。
