Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions raspi/line_detection/.env.template → .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@
HOME_DIR=/Users/ycn/Workspace/NUTMEG/tracking-parking

# YOLOモデル
MODEL_PATH=${HOME_DIR}/yolo_fine_tuning/runs/detect/train14/weights/best.pt
MODEL_PATH=${HOME_DIR}/models/yolov8s.pt
CONFIDENCE_THRESHOLD=0.25
IOU_THRESHOLD=0.7
VEHICLE_CLASSES=2,7

# 速度比較条件(ROI方式と同じ値に揃える)
# 速度計測条件
YOLO_DEVICE=cpu
YOLO_IMGSZ=640
YOLO_TRACKER=botsort.yaml
WARMUP_FRAMES=30
EXP_DEVICE_NAME=raspi5
EXP_DEVICE_ACCELERATOR=cpu

# Line1設定(入口側ライン) - setup/setup_lines.pyで自動設定
# Line1設定(入口側ライン) - scripts/setup_lines.pyで自動設定
LINE1_START_X=300
LINE1_START_Y=400
LINE1_END_X=800
LINE1_END_Y=400

# Line2設定(駐車場側ライン) - setup/setup_lines.pyで自動設定
# Line2設定(駐車場側ライン) - scripts/setup_lines.pyで自動設定
LINE2_START_X=300
LINE2_START_Y=200
LINE2_END_X=800
LINE2_END_Y=200

# 駐車場基準点(駐車場側を定義) - setup/setup_lines.pyで自動設定
# 駐車場基準点(駐車場側を定義) - scripts/setup_lines.pyで自動設定
PARKING_REF_X=550
PARKING_REF_Y=100

Expand Down
40 changes: 22 additions & 18 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
mongo/
web/
trapa/
# Python
__pycache__/
.venv/
.pytest_cache/

# 設定(画角ごとの.envを含む。テンプレートのみ追跡する)
*.env
*.yaml
.DS_Store
!dataset.yaml
/sahi
.env
raspi/result/prediction_visual.png
!.env.template

# 入出力データ・モデル重み(サイズが大きくローカル資産)
# ディレクトリ自体を除外すると中の.gitkeepを再包含できないため、中身を除外する
/data/**
/models/**
!/data/**/
!/data/**/.gitkeep
!/data/inputs/videos.example.json
!/models/.gitkeep
*.pt
.venv/

# 2ライン検知システムの出力ファイル
data
# docker-compose.prod.ymlがマウントするローカルディレクトリ
mongo/
web/

