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:
minsung
2026-04-28 08:58:54 +09:00
parent 417f880a87
commit 287f5c256b
8 changed files with 87 additions and 90 deletions

58
PLAN.md
View File

@@ -1,56 +1,52 @@
# RailPose3D — PLAN
# PoleDetect2D — PLAN
> 이 문서는 **불변 기준선(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
드론 영상(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 만 사용.
2. **2D 정확 검출 → 3D 삼각측량.** 가는 물체는 detection-then-triangulate 가 mesh 기반보다 정확.
3. **Pose/keypoint 모델 (bbox 아님).** 4-keypoint `{base, top, L_arm, R_arm}` 로 base/완금 구조적 구분.
4. **Segmentation + skeletonize (lane detector 아님).** 레일은 nadir/oblique view-invariant.
5. **Self-training over SfM.** 30장 라벨을 카메라 포즈로 520× 증식.
1. **Pose/keypoint 모델 (bbox 아님).** 라멘구조 4-keypoint `{foot_L, foot_R, head_L, head_R}` 로 기둥 발목/머리를 구조적으로 구분한다.
2. **라멘구조 전용 스키마.** 두 수직 기둥과 연결 보(beam)를 가진 H-frame / 문형 가구 구조.
3. **Self-training over SfM.** 30장 라벨을 SfM 카메라 포즈 reprojection 으로 520× 증식하여 2D pseudo-label 생성.
4. **Zero-shot bootstrap 우선.** Grounding-DINO + SAM2 로 라벨 없이 시작.
## 3-모듈 분해
## 단일 모듈 구성
- **Module A — Pole Keypoint Detection** (RTMPose-m, 4-keypoint)
- **Module B — Rail Segmentation** (SegFormer-B2, 3-stage transfer + skeletonize)
- **Module C — 2D→3D Triangulation** (DBSCAN association + pycolmap + pyceres / PDAL CSF + Open3D + scipy splprep)
- **Module A — Pole Keypoint Detection**
- 대상: 라멘구조 전철주 (portal-frame, 문형 가구)
- 모델: RTMPose-m (primary) / ViTPose-Base (fallback)
- Keypoint: `{foot_L, foot_R, head_L, head_R}` — COCO-keypoints 포맷
## Sprint 분할 (마일스톤)
| Sprint | 모듈 | 목표 | 성공 조건 (contract) |
|---|---|---|---|
| **S0** Bootstrap | Infra | 디렉터리·환경·CI 골격 | `pipeline/run_full.py --version` 동작, lint/format pass |
| **S1** MVP-Zero | A+B | Grounding-DINO + SAM2 zero-label baseline | 30장 검증, pole base 픽셀 오차·rail mIoU 정량화 |
| **S2** Pole-A1 | A | RTMPose-m fine-tune (30장300장 copy-paste aug) | PCK@5pxMVP baseline + 20% |
| **S3** Rail-B1 | B | SegFormer 3-stage transfer | rail mIoU ≥ 0.70 on 30 holdout |
| **S4** Triangulate | C | DBSCAN + pycolmap + pyceres pole pipeline | 3D pole point reprojection error < 5 px median |
| **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) |
|---|---|---|
| **S0** Bootstrap | 디렉터리·환경·CI 골격 | `pipeline/run_detect.py --version` 동작, lint/format pass |
| **S1** MVP-Zero | Grounding-DINO+SAM2 zero-label baseline | 30장 pole keypoint 픽셀 오차 baseline 정량화 |
| **S2** Pole-Train | RTMPose-m fine-tune (30장300장 copy-paste aug) | PCK@5pxS1 baseline + 20% |
| **S3** Self-train | SfM-consistent self-training loop (2D pseudo-label) | 라운드 N+1 PCK > 라운드 N, 3라운드 연속 |
| **S4** Korean-variants | 라멘구조 vs 단주 분류 분기, 다형 keypoint | 두 타입 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 B**: mIoU (rail mask), Hausdorff (polyline)
- **Module C**: reprojection error (pole), Hausdorff vs GCP (rail), GeoJSON CRS=EPSG:5186 통과
- **Module A**: PCK@5px (4 keypoint 전체, 특히 foot_L / foot_R), 30장 holdout
- 기준 파일: `data/eval/pole_pck.json`
## 위험 관리
| 위험 | 대응 |
|---|---|
| 전철주 base 가림 | self-training 으로 다중뷰 일관성 검증 |
| Windows pycolmap/pyceres 빌드 | conda-forge wheel 우선, 실패 시 WSL2 fallback |
| 좌표계 mismatch | GCP 3점 이상으로 7-param Helmert |
| 한국 catenary 다양성 (단주/문형) | S8에서 분기 처리 |
| 기둥 하단(foot)이 ballast·식생에 가려짐 | SfM pseudo-label 로 다른 뷰의 가시 foot 활용 |
| 라멘구조 외 단주 혼입 | S4 에서 pole_type 분기 처리 |
| 한국 catenary 다양성 (간격·폭 다양) | copy-paste aug 시 scale 범위 확장 |
| Windows MMPose 빌드 | conda-forge wheel, ONNX export fallback |
## 참고 산출물