feat(perception): restore camera-first semantic candidate
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# LAB E52 · восстановление camera-first семантики
|
||||
|
||||
Дата: 2026-07-30
|
||||
|
||||
Статус: принят инженерный кандидат; runtime-модель не изменена и не
|
||||
авторизована
|
||||
|
||||
## Причина
|
||||
|
||||
Операторская проверка E40 показала, что интерфейс выдавал фиксированную
|
||||
`stratum-policy` за уверенность модели. В частности,
|
||||
`geometry-only → occupied-environment` отображалось как решение модели с
|
||||
уверенностью 100%. Из-за этого человек, тележка или часть фасада могли
|
||||
выглядеть как ошибочно распознанный «фон/шум».
|
||||
|
||||
Это не было результатом рабочего camera-first контура. E29 по-прежнему
|
||||
реализует исходное разделение ответственности:
|
||||
|
||||
- камера владеет классом и идентичностью объекта;
|
||||
- LiDAR проверяет геометрическую поддержку и вычисляет дальность;
|
||||
- LiDAR-кластер без camera-детекта не получает семантический класс.
|
||||
|
||||
E40 являлся историческим видимым мета-оценщиком и повторно решал presence по
|
||||
фиксированным правилам поверх E29. E52 не переносит эти правила в runtime.
|
||||
|
||||
## Неизменяемые входы
|
||||
|
||||
- E29/E30:
|
||||
`e30-materialization-841af926d8d28ab93538c46d8f31278a2234c4d1c12c7dc4dc296b249d59735a`;
|
||||
- E40:
|
||||
`e40-perception-product-gate-e96eec9fd68c3ffaaee898d46285dd329191267200011680f084c75095b92e9a`;
|
||||
- полная операторская ревизия E40: 23 из 23 случаев;
|
||||
- camera candidate:
|
||||
`result-f4cebdea8a82698a5b8a65d2c3fbdb0428b88b9dc49fe45f8cb37d740ed83d02`;
|
||||
- camera source:
|
||||
`recorded-camera-602ac89026ed12978619801d`, 4 489 кадров;
|
||||
- Mask R-CNN:
|
||||
`torchvision/maskrcnn_resnet50_fpn_v2`, COCO, threshold 0.5,
|
||||
checkpoint SHA-256
|
||||
`73cbd0190fcbe3ba339921fbce2c3a0b6bb9126c9a133c85e43a2a8e060a109e`.
|
||||
|
||||
Все входные SHA-256 проверены до и после E52. Исходные артефакты не
|
||||
перезаписывались.
|
||||
|
||||
## Метод
|
||||
|
||||
E52 использует уже рассчитанные camera-детекты и выполняет только лёгкое
|
||||
source-bound сопоставление:
|
||||
|
||||
1. берёт 20 случаев, где оператор подтвердил ошибку представления E40;
|
||||
2. отбрасывает camera-боксы больше 25% изображения как патологические;
|
||||
3. для `geometry-only` требует не меньше четырёх выбранных LiDAR-точек;
|
||||
4. camera-бокс должен покрывать не меньше 70% точек выбранного кластера;
|
||||
5. класс берётся только из camera-детекта;
|
||||
6. дальность вычисляется как медиана глубин связанных LiDAR-точек;
|
||||
7. нерешённый кластер остаётся геометрией без класса.
|
||||
|
||||
Для исходных camera-observation используется camera-box IoU не ниже 0.25.
|
||||
Группы `car/bus/truck` сравниваются как транспорт, но исходная camera-метка
|
||||
сохраняется в evidence.
|
||||
|
||||
## Результат
|
||||
|
||||
```text
|
||||
e52-camera-first-restoration-37ea5269a7f49fc84cbe2c394682f30ccc0d06b781d7d734c2f5420ba764b09f
|
||||
```
|
||||
|
||||
| Измерение | Результат |
|
||||
| --- | ---: |
|
||||
| Подтверждённые оператором случаи | 20 |
|
||||
| Подтверждённые `geometry-only` | 8 |
|
||||
| Восстановлена camera-семантика + LiDAR-дальность | 3 |
|
||||
| Намеренно оставлены нерешёнными | 5 |
|
||||
| Pathological full-frame box принят | 0 |
|
||||
|
||||
Восстановленные случаи:
|
||||
|
||||
| Кадр | Camera-класс | Camera score | Покрытие LiDAR | LiDAR range |
|
||||
| ---: | --- | ---: | ---: | ---: |
|
||||
| 167 | truck | 0.979998 | 15/15 | 8.038404 m |
|
||||
| 259 | person | 0.999834 | 49/50 | 0.512825 m |
|
||||
| 3181 | car | 0.878104 | 4/4 | 0.301412 m |
|
||||
|
||||
Кадр 259 подтверждает исходную проблему: YOLOX не дал семантического
|
||||
наблюдения, однако уже рассчитанный camera candidate уверенно выделил человека,
|
||||
а LiDAR обеспечил независимую метрическую дальность.
|
||||
|
||||
Пять случаев не были автоматически «исправлены»:
|
||||
|
||||
- кадры 1270, 1878 и 2535 имеют только 1–2 выбранные LiDAR-точки;
|
||||
- на кадрах 267 и 1080 пересечение давал патологический бокс почти на весь
|
||||
кадр;
|
||||
- E52 не повышает такие случаи до объектов и не выдаёт отсутствие точек за
|
||||
свободное пространство.
|
||||
|
||||
## Решение
|
||||
|
||||
Camera-first принцип восстановлен в отдельном инженерном кандидате:
|
||||
|
||||
```text
|
||||
camera detection
|
||||
→ проверка LiDAR-точек внутри camera bbox
|
||||
→ camera semantic + LiDAR range
|
||||
```
|
||||
|
||||
Runtime E29, sealed E37–E40, K1-команды и persistent map не изменены. Общий
|
||||
Mask R-CNN пока не принят как production detector.
|
||||
|
||||
Следующий gate — прогнать уже рассчитанные детекты через неизменённую
|
||||
ассоциацию E29 в полном source-bound shadow-контуре и измерить:
|
||||
|
||||
- восстановление camera-семантики;
|
||||
- отбрасывание больших ложных боксов;
|
||||
- временную стабильность;
|
||||
- задержку и ресурсную стоимость;
|
||||
- отсутствие регрессии текущих корректных camera-first объектов.
|
||||
|
||||
Только после отдельного явного принятия этого gate кандидат может заменить или
|
||||
дополнить YOLOX в runtime.
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"schema_version": "missioncore.e52-camera-first-restoration-profile/v1",
|
||||
"profile_id": "e52-ravnoves00-camera-first-restoration/v1",
|
||||
"expected_e30_materialization_id": "e30-materialization-841af926d8d28ab93538c46d8f31278a2234c4d1c12c7dc4dc296b249d59735a",
|
||||
"expected_e40_result_id": "e40-perception-product-gate-e96eec9fd68c3ffaaee898d46285dd329191267200011680f084c75095b92e9a",
|
||||
"expected_detector_result_id": "result-f4cebdea8a82698a5b8a65d2c3fbdb0428b88b9dc49fe45f8cb37d740ed83d02",
|
||||
"expected_camera_job_id": "recorded-camera-602ac89026ed12978619801d",
|
||||
"target_labels": [
|
||||
"person",
|
||||
"bicycle",
|
||||
"car",
|
||||
"motorcycle",
|
||||
"bus",
|
||||
"truck"
|
||||
],
|
||||
"label_groups": {
|
||||
"person": [
|
||||
"person"
|
||||
],
|
||||
"two-wheel": [
|
||||
"bicycle",
|
||||
"motorcycle"
|
||||
],
|
||||
"vehicle": [
|
||||
"car",
|
||||
"bus",
|
||||
"truck"
|
||||
]
|
||||
},
|
||||
"minimum_detector_score": 0.5,
|
||||
"maximum_bbox_image_fraction": 0.25,
|
||||
"minimum_selected_lidar_points": 4,
|
||||
"minimum_selected_lidar_coverage": 0.7,
|
||||
"minimum_original_bbox_iou": 0.25
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the immutable E52 camera-first restoration candidate."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from k1link.compute.e52_camera_first_restoration import (
|
||||
build_e52_camera_first_restoration,
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--e30-materialization", type=Path, required=True)
|
||||
parser.add_argument("--e40-result", type=Path, required=True)
|
||||
parser.add_argument("--operator-review", type=Path, required=True)
|
||||
parser.add_argument("--detector-result", type=Path, required=True)
|
||||
parser.add_argument("--profile", type=Path, required=True)
|
||||
parser.add_argument("--output-root", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
result = build_e52_camera_first_restoration(
|
||||
e30_materialization_root=args.e30_materialization,
|
||||
e40_result_root=args.e40_result,
|
||||
operator_review_path=args.operator_review,
|
||||
detector_result_root=args.detector_result,
|
||||
profile_path=args.profile,
|
||||
output_root=args.output_root,
|
||||
)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"result_id": result.result_id,
|
||||
"result_root": str(result.result_root),
|
||||
"metrics": result.report["metrics"],
|
||||
"decision": result.report["decision"],
|
||||
},
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
)
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user