# ドキュメント
docs/
docs/*
!raspi/line_detection/docs/
!raspi/line_detection/docs/wandb_integration_spec_v2.md
# macOS
.DS_Store

# ローカルディレクトリ
**/*.local
# ローカル専用ディレクトリ(docs.local など)
**/*.local
6 changes: 3 additions & 3 deletions .gitkeep
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
yolo_fine_tuning/resorces/dataset/background_images
yolo_fine_tuning/resorces/dataset/output_ground_truth
yolo_fine_tuning/resorces/dataset/output_png
training/resorces/dataset/background_images
training/resorces/dataset/output_ground_truth
training/resorces/dataset/output_png
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# tracking-parking

駐車場の入出庫を検知し、駐車台数を管理するシステム。

車両の検知には**2ライン方式**を採用している。出入口側の `Line1` を主判定ライン、
奥側の `Line2` を補助判定ラインとして、YOLOv8のトラッキング結果からライン通過を
検知し、入庫・出庫をカウントする。方式選定の経緯は
[docs/decisions/0001-two-line-method.md](docs/decisions/0001-two-line-method.md) を参照。

プロジェクト全体の背景は [Wiki](https://github.com/NUTFes/tracking-parking/wiki) にある。

## セットアップ

```bash
uv sync
```

`src/tracking_parking` がeditable installされ、`import tracking_parking` が使えるようになる。

続いて設定ファイルとモデル重み、入力動画を用意する。いずれもGit管理外。

```bash
cp .env.template .env # HOME_DIR と MODEL_PATH を環境に合わせる
mkdir -p models data/inputs # models/ に .pt を、data/inputs/ に動画を置く
```

## 使い方

```bash
# 1. GUIでライン座標を設定する(動画の先頭フレームに5点クリック)
uv run python scripts/setup_lines.py --video data/inputs/test.mp4

# 2. 動画を処理して入出庫をカウントする
uv run python scripts/run_detection.py --input data/inputs/test.mp4

# 3. ライン位置と車両代表点の関係を確認する
uv run python scripts/visualize_lines.py data/inputs/test.mp4

# 4. 複数動画をまとめて処理し、サマリーへ集約する
# 対象動画は data/inputs/videos.json に書く(雛形は videos.example.json)
cp data/inputs/videos.example.json data/inputs/videos.json
uv run python scripts/run_multi_video.py
```

結果は `data/outputs/` に出る(アノテーション動画、イベントログのJSON/CSV、run manifest)。

## テスト

```bash
uv run pytest -q
```

## ディレクトリ構成

| パス | 役割 |
|---|---|
| `scripts/` | CLIエントリポイント |
| `src/tracking_parking/` | 本体パッケージ(検知ロジック、出力、共通基盤、評価) |
| `tests/` | テスト |
| `docs/` | 設計・検証・決定の記録 |
| `plate_recognition/` | ナンバープレート認識 |
| `training/` | YOLOのファインチューニング |
| `view/` | フロントエンド(Next.js) |
| `data/`, `models/` | 入出力データとモデル重み(Git管理外) |

詳細は [docs/two-line-system.md](docs/two-line-system.md) にある。

## ドキュメント

- [docs/two-line-system.md](docs/two-line-system.md) — システム構成、設定パラメータ、アルゴリズム
- [docs/verification.md](docs/verification.md) — 実動画1本での検証手順
- [docs/wandb_integration_spec_v2.md](docs/wandb_integration_spec_v2.md) — 実験記録(W&B連携)の仕様
- [docs/decisions/](docs/decisions/) — 設計上の決定記録
5 changes: 0 additions & 5 deletions Readme.md

This file was deleted.

69 changes: 0 additions & 69 deletions cron/main.py

This file was deleted.

File renamed without changes.
5 changes: 5 additions & 0 deletions data/inputs/videos.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{ "video": "data/inputs/sample_a.mp4", "env": "camera_a.env" },
{ "video": "data/inputs/sample_b.mp4", "env": "camera_a.env" },
{ "video": "data/inputs/sample_c.MOV", "env": "camera_b.env" }
]
File renamed without changes.
File renamed without changes.
111 changes: 111 additions & 0 deletions docs/decisions/0001-two-line-method.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# 0001. 入出庫検知方式に2ライン方式を採用する

- ステータス: 採用
- 決定日: 2026-09-04
- 関連: Issue #88(2ライン方式の検証)、Issue #89(ROI方式の検証)、PR #90

## 背景

駐車場の入出庫検知には、2つの方式を並行して実装し比較してきた。

- **2ライン方式**(Issue #88 / ブランチ `experiment/ucn/two-lines-detection`)
出入口側の `Line1` を主判定、奥側の `Line2` を補助判定として、外積法でライン交差を検知する。
- **ROI方式**(Issue #89 / ブランチ `feat/mike/89-bbox-analysis-within-roi`)
ROI内の進行度 `s` に対する閾値(`s_low` / `s_high`)による状態機械で検知する。

どちらを本番の検知方式として採用するかを決める必要があった。

## 決定

**2ライン方式を採用する。** ROI方式のコードは本リポジトリの `develop` へは取り込まず、
`feat/mike/89-bbox-analysis-within-roi` ブランチに残す(`raspi/roi-counter/` 配下、
本ADR作成時点のコミットは `3968e2d`)。ROI方式は `develop` にマージされたことがないため、
整理前の状態を指す `archive/pre-cleanup` タグにもROI方式のコードは含まれない。

## 根拠

### 速度と集計精度には差がなかった

当初、方式ごとに別々の時間帯で測った結果ではROI方式が2.27倍速いと出ていた。
しかしこれは開発機の熱状態(サーマルスロットリング)によるもので、方式の差ではなかった。
開始から約4000フレーム(約7分)でスロットリングが頭打ちになるため、
別々の時間帯に測った2つのrun同士は比較できない。

そこで動画ごとにROI→2ライン→ROI→…と交互実行し、熱状態の上がり方を両方式へ均等にかけて
測り直した(2026-09-03〜04 実施)。結果、2.27倍の差は消えた。

| 動画 | ROI `core_ms_p95` | 2ライン `core_ms_p95` | 比(2ライン/ROI) | ROI誤差 | 2ライン誤差 |
|---|---|---|---|---|---|
| 1787008160.558032 | 416.2ms | 409.8ms | 0.98x | 0 | 0 |
| 1787009706.719727 | 500.6ms | 440.8ms | 0.88x | 0 | 0 |
| 1787011229.231516 | 364.3ms | 375.2ms | 1.03x | 0 | 0 |
| 1787012751.179971 | 352.9ms | 364.1ms | 1.03x | 0 | 0 |
| 1787014266.421887 | 303.2ms | 335.5ms | 1.11x | 0 | 0 |
| IMG_2787 | 368.4ms | 329.9ms | 0.90x | 0 | 0 |

比の平均は0.99倍、範囲は0.88〜1.11倍で、どちらか一方へ偏ってもいない。
この振れ幅は判定ロジックの差ではなく計測ごとのばらつきとして説明できる。
YOLO推論が `core_ms` の99.9%以上を占め、ROI方式の進行度計算も2ライン方式の交差判定も
0.1ms未満で同水準であることとも整合する。

集計台数は6動画とも両方式でGTと一致した(`count_error=0`)。
`comparison_key` も動画ごとに両方式で一致しており、比較条件の同一性は保証されている。

つまり**速度も集計精度も方式選択の決め手にならなかった**。

なお、この表の絶対値(300〜500ms)は確定run当時(ROI方式127〜142ms、2ライン方式275〜338ms)より
大幅に悪い。12runを約10時間ノンストップで回した連続負荷によるもので、実装の劣化ではない。
開発機の計測値はもとより参考値であり、実機(Raspberry Pi / Jetson)での計測が別途必要である。

### 決め手は「実行と観測の基盤」

2ライン方式の実行スクリプトは、GTとの誤差計算、W&Bへの記録、フレームごとのタイミング計測、
`comparison_key` 付きrun manifestの保存までを単体で内蔵している。
ROI方式では同水準の計測が別の実験用スクリプト
(`raspi/roi-counter/scripts/04_multi_video_mae.py`)側にあり、
通常の実行経路(`raspi/roi-counter/main.py`)には統合されていない。

これは検証の再現と障害調査のしやすさの差である。方式そのものの優位性ではなく、
**現時点で実証運用へ進める基盤が整っている**ことを理由に2ライン方式を選ぶ。

## この決定が主張していないこと

判断を後から読み違えないために、根拠が及ばない範囲を明記しておく。

- **イベント単位の精度は未評価。** `count_error=0` はIN/OUT合計値の一致を示すだけで、
見逃しと誤検出が相殺した場合を区別できない。正解データにイベント時刻がないため。
- **エッジ実機でのロバスト性は未検証。** 2ライン方式には有限線分の端で交差が不成立になる
失敗条件(`ENDPOINT_MARGIN_PX=0.0` のため余裕がない)、ROI方式には低fpsでの領域飛び越しがある。
これらを同条件で分離計測していない。
- **設置のしやすさは未計測。** ROI方式は4点、2ライン方式はライン2本と駐車場基準点で5点を
クリックする。ROI側には既存点のドラッグ・動画のシーク・形状検証があり、2ライン側は
先頭フレーム上での点追加とリセットが中心と、機能にも差がある。
設定時間・初回成功率・作業者間のばらつきを測っていないため、優劣は判断しない。
- **画角変更への強さと遮蔽への耐性は判断材料なし。** 6動画のうち5本が同じ画角、
出庫イベントは全体で9件。夜間・雨・逆光・複数車両の接近なども評価対象外。
- **判定の解釈性も決め手にしていない。** 2ライン方式の規則は「Line1との交差」として
説明しやすいが、交差判定には直前の安定点・現在点・線分との交点・駐車場基準点が必要で、
現在のイベントログはそれらを保存していない。該当フレーム1枚での事後監査はできない。

## パラメータ調整基盤の欠落(引き継ぐ課題)

ROI方式には、YOLO推論を動画1本につき1回だけ実行し、検出結果のキャッシュに対して
カウントロジックだけを再生することで閾値の組み合わせを安く探索する仕組みがあった。
2ライン方式には `MARGIN_PX` や `MAX_FRAME_GAP_SEC` を自動探索する対応物がない。

パラメータ調整が必要になった時点で、
`feat/mike/89-bbox-analysis-within-roi` ブランチの
`raspi/roi-counter/scripts/03_sweep_params.py` を参照し、2ライン方式向けに作り直すこと。

ただしROI方式の探索にも限界があった。閾値探索と結果評価に同じ6動画を使っており、
集計台数のMAEだけを目的関数にすると見逃しと誤検出の相殺も選べてしまう。
作り直す際は、未使用動画とイベント時刻付きの正解データを評価に加えること。

## 残っている既知の課題

- **Line2通過の扱いが未定。** 6動画の128イベントのうち99件が `high`、29件が `normal` だった。
Line2を通過しない `normal` も台数に含まれるため、この信頼度をAPI送信や運用判断で
どう扱うかを決める必要がある。
- **入出庫イベントをAPIへ送る処理が両方式とも未実装。** 方式共通の統合作業として残る。
- **Jetson Orin NXでライン座標設定GUIが起動しない**(Issue #103)。
OpenCVのGUIバックエンドの問題で、`SHOW_DISPLAY=false` のカウント処理自体は動作する。
Loading