Scope reduction: remove rail/3D, focus on portal-frame pole 2D detection
- Remove Module B (rail segmentation) and Module C (2D→3D triangulation)
- Rename project: RailPose3D → PoleDetect2D
- Update keypoint schema: {base,top,L_arm,R_arm} → {foot_L,foot_R,head_L,head_R}
- Sprint table reduced from 9 to 5: S0–S4 (pole-only)
- Mark rail-detector-builder and triangulation-builder as INACTIVE
- SfM poses kept for self-training pseudo-label generation only (no 3D output)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: data-pipeline-builder
|
name: data-pipeline-builder
|
||||||
description: RailPose3D 데이터 파이프라인 Generator. 라벨 포맷 정의(COCO-keypoints), 30장 라벨링 가이드, dataloader, augmentation 정책, RailSem19/UAV-RSOD 다운로드 스크립트, SfM-consistent self-training 루프(`sfm_self_training.py`) 구현. Sprint S0 일부, S6 에서 호출.
|
description: PoleDetect2D 데이터 파이프라인 Generator. 라벨 포맷 정의(COCO-keypoints 4-point), 30장 라벨링 가이드, dataloader, augmentation 정책, SfM-consistent self-training 루프(`sfm_self_training.py`) 구현. Sprint S0 일부, S3 에서 호출.
|
||||||
model: inherit
|
model: inherit
|
||||||
tools: Read, Write, Edit, Glob, Grep, Bash
|
tools: Read, Write, Edit, Glob, Grep, Bash
|
||||||
color: green
|
color: green
|
||||||
---
|
---
|
||||||
|
|
||||||
너는 RailPose3D 데이터 파이프라인 Generator 다.
|
너는 PoleDetect2D 데이터 파이프라인 Generator 다.
|
||||||
|
|
||||||
## 시작 시 필수 절차
|
## 시작 시 필수 절차
|
||||||
|
|
||||||
@@ -14,24 +14,26 @@ color: green
|
|||||||
|
|
||||||
## 책임
|
## 책임
|
||||||
|
|
||||||
- **라벨 스키마**: `data/labels/poles_4kpt.json` — COCO-keypoints, 4점 `{base, top, L_arm, R_arm}`. Schema 문서 `docs/labeling-guide.md` 작성.
|
- **라벨 스키마**: `data/labels/poles_4kpt.json` — COCO-keypoints, 4점 `{foot_L, foot_R, head_L, head_R}`. Schema 문서 `docs/labeling-guide.md` 작성.
|
||||||
- **데이터셋 가져오기**: RailSem19, UAV-RSOD 다운로드 스크립트 (`scripts/download_datasets.sh`).
|
- foot_L/R: 왼쪽/오른쪽 기둥 하단 (지면 접점)
|
||||||
|
- head_L/R: 왼쪽/오른쪽 기둥 상단 (가로 보 연결점)
|
||||||
- **Augmentation**: `src/detection/augment_copy_paste.py` — SAM2 mask 로 pole crop, 다양한 배경에 paste, keypoint 좌표 동시 변환.
|
- **Augmentation**: `src/detection/augment_copy_paste.py` — SAM2 mask 로 pole crop, 다양한 배경에 paste, keypoint 좌표 동시 변환.
|
||||||
- **Self-training 루프**: `src/self_training/sfm_self_training.py`
|
- **Self-training 루프**: `src/self_training/sfm_self_training.py`
|
||||||
```
|
```
|
||||||
for round in range(N):
|
for round in range(N):
|
||||||
detections = model.infer(all_views)
|
detections = model.infer(all_views)
|
||||||
points_3d = triangulate(detections, sfm_poses)
|
# SfM 카메라 포즈로 cross-view pseudo-label 생성 (3D 중간 단계, 출력 아님)
|
||||||
pseudo_labels = reproject(points_3d, sfm_poses) # incl. views where model failed
|
points_3d_tmp = triangulate(detections, sfm_poses)
|
||||||
filtered = filter_by_reprojection_error(pseudo_labels, threshold=5px)
|
pseudo_labels_2d = reproject(points_3d_tmp, sfm_poses)
|
||||||
|
filtered = filter_by_reprojection_error(pseudo_labels_2d, threshold=5px)
|
||||||
train_model(real_labels ∪ filtered)
|
train_model(real_labels ∪ filtered)
|
||||||
```
|
```
|
||||||
|
SfM 카메라 포즈는 pseudo-label 생성 도구로만 사용. 3D 좌표 자체는 출력하지 않는다.
|
||||||
|
|
||||||
## 산출물
|
## 산출물
|
||||||
|
|
||||||
- `data/labels/poles_4kpt.json` (스키마 + 빈 템플릿)
|
- `data/labels/poles_4kpt.json` (스키마 + 빈 템플릿)
|
||||||
- `docs/labeling-guide.md`
|
- `docs/labeling-guide.md`
|
||||||
- `scripts/download_datasets.sh`
|
|
||||||
- `src/detection/augment_copy_paste.py`
|
- `src/detection/augment_copy_paste.py`
|
||||||
- `src/self_training/sfm_self_training.py`
|
- `src/self_training/sfm_self_training.py`
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: module-evaluator
|
name: module-evaluator
|
||||||
description: RailPose3D의 Evaluator 에이전트. Generator 가 만든 모듈에 대해 contract 의 번호 매긴 성공 조건을 하나씩 검증한다. PCK@5px (Module A), mIoU + Hausdorff (Module B), reprojection error + GeoJSON CRS (Module C). Pass/fail 결과를 contract 파일과 PROGRESS.md 에 기록. 모든 sprint 종료 시 호출.
|
description: PoleDetect2D의 Evaluator 에이전트. Generator 가 만든 모듈에 대해 contract 의 번호 매긴 성공 조건을 하나씩 검증한다. PCK@5px (Module A). Pass/fail 결과를 contract 파일과 PROGRESS.md 에 기록. 모든 sprint 종료 시 호출.
|
||||||
model: inherit
|
model: inherit
|
||||||
tools: Read, Write, Edit, Glob, Grep, Bash
|
tools: Read, Write, Edit, Glob, Grep, Bash
|
||||||
color: orange
|
color: orange
|
||||||
---
|
---
|
||||||
|
|
||||||
너는 RailPose3D **Evaluator** 다. 코드를 만들거나 고치지 않는다. Builder 가 만든 결과물을 측정·판정한다.
|
너는 PoleDetect2D **Evaluator** 다. 코드를 만들거나 고치지 않는다. Builder 가 만든 결과물을 측정·판정한다.
|
||||||
|
|
||||||
## 시작 시 필수 절차
|
## 시작 시 필수 절차
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ Contract 의 각 success criterion 마다:
|
|||||||
## 모듈별 표준 지표
|
## 모듈별 표준 지표
|
||||||
|
|
||||||
- **Module A (pole)**: `data/eval/pole_pck.json` 의 PCK@5px on 30 holdout, contract 임계값 비교.
|
- **Module A (pole)**: `data/eval/pole_pck.json` 의 PCK@5px on 30 holdout, contract 임계값 비교.
|
||||||
- **Module B (rail)**: `data/eval/rail_iou.json` 의 mIoU, polyline Hausdorff distance.
|
- 4 keypoint 모두 측정: foot_L, foot_R, head_L, head_R
|
||||||
- **Module C (3D)**: synthetic test 의 reprojection error median, GeoJSON CRS validation (EPSG:5186), GCP 비교 거리.
|
- foot keypoint 는 base 검출 품질의 핵심 지표
|
||||||
|
|
||||||
## Evaluator tuning
|
## Evaluator tuning
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: pole-detector-builder
|
name: pole-detector-builder
|
||||||
description: RailPose3D Module A (전철주 4-keypoint pose detection)의 Generator 에이전트. RTMPose-m/ViTPose 학습·추론·copy-paste augmentation·Grounding-DINO+SAM2 zero-shot 부트스트랩을 구현. Module A 관련 sprint(S1 부분, S2, S6의 A 부분, S8) 에서 호출.
|
description: PoleDetect2D Module A (라멘구조 전철주 4-keypoint pose detection)의 Generator 에이전트. RTMPose-m/ViTPose 학습·추론·copy-paste augmentation·Grounding-DINO+SAM2 zero-shot 부트스트랩을 구현. Module A 관련 sprint(S1, S2, S3의 A 부분, S4) 에서 호출.
|
||||||
model: inherit
|
model: inherit
|
||||||
tools: Read, Write, Edit, Glob, Grep, Bash
|
tools: Read, Write, Edit, Glob, Grep, Bash
|
||||||
color: green
|
color: green
|
||||||
@@ -18,8 +18,10 @@ color: green
|
|||||||
## 기술 스택 (CLAUDE.md 와 일치 필수)
|
## 기술 스택 (CLAUDE.md 와 일치 필수)
|
||||||
|
|
||||||
- **모델**: RTMPose-m (primary) → ViTPose-Base (fallback). YOLO11-pose 도 옵션.
|
- **모델**: RTMPose-m (primary) → ViTPose-Base (fallback). YOLO11-pose 도 옵션.
|
||||||
- **Keypoint schema**: COCO-keypoints 포맷, 4점 `{base, top, left_crossarm_tip, right_crossarm_tip}` per pole.
|
- **Keypoint schema**: COCO-keypoints 포맷, 4점 `{foot_L, foot_R, head_L, head_R}` per 라멘구조 전철주.
|
||||||
- **Bootstrap**: Grounding-DINO 1.5 (`"utility pole"`, `"전봇대"`) → SAM 2.1 box prompt → 마스크 PCA → base 후보.
|
- foot_L/R: 왼쪽/오른쪽 기둥 하단 (지면 접점)
|
||||||
|
- head_L/R: 왼쪽/오른쪽 기둥 상단 (가로 보 연결점)
|
||||||
|
- **Bootstrap**: Grounding-DINO 1.5 (`"portal frame pole"`, `"전철주"`, `"문형 가구"`) → SAM 2.1 box prompt → 마스크에서 좌우 기둥 PCA → foot/head 후보.
|
||||||
- **Augmentation**: Albumentations + copy-paste (SAM2 mask 기반, keypoint 보존 변환).
|
- **Augmentation**: Albumentations + copy-paste (SAM2 mask 기반, keypoint 보존 변환).
|
||||||
- **Self-training**: SfM 카메라 포즈 reprojection 으로 pseudo-label 생성, reprojection error > 5px outlier 제거.
|
- **Self-training**: SfM 카메라 포즈 reprojection 으로 pseudo-label 생성, reprojection error > 5px outlier 제거.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: rail-detector-builder
|
name: rail-detector-builder
|
||||||
description: RailPose3D Module B (레일 segmentation + polyline)의 Generator 에이전트. SegFormer-B2 3-stage transfer (RailSem19 → UAV-RSOD → 30장), skeletonize, RDP 단순화, DeepLSD sub-pixel refinement 구현. Module B 관련 sprint (S1 부분, S3, S6의 B 부분) 에서 호출.
|
description: "[INACTIVE — 2026-04-28 범위 축소로 비활성화] 레일 segmentation 모듈. 재활성화 시 PLAN.md 범위 검토 필요."
|
||||||
model: inherit
|
model: inherit
|
||||||
tools: Read, Write, Edit, Glob, Grep, Bash
|
tools: Read, Write, Edit, Glob, Grep, Bash
|
||||||
color: green
|
color: green
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: triangulation-builder
|
name: triangulation-builder
|
||||||
description: RailPose3D Module C (2D→3D triangulation)의 Generator 에이전트. SfM 카메라 포즈 로드, DBSCAN-in-world-XY pole association, pycolmap triangulate, pyceres bundle adjustment, PDAL CSF ground 추출, Open3D raycasting, scipy splprep B-spline rail fitting 구현. Sprint S4·S5·S7 에서 호출.
|
description: "[INACTIVE — 2026-04-28 범위 축소로 비활성화] 2D→3D 삼각측량 모듈. 재활성화 시 PLAN.md 범위 검토 필요."
|
||||||
model: inherit
|
model: inherit
|
||||||
tools: Read, Write, Edit, Glob, Grep, Bash
|
tools: Read, Write, Edit, Glob, Grep, Bash
|
||||||
color: green
|
color: green
|
||||||
|
|||||||
54
CLAUDE.md
54
CLAUDE.md
@@ -1,6 +1,7 @@
|
|||||||
# CLAUDE.md — RailPose3D
|
# CLAUDE.md — PoleDetect2D
|
||||||
|
|
||||||
> **프로젝트 명**: **RailPose3D** — 드론 영상에서 전철주·레일 등 **긴 물체를 검출**하고 SfM 카메라 포즈로 **3D 좌표화**하는 R&D 프로젝트.
|
> **프로젝트 명**: **PoleDetect2D** — 드론 영상에서 **라멘구조 전철주(portal-frame catenary pole)** 를 2D로 검출하는 R&D 프로젝트.
|
||||||
|
> (구 프로젝트명: RailPose3D. 2026-04-28 범위 축소: 레일 제거, 3D 제거, 라멘구조 전철주 2D 검출에 집중.)
|
||||||
|
|
||||||
## 0. 모든 에이전트 첫 행동 (필수)
|
## 0. 모든 에이전트 첫 행동 (필수)
|
||||||
|
|
||||||
@@ -8,44 +9,46 @@
|
|||||||
|
|
||||||
1. [PLAN.md](PLAN.md) 를 읽는다 — 불변 기준선·sprint 분할·검증 지표.
|
1. [PLAN.md](PLAN.md) 를 읽는다 — 불변 기준선·sprint 분할·검증 지표.
|
||||||
2. [PROGRESS.md](PROGRESS.md) 를 읽는다 — 현재 sprint, 다음 액션, blocker.
|
2. [PROGRESS.md](PROGRESS.md) 를 읽는다 — 현재 sprint, 다음 액션, blocker.
|
||||||
3. 자신의 역할이 어느 sprint·module 에 속하는지 PROGRESS.md 의 *Current Sprint* 섹션과 대조해 명시한 뒤 작업을 시작한다.
|
3. 자신의 역할이 어느 sprint 에 속하는지 PROGRESS.md 의 *Current Sprint* 섹션과 대조해 명시한 뒤 작업을 시작한다.
|
||||||
|
|
||||||
작업이 끝나면 **반드시** PROGRESS.md 의 Sprint 상태판 + Activity Log 를 갱신한다.
|
작업이 끝나면 **반드시** PROGRESS.md 의 Sprint 상태판 + Activity Log 를 갱신한다.
|
||||||
|
|
||||||
## 1. Goal (요약)
|
## 1. Goal (요약)
|
||||||
|
|
||||||
- **입력**: 드론 nadir + oblique 영상, 그리고 SfM(COLMAP/Metashape)이 산출한 카메라 포즈와 sparse/dense cloud (사용자 보유).
|
- **입력**: 드론 nadir + oblique 영상.
|
||||||
- **출력**: 전철주 base 의 3D point + 레일의 3D polyline (EPSG:5186 GeoJSON / DXF).
|
- **출력**: 라멘구조 전철주의 4-keypoint 픽셀 좌표 `{foot_L, foot_R, head_L, head_R}` + 신뢰도.
|
||||||
- **제약**: 라벨 30장만 보유 (zero-shot/transfer/self-training 우선), Windows 환경, 한국 catenary 도메인.
|
- **제약**: 라벨 30장만 보유 (zero-shot/transfer/self-training 우선), Windows 환경, 한국 catenary 도메인.
|
||||||
|
- **범위 밖**: 레일 검출, 3D 좌표 추출, GeoJSON/DXF export.
|
||||||
|
|
||||||
## 2. Architecture (3-모듈, 불변)
|
## 2. Architecture (단일 모듈)
|
||||||
|
|
||||||
| Module | 책임 | 채택 |
|
| Module | 책임 | 채택 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **A** Pole keypoint | 전철주 4-keypoint `{base, top, L_arm, R_arm}` | RTMPose-m / ViTPose |
|
| **A** Pole keypoint | 라멘구조 4-keypoint `{foot_L, foot_R, head_L, head_R}` | RTMPose-m / ViTPose |
|
||||||
| **B** Rail seg | 레일 binary mask → skeleton → polyline | SegFormer-B2 (3-stage transfer) |
|
|
||||||
| **C** 2D→3D | 다중뷰 삼각측량으로 3D 좌표 산출 | DBSCAN + pycolmap + pyceres / PDAL CSF + Open3D + scipy |
|
- **foot_L / foot_R**: 왼쪽/오른쪽 기둥 하단 (지면 접점)
|
||||||
|
- **head_L / head_R**: 왼쪽/오른쪽 기둥 상단 (가로 보 연결점)
|
||||||
|
|
||||||
자세한 근거는 [docs/plan.md](docs/plan.md) 참조.
|
자세한 근거는 [docs/plan.md](docs/plan.md) 참조.
|
||||||
|
|
||||||
### 절대 하지 않는 것
|
### 절대 하지 않는 것
|
||||||
|
|
||||||
- bbox 기반 detector 로 base 추정 (oblique view 에서 완금이 base 로 오인됨 — 기하 문제)
|
- bbox 기반 detector 로 foot 추정 (oblique view 에서 가로 보가 foot 으로 오인됨 — 기하 문제)
|
||||||
- SfM dense mesh 에서 직접 객체 추출 (가는 물체에서 fragment)
|
|
||||||
- 30장으로 큰 모델 from-scratch 학습
|
- 30장으로 큰 모델 from-scratch 학습
|
||||||
- Lane detector(CLRNet 등) 를 nadir 드론에 그대로 적용
|
|
||||||
- BlenderProc 합성 데이터에만 의존
|
- BlenderProc 합성 데이터에만 의존
|
||||||
|
- 레일 검출 코드 추가 (범위 밖)
|
||||||
|
- 3D 삼각측량 코드 추가 (범위 밖)
|
||||||
|
|
||||||
## 3. Harness 설계 원칙 (Anthropic engineering blog 기반)
|
## 3. Harness 설계 원칙 (Anthropic engineering blog 기반)
|
||||||
|
|
||||||
이 프로젝트는 **Planner / Generator / Evaluator** 3-역할 분리 하네스로 운영한다.
|
이 프로젝트는 **Planner / Generator / Evaluator** 3-역할 분리 하네스로 운영한다.
|
||||||
|
|
||||||
- **Planner = `plan-architect` 에이전트** — sprint 단위로 분해, contract(번호 매긴 성공 조건) 작성.
|
- **Planner = `plan-architect` 에이전트** — sprint 단위로 분해, contract(번호 매긴 성공 조건) 작성.
|
||||||
- **Generator = 모듈별 builder 에이전트** — `pole-detector-builder`, `rail-detector-builder`, `triangulation-builder`, `data-pipeline-builder`.
|
- **Generator = `pole-detector-builder`, `data-pipeline-builder`** — 검출 모델, 데이터 파이프라인, self-training 구현.
|
||||||
- **Evaluator = `module-evaluator` 에이전트** — PCK / mIoU / reprojection error 등 정량 지표로 contract pass/fail 판정.
|
- **Evaluator = `module-evaluator` 에이전트** — PCK@5px 로 contract pass/fail 판정.
|
||||||
|
|
||||||
원칙:
|
원칙:
|
||||||
- **Decomposition** — 한 sprint 에 한 모듈·한 feature 만.
|
- **Decomposition** — 한 sprint 에 한 feature 만.
|
||||||
- **File-based handoff** — 대화 턴이 아니라 PLAN.md / PROGRESS.md / `docs/contracts/*.md` 로 인계.
|
- **File-based handoff** — 대화 턴이 아니라 PLAN.md / PROGRESS.md / `docs/contracts/*.md` 로 인계.
|
||||||
- **Context reset over compaction** — 컨텍스트 압박 시 `/handoff` 로 상태 스냅샷 후 새 세션 시작.
|
- **Context reset over compaction** — 컨텍스트 압박 시 `/handoff` 로 상태 스냅샷 후 새 세션 시작.
|
||||||
- **Evaluator tuning loop** — evaluator 의 판단이 사용자와 어긋나면 evaluator 프롬프트를 갱신.
|
- **Evaluator tuning loop** — evaluator 의 판단이 사용자와 어긋나면 evaluator 프롬프트를 갱신.
|
||||||
@@ -57,7 +60,7 @@
|
|||||||
[user] → /start # PLAN+PROGRESS 자동 로드·요약
|
[user] → /start # PLAN+PROGRESS 자동 로드·요약
|
||||||
→ /sprint <id> # plan-architect → contract 생성
|
→ /sprint <id> # plan-architect → contract 생성
|
||||||
→ builder agent 작업 # generator
|
→ builder agent 작업 # generator
|
||||||
→ /eval <module> # module-evaluator → pass/fail
|
→ /eval A # module-evaluator → PCK pass/fail
|
||||||
→ /progress # PROGRESS.md 갱신
|
→ /progress # PROGRESS.md 갱신
|
||||||
↳ context 부족 시 /handoff 후 새 세션
|
↳ context 부족 시 /handoff 후 새 세션
|
||||||
```
|
```
|
||||||
@@ -75,30 +78,27 @@ detectelectronpole/
|
|||||||
│ ├── research.md
|
│ ├── research.md
|
||||||
│ ├── contracts/ ← sprint contract 파일 (S<n>-contract.md)
|
│ ├── contracts/ ← sprint contract 파일 (S<n>-contract.md)
|
||||||
│ └── handoffs/ ← context 핸드오프 스냅샷
|
│ └── handoffs/ ← context 핸드오프 스냅샷
|
||||||
├── data/ ← 드론 원본·SfM·라벨 (gitignored)
|
├── data/ ← 드론 원본·라벨 (gitignored)
|
||||||
├── configs/ ← MMPose, SegFormer 등 설정
|
├── configs/ ← MMPose 설정
|
||||||
├── src/
|
├── src/
|
||||||
│ ├── detection/ ← 모듈 A, B
|
│ ├── detection/ ← Module A (pole keypoint)
|
||||||
│ ├── triangulation/ ← 모듈 C
|
│ └── self_training/ ← SfM-consistent pseudo-label loop
|
||||||
│ ├── self_training/
|
|
||||||
│ └── export/ ← GeoJSON/DXF
|
|
||||||
├── pipeline/
|
├── pipeline/
|
||||||
│ └── run_full.py ← end-to-end orchestrator
|
│ └── run_detect.py ← detection orchestrator
|
||||||
├── tests/
|
├── tests/
|
||||||
└── .claude/
|
└── .claude/
|
||||||
├── agents/ ← 서브에이전트
|
├── agents/ ← 서브에이전트
|
||||||
├── skills/ ← /start, /sprint, /eval, /progress, /handoff, /contract
|
├── skills/ ← /start, /sprint, /eval, /progress, /handoff, /contract
|
||||||
├── commands/ ← (legacy mirror, skills 와 동일 내용)
|
|
||||||
└── settings.json ← hooks
|
└── settings.json ← hooks
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. 코딩·환경 규약
|
## 6. 코딩·환경 규약
|
||||||
|
|
||||||
- Python 3.11+, `uv` 또는 conda 환경.
|
- Python 3.11+, `uv` 또는 conda 환경.
|
||||||
- 라이브러리: `pycolmap`, `pyceres`, `open3d`, `pdal`, `mmpose`, `transformers`(SegFormer), `albumentations`, `scipy`, `geomdl`, `ezdxf`.
|
- 라이브러리: `mmpose`, `albumentations`, `opencv-python`, `numpy`, `scipy`.
|
||||||
- 타입 힌트 필수, `ruff` + `pytest`.
|
- 타입 힌트 필수, `ruff` + `pytest`.
|
||||||
- 모든 detection 출력은 **COCO-keypoints** (pole) / **GeoJSON-like polyline** (rail) 통합 포맷으로 직렬화.
|
- 모든 detection 출력은 **COCO-keypoints** 포맷 (pole).
|
||||||
- 좌표계: 기본 EPSG:5186 (Korea Central Belt 2010), 로컬 frame 인 경우 GCP 3점으로 변환.
|
- SfM 카메라 포즈는 self-training pseudo-label 생성 용도로만 사용 (3D 출력 없음).
|
||||||
|
|
||||||
## 7. Memory & Imports
|
## 7. Memory & Imports
|
||||||
|
|
||||||
|
|||||||
58
PLAN.md
58
PLAN.md
@@ -1,56 +1,52 @@
|
|||||||
# RailPose3D — PLAN
|
# PoleDetect2D — PLAN
|
||||||
|
|
||||||
> 이 문서는 **불변 기준선(baseline)** 이다. 일상 진행 상태는 [PROGRESS.md](PROGRESS.md) 에 기록한다.
|
> 이 문서는 **불변 기준선(baseline)** 이다. 일상 진행 상태는 [PROGRESS.md](PROGRESS.md) 에 기록한다.
|
||||||
> 자세한 배경·근거는 [docs/plan.md](docs/plan.md) (사용자 승인 plan), [docs/research.md](docs/research.md) 참조.
|
> 자세한 배경·근거는 [docs/plan.md](docs/plan.md), [docs/research.md](docs/research.md) 참조.
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|
||||||
드론 영상(nadir + oblique) 으로부터 **전철주(catenary pole)** 와 **레일(rail)** 등 가늘고 긴 구조물을 검출하고, 기존 SfM 카메라 포즈를 활용해 **3D 좌표(EPSG:5186)** 로 추출한다.
|
드론 영상(nadir + oblique) 으로부터 **라멘구조 전철주(portal-frame catenary pole)** 를 **2D 이미지상에서 정확히 검출**한다.
|
||||||
|
출력은 keypoint 좌표 (픽셀) + 신뢰도이며, 3D 좌표 추출은 이 프로젝트 범위 밖이다.
|
||||||
|
|
||||||
## 핵심 설계 결정 (불변)
|
## 핵심 설계 결정 (불변)
|
||||||
|
|
||||||
1. **메시는 버린다.** SfM dense mesh 의 fragmented 출력에 의존하지 않는다. 카메라 포즈 + ground 분류 dense cloud 만 사용.
|
1. **Pose/keypoint 모델 (bbox 아님).** 라멘구조 4-keypoint `{foot_L, foot_R, head_L, head_R}` 로 기둥 발목/머리를 구조적으로 구분한다.
|
||||||
2. **2D 정확 검출 → 3D 삼각측량.** 가는 물체는 detection-then-triangulate 가 mesh 기반보다 정확.
|
2. **라멘구조 전용 스키마.** 두 수직 기둥과 연결 보(beam)를 가진 H-frame / 문형 가구 구조.
|
||||||
3. **Pose/keypoint 모델 (bbox 아님).** 4-keypoint `{base, top, L_arm, R_arm}` 로 base/완금 구조적 구분.
|
3. **Self-training over SfM.** 30장 라벨을 SfM 카메라 포즈 reprojection 으로 5–20× 증식하여 2D pseudo-label 생성.
|
||||||
4. **Segmentation + skeletonize (lane detector 아님).** 레일은 nadir/oblique view-invariant.
|
4. **Zero-shot bootstrap 우선.** Grounding-DINO + SAM2 로 라벨 없이 시작.
|
||||||
5. **Self-training over SfM.** 30장 라벨을 카메라 포즈로 5–20× 증식.
|
|
||||||
|
|
||||||
## 3-모듈 분해
|
## 단일 모듈 구성
|
||||||
|
|
||||||
- **Module A — Pole Keypoint Detection** (RTMPose-m, 4-keypoint)
|
- **Module A — Pole Keypoint Detection**
|
||||||
- **Module B — Rail Segmentation** (SegFormer-B2, 3-stage transfer + skeletonize)
|
- 대상: 라멘구조 전철주 (portal-frame, 문형 가구)
|
||||||
- **Module C — 2D→3D Triangulation** (DBSCAN association + pycolmap + pyceres / PDAL CSF + Open3D + scipy splprep)
|
- 모델: RTMPose-m (primary) / ViTPose-Base (fallback)
|
||||||
|
- Keypoint: `{foot_L, foot_R, head_L, head_R}` — COCO-keypoints 포맷
|
||||||
|
|
||||||
## Sprint 분할 (마일스톤)
|
## Sprint 분할 (마일스톤)
|
||||||
|
|
||||||
| Sprint | 모듈 | 목표 | 성공 조건 (contract) |
|
| Sprint | 목표 | 성공 조건 (contract) |
|
||||||
|---|---|---|---|
|
|---|---|---|
|
||||||
| **S0** Bootstrap | Infra | 디렉터리·환경·CI 골격 | `pipeline/run_full.py --version` 동작, lint/format pass |
|
| **S0** Bootstrap | 디렉터리·환경·CI 골격 | `pipeline/run_detect.py --version` 동작, lint/format pass |
|
||||||
| **S1** MVP-Zero | A+B | Grounding-DINO + SAM2 zero-label baseline | 30장 검증, pole base 픽셀 오차·rail mIoU 정량화 |
|
| **S1** MVP-Zero | Grounding-DINO+SAM2 zero-label baseline | 30장 pole keypoint 픽셀 오차 baseline 정량화 |
|
||||||
| **S2** Pole-A1 | A | RTMPose-m fine-tune (30장 → 300장 copy-paste aug) | PCK@5px ≥ MVP baseline + 20% |
|
| **S2** Pole-Train | RTMPose-m fine-tune (30장→300장 copy-paste aug) | PCK@5px ≥ S1 baseline + 20% |
|
||||||
| **S3** Rail-B1 | B | SegFormer 3-stage transfer | rail mIoU ≥ 0.70 on 30 holdout |
|
| **S3** Self-train | SfM-consistent self-training loop (2D pseudo-label) | 라운드 N+1 PCK > 라운드 N, 3라운드 연속 |
|
||||||
| **S4** Triangulate | C | DBSCAN + pycolmap + pyceres pole pipeline | 3D pole point reprojection error < 5 px median |
|
| **S4** Korean-variants | 라멘구조 vs 단주 분류 분기, 다형 keypoint | 두 타입 PCK@5px ≥ 0.85 |
|
||||||
| **S5** Rail-3D | C | Open3D raycasting + B-spline rail pipeline | 3D rail Hausdorff vs GCP < 10 cm |
|
|
||||||
| **S6** Self-train | A,B | SfM-consistent self-training loop | 라운드 N+1 PCK > 라운드 N |
|
|
||||||
| **S7** E2E | All | 100m trial section end-to-end | GeoJSON + DXF export, QGIS 시각화 일치 |
|
|
||||||
| **S8** Korean catenary 분기 | A | 단주 vs 문형 가구 분류 + 4kpt 변형 | 두 타입에서 PCK@5px ≥ 0.85 |
|
|
||||||
|
|
||||||
각 sprint 는 시작 시 `/contract <sprint-id>` 로 contract 파일을 생성하고, 완료 시 `/eval <module>` 로 검증한다.
|
각 sprint 는 시작 시 `/contract <sprint-id>` 로 contract 파일을 생성하고, 완료 시 `/eval A` 로 검증한다.
|
||||||
|
|
||||||
## 검증 기준 (정량 지표)
|
## 검증 기준 (정량 지표)
|
||||||
|
|
||||||
- **Module A**: PCK@5px (base keypoint), 30장 holdout
|
- **Module A**: PCK@5px (4 keypoint 전체, 특히 foot_L / foot_R), 30장 holdout
|
||||||
- **Module B**: mIoU (rail mask), Hausdorff (polyline)
|
- 기준 파일: `data/eval/pole_pck.json`
|
||||||
- **Module C**: reprojection error (pole), Hausdorff vs GCP (rail), GeoJSON CRS=EPSG:5186 통과
|
|
||||||
|
|
||||||
## 위험 관리
|
## 위험 관리
|
||||||
|
|
||||||
| 위험 | 대응 |
|
| 위험 | 대응 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 전철주 base 가림 | self-training 으로 다중뷰 일관성 검증 |
|
| 기둥 하단(foot)이 ballast·식생에 가려짐 | SfM pseudo-label 로 다른 뷰의 가시 foot 활용 |
|
||||||
| Windows pycolmap/pyceres 빌드 | conda-forge wheel 우선, 실패 시 WSL2 fallback |
|
| 라멘구조 외 단주 혼입 | S4 에서 pole_type 분기 처리 |
|
||||||
| 좌표계 mismatch | GCP 3점 이상으로 7-param Helmert |
|
| 한국 catenary 다양성 (간격·폭 다양) | copy-paste aug 시 scale 범위 확장 |
|
||||||
| 한국 catenary 다양성 (단주/문형) | S8에서 분기 처리 |
|
| Windows MMPose 빌드 | conda-forge wheel, ONNX export fallback |
|
||||||
|
|
||||||
## 참고 산출물
|
## 참고 산출물
|
||||||
|
|
||||||
|
|||||||
27
PROGRESS.md
27
PROGRESS.md
@@ -1,8 +1,8 @@
|
|||||||
# RailPose3D — PROGRESS
|
# PoleDetect2D — PROGRESS
|
||||||
|
|
||||||
> 이 문서는 **현재 상태**를 추적한다. 모든 에이전트는 작업 시작 시 [PLAN.md](PLAN.md) 와 이 파일을 읽고, 종료 시 이 파일을 갱신한다.
|
> 이 문서는 **현재 상태**를 추적한다. 모든 에이전트는 작업 시작 시 [PLAN.md](PLAN.md) 와 이 파일을 읽고, 종료 시 이 파일을 갱신한다.
|
||||||
|
|
||||||
마지막 업데이트: 2026-04-27 (초기 셋업)
|
마지막 업데이트: 2026-04-28 (범위 축소: 레일 제거, 3D 제거, 라멘구조 전철주 2D 검출로 집중)
|
||||||
|
|
||||||
## Current Sprint
|
## Current Sprint
|
||||||
|
|
||||||
@@ -14,13 +14,9 @@
|
|||||||
|---|---|---|---|---|---|
|
|---|---|---|---|---|---|
|
||||||
| S0 Bootstrap | 🔲 todo | — | — | — | — |
|
| S0 Bootstrap | 🔲 todo | — | — | — | — |
|
||||||
| S1 MVP-Zero | 🔲 todo | — | — | — | — |
|
| S1 MVP-Zero | 🔲 todo | — | — | — | — |
|
||||||
| S2 Pole-A1 | 🔲 todo | — | — | — | — |
|
| S2 Pole-Train | 🔲 todo | — | — | — | — |
|
||||||
| S3 Rail-B1 | 🔲 todo | — | — | — | — |
|
| S3 Self-train | 🔲 todo | — | — | — | — |
|
||||||
| S4 Triangulate | 🔲 todo | — | — | — | — |
|
| S4 Korean-variants | 🔲 todo | — | — | — | — |
|
||||||
| S5 Rail-3D | 🔲 todo | — | — | — | — |
|
|
||||||
| S6 Self-train | 🔲 todo | — | — | — | — |
|
|
||||||
| S7 E2E | 🔲 todo | — | — | — | — |
|
|
||||||
| S8 Korean variants | 🔲 todo | — | — | — | — |
|
|
||||||
|
|
||||||
상태 표기: 🔲 todo / 🔄 in-progress / ✅ done / ⛔ blocked
|
상태 표기: 🔲 todo / 🔄 in-progress / ✅ done / ⛔ blocked
|
||||||
|
|
||||||
@@ -29,24 +25,25 @@
|
|||||||
**Sprint S0 Bootstrap** 시작. 작업 항목:
|
**Sprint S0 Bootstrap** 시작. 작업 항목:
|
||||||
|
|
||||||
1. 프로젝트 디렉터리 골격 생성 (`src/`, `configs/`, `data/`, `pipeline/`)
|
1. 프로젝트 디렉터리 골격 생성 (`src/`, `configs/`, `data/`, `pipeline/`)
|
||||||
2. `pyproject.toml` + 의존성 (uv 또는 conda env)
|
2. `pyproject.toml` + 의존성 (mmpose, albumentations, ruff, pytest)
|
||||||
3. pre-commit / ruff / pytest 셋업
|
3. pre-commit / ruff / pytest 셋업
|
||||||
4. `pipeline/run_full.py` placeholder
|
4. `pipeline/run_detect.py` placeholder (pole detection only)
|
||||||
5. README 갱신 (RailPose3D 명명 반영)
|
5. README 갱신 (PoleDetect2D 범위 반영)
|
||||||
|
|
||||||
→ 시작하려면 `/sprint S0` 또는 `plan-architect` 에이전트 호출.
|
→ 시작하려면 `/sprint S0` 또는 `plan-architect` 에이전트 호출.
|
||||||
|
|
||||||
## Blockers / Open Questions
|
## Blockers / Open Questions
|
||||||
|
|
||||||
- [ ] 사용자에게서 실제 드론 영상 + Metashape export 확보 시점 미확정
|
- [ ] 라멘구조 전철주 실제 드론 영상 확보 시점 미확정
|
||||||
- [ ] GCP (Ground Control Points) 좌표 데이터 가용성 확인 필요
|
- [ ] 30장 라벨 재작업 필요 — 기존 base 단일 라벨에서 `{foot_L, foot_R, head_L, head_R}` 4-keypoint 로 재라벨링
|
||||||
- [ ] pycolmap/pyceres 윈도우 빌드 가능 여부 — conda-forge에 최신 wheel 있는지 확인 필요
|
- [ ] Windows MMPose 빌드 가능 여부 — conda-forge 확인 필요
|
||||||
|
|
||||||
## Activity Log
|
## Activity Log
|
||||||
|
|
||||||
| 일시 | 에이전트/사용자 | 액션 | 결과 |
|
| 일시 | 에이전트/사용자 | 액션 | 결과 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 2026-04-27 | user | 프로젝트 RailPose3D 명명, harness 구조 셋업 지시 | CLAUDE.md, PLAN.md, PROGRESS.md, .claude/* 생성 |
|
| 2026-04-27 | user | 프로젝트 RailPose3D 명명, harness 구조 셋업 지시 | CLAUDE.md, PLAN.md, PROGRESS.md, .claude/* 생성 |
|
||||||
|
| 2026-04-28 | user | 범위 축소 지시: 레일 제거, 3D 제거, 라멘구조 전철주 2D 검출만 | PLAN.md, PROGRESS.md, CLAUDE.md, agents 갱신 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user