单目3D初始代码
This commit is contained in:
5
tools/model_inference/.gitignore
vendored
Executable file
5
tools/model_inference/.gitignore
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
.cache/
|
||||
__pycache__/
|
||||
core/__pycache__/
|
||||
adapters/__pycache__/
|
||||
data_tools/__pycache__/
|
||||
189
tools/model_inference/README.md
Executable file
189
tools/model_inference/README.md
Executable file
@@ -0,0 +1,189 @@
|
||||
# Two-ROI Exported Model Inference
|
||||
|
||||
`tools/model_inference` contains a self-contained inference pipeline for the exported two-ROI ONNX or TorchScript model.
|
||||
|
||||
## Layout
|
||||
|
||||
- `run_two_roi_exported_onnx_infer.py`
|
||||
Compatibility entry point kept at the original path.
|
||||
- `core/`
|
||||
Core inference pipeline, decode logic, geometry helpers, and shared types.
|
||||
- `adapters/`
|
||||
Input-source adapters for video directories, PDCL clip exports, and event-id resolution.
|
||||
- `scripts/`
|
||||
Shell launchers grouped by usage mode.
|
||||
- `data_tools/`
|
||||
Small preprocessing helpers for CSV/XLSX conversion.
|
||||
- `docs/`
|
||||
Design notes and usage background documents.
|
||||
- `examples/`
|
||||
Sample JSON/CSV/XLSX/txt inputs used by the helper scripts.
|
||||
|
||||
## Files
|
||||
|
||||
- `core/run_two_roi_exported_onnx_infer.py`
|
||||
Main implementation. Reads one clip-export directory, runs two-ROI ONNX or TorchScript inference, decodes 2D/3D results, and saves visualizations plus `predictions.json`.
|
||||
- `core/two_roi_infer_utils.py`
|
||||
Minimal local utilities for ROI crop, calibration handling, 2D decode, top-k selection, and common serialization helpers.
|
||||
- `core/two_roi_3d_utils.py`
|
||||
Minimal local 3D geometry, projection, yaw decoding, and 3D drawing helpers.
|
||||
- `scripts/run_two_roi_exported_onnx_infer.sh`
|
||||
Example shell wrapper.
|
||||
|
||||
## External Dependencies
|
||||
|
||||
This package does not depend on `ultralytics` at runtime.
|
||||
|
||||
Required Python packages:
|
||||
|
||||
- `numpy`
|
||||
- `opencv-python`
|
||||
- `pyyaml`
|
||||
- `onnxruntime` for `.onnx` models
|
||||
- `torch` for `.torchscript` models
|
||||
|
||||
## Expected Input Layout
|
||||
|
||||
The script can take a clip-export directory directly.
|
||||
|
||||
Expected structure:
|
||||
|
||||
```text
|
||||
clip_export_xxx/
|
||||
├── images/
|
||||
│ ├── *.png
|
||||
│ └── ...
|
||||
├── calib/
|
||||
│ └── L2_calib/
|
||||
│ └── camera4.json
|
||||
├── manifest.json
|
||||
└── calib_summary.json
|
||||
```
|
||||
|
||||
The script automatically reads:
|
||||
|
||||
- images from `images/`
|
||||
- calibration from `calib/L2_calib/camera4.json` or `calib/camera4.json`
|
||||
|
||||
## Expected Exported Model Outputs
|
||||
|
||||
The exported model should be the raw-head merged artifact produced by `tools/model_merging/merge_models_of_2roi_yolo26.py`. The same output contract is used for both ONNX and TorchScript.
|
||||
|
||||
Required output tensor names:
|
||||
|
||||
- `roi0_boxes_head_raw`
|
||||
- `roi0_scores_head_raw`
|
||||
- `roi0_preds_3d_head_raw`
|
||||
- `roi1_boxes_head_raw`
|
||||
- `roi1_scores_head_raw`
|
||||
- `roi1_preds_3d_head_raw`
|
||||
|
||||
Optional output tensor names:
|
||||
|
||||
- `roi0_preds_edge_head_raw`
|
||||
- `roi1_preds_edge_head_raw`
|
||||
|
||||
If the merged model is exported with `--edge-head-mode drop`, the runtime keeps the
|
||||
same 2D/3D decode path and automatically disables edge-yaw reconstruction.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```bash
|
||||
python tools/model_inference/run_two_roi_exported_onnx_infer.py \
|
||||
--case-dir tools/pdcl_inference/clip_exports/clip_export_G1M3_G1Q3_6284_019cb7f4-a944-7c22-5427-5b75b25545c7 \
|
||||
--exported-model runs/export/train_mono3d_two_roi_202603251430/merged_model.onnx \
|
||||
--output-dir /tmp/two_roi_exported_model_run
|
||||
```
|
||||
|
||||
For CNCAP JSON batch video inference:
|
||||
|
||||
```bash
|
||||
python tools/model_inference/run_two_roi_exported_onnx_infer.py \
|
||||
--cncap-json-file tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-202411.json \
|
||||
--cncap-path-prefix-src /mnt/hfs/project-G1M3 \
|
||||
--cncap-path-prefix-dst /mnt/G1M3 \
|
||||
--exported-model runs/export/train_mono3d_two_roi_20260403-raw-fuse/merged_model.onnx \
|
||||
--output-dir /tmp/two_roi_exported_model_cncap_run
|
||||
```
|
||||
|
||||
## Shell Wrapper
|
||||
|
||||
```bash
|
||||
bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer.sh
|
||||
```
|
||||
|
||||
Update the paths in the shell script before handing it to downstream users if needed.
|
||||
|
||||
## Important Arguments
|
||||
|
||||
- `--case-dir`
|
||||
Clip-export directory containing `images/` and either `calib/L2_calib/camera4.json` or `calib/camera4.json`.
|
||||
- `--cncap-json-file`
|
||||
CNCAP JSON file containing `values` entries that point to `sigmastar.1` directories. The script rewrites each mounted path prefix, resolves `camera4.bin` plus `test_data/calibs/camera4.json`, and then reuses the video-case inference flow.
|
||||
- `--exported-model`
|
||||
Merged raw-head exported model path. Supports `.onnx` and `.torchscript`.
|
||||
- `--output-dir`
|
||||
Directory used to save visualization images and `predictions.json`.
|
||||
- `--roi0-model`, `--roi1-model`
|
||||
Training checkpoints used only for metadata-free ROI preset alignment are no longer required by any external framework, but are still used as plain path fields in the current CLI contract. Keep them aligned with your deployment pair.
|
||||
- `--roi0-roi`, `--roi1-roi`
|
||||
ROI crop sizes before resize.
|
||||
- `--roi0-imgsz`, `--roi1-imgsz`
|
||||
ROI input tensor sizes used by the exported model. If omitted, the script first tries the export manifest.
|
||||
- `--classes`
|
||||
Optional class-id filter.
|
||||
- `--max-images`
|
||||
Limit the number of images for quick smoke tests.
|
||||
- `--providers`
|
||||
Optional ONNX Runtime providers, for example `CUDAExecutionProvider CPUExecutionProvider`. Only used for `.onnx` models.
|
||||
|
||||
## Outputs
|
||||
|
||||
The script writes:
|
||||
|
||||
- one visualization image per input frame
|
||||
- `predictions.json`
|
||||
|
||||
`predictions.json` contains per-frame, per-ROI prediction records including:
|
||||
|
||||
- 2D box
|
||||
- confidence
|
||||
- class id and class name
|
||||
- yaw
|
||||
- edge-yaw diagnostics
|
||||
- decoded 3D center
|
||||
- ROI crop bounds
|
||||
|
||||
## Notes
|
||||
|
||||
- This pipeline intentionally runs decode and postprocess outside the exported graph.
|
||||
- It is useful for downstream deployment and migration because the runtime path only depends on common Python packages.
|
||||
- If the exported model export mode changes, make sure the output tensor names still match the names listed above.
|
||||
|
||||
## Known Residuals
|
||||
|
||||
Validation against the batch PyTorch reference path
|
||||
`tools/pdcl_inference/two_roi_inference.py` on the first 20 frames of
|
||||
`clip_export_G1M3_G1Q3_6284_019cb7f4-a944-7c22-5427-5b75b25545c7`
|
||||
shows that the self-contained ONNX path matches the 3D branch decisions
|
||||
after bbox-based matching:
|
||||
|
||||
- `visible_face_type` mismatch: `0`
|
||||
- `visible_face_types` mismatch: `0`
|
||||
- `edge_yaw_confident` mismatch: `0`
|
||||
|
||||
Two near-threshold count mismatches are still treated as known residuals.
|
||||
In both cases the PyTorch batch path keeps one extra `cls_id=6` detection
|
||||
with confidence just above the `0.25` threshold, while the ONNX path drops it:
|
||||
|
||||
- `019cb7f4-a944-7c22-5427-5b75b25545c7_80364.png`, `roi0`
|
||||
Batch-only detection: `conf=0.252197`
|
||||
- `019cb7f4-a944-7c22-5427-5b75b25545c7_80370.png`, `roi0`
|
||||
Batch-only detection: `conf=0.251094`
|
||||
|
||||
Current interpretation:
|
||||
|
||||
- These residuals are consistent with small ONNX vs PyTorch numerical drift
|
||||
around the confidence threshold.
|
||||
- The implementation is intentionally kept unchanged; no extra confidence
|
||||
epsilon is applied just to eliminate these edge cases.
|
||||
1
tools/model_inference/__init__.py
Executable file
1
tools/model_inference/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
"""Two-ROI model inference package."""
|
||||
1
tools/model_inference/adapters/__init__.py
Executable file
1
tools/model_inference/adapters/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
"""Input adapters for model_inference batch sources."""
|
||||
822
tools/model_inference/adapters/eventid_clip_resolver.py
Executable file
822
tools/model_inference/adapters/eventid_clip_resolver.py
Executable file
@@ -0,0 +1,822 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
import re
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
try:
|
||||
from .get_clip_by_eventid import get_associated_clip_ids
|
||||
from .pdcl_clip_export_utils import (
|
||||
build_clip_tasks_from_clip_ids,
|
||||
run_clip_tasks_inference_exported,
|
||||
)
|
||||
except ImportError:
|
||||
from get_clip_by_eventid import get_associated_clip_ids
|
||||
from pdcl_clip_export_utils import (
|
||||
build_clip_tasks_from_clip_ids,
|
||||
run_clip_tasks_inference_exported,
|
||||
)
|
||||
|
||||
DEFAULT_EVENT_CACHE_FILE = Path(__file__).resolve().parents[1] / ".cache" / "event_clip_cache.json"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ResolvedEventRecord:
|
||||
scene: str
|
||||
record_index: int
|
||||
event_id: str
|
||||
event_id_field_used: str
|
||||
source_record: dict[str, Any]
|
||||
clip_ids: list[str]
|
||||
clip_source: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EventResolutionStats:
|
||||
total_events: int
|
||||
cache_hits: int
|
||||
cache_misses: int
|
||||
request_workers: int
|
||||
cache_file: str
|
||||
direct_clip_records: int = 0
|
||||
event_lookup_records: int = 0
|
||||
|
||||
|
||||
def _dedupe_preserve_order(values: list[str]) -> list[str]:
|
||||
ordered: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for value in values:
|
||||
token = str(value).strip()
|
||||
if not token or token in seen:
|
||||
continue
|
||||
seen.add(token)
|
||||
ordered.append(token)
|
||||
return ordered
|
||||
|
||||
|
||||
def _sanitize_identifier_for_path(identifier: str, prefix: str = "event_id") -> str:
|
||||
token = re.sub(r'[\\/:*?"<>|\s]+', "_", str(identifier or "").strip())
|
||||
token = token.strip("._")
|
||||
token = token or "unknown_id"
|
||||
normalized_prefix = re.sub(r"[^0-9A-Za-z]+", "_", str(prefix or "").strip())
|
||||
normalized_prefix = normalized_prefix.strip("._") or "id"
|
||||
return f"{normalized_prefix}_{token}"
|
||||
|
||||
|
||||
def _build_resolution_stats_payload(resolution_stats: "EventResolutionStats") -> dict[str, Any]:
|
||||
return {
|
||||
"total_events": resolution_stats.total_events,
|
||||
"cache_hits": resolution_stats.cache_hits,
|
||||
"cache_misses": resolution_stats.cache_misses,
|
||||
"request_workers": resolution_stats.request_workers,
|
||||
"cache_file": resolution_stats.cache_file,
|
||||
"direct_clip_records": resolution_stats.direct_clip_records,
|
||||
"event_lookup_records": resolution_stats.event_lookup_records,
|
||||
}
|
||||
|
||||
|
||||
def _record_key(record: "ResolvedEventRecord") -> tuple[str, int, str]:
|
||||
return (record.scene, int(record.record_index), str(record.event_id))
|
||||
|
||||
|
||||
def _normalize_direct_clip_ids(raw_value: Any) -> list[str]:
|
||||
if isinstance(raw_value, list):
|
||||
return _dedupe_preserve_order([str(item).strip() for item in raw_value if str(item).strip()])
|
||||
|
||||
if isinstance(raw_value, str):
|
||||
text = raw_value.strip()
|
||||
if not text:
|
||||
return []
|
||||
if text.startswith("["):
|
||||
try:
|
||||
parsed = json.loads(text)
|
||||
except Exception:
|
||||
parsed = None
|
||||
if isinstance(parsed, list):
|
||||
return _dedupe_preserve_order([str(item).strip() for item in parsed if str(item).strip()])
|
||||
return _dedupe_preserve_order([token for token in re.split(r"[\s,]+", text) if token])
|
||||
|
||||
if raw_value is None:
|
||||
return []
|
||||
|
||||
token = str(raw_value).strip()
|
||||
if not token:
|
||||
return []
|
||||
return [token]
|
||||
|
||||
|
||||
def _extract_direct_clip_ids(record: dict[str, Any], clip_ids_field: str) -> tuple[bool, list[str]]:
|
||||
field_name = str(clip_ids_field or "").strip()
|
||||
if not field_name or field_name not in record:
|
||||
return False, []
|
||||
return True, _normalize_direct_clip_ids(record.get(field_name))
|
||||
|
||||
|
||||
def _resolve_record_identifier(
|
||||
record: dict[str, Any],
|
||||
preferred_field: str,
|
||||
*,
|
||||
allow_direct_clip_fallback: bool = False,
|
||||
) -> tuple[str, str]:
|
||||
candidate_fields: list[str] = []
|
||||
preferred_token = str(preferred_field or "").strip()
|
||||
if preferred_token:
|
||||
candidate_fields.append(preferred_token)
|
||||
|
||||
if allow_direct_clip_fallback:
|
||||
for field_name in ("rawid", "event_id", "data_path"):
|
||||
if field_name not in candidate_fields:
|
||||
candidate_fields.append(field_name)
|
||||
|
||||
for field_name in candidate_fields:
|
||||
identifier = str(record.get(field_name, "")).strip()
|
||||
if identifier:
|
||||
return identifier, field_name
|
||||
|
||||
return "", preferred_token
|
||||
|
||||
|
||||
def _extract_condition_values(source_record: dict[str, Any], condition_fields: list[str]) -> dict[str, str]:
|
||||
return {
|
||||
str(field): str(source_record.get(field, "")).strip()
|
||||
for field in condition_fields
|
||||
}
|
||||
|
||||
|
||||
def _select_event_records_by_condition(
|
||||
records: list["ResolvedEventRecord"],
|
||||
*,
|
||||
condition_fields: list[str],
|
||||
max_records_per_condition: int,
|
||||
selection_strategy: str,
|
||||
) -> tuple[list["ResolvedEventRecord"], dict[str, Any]]:
|
||||
normalized_fields = [str(field).strip() for field in condition_fields if str(field).strip()]
|
||||
limit = max(0, int(max_records_per_condition))
|
||||
selection_enabled = bool(normalized_fields and limit > 0)
|
||||
summary: dict[str, Any] = {
|
||||
"enabled": selection_enabled,
|
||||
"condition_fields": normalized_fields,
|
||||
"max_records_per_condition": limit,
|
||||
"selection_strategy": selection_strategy,
|
||||
"records_before_selection": len(records),
|
||||
"records_after_selection": len(records),
|
||||
"group_count": 0,
|
||||
"groups": [],
|
||||
}
|
||||
if not selection_enabled:
|
||||
return list(records), summary
|
||||
|
||||
if selection_strategy != "first":
|
||||
raise ValueError(f"Unsupported condition selection strategy: {selection_strategy!r}")
|
||||
|
||||
selected_records: list[ResolvedEventRecord] = []
|
||||
selected_counts: dict[tuple[str, tuple[str, ...]], int] = {}
|
||||
group_summaries: dict[tuple[str, tuple[str, ...]], dict[str, Any]] = {}
|
||||
|
||||
for record in records:
|
||||
condition_values = _extract_condition_values(record.source_record, normalized_fields)
|
||||
condition_tuple = tuple(condition_values[field] for field in normalized_fields)
|
||||
group_key = (record.scene, condition_tuple)
|
||||
group_summary = group_summaries.setdefault(
|
||||
group_key,
|
||||
{
|
||||
"scene": record.scene,
|
||||
"condition_values": condition_values,
|
||||
"record_count": 0,
|
||||
"selected_count": 0,
|
||||
"skipped_count": 0,
|
||||
"selected_record_ids": [],
|
||||
"selected_record_indices": [],
|
||||
"skipped_record_ids": [],
|
||||
"skipped_record_indices": [],
|
||||
},
|
||||
)
|
||||
group_summary["record_count"] += 1
|
||||
current_selected_count = selected_counts.get(group_key, 0)
|
||||
|
||||
if current_selected_count < limit:
|
||||
selected_records.append(record)
|
||||
selected_counts[group_key] = current_selected_count + 1
|
||||
group_summary["selected_count"] += 1
|
||||
group_summary["selected_record_ids"].append(record.event_id)
|
||||
group_summary["selected_record_indices"].append(record.record_index)
|
||||
continue
|
||||
|
||||
group_summary["skipped_count"] += 1
|
||||
group_summary["skipped_record_ids"].append(record.event_id)
|
||||
group_summary["skipped_record_indices"].append(record.record_index)
|
||||
|
||||
summary["records_after_selection"] = len(selected_records)
|
||||
summary["group_count"] = len(group_summaries)
|
||||
summary["groups"] = list(group_summaries.values())
|
||||
return selected_records, summary
|
||||
|
||||
|
||||
def _filter_selection_summary_for_scene(selection_summary: dict[str, Any], scene: str) -> dict[str, Any]:
|
||||
if not selection_summary:
|
||||
return {}
|
||||
|
||||
scene_groups = [
|
||||
dict(group)
|
||||
for group in selection_summary.get("groups", [])
|
||||
if str(group.get("scene", "")) == str(scene)
|
||||
]
|
||||
filtered = dict(selection_summary)
|
||||
filtered["groups"] = scene_groups
|
||||
filtered["group_count"] = len(scene_groups)
|
||||
if scene_groups:
|
||||
filtered["records_before_selection"] = sum(int(group.get("record_count", 0)) for group in scene_groups)
|
||||
filtered["records_after_selection"] = sum(int(group.get("selected_count", 0)) for group in scene_groups)
|
||||
else:
|
||||
filtered["records_before_selection"] = 0
|
||||
filtered["records_after_selection"] = 0
|
||||
return filtered
|
||||
|
||||
|
||||
def _format_condition_summary(source_record: dict[str, Any], condition_fields: list[str]) -> str:
|
||||
normalized_fields = [str(field).strip() for field in condition_fields if str(field).strip()]
|
||||
if not normalized_fields:
|
||||
return ""
|
||||
values = _extract_condition_values(source_record, normalized_fields)
|
||||
return ", ".join(f"{field}={values.get(field, '')}" for field in normalized_fields)
|
||||
|
||||
|
||||
def _print_event_json_summary(
|
||||
*,
|
||||
args: argparse.Namespace,
|
||||
manifest_path: Path,
|
||||
resolved_records: list["ResolvedEventRecord"],
|
||||
selected_records: list["ResolvedEventRecord"],
|
||||
selection_summary: dict[str, Any],
|
||||
scene_results: dict[str, dict[str, Any]],
|
||||
) -> None:
|
||||
print(f"Event JSON file: {args.event_json_file}")
|
||||
if args.scene:
|
||||
print(f"Scene filter: {args.scene}")
|
||||
print(
|
||||
"Resolved records: "
|
||||
f"{len(resolved_records)}, selected records: {len(selected_records)}"
|
||||
)
|
||||
print(f"Manifest: {manifest_path}")
|
||||
|
||||
if not selected_records:
|
||||
print("No records selected.")
|
||||
return
|
||||
|
||||
condition_fields = [str(field).strip() for field in getattr(args, "condition_fields", []) if str(field).strip()]
|
||||
if args.selection_only:
|
||||
print("Selection-only mode: no clip export or inference was run.")
|
||||
elif selection_summary.get("enabled"):
|
||||
print(
|
||||
"Condition selection: "
|
||||
f"{selection_summary.get('group_count', 0)} groups, "
|
||||
f"strategy={selection_summary.get('selection_strategy', '')}, "
|
||||
f"max_records_per_condition={selection_summary.get('max_records_per_condition', 0)}"
|
||||
)
|
||||
|
||||
for scene in sorted(scene_results):
|
||||
scene_result = scene_results[scene]
|
||||
print(
|
||||
f"Scene {scene}: selected_record_count="
|
||||
f"{scene_result.get('selected_record_count', len([record for record in selected_records if record.scene == scene]))}"
|
||||
)
|
||||
scene_manifest_path = scene_result.get("scene_manifest_path")
|
||||
if scene_manifest_path:
|
||||
print(f" Scene manifest: {scene_manifest_path}")
|
||||
if scene_result.get("scene_output_dir"):
|
||||
print(f" Output dir: {scene_result['scene_output_dir']}")
|
||||
|
||||
scene_records = [record for record in selected_records if record.scene == scene]
|
||||
for record in scene_records:
|
||||
condition_summary = _format_condition_summary(record.source_record, condition_fields)
|
||||
summary_parts = []
|
||||
if condition_summary:
|
||||
summary_parts.append(condition_summary)
|
||||
summary_parts.append(f"record_id={record.event_id}")
|
||||
summary_parts.append(f"clips={len(record.clip_ids)}")
|
||||
print(f" - {'; '.join(summary_parts)}")
|
||||
|
||||
|
||||
def _build_scene_manifest_payload(
|
||||
*,
|
||||
args: argparse.Namespace,
|
||||
scene: str,
|
||||
scene_records: list["ResolvedEventRecord"],
|
||||
resolution_stats: "EventResolutionStats",
|
||||
selection_summary: Optional[dict[str, Any]] = None,
|
||||
) -> dict[str, Any]:
|
||||
payload = {
|
||||
"event_json_file": args.event_json_file,
|
||||
"scene": scene,
|
||||
"event_id_field": args.event_id_field,
|
||||
"event_clip_ids_field": args.event_clip_ids_field,
|
||||
"resolution_stats": _build_resolution_stats_payload(resolution_stats),
|
||||
"event_record_count": len(scene_records),
|
||||
"records": [
|
||||
{
|
||||
"record_index": record.record_index,
|
||||
"event_id": record.event_id,
|
||||
"event_id_field_used": record.event_id_field_used,
|
||||
"clip_ids": record.clip_ids,
|
||||
"clip_source": record.clip_source,
|
||||
"source_record": record.source_record,
|
||||
}
|
||||
for record in scene_records
|
||||
],
|
||||
}
|
||||
if selection_summary is not None:
|
||||
payload["selection"] = selection_summary
|
||||
return payload
|
||||
|
||||
|
||||
def _build_event_manifest_payload(
|
||||
*,
|
||||
args: argparse.Namespace,
|
||||
scene: str,
|
||||
event_id: str,
|
||||
event_records: list["ResolvedEventRecord"],
|
||||
clip_ids: list[str],
|
||||
resolution_stats: "EventResolutionStats",
|
||||
) -> dict[str, Any]:
|
||||
condition_fields = [str(field).strip() for field in getattr(args, "condition_fields", []) if str(field).strip()]
|
||||
payload = {
|
||||
"event_json_file": args.event_json_file,
|
||||
"scene": scene,
|
||||
"event_id_field": args.event_id_field,
|
||||
"event_clip_ids_field": args.event_clip_ids_field,
|
||||
"event_id": event_id,
|
||||
"resolution_stats": _build_resolution_stats_payload(resolution_stats),
|
||||
"event_record_count": len(event_records),
|
||||
"clip_ids": clip_ids,
|
||||
"clip_count": len(clip_ids),
|
||||
"records": [
|
||||
{
|
||||
"record_index": record.record_index,
|
||||
"event_id": record.event_id,
|
||||
"event_id_field_used": record.event_id_field_used,
|
||||
"clip_ids": record.clip_ids,
|
||||
"clip_source": record.clip_source,
|
||||
"source_record": record.source_record,
|
||||
}
|
||||
for record in event_records
|
||||
],
|
||||
}
|
||||
if event_records:
|
||||
payload["event_id_field_used"] = event_records[0].event_id_field_used
|
||||
payload["clip_source"] = sorted({record.clip_source for record in event_records})
|
||||
if condition_fields and event_records:
|
||||
payload["condition_values"] = _extract_condition_values(event_records[0].source_record, condition_fields)
|
||||
return payload
|
||||
|
||||
|
||||
def load_event_scene_json(json_file: str) -> dict[str, list[dict[str, Any]]]:
|
||||
path = Path(json_file)
|
||||
with path.open("r", encoding="utf-8") as file:
|
||||
payload = json.load(file)
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError(f"Expected top-level dict in {path}, got {type(payload).__name__}")
|
||||
|
||||
normalized: dict[str, list[dict[str, Any]]] = {}
|
||||
for scene, records in payload.items():
|
||||
if not isinstance(records, list):
|
||||
raise ValueError(f"Scene {scene!r} should map to a list, got {type(records).__name__}")
|
||||
normalized[str(scene)] = [dict(item) if isinstance(item, dict) else {"value": item} for item in records]
|
||||
return normalized
|
||||
|
||||
|
||||
def load_event_clip_cache(cache_file: str | Path) -> dict[str, list[str]]:
|
||||
cache_path = Path(cache_file)
|
||||
if not cache_path.exists():
|
||||
return {}
|
||||
|
||||
try:
|
||||
payload = json.loads(cache_path.read_text(encoding="utf-8"))
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
if not isinstance(payload, dict):
|
||||
return {}
|
||||
|
||||
cache: dict[str, list[str]] = {}
|
||||
for event_id, clip_ids in payload.items():
|
||||
if isinstance(clip_ids, list):
|
||||
cache[str(event_id)] = [str(item).strip() for item in clip_ids if str(item).strip()]
|
||||
return cache
|
||||
|
||||
|
||||
def save_event_clip_cache(cache_file: str | Path, cache_payload: dict[str, list[str]]) -> Path:
|
||||
cache_path = Path(cache_file)
|
||||
cache_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
normalized = {
|
||||
str(event_id): [str(item).strip() for item in clip_ids if str(item).strip()]
|
||||
for event_id, clip_ids in cache_payload.items()
|
||||
}
|
||||
with cache_path.open("w", encoding="utf-8") as file:
|
||||
json.dump(normalized, file, indent=2, ensure_ascii=False)
|
||||
return cache_path
|
||||
|
||||
|
||||
def resolve_event_clip_ids(
|
||||
event_ids: list[str],
|
||||
*,
|
||||
timeout: float = 60.0,
|
||||
cache_file: str | Path = DEFAULT_EVENT_CACHE_FILE,
|
||||
workers: int = 4,
|
||||
max_retries: int = 3,
|
||||
retry_backoff_sec: float = 2.0,
|
||||
) -> tuple[dict[str, list[str]], EventResolutionStats]:
|
||||
ordered_event_ids: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for event_id in event_ids:
|
||||
normalized = str(event_id).strip()
|
||||
if not normalized or normalized in seen:
|
||||
continue
|
||||
seen.add(normalized)
|
||||
ordered_event_ids.append(normalized)
|
||||
|
||||
cache_payload = load_event_clip_cache(cache_file)
|
||||
resolved: dict[str, list[str]] = {}
|
||||
unresolved_event_ids: list[str] = []
|
||||
cache_hits = 0
|
||||
cache_misses = 0
|
||||
|
||||
for event_id in ordered_event_ids:
|
||||
if event_id in cache_payload:
|
||||
resolved[event_id] = list(cache_payload[event_id])
|
||||
cache_hits += 1
|
||||
else:
|
||||
unresolved_event_ids.append(event_id)
|
||||
cache_misses += 1
|
||||
|
||||
if unresolved_event_ids:
|
||||
max_workers = max(1, min(int(workers), len(unresolved_event_ids)))
|
||||
if max_workers == 1:
|
||||
for event_id in unresolved_event_ids:
|
||||
clip_ids = get_associated_clip_ids(
|
||||
event_id,
|
||||
timeout=timeout,
|
||||
max_retries=max_retries,
|
||||
retry_backoff_sec=retry_backoff_sec,
|
||||
)
|
||||
resolved[event_id] = clip_ids
|
||||
cache_payload[event_id] = clip_ids
|
||||
else:
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
future_to_event_id = {
|
||||
executor.submit(
|
||||
get_associated_clip_ids,
|
||||
event_id,
|
||||
timeout,
|
||||
max_retries,
|
||||
retry_backoff_sec,
|
||||
): event_id
|
||||
for event_id in unresolved_event_ids
|
||||
}
|
||||
for future in as_completed(future_to_event_id):
|
||||
event_id = future_to_event_id[future]
|
||||
clip_ids = future.result()
|
||||
resolved[event_id] = clip_ids
|
||||
cache_payload[event_id] = clip_ids
|
||||
save_event_clip_cache(cache_file, cache_payload)
|
||||
worker_count = max(1, min(int(workers), len(unresolved_event_ids)))
|
||||
else:
|
||||
worker_count = 0
|
||||
|
||||
stats = EventResolutionStats(
|
||||
total_events=len(ordered_event_ids),
|
||||
cache_hits=cache_hits,
|
||||
cache_misses=cache_misses,
|
||||
request_workers=worker_count,
|
||||
cache_file=str(Path(cache_file).resolve()),
|
||||
)
|
||||
return resolved, stats
|
||||
|
||||
|
||||
def resolve_event_records(
|
||||
json_file: str,
|
||||
scene_filter: Optional[str] = None,
|
||||
event_id_field: str = "data_path",
|
||||
clip_ids_field: str = "clips",
|
||||
max_events: int = 0,
|
||||
timeout: float = 60.0,
|
||||
cache_file: str | Path = DEFAULT_EVENT_CACHE_FILE,
|
||||
workers: int = 4,
|
||||
max_retries: int = 3,
|
||||
retry_backoff_sec: float = 2.0,
|
||||
) -> tuple[list[ResolvedEventRecord], EventResolutionStats]:
|
||||
scene_payload = load_event_scene_json(json_file)
|
||||
scene_names = [scene_filter] if scene_filter else list(scene_payload)
|
||||
pending_records: list[tuple[str, int, dict[str, Any], str, str, list[str], str]] = []
|
||||
lookup_event_ids: list[str] = []
|
||||
processed = 0
|
||||
direct_clip_records = 0
|
||||
event_lookup_records = 0
|
||||
|
||||
for scene in scene_names:
|
||||
records = scene_payload.get(scene)
|
||||
if records is None:
|
||||
raise ValueError(f"Scene {scene!r} not found in {json_file}")
|
||||
|
||||
for index, record in enumerate(records):
|
||||
has_direct_clip_ids, direct_clip_ids = _extract_direct_clip_ids(record, clip_ids_field)
|
||||
event_id, resolved_id_field = _resolve_record_identifier(
|
||||
record,
|
||||
event_id_field,
|
||||
allow_direct_clip_fallback=has_direct_clip_ids,
|
||||
)
|
||||
if not event_id:
|
||||
continue
|
||||
|
||||
clip_source = "direct_clip_ids_field" if has_direct_clip_ids else "event_lookup"
|
||||
if has_direct_clip_ids:
|
||||
direct_clip_records += 1
|
||||
else:
|
||||
event_lookup_records += 1
|
||||
lookup_event_ids.append(event_id)
|
||||
|
||||
pending_records.append(
|
||||
(scene, index, record, event_id, resolved_id_field, direct_clip_ids, clip_source)
|
||||
)
|
||||
processed += 1
|
||||
if max_events > 0 and processed >= max_events:
|
||||
break
|
||||
if max_events > 0 and processed >= max_events:
|
||||
break
|
||||
|
||||
resolved_clip_map: dict[str, list[str]] = {}
|
||||
lookup_stats = EventResolutionStats(
|
||||
total_events=0,
|
||||
cache_hits=0,
|
||||
cache_misses=0,
|
||||
request_workers=0,
|
||||
cache_file=str(Path(cache_file).resolve()),
|
||||
)
|
||||
if lookup_event_ids:
|
||||
resolved_clip_map, lookup_stats = resolve_event_clip_ids(
|
||||
lookup_event_ids,
|
||||
timeout=timeout,
|
||||
cache_file=cache_file,
|
||||
workers=workers,
|
||||
max_retries=max_retries,
|
||||
retry_backoff_sec=retry_backoff_sec,
|
||||
)
|
||||
|
||||
resolved = [
|
||||
ResolvedEventRecord(
|
||||
scene=scene,
|
||||
record_index=index,
|
||||
event_id=event_id,
|
||||
event_id_field_used=resolved_id_field,
|
||||
source_record=record,
|
||||
clip_ids=direct_clip_ids if clip_source == "direct_clip_ids_field" else resolved_clip_map.get(event_id, []),
|
||||
clip_source=clip_source,
|
||||
)
|
||||
for scene, index, record, event_id, resolved_id_field, direct_clip_ids, clip_source in pending_records
|
||||
]
|
||||
stats = EventResolutionStats(
|
||||
total_events=len(pending_records),
|
||||
cache_hits=lookup_stats.cache_hits,
|
||||
cache_misses=lookup_stats.cache_misses,
|
||||
request_workers=lookup_stats.request_workers,
|
||||
cache_file=str(Path(cache_file).resolve()),
|
||||
direct_clip_records=direct_clip_records,
|
||||
event_lookup_records=event_lookup_records,
|
||||
)
|
||||
return resolved, stats
|
||||
|
||||
|
||||
def build_event_resolution_payload(
|
||||
json_file: str,
|
||||
resolved_records: list[ResolvedEventRecord],
|
||||
event_id_field: str,
|
||||
clip_ids_field: str,
|
||||
stats: EventResolutionStats,
|
||||
selection_summary: Optional[dict[str, Any]] = None,
|
||||
selected_record_keys: Optional[set[tuple[str, int, str]]] = None,
|
||||
) -> dict[str, Any]:
|
||||
selection_enabled = bool(selection_summary and selection_summary.get("enabled"))
|
||||
selected_keys = selected_record_keys or set()
|
||||
scenes: dict[str, list[dict[str, Any]]] = {}
|
||||
for record in resolved_records:
|
||||
scenes.setdefault(record.scene, []).append(
|
||||
{
|
||||
"record_index": record.record_index,
|
||||
"event_id_field": event_id_field,
|
||||
"event_id_field_used": record.event_id_field_used,
|
||||
"event_id": record.event_id,
|
||||
"event_clip_ids_field": clip_ids_field,
|
||||
"clip_ids": record.clip_ids,
|
||||
"clip_count": len(record.clip_ids),
|
||||
"clip_source": record.clip_source,
|
||||
"selected_for_inference": True if not selection_enabled else _record_key(record) in selected_keys,
|
||||
"source_record": record.source_record,
|
||||
}
|
||||
)
|
||||
|
||||
payload = {
|
||||
"event_json_file": json_file,
|
||||
"event_id_field": event_id_field,
|
||||
"event_clip_ids_field": clip_ids_field,
|
||||
"scene_count": len(scenes),
|
||||
"record_count": len(resolved_records),
|
||||
"selected_record_count": len(selected_keys) if selection_enabled else len(resolved_records),
|
||||
"resolution_stats": _build_resolution_stats_payload(stats),
|
||||
"scenes": scenes,
|
||||
}
|
||||
if selection_summary is not None:
|
||||
payload["selection"] = selection_summary
|
||||
return payload
|
||||
|
||||
|
||||
def save_event_resolution_manifest(
|
||||
output_root: Path,
|
||||
json_file: str,
|
||||
resolved_records: list[ResolvedEventRecord],
|
||||
event_id_field: str,
|
||||
clip_ids_field: str,
|
||||
stats: EventResolutionStats,
|
||||
selection_summary: Optional[dict[str, Any]] = None,
|
||||
selected_record_keys: Optional[set[tuple[str, int, str]]] = None,
|
||||
) -> Path:
|
||||
manifest_path = output_root / "_status" / "event_scene_manifest.json"
|
||||
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
payload = build_event_resolution_payload(
|
||||
json_file,
|
||||
resolved_records,
|
||||
event_id_field,
|
||||
clip_ids_field,
|
||||
stats,
|
||||
selection_summary=selection_summary,
|
||||
selected_record_keys=selected_record_keys,
|
||||
)
|
||||
with manifest_path.open("w", encoding="utf-8") as file:
|
||||
json.dump(payload, file, indent=2, ensure_ascii=False)
|
||||
return manifest_path
|
||||
|
||||
|
||||
def run_event_json_inference_exported(
|
||||
*,
|
||||
context: Any,
|
||||
args: argparse.Namespace,
|
||||
load_env: Callable[[], Any],
|
||||
run_case_inference: Callable[..., dict[str, Any]],
|
||||
) -> dict[str, Any]:
|
||||
resolved_records, resolution_stats = resolve_event_records(
|
||||
json_file=args.event_json_file,
|
||||
scene_filter=args.scene,
|
||||
event_id_field=args.event_id_field,
|
||||
clip_ids_field=args.event_clip_ids_field,
|
||||
max_events=args.max_events,
|
||||
timeout=args.event_request_timeout,
|
||||
cache_file=args.event_cache_file,
|
||||
workers=args.event_resolve_workers,
|
||||
max_retries=args.event_request_retries,
|
||||
retry_backoff_sec=args.event_request_retry_backoff_sec,
|
||||
)
|
||||
selected_records, selection_summary = _select_event_records_by_condition(
|
||||
resolved_records,
|
||||
condition_fields=[str(field).strip() for field in getattr(args, "condition_fields", []) if str(field).strip()],
|
||||
max_records_per_condition=int(getattr(args, "max_records_per_condition", 0)),
|
||||
selection_strategy=str(getattr(args, "condition_select_strategy", "first")),
|
||||
)
|
||||
selected_record_keys = {_record_key(record) for record in selected_records}
|
||||
output_root = Path(args.output_dir).resolve()
|
||||
output_root.mkdir(parents=True, exist_ok=True)
|
||||
manifest_path = save_event_resolution_manifest(
|
||||
output_root=output_root,
|
||||
json_file=args.event_json_file,
|
||||
resolved_records=resolved_records,
|
||||
event_id_field=args.event_id_field,
|
||||
clip_ids_field=args.event_clip_ids_field,
|
||||
stats=resolution_stats,
|
||||
selection_summary=selection_summary,
|
||||
selected_record_keys=selected_record_keys,
|
||||
)
|
||||
|
||||
summary_by_scene: dict[str, dict[str, Any]] = {}
|
||||
for scene in sorted({record.scene for record in selected_records}):
|
||||
scene_records = [record for record in selected_records if record.scene == scene]
|
||||
scene_selection_summary = _filter_selection_summary_for_scene(selection_summary, scene)
|
||||
scene_export_root = Path(args.export_root).resolve() / scene
|
||||
scene_output_root = output_root / scene
|
||||
scene_output_root.mkdir(parents=True, exist_ok=True)
|
||||
scene_manifest_path = scene_output_root / "_status" / "scene_event_manifest.json"
|
||||
scene_manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with scene_manifest_path.open("w", encoding="utf-8") as file:
|
||||
json.dump(
|
||||
_build_scene_manifest_payload(
|
||||
args=args,
|
||||
scene=scene,
|
||||
scene_records=scene_records,
|
||||
resolution_stats=resolution_stats,
|
||||
selection_summary=scene_selection_summary,
|
||||
),
|
||||
file,
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
if args.selection_only:
|
||||
summary_by_scene[scene] = {
|
||||
"scene_output_dir": str(scene_output_root),
|
||||
"scene_manifest_path": str(scene_manifest_path),
|
||||
"selected_record_count": len(scene_records),
|
||||
"selection_only": True,
|
||||
}
|
||||
continue
|
||||
|
||||
event_records_by_id: dict[str, list[ResolvedEventRecord]] = {}
|
||||
event_order: list[str] = []
|
||||
for record in scene_records:
|
||||
if record.event_id not in event_records_by_id:
|
||||
event_order.append(record.event_id)
|
||||
event_records_by_id.setdefault(record.event_id, []).append(record)
|
||||
|
||||
selected_scene_clip_ids: set[str] = set()
|
||||
event_results: dict[str, dict[str, Any]] = {}
|
||||
event_dirs: dict[str, str] = {}
|
||||
event_export_dirs: dict[str, str] = {}
|
||||
for event_id in event_order:
|
||||
event_records = event_records_by_id[event_id]
|
||||
event_clip_ids = _dedupe_preserve_order(
|
||||
[clip_id for record in event_records for clip_id in record.clip_ids]
|
||||
)
|
||||
if args.limit_clips > 0:
|
||||
limited_clip_ids: list[str] = []
|
||||
for clip_id in event_clip_ids:
|
||||
if clip_id in selected_scene_clip_ids:
|
||||
limited_clip_ids.append(clip_id)
|
||||
continue
|
||||
if len(selected_scene_clip_ids) >= args.limit_clips:
|
||||
continue
|
||||
selected_scene_clip_ids.add(clip_id)
|
||||
limited_clip_ids.append(clip_id)
|
||||
event_clip_ids = limited_clip_ids
|
||||
|
||||
clip_tasks = build_clip_tasks_from_clip_ids(event_clip_ids)
|
||||
dir_prefix = "event_id"
|
||||
if any(record.clip_source == "direct_clip_ids_field" for record in event_records):
|
||||
dir_prefix = event_records[0].event_id_field_used or args.event_id_field or "record_id"
|
||||
event_dir_name = _sanitize_identifier_for_path(event_id, prefix=dir_prefix)
|
||||
event_export_root = scene_export_root / event_dir_name
|
||||
event_output_root = scene_output_root / event_dir_name
|
||||
event_export_dirs[event_id] = str(event_export_root)
|
||||
event_dirs[event_id] = str(event_output_root)
|
||||
|
||||
def on_before_run(export_root: Path, inference_root: Path, tasks: list[Any], *, _event_id: str = event_id, _event_records: list[ResolvedEventRecord] = event_records, _event_clip_ids: list[str] = event_clip_ids) -> None:
|
||||
payload = _build_event_manifest_payload(
|
||||
args=args,
|
||||
scene=scene,
|
||||
event_id=_event_id,
|
||||
event_records=_event_records,
|
||||
clip_ids=_event_clip_ids,
|
||||
resolution_stats=resolution_stats,
|
||||
)
|
||||
manifest_path = inference_root / "_status" / "event_manifest.json"
|
||||
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with manifest_path.open("w", encoding="utf-8") as file:
|
||||
json.dump(payload, file, indent=2, ensure_ascii=False)
|
||||
|
||||
event_results[event_id] = run_clip_tasks_inference_exported(
|
||||
context=context,
|
||||
args=args,
|
||||
clip_tasks=clip_tasks,
|
||||
load_env=load_env,
|
||||
run_case_inference=run_case_inference,
|
||||
export_root=event_export_root,
|
||||
output_root=event_output_root,
|
||||
on_before_run=on_before_run,
|
||||
)
|
||||
|
||||
summary_by_scene[scene] = {
|
||||
"scene_output_dir": str(scene_output_root),
|
||||
"scene_manifest_path": str(scene_manifest_path),
|
||||
"event_export_dirs": event_export_dirs,
|
||||
"event_dirs": event_dirs,
|
||||
"event_results": event_results,
|
||||
}
|
||||
|
||||
result = {
|
||||
"event_json_file": args.event_json_file,
|
||||
"scene": args.scene or "",
|
||||
"event_id_field": args.event_id_field,
|
||||
"event_clip_ids_field": args.event_clip_ids_field,
|
||||
"manifest_path": str(manifest_path),
|
||||
"selection": selection_summary,
|
||||
"selected_record_count": len(selected_records),
|
||||
"resolution_stats": _build_resolution_stats_payload(resolution_stats),
|
||||
"scene_results": summary_by_scene,
|
||||
}
|
||||
_print_event_json_summary(
|
||||
args=args,
|
||||
manifest_path=manifest_path,
|
||||
resolved_records=resolved_records,
|
||||
selected_records=selected_records,
|
||||
selection_summary=selection_summary,
|
||||
scene_results=summary_by_scene,
|
||||
)
|
||||
return result
|
||||
141
tools/model_inference/adapters/get_clip_by_eventid.py
Executable file
141
tools/model_inference/adapters/get_clip_by_eventid.py
Executable file
@@ -0,0 +1,141 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
EVENT_META_INFO_URL = "https://d.minieye.tech/ess-api/dashoard/event/meta_info"
|
||||
CLIP_ID_KEYS = ("clip_id", "clip_uuid", "clip_ukey", "ukey", "id")
|
||||
|
||||
|
||||
def fetch_event_meta(
|
||||
event_id: str,
|
||||
timeout: float = 60.0,
|
||||
max_retries: int = 3,
|
||||
retry_backoff_sec: float = 2.0,
|
||||
) -> dict[str, Any]:
|
||||
event_id = str(event_id).strip()
|
||||
if not event_id:
|
||||
raise ValueError("event_id is required")
|
||||
|
||||
last_error: Exception | None = None
|
||||
total_attempts = max(1, int(max_retries))
|
||||
for attempt in range(1, total_attempts + 1):
|
||||
try:
|
||||
response = requests.post(
|
||||
url=EVENT_META_INFO_URL,
|
||||
json={"event_id": event_id},
|
||||
timeout=timeout,
|
||||
)
|
||||
response.raise_for_status()
|
||||
payload = response.json()
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError(f"Unexpected event meta response type: {type(payload).__name__}")
|
||||
return payload
|
||||
except (requests.exceptions.Timeout, requests.exceptions.RequestException, ValueError) as exc:
|
||||
last_error = exc
|
||||
if attempt >= total_attempts:
|
||||
break
|
||||
sleep_sec = max(0.0, float(retry_backoff_sec)) * (2 ** (attempt - 1))
|
||||
print(
|
||||
f"[warn] event_id={event_id} request attempt {attempt}/{total_attempts} failed: "
|
||||
f"{type(exc).__name__}: {exc}. retry in {sleep_sec:.1f}s"
|
||||
)
|
||||
if sleep_sec > 0:
|
||||
time.sleep(sleep_sec)
|
||||
|
||||
assert last_error is not None
|
||||
raise last_error
|
||||
|
||||
|
||||
def _append_clip_id(clip_ids: list[str], seen: set[str], value: Any) -> None:
|
||||
clip_id = str(value).strip()
|
||||
if clip_id and clip_id not in seen:
|
||||
seen.add(clip_id)
|
||||
clip_ids.append(clip_id)
|
||||
|
||||
|
||||
def _extract_clip_ids_from_item(item: Any, clip_ids: list[str], seen: set[str]) -> None:
|
||||
if item is None:
|
||||
return
|
||||
if isinstance(item, str):
|
||||
_append_clip_id(clip_ids, seen, item)
|
||||
return
|
||||
if isinstance(item, (list, tuple, set)):
|
||||
for sub_item in item:
|
||||
_extract_clip_ids_from_item(sub_item, clip_ids, seen)
|
||||
return
|
||||
if isinstance(item, dict):
|
||||
matched_key = False
|
||||
for key in CLIP_ID_KEYS:
|
||||
value = item.get(key)
|
||||
if value is not None:
|
||||
matched_key = True
|
||||
_extract_clip_ids_from_item(value, clip_ids, seen)
|
||||
if matched_key:
|
||||
return
|
||||
for value in item.values():
|
||||
_extract_clip_ids_from_item(value, clip_ids, seen)
|
||||
return
|
||||
|
||||
_append_clip_id(clip_ids, seen, item)
|
||||
|
||||
|
||||
def extract_associated_clip_ids(payload: dict[str, Any]) -> list[str]:
|
||||
clip_items = payload.get("associated_clip_list", [])
|
||||
if clip_items is None:
|
||||
return []
|
||||
clip_ids: list[str] = []
|
||||
seen: set[str] = set()
|
||||
_extract_clip_ids_from_item(clip_items, clip_ids, seen)
|
||||
return clip_ids
|
||||
|
||||
|
||||
def get_associated_clip_ids(
|
||||
event_id: str,
|
||||
timeout: float = 60.0,
|
||||
max_retries: int = 3,
|
||||
retry_backoff_sec: float = 2.0,
|
||||
) -> list[str]:
|
||||
payload = fetch_event_meta(
|
||||
event_id,
|
||||
timeout=timeout,
|
||||
max_retries=max_retries,
|
||||
retry_backoff_sec=retry_backoff_sec,
|
||||
)
|
||||
return extract_associated_clip_ids(payload)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Resolve PDCL clip ids from one or more event ids.")
|
||||
parser.add_argument("event_ids", nargs="+", help="One or more event ids to resolve.")
|
||||
parser.add_argument("--timeout", type=float, default=60.0, help="HTTP request timeout in seconds.")
|
||||
parser.add_argument("--retries", type=int, default=3, help="Max request attempts per event id.")
|
||||
parser.add_argument("--retry-backoff-sec", type=float, default=2.0, help="Base retry backoff in seconds.")
|
||||
parser.add_argument("--pretty", action="store_true", help="Pretty-print the JSON result.")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
result = {
|
||||
event_id: get_associated_clip_ids(
|
||||
event_id,
|
||||
timeout=args.timeout,
|
||||
max_retries=args.retries,
|
||||
retry_backoff_sec=args.retry_backoff_sec,
|
||||
)
|
||||
for event_id in args.event_ids
|
||||
}
|
||||
if args.pretty:
|
||||
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print(json.dumps(result, ensure_ascii=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
826
tools/model_inference/adapters/pdcl_clip_export_utils.py
Executable file
826
tools/model_inference/adapters/pdcl_clip_export_utils.py
Executable file
@@ -0,0 +1,826 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import traceback
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from threading import Lock
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
|
||||
CALIB_ATTACHMENT_NAMES = (
|
||||
"sigmastar.1/calibs/camera4.json",
|
||||
"test_data/calibs/camera4.json",
|
||||
"calibs/camera4.json",
|
||||
)
|
||||
BEIJING_TZ = timezone(timedelta(hours=8))
|
||||
DEFAULT_DATE_NAME = "unknown_date"
|
||||
DEFAULT_VEHICLE_NAME = "unknown_vehicle"
|
||||
LOCAL_MCAP_VEHICLE_NAME = "local_mcap"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ClipTask:
|
||||
clip_uuid: str
|
||||
date_name: str
|
||||
vehicle_name: str
|
||||
clip_path: str
|
||||
|
||||
@property
|
||||
def task_id(self) -> str:
|
||||
return self.clip_uuid
|
||||
|
||||
|
||||
@dataclass
|
||||
class TaskResult:
|
||||
task_id: str
|
||||
success: bool
|
||||
message: str
|
||||
output_dir: Optional[str] = None
|
||||
|
||||
|
||||
class StatusStore:
|
||||
"""Persistent status tracker for resumable batch inference."""
|
||||
|
||||
def __init__(self, status_file: Path):
|
||||
self.status_file = status_file
|
||||
self.lock = Lock()
|
||||
self._status: dict[str, dict[str, str]] = {}
|
||||
self.status_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
if self.status_file.exists():
|
||||
try:
|
||||
self._status = json.loads(self.status_file.read_text())
|
||||
except Exception:
|
||||
self._status = {}
|
||||
|
||||
def is_done(self, task_id: str) -> bool:
|
||||
return self._status.get(task_id, {}).get("state") == "done"
|
||||
|
||||
def get(self, task_id: str) -> Optional[dict[str, str]]:
|
||||
return self._status.get(task_id)
|
||||
|
||||
def mark_running(self, task_id: str, detail: str) -> None:
|
||||
with self.lock:
|
||||
self._status[task_id] = {"state": "running", "detail": detail}
|
||||
self._flush()
|
||||
|
||||
def mark_done(self, task_id: str, detail: str) -> None:
|
||||
with self.lock:
|
||||
self._status[task_id] = {"state": "done", "detail": detail}
|
||||
self._flush()
|
||||
|
||||
def mark_failed(self, task_id: str, detail: str) -> None:
|
||||
with self.lock:
|
||||
self._status[task_id] = {"state": "failed", "detail": detail}
|
||||
self._flush()
|
||||
|
||||
def summary(self) -> dict[str, int]:
|
||||
done = 0
|
||||
running = 0
|
||||
failed = 0
|
||||
for item in self._status.values():
|
||||
state = item.get("state")
|
||||
if state == "done":
|
||||
done += 1
|
||||
elif state == "running":
|
||||
running += 1
|
||||
elif state == "failed":
|
||||
failed += 1
|
||||
return {"done": done, "running": running, "failed": failed, "total": len(self._status)}
|
||||
|
||||
def _flush(self) -> None:
|
||||
self.status_file.write_text(json.dumps(self._status, indent=2, ensure_ascii=False))
|
||||
|
||||
|
||||
def _ensure_pdcl_auth_defaults() -> None:
|
||||
os.environ.setdefault("STS_UID", "dis-uploader")
|
||||
os.environ.setdefault("STS_SECRET_KEY", "277310cc09724d315514a79701fecb0f")
|
||||
|
||||
|
||||
def validate_pdcl_auth_env() -> None:
|
||||
_ensure_pdcl_auth_defaults()
|
||||
required_vars = ["STS_UID", "STS_SECRET_KEY"]
|
||||
missing = [name for name in required_vars if not os.getenv(name)]
|
||||
if missing:
|
||||
raise ValueError(
|
||||
"Missing required PDCL auth env vars: "
|
||||
+ ", ".join(missing)
|
||||
+ ". Please export them in shell or set them in .env before running."
|
||||
)
|
||||
|
||||
|
||||
def _normalize_metadata_value(value: Any) -> str:
|
||||
text = str(value or "").strip()
|
||||
return text if text and text.lower() != "none" else ""
|
||||
|
||||
|
||||
def _normalize_frame_name_token(value: Any) -> str:
|
||||
text = str(value or "").strip()
|
||||
if not text or text.lower() == "none":
|
||||
return ""
|
||||
return text.replace("/", "_").replace("\\", "_").replace(" ", "")
|
||||
|
||||
|
||||
def _format_ms_to_date_name(timestamp_ms: Any) -> str:
|
||||
if not isinstance(timestamp_ms, (int, float)) or timestamp_ms <= 0:
|
||||
return ""
|
||||
dt = datetime.fromtimestamp(timestamp_ms / 1000, tz=timezone.utc).astimezone(BEIJING_TZ)
|
||||
return dt.strftime("%Y%m%d%H%M%S")
|
||||
|
||||
|
||||
def _build_clip_task(clip_uuid: str) -> Optional[ClipTask]:
|
||||
_ensure_pdcl_auth_defaults()
|
||||
from pdcl_dss import Clip
|
||||
|
||||
date_name = DEFAULT_DATE_NAME
|
||||
vehicle_name = DEFAULT_VEHICLE_NAME
|
||||
|
||||
try:
|
||||
clip = Clip(clip_uuid)
|
||||
clip_meta = dict(clip.meta)
|
||||
files, _ = clip.list_files()
|
||||
if not files:
|
||||
print(f"Skip clip_id={clip_uuid}: no files found")
|
||||
return None
|
||||
clip_path = clip.get_cache_path(files[0])
|
||||
except Exception as exc:
|
||||
print(f"Skip clip_id={clip_uuid}: failed to load clip metadata. {type(exc).__name__}: {exc}")
|
||||
return None
|
||||
|
||||
clip_date_name = _format_ms_to_date_name(clip_meta.get("start_time_ms"))
|
||||
if clip_date_name:
|
||||
date_name = clip_date_name
|
||||
|
||||
try:
|
||||
group_id = clip.get_group_id()
|
||||
if group_id:
|
||||
group_meta = dict(clip.get_group().meta)
|
||||
for key in ("plate_number", "vehicle_name", "car_name", "plateNumber", "vehicleName", "carName"):
|
||||
value = _normalize_metadata_value(group_meta.get(key))
|
||||
if value:
|
||||
vehicle_name = value
|
||||
break
|
||||
|
||||
project_name = _normalize_metadata_value(group_meta.get("project_name"))
|
||||
if vehicle_name == DEFAULT_VEHICLE_NAME and project_name:
|
||||
vehicle_name = project_name
|
||||
|
||||
group_date_name = _format_ms_to_date_name(group_meta.get("collection_time"))
|
||||
if group_date_name:
|
||||
date_name = group_date_name
|
||||
except Exception as exc:
|
||||
print(
|
||||
f"[warn] clip_id={clip_uuid}: failed to load group metadata, "
|
||||
f"fallback vehicle={vehicle_name} date={date_name}. {type(exc).__name__}: {exc}"
|
||||
)
|
||||
|
||||
return ClipTask(
|
||||
clip_uuid=clip_uuid,
|
||||
date_name=date_name,
|
||||
vehicle_name=vehicle_name,
|
||||
clip_path=clip_path,
|
||||
)
|
||||
|
||||
|
||||
def parse_clip_list(clip_list_file: str) -> list[ClipTask]:
|
||||
tasks: list[ClipTask] = []
|
||||
with open(clip_list_file, "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
|
||||
clip_uuid = line.split()[0]
|
||||
task = _build_clip_task(clip_uuid)
|
||||
if task is not None:
|
||||
tasks.append(task)
|
||||
return tasks
|
||||
|
||||
|
||||
def build_clip_tasks_from_clip_ids(clip_ids: list[str]) -> list[ClipTask]:
|
||||
tasks: list[ClipTask] = []
|
||||
seen: set[str] = set()
|
||||
for clip_id in clip_ids:
|
||||
clip_uuid = str(clip_id).strip()
|
||||
if not clip_uuid or clip_uuid in seen:
|
||||
continue
|
||||
seen.add(clip_uuid)
|
||||
task = _build_clip_task(clip_uuid)
|
||||
if task is not None:
|
||||
tasks.append(task)
|
||||
return tasks
|
||||
|
||||
|
||||
def build_clip_task_from_mcap_file(
|
||||
mcap_file: str | Path,
|
||||
*,
|
||||
clip_id: str = "",
|
||||
date_name: str = "",
|
||||
vehicle_name: str = "",
|
||||
) -> ClipTask:
|
||||
mcap_path = Path(mcap_file).expanduser().resolve()
|
||||
if not mcap_path.is_file():
|
||||
raise FileNotFoundError(f"MCAP file not found: {mcap_path}")
|
||||
|
||||
stem = mcap_path.stem
|
||||
resolved_clip_id = _normalize_metadata_value(clip_id) or stem
|
||||
resolved_date_name = _normalize_metadata_value(date_name)
|
||||
if not resolved_date_name and len(stem) == 14 and stem.isdigit():
|
||||
resolved_date_name = stem
|
||||
resolved_vehicle_name = _normalize_metadata_value(vehicle_name) or LOCAL_MCAP_VEHICLE_NAME
|
||||
|
||||
return ClipTask(
|
||||
clip_uuid=resolved_clip_id,
|
||||
date_name=resolved_date_name or DEFAULT_DATE_NAME,
|
||||
vehicle_name=resolved_vehicle_name,
|
||||
clip_path=str(mcap_path),
|
||||
)
|
||||
|
||||
|
||||
def build_case_dir_name(prefix: str, clip_task: ClipTask) -> str:
|
||||
safe_clip_uuid = clip_task.clip_uuid.replace("/", "_")
|
||||
return f"{prefix}_{clip_task.vehicle_name}_{clip_task.date_name}_{safe_clip_uuid}"
|
||||
|
||||
|
||||
def _plane_to_ndarray(plane: Any) -> np.ndarray:
|
||||
stride = plane.line_size
|
||||
height = plane.height
|
||||
width = plane.width
|
||||
array = np.frombuffer(plane, dtype=np.uint8)
|
||||
if stride == width:
|
||||
return array.reshape(height, width)
|
||||
return array.reshape(height, stride)[:, :width]
|
||||
|
||||
|
||||
def _yuvj420p_to_nv12(
|
||||
y_plane: np.ndarray,
|
||||
u_plane: np.ndarray,
|
||||
v_plane: np.ndarray,
|
||||
) -> tuple[np.ndarray, np.ndarray]:
|
||||
uv_height = u_plane.shape[0]
|
||||
uv_width = u_plane.shape[1]
|
||||
uv_plane = np.zeros((uv_height, uv_width * 2), dtype=np.uint8)
|
||||
uv_plane[:, 0::2] = u_plane
|
||||
uv_plane[:, 1::2] = v_plane
|
||||
return y_plane.copy(), uv_plane
|
||||
|
||||
|
||||
def _h265_payload_to_bgr(payload: bytes) -> np.ndarray:
|
||||
try:
|
||||
import av
|
||||
except ImportError as exc:
|
||||
raise ImportError("PyAV is required for mcap decoding. Please install: pip install av") from exc
|
||||
|
||||
container = av.open(io.BytesIO(payload))
|
||||
for frame in container.decode(video=0):
|
||||
y_plane = _plane_to_ndarray(frame.planes[0])
|
||||
u_plane = _plane_to_ndarray(frame.planes[1])
|
||||
v_plane = _plane_to_ndarray(frame.planes[2])
|
||||
y_nv12, uv_nv12 = _yuvj420p_to_nv12(y_plane, u_plane, v_plane)
|
||||
yuv_image = np.concatenate((y_nv12, uv_nv12), axis=0)
|
||||
return cv2.cvtColor(yuv_image, cv2.COLOR_YUV2BGR_NV12)
|
||||
raise ValueError("decode failed: no video frame in payload")
|
||||
|
||||
|
||||
def _resolve_calib_file_for_clip(clip_path: str) -> Optional[Path]:
|
||||
base = Path(clip_path).resolve()
|
||||
search_dir = base.parent
|
||||
candidates: list[Path] = []
|
||||
|
||||
for _ in range(4):
|
||||
candidates.extend(
|
||||
[
|
||||
search_dir / "calibs" / "camera4.json",
|
||||
search_dir / "test_data" / "calibs" / "camera4.json",
|
||||
search_dir / "L2_calib" / "camera4.json",
|
||||
search_dir / "calib" / "L2_calib" / "camera4.json",
|
||||
]
|
||||
)
|
||||
parent = search_dir.parent
|
||||
if parent == search_dir:
|
||||
break
|
||||
search_dir = parent
|
||||
|
||||
for calib_path in candidates:
|
||||
if calib_path.exists():
|
||||
return calib_path
|
||||
return None
|
||||
|
||||
|
||||
def _candidate_camera_topics(camera_topic: str) -> list[str]:
|
||||
topic = str(camera_topic or "").strip()
|
||||
if not topic:
|
||||
return []
|
||||
|
||||
topics = [topic]
|
||||
if "." in topic:
|
||||
topics.append(topic.rsplit(".", 1)[-1])
|
||||
else:
|
||||
topics.append(f"sigmastar.1.{topic}")
|
||||
return list(dict.fromkeys(topics))
|
||||
|
||||
|
||||
def _resolve_reader_camera_topics(reader: Any, camera_topic: str) -> list[str]:
|
||||
candidates = _candidate_camera_topics(camera_topic)
|
||||
topic_map = getattr(reader, "_topic_map", None)
|
||||
if isinstance(topic_map, dict):
|
||||
for candidate in candidates:
|
||||
if candidate in topic_map:
|
||||
return [candidate]
|
||||
for key, values in topic_map.items():
|
||||
if any(candidate in values for candidate in candidates):
|
||||
return [key]
|
||||
return candidates
|
||||
|
||||
|
||||
def _decode_mcap_to_images(
|
||||
clip_uuid: str,
|
||||
clip_path: str,
|
||||
output_dir: Path,
|
||||
camera_topic: str,
|
||||
max_frames: int,
|
||||
) -> tuple[int, Optional[dict[str, Any]], list[dict[str, Any]]]:
|
||||
from pdcl_pyclip.decoder_struct import StructDecoder
|
||||
from pdcl_pyclip.msg_camera import VideoMessage
|
||||
from pdcl_pyclip.reader import ClipReader
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
reader = ClipReader(clip_path)
|
||||
struct_decoder = StructDecoder()
|
||||
saved = 0
|
||||
camera4_json = None
|
||||
decode_errors: list[dict[str, Any]] = []
|
||||
camera_topics = _resolve_reader_camera_topics(reader, camera_topic)
|
||||
|
||||
for schema, channel, msg in reader.iter_messages(topics=camera_topics):
|
||||
if schema.encoding != "struct":
|
||||
continue
|
||||
data = struct_decoder.decode(schema, channel, msg)
|
||||
if not isinstance(data, VideoMessage):
|
||||
continue
|
||||
|
||||
try:
|
||||
image = _h265_payload_to_bgr(data.payload)
|
||||
except Exception as exc:
|
||||
frame_id = getattr(data, "frame_id", None)
|
||||
error_record = {
|
||||
"frame_id": None if frame_id is None else str(frame_id),
|
||||
"error_type": type(exc).__name__,
|
||||
"error": str(exc),
|
||||
}
|
||||
decode_errors.append(error_record)
|
||||
print(
|
||||
f"[warn] clip_id={clip_uuid} frame_id={error_record['frame_id']} "
|
||||
f"-> skip bad frame: {error_record['error_type']}: {error_record['error']}"
|
||||
)
|
||||
continue
|
||||
|
||||
frame_id_token = _normalize_frame_name_token(getattr(data, "frame_id", None))
|
||||
timestamp_token = _normalize_frame_name_token(getattr(msg, "log_time", None))
|
||||
if frame_id_token and timestamp_token:
|
||||
frame_name = f"{clip_uuid}_{frame_id_token}_{timestamp_token}.png"
|
||||
elif frame_id_token:
|
||||
frame_name = f"{clip_uuid}_{frame_id_token}.png"
|
||||
elif timestamp_token:
|
||||
frame_name = f"{clip_uuid}_{saved:06d}_{timestamp_token}.png"
|
||||
else:
|
||||
frame_name = f"{clip_uuid}_{saved:06d}.png"
|
||||
if not cv2.imwrite(str(output_dir / frame_name), image):
|
||||
raise IOError(f"Failed to write image: {output_dir / frame_name}")
|
||||
|
||||
saved += 1
|
||||
if max_frames > 0 and saved >= max_frames:
|
||||
break
|
||||
|
||||
for attachment in reader.iter_attachments():
|
||||
if attachment.name in CALIB_ATTACHMENT_NAMES:
|
||||
camera4_json = json.loads(attachment.data.decode("utf-8"))
|
||||
break
|
||||
|
||||
return saved, camera4_json, decode_errors
|
||||
|
||||
|
||||
def _save_decode_errors(output_dir: Path, clip_uuid: str, decode_errors: list[dict[str, Any]]) -> Optional[Path]:
|
||||
if not decode_errors:
|
||||
return None
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
decode_errors_path = output_dir / "decode_errors.json"
|
||||
payload = {
|
||||
"clip_uuid": clip_uuid,
|
||||
"skipped_bad_frame_count": len(decode_errors),
|
||||
"errors": decode_errors,
|
||||
}
|
||||
with open(decode_errors_path, "w", encoding="utf-8") as file:
|
||||
json.dump(payload, file, indent=2, ensure_ascii=False)
|
||||
return decode_errors_path
|
||||
|
||||
|
||||
def _save_calib_for_clip(
|
||||
clip_path: str,
|
||||
calib_output_path: Path,
|
||||
calib_file_override: str,
|
||||
embedded_calib: Optional[dict[str, Any]],
|
||||
) -> str:
|
||||
calib_output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if calib_file_override:
|
||||
calib_src = Path(calib_file_override).resolve()
|
||||
if not calib_src.exists():
|
||||
raise FileNotFoundError(f"Calibration file {calib_src} does not exist.")
|
||||
calib_output_path.write_bytes(calib_src.read_bytes())
|
||||
return f"override:{calib_src}"
|
||||
|
||||
calib_src = _resolve_calib_file_for_clip(clip_path)
|
||||
if calib_src is not None:
|
||||
calib_output_path.write_bytes(calib_src.read_bytes())
|
||||
return f"file:{calib_src}"
|
||||
|
||||
if embedded_calib is None:
|
||||
raise FileNotFoundError(
|
||||
"Calibration file camera4.json not found near clip and not found in mcap attachments. "
|
||||
"Please provide --calib-file explicitly."
|
||||
)
|
||||
|
||||
with open(calib_output_path, "w", encoding="utf-8") as file:
|
||||
json.dump(embedded_calib, file, indent=2, ensure_ascii=False)
|
||||
return "mcap_attachment"
|
||||
|
||||
|
||||
def _build_calib_summary(calib_payload: Optional[dict[str, Any]]) -> dict[str, Any]:
|
||||
if not isinstance(calib_payload, dict):
|
||||
return {
|
||||
"format": "unknown",
|
||||
"has_distortion": False,
|
||||
}
|
||||
|
||||
intrinsics = calib_payload
|
||||
extrinsics = None
|
||||
calib_format = "flat_camera4"
|
||||
|
||||
if "intrinsics" in calib_payload:
|
||||
intrinsics = calib_payload.get("intrinsics", {}).get("camera4.json", {}) or {}
|
||||
extrinsics = calib_payload.get("extrinsics", {}).get("camera4.json", {}) or {}
|
||||
calib_format = "combined_calibration"
|
||||
|
||||
distort_coeffs = intrinsics.get("distort_coeffs", calib_payload.get("distort_coeffs", [])) or []
|
||||
return {
|
||||
"format": calib_format,
|
||||
"focal_u": intrinsics.get("focal_u"),
|
||||
"focal_v": intrinsics.get("focal_v"),
|
||||
"cu": intrinsics.get("cu"),
|
||||
"cv": intrinsics.get("cv"),
|
||||
"pitch": calib_payload.get("pitch", extrinsics.get("rpy", [None, None, None])[1] if extrinsics else None),
|
||||
"yaw": calib_payload.get("yaw", extrinsics.get("rpy", [None, None, None])[2] if extrinsics else None),
|
||||
"image_width": calib_payload.get("image_width", calib_payload.get("img_width")),
|
||||
"image_height": calib_payload.get("image_height", calib_payload.get("img_height")),
|
||||
"distort_coeff_count": len(distort_coeffs),
|
||||
"has_distortion": bool(distort_coeffs),
|
||||
}
|
||||
|
||||
|
||||
def _save_export_manifest(
|
||||
output_dir: Path,
|
||||
clip_task: ClipTask,
|
||||
frame_count: int,
|
||||
calib_source: str,
|
||||
camera_topic: str,
|
||||
calib_summary: Optional[dict[str, Any]] = None,
|
||||
skipped_bad_frame_count: int = 0,
|
||||
decode_errors_path: Optional[str] = None,
|
||||
) -> None:
|
||||
manifest = {
|
||||
"clip_uuid": clip_task.clip_uuid,
|
||||
"date_name": clip_task.date_name,
|
||||
"vehicle_name": clip_task.vehicle_name,
|
||||
"clip_path": clip_task.clip_path,
|
||||
"camera_topic": camera_topic,
|
||||
"frame_count": frame_count,
|
||||
"skipped_bad_frame_count": skipped_bad_frame_count,
|
||||
"calib_source": calib_source,
|
||||
"calib_summary": calib_summary,
|
||||
}
|
||||
if decode_errors_path:
|
||||
manifest["decode_errors_path"] = decode_errors_path
|
||||
with open(output_dir / "manifest.json", "w", encoding="utf-8") as file:
|
||||
json.dump(manifest, file, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def _input_source_label(args: argparse.Namespace) -> str:
|
||||
return str(getattr(args, "mcap_file", "") or getattr(args, "clip_list_file", ""))
|
||||
|
||||
|
||||
def _input_source_mode(args: argparse.Namespace) -> str:
|
||||
if getattr(args, "mcap_file", ""):
|
||||
return "mcap_file"
|
||||
return "clip_list"
|
||||
|
||||
|
||||
def _save_calib_summary(output_dir: Path, calib_source: str, calib_summary: dict[str, Any]) -> None:
|
||||
payload = {
|
||||
"calib_source": calib_source,
|
||||
"calib_summary": calib_summary,
|
||||
}
|
||||
with open(output_dir / "calib_summary.json", "w", encoding="utf-8") as file:
|
||||
json.dump(payload, file, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def export_one_clip(
|
||||
clip_task: ClipTask,
|
||||
args: argparse.Namespace,
|
||||
status: StatusStore,
|
||||
) -> TaskResult:
|
||||
task_id = clip_task.task_id
|
||||
if args.skip_done and status.is_done(task_id):
|
||||
info = status.get(task_id) or {}
|
||||
return TaskResult(task_id=task_id, success=True, message=f"skip done: {info.get('detail', '')}")
|
||||
|
||||
case_dir = Path(args.output_root) / build_case_dir_name(args.output_prefix, clip_task)
|
||||
images_dir = case_dir / "images"
|
||||
calib_path = case_dir / "calib" / "L2_calib" / "camera4.json"
|
||||
status.mark_running(task_id, f"running source={clip_task.clip_path}")
|
||||
|
||||
try:
|
||||
frame_count, embedded_calib, decode_errors = _decode_mcap_to_images(
|
||||
clip_uuid=clip_task.clip_uuid,
|
||||
clip_path=clip_task.clip_path,
|
||||
output_dir=images_dir,
|
||||
camera_topic=args.camera_topic,
|
||||
max_frames=args.max_frames_per_clip,
|
||||
)
|
||||
decode_errors_path = _save_decode_errors(case_dir, clip_task.clip_uuid, decode_errors)
|
||||
if frame_count <= 0:
|
||||
if decode_errors:
|
||||
first_error = decode_errors[0]
|
||||
raise RuntimeError(
|
||||
f"Failed to decode any frames; skipped {len(decode_errors)} bad frames. "
|
||||
f"First error: {first_error['error_type']}: {first_error['error']}. "
|
||||
f"See {decode_errors_path}"
|
||||
)
|
||||
raise RuntimeError(
|
||||
f"No frames were decoded from clip {clip_task.clip_uuid} on topic "
|
||||
f"{args.camera_topic!r} (tried: {', '.join(_candidate_camera_topics(args.camera_topic))})."
|
||||
)
|
||||
calib_source = _save_calib_for_clip(
|
||||
clip_path=clip_task.clip_path,
|
||||
calib_output_path=calib_path,
|
||||
calib_file_override=args.calib_file,
|
||||
embedded_calib=embedded_calib,
|
||||
)
|
||||
with open(calib_path, "r", encoding="utf-8") as file:
|
||||
calib_payload = json.load(file)
|
||||
calib_summary = _build_calib_summary(calib_payload)
|
||||
_save_export_manifest(
|
||||
output_dir=case_dir,
|
||||
clip_task=clip_task,
|
||||
frame_count=frame_count,
|
||||
calib_source=calib_source,
|
||||
camera_topic=args.camera_topic,
|
||||
calib_summary=calib_summary,
|
||||
skipped_bad_frame_count=len(decode_errors),
|
||||
decode_errors_path=str(decode_errors_path) if decode_errors_path else None,
|
||||
)
|
||||
_save_calib_summary(case_dir, calib_source=calib_source, calib_summary=calib_summary)
|
||||
status.mark_done(task_id, str(case_dir))
|
||||
return TaskResult(
|
||||
task_id=task_id,
|
||||
success=True,
|
||||
message=f"ok frames={frame_count} skipped_bad_frames={len(decode_errors)}",
|
||||
output_dir=str(case_dir),
|
||||
)
|
||||
except Exception as exc:
|
||||
message = f"{type(exc).__name__}: {exc}"
|
||||
status.mark_failed(task_id, message)
|
||||
err_log = Path(args.output_root) / "_status" / "errors.log"
|
||||
err_log.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(err_log, "a", encoding="utf-8") as file:
|
||||
file.write(f"[{task_id}] {message}\n{traceback.format_exc()}\n")
|
||||
return TaskResult(task_id=task_id, success=False, message=message)
|
||||
|
||||
|
||||
def save_run_manifest(args: argparse.Namespace, clip_tasks: list[ClipTask]) -> None:
|
||||
manifest_path = Path(args.output_root) / "_status" / "run_manifest.json"
|
||||
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
payload = {
|
||||
"source_mode": _input_source_mode(args),
|
||||
"source": _input_source_label(args),
|
||||
"clip_list_file": getattr(args, "clip_list_file", ""),
|
||||
"mcap_file": getattr(args, "mcap_file", ""),
|
||||
"output_root": args.output_root,
|
||||
"camera_topic": args.camera_topic,
|
||||
"max_frames_per_clip": args.max_frames_per_clip,
|
||||
"num_tasks": len(clip_tasks),
|
||||
"tasks": [
|
||||
{
|
||||
"task_id": task.task_id,
|
||||
"clip_uuid": task.clip_uuid,
|
||||
"date_name": task.date_name,
|
||||
"vehicle_name": task.vehicle_name,
|
||||
"clip_path": task.clip_path,
|
||||
}
|
||||
for task in clip_tasks
|
||||
],
|
||||
}
|
||||
with open(manifest_path, "w", encoding="utf-8") as file:
|
||||
json.dump(payload, file, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def has_reusable_exported_case(case_dir: Path) -> bool:
|
||||
images_dir = case_dir / "images"
|
||||
calib_path = case_dir / "calib" / "L2_calib" / "camera4.json"
|
||||
if not images_dir.is_dir() or not calib_path.is_file():
|
||||
return False
|
||||
return any(path.is_file() for path in images_dir.iterdir())
|
||||
|
||||
|
||||
def save_exported_batch_manifest(args: argparse.Namespace, clip_tasks: list[ClipTask], output_root: Path) -> None:
|
||||
manifest_path = output_root / "_status" / "run_manifest.json"
|
||||
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
payload = {
|
||||
"source_mode": _input_source_mode(args),
|
||||
"source": _input_source_label(args),
|
||||
"clip_list_file": getattr(args, "clip_list_file", ""),
|
||||
"mcap_file": getattr(args, "mcap_file", ""),
|
||||
"export_root": args.export_root,
|
||||
"output_dir": str(output_root),
|
||||
"camera_topic": args.camera_topic,
|
||||
"max_frames_per_clip": args.max_frames_per_clip,
|
||||
"exported_model": args.exported_model,
|
||||
"edge_yaw_max_lateral_dist_m": args.edge_yaw_max_lateral_dist,
|
||||
"roi_models": {
|
||||
"roi0": args.roi0_model,
|
||||
"roi1": args.roi1_model,
|
||||
},
|
||||
"num_tasks": len(clip_tasks),
|
||||
"tasks": [
|
||||
{
|
||||
"task_id": task.task_id,
|
||||
"clip_uuid": task.clip_uuid,
|
||||
"date_name": task.date_name,
|
||||
"vehicle_name": task.vehicle_name,
|
||||
"clip_path": task.clip_path,
|
||||
}
|
||||
for task in clip_tasks
|
||||
],
|
||||
}
|
||||
with manifest_path.open("w", encoding="utf-8") as file:
|
||||
json.dump(payload, file, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def run_clip_tasks_inference_exported(
|
||||
*,
|
||||
context: Any,
|
||||
args: argparse.Namespace,
|
||||
clip_tasks: list[ClipTask],
|
||||
load_env: Callable[[], Any],
|
||||
run_case_inference: Callable[..., dict[str, Any]],
|
||||
export_root: str | Path | None = None,
|
||||
output_root: str | Path | None = None,
|
||||
on_before_run: Optional[Callable[[Path, Path, list[ClipTask]], None]] = None,
|
||||
require_pdcl_auth: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
load_env()
|
||||
if require_pdcl_auth:
|
||||
validate_pdcl_auth_env()
|
||||
|
||||
export_root = Path(args.export_root if export_root is None else export_root).resolve()
|
||||
output_root = Path(args.output_dir if output_root is None else output_root).resolve()
|
||||
export_root.mkdir(parents=True, exist_ok=True)
|
||||
output_root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
args.output_root = str(export_root)
|
||||
|
||||
if not clip_tasks:
|
||||
print("No clip tasks discovered. Exit.")
|
||||
return {
|
||||
"source_mode": _input_source_mode(args),
|
||||
"source": _input_source_label(args),
|
||||
"clip_list_file": getattr(args, "clip_list_file", ""),
|
||||
"mcap_file": getattr(args, "mcap_file", ""),
|
||||
"output_dir": str(output_root),
|
||||
"total": 0,
|
||||
"success": 0,
|
||||
"failed": 0,
|
||||
}
|
||||
|
||||
export_status = StatusStore(export_root / "_status" / "task_status.json")
|
||||
infer_status = StatusStore(output_root / "_status" / "task_status.json")
|
||||
if on_before_run is not None:
|
||||
on_before_run(export_root, output_root, clip_tasks)
|
||||
save_run_manifest(args, clip_tasks)
|
||||
save_exported_batch_manifest(args, clip_tasks, output_root)
|
||||
|
||||
print(f"Discovered {len(clip_tasks)} clips.")
|
||||
print(f"Export root: {export_root}")
|
||||
print(f"Visualization root: {output_root}")
|
||||
|
||||
success = 0
|
||||
fail = 0
|
||||
for index, clip_task in enumerate(clip_tasks, start=1):
|
||||
task_id = clip_task.task_id
|
||||
if args.skip_done and infer_status.is_done(task_id):
|
||||
info = infer_status.get(task_id) or {}
|
||||
print(f"[{index}/{len(clip_tasks)}] clip_id={task_id} -> skip done: {info.get('detail', '')}")
|
||||
continue
|
||||
|
||||
print(f"[{index}/{len(clip_tasks)}] clip_id={task_id} source={clip_task.clip_path}")
|
||||
infer_status.mark_running(task_id, "exporting clip and running exported two-roi inference")
|
||||
try:
|
||||
case_dir = export_root / build_case_dir_name(args.output_prefix, clip_task)
|
||||
if has_reusable_exported_case(case_dir):
|
||||
export_status.mark_done(task_id, f"reuse existing export: {case_dir}")
|
||||
print(f" -> reuse exported clip data from {case_dir}")
|
||||
else:
|
||||
export_result = export_one_clip(clip_task, args, export_status)
|
||||
if not export_result.success or not export_result.output_dir:
|
||||
raise RuntimeError(export_result.message)
|
||||
case_dir = Path(export_result.output_dir)
|
||||
|
||||
infer_result = run_case_inference(
|
||||
context=context,
|
||||
case_dir=str(case_dir),
|
||||
output_dir=output_root / case_dir.name,
|
||||
glob_pattern=args.glob,
|
||||
max_images=args.max_images,
|
||||
save_aggregate_predictions=bool(getattr(args, "save_aggregate_predictions", False)),
|
||||
save_visualizations=not bool(getattr(args, "skip_visualizations", False)),
|
||||
)
|
||||
infer_status.mark_done(task_id, infer_result["output_dir"])
|
||||
success += 1
|
||||
print(f" -> saved {infer_result['num_frames']} frames to {infer_result['output_dir']}")
|
||||
except Exception as exc:
|
||||
fail += 1
|
||||
message = f"{type(exc).__name__}: {exc}"
|
||||
infer_status.mark_failed(task_id, message)
|
||||
err_log = output_root / "_status" / "errors.log"
|
||||
err_log.parent.mkdir(parents=True, exist_ok=True)
|
||||
with err_log.open("a", encoding="utf-8") as file:
|
||||
file.write(f"[{task_id}] {message}\n{traceback.format_exc()}\n")
|
||||
print(f" -> failed: {message}")
|
||||
|
||||
print("\nBatch inference done.")
|
||||
print(f"success={success}, fail={fail}")
|
||||
print(f"infer_status_summary={infer_status.summary()}")
|
||||
return {
|
||||
"source_mode": _input_source_mode(args),
|
||||
"source": _input_source_label(args),
|
||||
"clip_list_file": getattr(args, "clip_list_file", ""),
|
||||
"mcap_file": getattr(args, "mcap_file", ""),
|
||||
"export_root": str(export_root),
|
||||
"output_dir": str(output_root),
|
||||
"total": len(clip_tasks),
|
||||
"success": success,
|
||||
"failed": fail,
|
||||
}
|
||||
|
||||
|
||||
def run_clip_list_inference_exported(
|
||||
*,
|
||||
context: Any,
|
||||
args: argparse.Namespace,
|
||||
load_env: Callable[[], Any],
|
||||
run_case_inference: Callable[..., dict[str, Any]],
|
||||
) -> dict[str, Any]:
|
||||
clip_tasks = parse_clip_list(args.clip_list_file)
|
||||
if args.limit_clips > 0:
|
||||
clip_tasks = clip_tasks[: args.limit_clips]
|
||||
return run_clip_tasks_inference_exported(
|
||||
context=context,
|
||||
args=args,
|
||||
clip_tasks=clip_tasks,
|
||||
load_env=load_env,
|
||||
run_case_inference=run_case_inference,
|
||||
)
|
||||
|
||||
|
||||
def run_mcap_file_inference_exported(
|
||||
*,
|
||||
context: Any,
|
||||
args: argparse.Namespace,
|
||||
load_env: Callable[[], Any],
|
||||
run_case_inference: Callable[..., dict[str, Any]],
|
||||
) -> dict[str, Any]:
|
||||
clip_task = build_clip_task_from_mcap_file(
|
||||
args.mcap_file,
|
||||
clip_id=args.mcap_clip_id,
|
||||
date_name=args.mcap_date_name,
|
||||
vehicle_name=args.mcap_vehicle_name,
|
||||
)
|
||||
result = run_clip_tasks_inference_exported(
|
||||
context=context,
|
||||
args=args,
|
||||
clip_tasks=[clip_task],
|
||||
load_env=load_env,
|
||||
run_case_inference=run_case_inference,
|
||||
require_pdcl_auth=False,
|
||||
)
|
||||
if result.get("failed", 0) > 0 or result.get("success", 0) < result.get("total", 0):
|
||||
raise RuntimeError(f"MCAP inference failed for {args.mcap_file}")
|
||||
return result
|
||||
247
tools/model_inference/adapters/video_dir_inference_utils.py
Executable file
247
tools/model_inference/adapters/video_dir_inference_utils.py
Executable file
@@ -0,0 +1,247 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable, Optional
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
|
||||
DEFAULT_CNCAP_PATH_PREFIX_SRC = "/mnt/hfs/project-G1M3"
|
||||
DEFAULT_CNCAP_PATH_PREFIX_DST = "/mnt/G1M3"
|
||||
DEFAULT_OUTPUT_RELATIVE_ANCHORS = ("CNCAP2024数采", "gt_org_data")
|
||||
|
||||
|
||||
def rewrite_path_prefix(path_str: str, prefix_src: str, prefix_dst: str) -> str:
|
||||
normalized_path = str(path_str).strip()
|
||||
normalized_src = str(prefix_src).rstrip("/")
|
||||
normalized_dst = str(prefix_dst).rstrip("/")
|
||||
if normalized_src and normalized_path.startswith(normalized_src):
|
||||
return f"{normalized_dst}{normalized_path[len(normalized_src):]}"
|
||||
return normalized_path
|
||||
|
||||
|
||||
def load_path_list_from_json(json_file: str | Path, values_key: str = "values") -> list[str]:
|
||||
json_path = Path(json_file).resolve()
|
||||
with json_path.open("r", encoding="utf-8") as file:
|
||||
payload = json.load(file)
|
||||
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError(f"Expected top-level dict in {json_path}, got {type(payload).__name__}")
|
||||
|
||||
values = payload.get(values_key)
|
||||
if not isinstance(values, list):
|
||||
raise ValueError(f"Expected {values_key!r} list in {json_path}, got {type(values).__name__}")
|
||||
|
||||
return [str(item).strip() for item in values if str(item).strip()]
|
||||
|
||||
|
||||
def _normalize_video_case_input(video_case_dir: str | Path) -> Path:
|
||||
input_path = Path(video_case_dir).resolve()
|
||||
if input_path.is_file() and input_path.name == "camera4.bin":
|
||||
return input_path.parent.parent
|
||||
if input_path.is_dir() and input_path.name == "sigmastar.1":
|
||||
return input_path.parent
|
||||
return input_path
|
||||
|
||||
|
||||
def build_case_output_rel_dir(
|
||||
case_dir: str | Path,
|
||||
preferred_anchor_names: Iterable[str] = DEFAULT_OUTPUT_RELATIVE_ANCHORS,
|
||||
) -> Path:
|
||||
resolved_case_dir = Path(case_dir).resolve()
|
||||
parts = resolved_case_dir.parts
|
||||
|
||||
for anchor_name in preferred_anchor_names:
|
||||
if anchor_name in parts:
|
||||
anchor_index = parts.index(anchor_name)
|
||||
suffix_parts = parts[anchor_index + 1 :]
|
||||
if suffix_parts:
|
||||
return Path(*suffix_parts)
|
||||
|
||||
if len(parts) >= 3:
|
||||
return Path(*parts[-3:])
|
||||
if len(parts) >= 2:
|
||||
return Path(*parts[-2:])
|
||||
if parts:
|
||||
return Path(parts[-1])
|
||||
return Path("case")
|
||||
|
||||
|
||||
def resolve_video_case_paths(video_case_dir: str | Path) -> tuple[Path, Path, Path]:
|
||||
case_dir = _normalize_video_case_input(video_case_dir)
|
||||
if not case_dir.is_dir():
|
||||
raise FileNotFoundError(f"Video case directory not found: {case_dir}")
|
||||
|
||||
video_path = case_dir / "sigmastar.1" / "camera4.bin"
|
||||
if not video_path.is_file():
|
||||
raise FileNotFoundError(f"camera4.bin not found under {case_dir}")
|
||||
|
||||
calib_candidates = [
|
||||
case_dir / "test_data" / "calibs" / "camera4.json",
|
||||
case_dir.parent / "test_data" / "calibs" / "camera4.json",
|
||||
case_dir / "sigmastar.1" / "calibs" / "camera4.json",
|
||||
case_dir / "calibs" / "camera4.json",
|
||||
]
|
||||
calib_path = next((path for path in calib_candidates if path.is_file()), None)
|
||||
if calib_path is None:
|
||||
checked = ", ".join(str(path) for path in calib_candidates)
|
||||
raise FileNotFoundError(f"camera4.json not found for {case_dir}. Checked: {checked}")
|
||||
|
||||
return case_dir, video_path, calib_path
|
||||
|
||||
|
||||
def collect_video_case_dirs(video_root_dir: str | Path) -> list[Path]:
|
||||
root_dir = Path(video_root_dir).resolve()
|
||||
if not root_dir.is_dir():
|
||||
raise FileNotFoundError(f"Video root directory not found: {root_dir}")
|
||||
|
||||
case_dirs: list[Path] = []
|
||||
for path in sorted(root_dir.iterdir()):
|
||||
if not path.is_dir():
|
||||
continue
|
||||
try:
|
||||
resolve_video_case_paths(path)
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
case_dirs.append(path)
|
||||
|
||||
if not case_dirs:
|
||||
raise FileNotFoundError(f"No valid video case directories found under {root_dir}")
|
||||
return case_dirs
|
||||
|
||||
|
||||
def read_video_frame_index(video_path: str | Path) -> Optional[dict[str, Any]]:
|
||||
try:
|
||||
video_path_obj = Path(video_path).resolve()
|
||||
case_dir = video_path_obj.parent.parent
|
||||
video_folder = video_path_obj.parent.name
|
||||
video_file = video_path_obj.stem
|
||||
index_path = case_dir / "L2" / f"{video_folder}.{video_file}.index.json"
|
||||
if not index_path.is_file():
|
||||
return None
|
||||
with index_path.open("r", encoding="utf-8") as file:
|
||||
payload = json.load(file)
|
||||
return payload if isinstance(payload, dict) else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def get_video_frame_info(frame_index_payload: Optional[dict[str, Any]], frame_idx: int) -> Optional[dict[str, Any]]:
|
||||
if not frame_index_payload:
|
||||
return None
|
||||
|
||||
try:
|
||||
fields = frame_index_payload.get("fields", {})
|
||||
index_list = frame_index_payload.get("index", [])
|
||||
if not isinstance(fields, dict) or not isinstance(index_list, list) or frame_idx >= len(index_list):
|
||||
return None
|
||||
frame_data = index_list[frame_idx]
|
||||
if not isinstance(frame_data, (list, tuple)):
|
||||
return None
|
||||
frame_info = {}
|
||||
for field_name, field_idx in fields.items():
|
||||
if isinstance(field_idx, int) and 0 <= field_idx < len(frame_data):
|
||||
frame_info[str(field_name)] = frame_data[field_idx]
|
||||
return frame_info
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _normalize_frame_info_token(value: Any) -> str:
|
||||
token = str(value or "").strip()
|
||||
if not token or token.lower() == "none":
|
||||
return ""
|
||||
return token.replace("/", "_").replace("\\", "_").replace(" ", "")
|
||||
|
||||
|
||||
def _safe_int(value: Any) -> Optional[int]:
|
||||
try:
|
||||
if value is None:
|
||||
return None
|
||||
return int(str(value).strip())
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def get_video_frame_id(frame_info: Optional[dict[str, Any]]) -> Optional[int]:
|
||||
if not frame_info:
|
||||
return None
|
||||
for key in ("frame_id", "cve_frame_id", "frameId"):
|
||||
frame_id = _safe_int(frame_info.get(key))
|
||||
if frame_id is not None:
|
||||
return frame_id
|
||||
return None
|
||||
|
||||
|
||||
def iter_video_case_frames(
|
||||
video_path: str | Path,
|
||||
*,
|
||||
frame_index_payload: Optional[dict[str, Any]] = None,
|
||||
frame_stride: int = 1,
|
||||
max_frames: int = 0,
|
||||
frame_index_start: Optional[int] = None,
|
||||
frame_index_end: Optional[int] = None,
|
||||
frame_id_start: Optional[int] = None,
|
||||
frame_id_end: Optional[int] = None,
|
||||
) -> Iterable[tuple[int, np.ndarray, str, Optional[dict[str, Any]]]]:
|
||||
resolved_video_path = Path(video_path).resolve()
|
||||
cap = cv2.VideoCapture(str(resolved_video_path))
|
||||
if not cap.isOpened():
|
||||
raise RuntimeError(f"Failed to open video file: {resolved_video_path}")
|
||||
|
||||
stride = max(1, int(frame_stride))
|
||||
resolved_frame_index_start = None if frame_index_start is None else max(0, int(frame_index_start))
|
||||
resolved_frame_index_end = None if frame_index_end is None else int(frame_index_end)
|
||||
resolved_frame_id_start = None if frame_id_start is None else int(frame_id_start)
|
||||
resolved_frame_id_end = None if frame_id_end is None else int(frame_id_end)
|
||||
read_frame_index = 0
|
||||
emitted_count = 0
|
||||
try:
|
||||
while True:
|
||||
ret, frame = cap.read()
|
||||
if not ret:
|
||||
break
|
||||
|
||||
if resolved_frame_index_end is not None and read_frame_index > resolved_frame_index_end:
|
||||
break
|
||||
|
||||
frame_info = get_video_frame_info(frame_index_payload, read_frame_index)
|
||||
frame_id_value = get_video_frame_id(frame_info)
|
||||
|
||||
if resolved_frame_index_start is not None and read_frame_index < resolved_frame_index_start:
|
||||
read_frame_index += 1
|
||||
continue
|
||||
|
||||
if resolved_frame_id_start is not None:
|
||||
if frame_id_value is None or frame_id_value < resolved_frame_id_start:
|
||||
read_frame_index += 1
|
||||
continue
|
||||
|
||||
if resolved_frame_id_end is not None and frame_id_value is not None and frame_id_value > resolved_frame_id_end:
|
||||
break
|
||||
|
||||
if read_frame_index % stride != 0:
|
||||
read_frame_index += 1
|
||||
continue
|
||||
|
||||
frame_id_token = _normalize_frame_info_token(frame_id_value)
|
||||
timestamp_token = _normalize_frame_info_token(None if frame_info is None else frame_info.get("timestamp"))
|
||||
if frame_id_token and timestamp_token:
|
||||
frame_name = f"{resolved_video_path.stem}_{frame_id_token}_{timestamp_token}.png"
|
||||
elif frame_id_token:
|
||||
frame_name = f"{resolved_video_path.stem}_{frame_id_token}.png"
|
||||
elif timestamp_token:
|
||||
frame_name = f"{resolved_video_path.stem}_{read_frame_index:06d}_{timestamp_token}.png"
|
||||
else:
|
||||
frame_name = f"{resolved_video_path.stem}_{read_frame_index:06d}.png"
|
||||
|
||||
yield read_frame_index, frame, frame_name, frame_info
|
||||
emitted_count += 1
|
||||
read_frame_index += 1
|
||||
|
||||
if max_frames > 0 and emitted_count >= max_frames:
|
||||
break
|
||||
finally:
|
||||
cap.release()
|
||||
1
tools/model_inference/core/__init__.py
Executable file
1
tools/model_inference/core/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
"""Core inference modules for the self-contained two-ROI runtime."""
|
||||
1070
tools/model_inference/core/attribute_infer_utils.py
Executable file
1070
tools/model_inference/core/attribute_infer_utils.py
Executable file
File diff suppressed because it is too large
Load Diff
346
tools/model_inference/core/download_rawid_l2_by_event_json.py
Executable file
346
tools/model_inference/core/download_rawid_l2_by_event_json.py
Executable file
@@ -0,0 +1,346 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Download L2 raw packages referenced by scene-grouped event JSON records."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
except ImportError:
|
||||
def load_dotenv(*args: Any, **kwargs: Any) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
FILE = Path(__file__).resolve()
|
||||
ROOT = FILE.parents[3]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.append(str(ROOT))
|
||||
|
||||
from tools.model_inference.adapters.eventid_clip_resolver import ( # noqa: E402
|
||||
DEFAULT_EVENT_CACHE_FILE,
|
||||
ResolvedEventRecord,
|
||||
_extract_condition_values,
|
||||
_sanitize_identifier_for_path,
|
||||
_select_event_records_by_condition,
|
||||
resolve_event_records,
|
||||
)
|
||||
|
||||
|
||||
TIMESTAMP_RE = re.compile(r"^\d{14}$")
|
||||
|
||||
|
||||
@dataclass
|
||||
class DownloadResult:
|
||||
scene: str
|
||||
record_index: int
|
||||
rawid: str
|
||||
rawid_field_used: str
|
||||
condition_values: dict[str, str]
|
||||
l2_timestamp: str | None
|
||||
mdi_key: str | None
|
||||
source_data_path: str | None
|
||||
output_dir: str
|
||||
expected_download_dir: str | None
|
||||
status: str
|
||||
detail: str
|
||||
command: list[str] | None = None
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"scene": self.scene,
|
||||
"record_index": self.record_index,
|
||||
"rawid": self.rawid,
|
||||
"rawid_field_used": self.rawid_field_used,
|
||||
"condition_values": self.condition_values,
|
||||
"l2_timestamp": self.l2_timestamp,
|
||||
"mdi_key": self.mdi_key,
|
||||
"source_data_path": self.source_data_path,
|
||||
"output_dir": self.output_dir,
|
||||
"expected_download_dir": self.expected_download_dir,
|
||||
"status": self.status,
|
||||
"detail": self.detail,
|
||||
"command": self.command,
|
||||
}
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Download L2 data packages by resolving rawid metadata from an event JSON file."
|
||||
)
|
||||
parser.add_argument("--event-json-file", required=True)
|
||||
parser.add_argument("--scene", default="")
|
||||
parser.add_argument("--event-id-field", default="rawid")
|
||||
parser.add_argument("--event-clip-ids-field", default="clips")
|
||||
parser.add_argument("--condition-fields", nargs="*", default=[])
|
||||
parser.add_argument("--max-records-per-condition", type=int, default=0)
|
||||
parser.add_argument("--condition-select-strategy", default="first")
|
||||
parser.add_argument("--max-events", type=int, default=0)
|
||||
parser.add_argument("--event-cache-file", default=str(DEFAULT_EVENT_CACHE_FILE))
|
||||
parser.add_argument("--event-resolve-workers", type=int, default=4)
|
||||
parser.add_argument("--event-request-timeout", type=float, default=60.0)
|
||||
parser.add_argument("--event-request-retries", type=int, default=3)
|
||||
parser.add_argument("--event-request-retry-backoff-sec", type=float, default=2.0)
|
||||
parser.add_argument("--output-root", required=True)
|
||||
parser.add_argument("--manifest-path", default="")
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
parser.add_argument("--skip-done", action="store_true")
|
||||
parser.add_argument("--strict", action="store_true")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def ensure_pdcl_auth_defaults() -> None:
|
||||
load_dotenv()
|
||||
os.environ.setdefault("STS_UID", "dis-uploader")
|
||||
os.environ.setdefault("STS_SECRET_KEY", "277310cc09724d315514a79701fecb0f")
|
||||
|
||||
|
||||
def log_progress(message: str) -> None:
|
||||
timestamp = datetime.now().astimezone().strftime("%Y-%m-%d %H:%M:%S")
|
||||
print(f"[download_rawid_l2 {timestamp}] {message}", flush=True)
|
||||
|
||||
|
||||
def extract_l2_timestamp_from_meta(meta: dict[str, Any]) -> tuple[str, str]:
|
||||
data_info = meta.get("data_info")
|
||||
if isinstance(data_info, dict):
|
||||
items = data_info.get("items")
|
||||
if isinstance(items, list):
|
||||
for item in items:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
if str(item.get("data_type", "")).strip() != "onboard":
|
||||
continue
|
||||
if item.get("available") is False:
|
||||
continue
|
||||
data_path = str(item.get("data_path", "")).strip()
|
||||
timestamp = Path(data_path).stem
|
||||
if TIMESTAMP_RE.fullmatch(timestamp):
|
||||
return timestamp, data_path
|
||||
|
||||
store_path = str(meta.get("store_path", "")).strip()
|
||||
timestamp = Path(store_path).stem
|
||||
if TIMESTAMP_RE.fullmatch(timestamp):
|
||||
return timestamp, store_path
|
||||
|
||||
return "", ""
|
||||
|
||||
|
||||
def load_raw_meta(rawid: str) -> dict[str, Any]:
|
||||
ensure_pdcl_auth_defaults()
|
||||
from pdcl_dss import Raw
|
||||
|
||||
with Raw(rawid) as raw:
|
||||
return dict(raw.meta)
|
||||
|
||||
|
||||
def build_output_dir(output_root: Path, record: ResolvedEventRecord) -> Path:
|
||||
rawid_dir = _sanitize_identifier_for_path(record.event_id, prefix=record.event_id_field_used or "rawid")
|
||||
return output_root / record.scene / rawid_dir
|
||||
|
||||
|
||||
def write_manifest(
|
||||
manifest_path: Path,
|
||||
*,
|
||||
args: argparse.Namespace,
|
||||
selected_records: list[ResolvedEventRecord],
|
||||
selection_summary: dict[str, Any],
|
||||
results: list[DownloadResult],
|
||||
) -> None:
|
||||
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
payload = {
|
||||
"event_json_file": str(Path(args.event_json_file).resolve()),
|
||||
"scene": args.scene,
|
||||
"event_id_field": args.event_id_field,
|
||||
"event_clip_ids_field": args.event_clip_ids_field,
|
||||
"output_root": str(Path(args.output_root).resolve()),
|
||||
"dry_run": bool(args.dry_run),
|
||||
"skip_done": bool(args.skip_done),
|
||||
"strict": bool(args.strict),
|
||||
"selected_record_count": len(selected_records),
|
||||
"selection": selection_summary,
|
||||
"summary": summarize_results(results),
|
||||
"results": [result.to_dict() for result in results],
|
||||
}
|
||||
manifest_path.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
|
||||
def summarize_results(results: list[DownloadResult]) -> dict[str, int]:
|
||||
summary: dict[str, int] = {}
|
||||
for result in results:
|
||||
summary[result.status] = summary.get(result.status, 0) + 1
|
||||
return dict(sorted(summary.items()))
|
||||
|
||||
|
||||
def run_mdi_download(mdi_key: str, output_dir: Path, expected_download_dir: Path, *, dry_run: bool, skip_done: bool) -> tuple[str, str, list[str]]:
|
||||
command = ["mdi", "raw", "-r", mdi_key, "-s", str(output_dir)]
|
||||
|
||||
if skip_done and expected_download_dir.exists():
|
||||
return "exists", f"target already exists: {expected_download_dir}", command
|
||||
|
||||
if dry_run:
|
||||
return "planned", f"would run {' '.join(command)}", command
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
if shutil.which("mdi") is None:
|
||||
return "failed", "mdi command not found in PATH", command
|
||||
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
if completed.returncode == 0:
|
||||
return "downloaded", completed.stdout.strip() or "mdi raw completed", command
|
||||
|
||||
detail = completed.stderr.strip() or completed.stdout.strip() or "mdi raw failed"
|
||||
return "failed", detail, command
|
||||
|
||||
|
||||
def download_one_record(
|
||||
record: ResolvedEventRecord,
|
||||
*,
|
||||
output_root: Path,
|
||||
condition_fields: list[str],
|
||||
dry_run: bool,
|
||||
skip_done: bool,
|
||||
) -> DownloadResult:
|
||||
rawid = record.event_id
|
||||
output_dir = build_output_dir(output_root, record)
|
||||
condition_values = _extract_condition_values(record.source_record, condition_fields)
|
||||
|
||||
try:
|
||||
meta = load_raw_meta(rawid)
|
||||
l2_timestamp, source_data_path = extract_l2_timestamp_from_meta(meta)
|
||||
except Exception as exc:
|
||||
return DownloadResult(
|
||||
scene=record.scene,
|
||||
record_index=record.record_index,
|
||||
rawid=rawid,
|
||||
rawid_field_used=record.event_id_field_used,
|
||||
condition_values=condition_values,
|
||||
l2_timestamp=None,
|
||||
mdi_key=None,
|
||||
source_data_path=None,
|
||||
output_dir=str(output_dir),
|
||||
expected_download_dir=None,
|
||||
status="failed_meta",
|
||||
detail=f"{type(exc).__name__}: {exc}",
|
||||
)
|
||||
|
||||
if not l2_timestamp:
|
||||
return DownloadResult(
|
||||
scene=record.scene,
|
||||
record_index=record.record_index,
|
||||
rawid=rawid,
|
||||
rawid_field_used=record.event_id_field_used,
|
||||
condition_values=condition_values,
|
||||
l2_timestamp=None,
|
||||
mdi_key=None,
|
||||
source_data_path=source_data_path or None,
|
||||
output_dir=str(output_dir),
|
||||
expected_download_dir=None,
|
||||
status="failed_no_l2_timestamp",
|
||||
detail="no onboard L2 timestamp was found in Raw.meta",
|
||||
)
|
||||
|
||||
mdi_key = f"{rawid}::{l2_timestamp}"
|
||||
expected_download_dir = output_dir / l2_timestamp
|
||||
status, detail, command = run_mdi_download(
|
||||
mdi_key,
|
||||
output_dir,
|
||||
expected_download_dir,
|
||||
dry_run=dry_run,
|
||||
skip_done=skip_done,
|
||||
)
|
||||
return DownloadResult(
|
||||
scene=record.scene,
|
||||
record_index=record.record_index,
|
||||
rawid=rawid,
|
||||
rawid_field_used=record.event_id_field_used,
|
||||
condition_values=condition_values,
|
||||
l2_timestamp=l2_timestamp,
|
||||
mdi_key=mdi_key,
|
||||
source_data_path=source_data_path,
|
||||
output_dir=str(output_dir),
|
||||
expected_download_dir=str(expected_download_dir),
|
||||
status=status,
|
||||
detail=detail,
|
||||
command=command,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
condition_fields = [str(field).strip() for field in args.condition_fields if str(field).strip()]
|
||||
output_root = Path(args.output_root).resolve()
|
||||
manifest_path = (
|
||||
Path(args.manifest_path).resolve()
|
||||
if args.manifest_path
|
||||
else output_root / "download_manifest.json"
|
||||
)
|
||||
|
||||
resolved_records, _ = resolve_event_records(
|
||||
json_file=args.event_json_file,
|
||||
scene_filter=args.scene or None,
|
||||
event_id_field=args.event_id_field,
|
||||
clip_ids_field=args.event_clip_ids_field,
|
||||
max_events=args.max_events,
|
||||
timeout=args.event_request_timeout,
|
||||
cache_file=args.event_cache_file,
|
||||
workers=args.event_resolve_workers,
|
||||
max_retries=args.event_request_retries,
|
||||
retry_backoff_sec=args.event_request_retry_backoff_sec,
|
||||
)
|
||||
selected_records, selection_summary = _select_event_records_by_condition(
|
||||
resolved_records,
|
||||
condition_fields=condition_fields,
|
||||
max_records_per_condition=args.max_records_per_condition,
|
||||
selection_strategy=args.condition_select_strategy,
|
||||
)
|
||||
|
||||
log_progress(
|
||||
f"selected {len(selected_records)} rawid record(s) from {len(resolved_records)} resolved record(s)"
|
||||
)
|
||||
|
||||
results: list[DownloadResult] = []
|
||||
for index, record in enumerate(selected_records, start=1):
|
||||
log_progress(f"[{index}/{len(selected_records)}] {record.scene} {record.event_id}")
|
||||
result = download_one_record(
|
||||
record,
|
||||
output_root=output_root,
|
||||
condition_fields=condition_fields,
|
||||
dry_run=args.dry_run,
|
||||
skip_done=args.skip_done,
|
||||
)
|
||||
results.append(result)
|
||||
log_progress(f" -> {result.status}: {result.mdi_key or result.detail}")
|
||||
write_manifest(
|
||||
manifest_path,
|
||||
args=args,
|
||||
selected_records=selected_records,
|
||||
selection_summary=selection_summary,
|
||||
results=results,
|
||||
)
|
||||
|
||||
summary = summarize_results(results)
|
||||
log_progress(f"manifest: {manifest_path}")
|
||||
log_progress("summary: " + ", ".join(f"{key}={value}" for key, value in summary.items()))
|
||||
|
||||
if args.strict and any(result.status.startswith("failed") for result in results):
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1013
tools/model_inference/core/edge_yaw_utils.py
Executable file
1013
tools/model_inference/core/edge_yaw_utils.py
Executable file
File diff suppressed because it is too large
Load Diff
4468
tools/model_inference/core/run_two_roi_exported_onnx_infer.py
Executable file
4468
tools/model_inference/core/run_two_roi_exported_onnx_infer.py
Executable file
File diff suppressed because it is too large
Load Diff
921
tools/model_inference/core/two_roi_3d_utils.py
Executable file
921
tools/model_inference/core/two_roi_3d_utils.py
Executable file
@@ -0,0 +1,921 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from typing import Any, Optional
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
from .two_roi_types import (
|
||||
Decoded3DPrediction,
|
||||
DecodedVisibleEdge,
|
||||
Prediction3DAttrs,
|
||||
ResizedCalib,
|
||||
)
|
||||
except ImportError:
|
||||
from two_roi_types import (
|
||||
Decoded3DPrediction,
|
||||
DecodedVisibleEdge,
|
||||
Prediction3DAttrs,
|
||||
ResizedCalib,
|
||||
)
|
||||
|
||||
|
||||
PROJECTION_Z_MIN = 0.1
|
||||
YAW_BIN_OFFSETS = (0.0, np.pi / 2, -np.pi / 2, np.pi)
|
||||
FACE_OFFSETS_41 = (0, 6, 12, 18)
|
||||
FACE_EDGE_OFFSETS_60 = (0, 15, 30, 45)
|
||||
FACE_CORNERS = {0: (4, 5, 6, 7), 1: (0, 1, 2, 3), 2: (1, 2, 5, 6), 3: (0, 3, 4, 7)}
|
||||
FACE_BOTTOM_EDGE_CORNERS = {0: (6, 7), 1: (2, 3), 2: (2, 6), 3: (3, 7)}
|
||||
FACE_CENTER_OFFSETS = {0: [1, 0.5, 0.5], 1: [0, 0.5, 0.5], 2: [0.5, 0.5, 1], 3: [0.5, 0.5, 0]}
|
||||
FACE_VISIBILITY_SCORE_THRESH = 0.05
|
||||
CUT_STATE_NORMAL = 0
|
||||
CUT_STATE_IN = 1
|
||||
CUT_STATE_OUT = 2
|
||||
FACE_COLORS = ((0, 0, 255), (255, 0, 0), (0, 255, 0), (0, 255, 255))
|
||||
|
||||
|
||||
def rotation_3d_in_axis(points, angles, axis=1):
|
||||
rot_sin = np.sin(angles)
|
||||
rot_cos = np.cos(angles)
|
||||
ones = np.ones_like(rot_cos)
|
||||
zeros = np.zeros_like(rot_cos)
|
||||
if axis == 1:
|
||||
rot_mat = np.stack(
|
||||
[
|
||||
np.stack([rot_cos, zeros, -rot_sin]),
|
||||
np.stack([zeros, ones, zeros]),
|
||||
np.stack([rot_sin, zeros, rot_cos]),
|
||||
]
|
||||
)
|
||||
elif axis == 2:
|
||||
rot_mat = np.stack(
|
||||
[
|
||||
np.stack([rot_cos, rot_sin, zeros]),
|
||||
np.stack([-rot_sin, rot_cos, zeros]),
|
||||
np.stack([zeros, zeros, ones]),
|
||||
]
|
||||
)
|
||||
elif axis == 0:
|
||||
rot_mat = np.stack(
|
||||
[
|
||||
np.stack([ones, zeros, zeros]),
|
||||
np.stack([zeros, rot_cos, rot_sin]),
|
||||
np.stack([zeros, -rot_sin, rot_cos]),
|
||||
]
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"axis should be in [0, 1, 2], got {axis}")
|
||||
return np.dot(points, rot_mat)
|
||||
|
||||
|
||||
def compute_3d_box_corners(center_3d, dimensions, rotation, face_type=-1):
|
||||
l, h, w = dimensions
|
||||
corners_norm = np.stack(np.unravel_index(np.arange(8), [2] * 3), axis=1).astype(np.float64)
|
||||
corners_norm = corners_norm[[0, 1, 3, 2, 4, 5, 7, 6]]
|
||||
corners_norm -= FACE_CENTER_OFFSETS.get(face_type, [0.5, 0.5, 0.5])
|
||||
corners = np.array([l, h, w]).reshape(1, 3) * corners_norm.reshape(8, 3)
|
||||
corners = rotation_3d_in_axis(corners, rotation, axis=1)
|
||||
corners += np.array(center_3d).reshape(1, 3)
|
||||
return corners
|
||||
|
||||
|
||||
def apply_fisheye_distortion(x, y, distort_coeffs):
|
||||
if distort_coeffs is None or len(distort_coeffs) < 4:
|
||||
return x, y
|
||||
k1, k2, k3, k4 = distort_coeffs[:4]
|
||||
r = np.sqrt(x * x + y * y)
|
||||
if r < 1e-8:
|
||||
return x, y
|
||||
theta = np.arctan(r)
|
||||
theta2 = theta * theta
|
||||
theta4 = theta2 * theta2
|
||||
theta6 = theta4 * theta2
|
||||
theta8 = theta4 * theta4
|
||||
theta_d = theta * (1 + k1 * theta2 + k2 * theta4 + k3 * theta6 + k4 * theta8)
|
||||
scale = theta_d / r
|
||||
return x * scale, y * scale
|
||||
|
||||
|
||||
def remove_fisheye_distortion(xd, yd, distort_coeffs, max_iter=20):
|
||||
if distort_coeffs is None or len(distort_coeffs) < 4:
|
||||
return xd, yd
|
||||
k1, k2, k3, k4 = distort_coeffs[:4]
|
||||
r_d = np.sqrt(xd * xd + yd * yd)
|
||||
if r_d < 1e-8:
|
||||
return xd, yd
|
||||
theta_d = r_d
|
||||
theta_d2 = theta_d * theta_d
|
||||
theta = theta_d / (1 + k1 * theta_d2)
|
||||
for _ in range(max_iter):
|
||||
theta2 = theta * theta
|
||||
theta4 = theta2 * theta2
|
||||
theta6 = theta4 * theta2
|
||||
theta8 = theta4 * theta4
|
||||
f = theta * (1 + k1 * theta2 + k2 * theta4 + k3 * theta6 + k4 * theta8) - theta_d
|
||||
f_prime = 1 + 3 * k1 * theta2 + 5 * k2 * theta4 + 7 * k3 * theta6 + 9 * k4 * theta8
|
||||
theta_new = theta - f / f_prime
|
||||
if abs(theta_new - theta) < 1e-8:
|
||||
theta = theta_new
|
||||
break
|
||||
theta = theta_new
|
||||
r = np.tan(theta)
|
||||
scale = r / r_d
|
||||
return xd * scale, yd * scale
|
||||
|
||||
|
||||
def project_3d_to_2d_with_distortion(points_3d, calib: ResizedCalib):
|
||||
fx, fy = calib["fx"], calib["fy"]
|
||||
cx, cy = calib["cx"], calib["cy"]
|
||||
distort_coeffs = calib.get("distort_coeffs", [])
|
||||
points_2d = np.full((len(points_3d), 2), np.nan)
|
||||
for index, (x, y, z) in enumerate(points_3d):
|
||||
if z > PROJECTION_Z_MIN:
|
||||
xn, yn = x / z, y / z
|
||||
xd, yd = apply_fisheye_distortion(xn, yn, distort_coeffs)
|
||||
points_2d[index] = [fx * xd + cx, fy * yd + cy]
|
||||
return points_2d
|
||||
|
||||
|
||||
def project_3d_to_2d_with_calib(points_3d, calib: ResizedCalib):
|
||||
fx, fy = calib["fx"], calib["fy"]
|
||||
cx, cy = calib["cx"], calib["cy"]
|
||||
points_2d = np.full((len(points_3d), 2), np.nan)
|
||||
for index, (x, y, z) in enumerate(points_3d):
|
||||
if z > PROJECTION_Z_MIN:
|
||||
points_2d[index] = [fx * x / z + cx, fy * y / z + cy]
|
||||
return points_2d
|
||||
|
||||
|
||||
def project_3d_to_2d(points_3d, calib: ResizedCalib):
|
||||
if calib is None:
|
||||
return np.full((len(points_3d), 2), np.nan)
|
||||
distort_coeffs = calib.get("distort_coeffs", [])
|
||||
if distort_coeffs is not None and len(distort_coeffs) >= 4:
|
||||
return project_3d_to_2d_with_distortion(points_3d, calib)
|
||||
return project_3d_to_2d_with_calib(points_3d, calib)
|
||||
|
||||
|
||||
def sample_3d_edge(p1, p2, num_samples=10):
|
||||
t = np.linspace(0.0, 1.0, num_samples, dtype=np.float64).reshape(-1, 1)
|
||||
return p1 + t * (p2 - p1)
|
||||
|
||||
|
||||
def _point_inside_image(point_2d, img_w, img_h):
|
||||
x, y = float(point_2d[0]), float(point_2d[1])
|
||||
return np.isfinite(x) and np.isfinite(y) and 0.0 <= x <= img_w - 1 and 0.0 <= y <= img_h - 1
|
||||
|
||||
|
||||
def _solve_edge_image_boundary_t(p0_2d, p1_2d, img_w, img_h):
|
||||
p0 = np.asarray(p0_2d, dtype=np.float64)
|
||||
p1 = np.asarray(p1_2d, dtype=np.float64)
|
||||
if not np.isfinite(p0).all() or not np.isfinite(p1).all():
|
||||
return None
|
||||
dx, dy = p1 - p0
|
||||
t_min, t_max = 0.0, 1.0
|
||||
for p, q in ((-dx, p0[0]), (dx, (img_w - 1) - p0[0]), (-dy, p0[1]), (dy, (img_h - 1) - p0[1])):
|
||||
if abs(p) < 1e-12:
|
||||
if q < 0:
|
||||
return None
|
||||
continue
|
||||
t = q / p
|
||||
if p < 0:
|
||||
t_min = max(t_min, t)
|
||||
else:
|
||||
t_max = min(t_max, t)
|
||||
if t_min > t_max:
|
||||
return None
|
||||
return t_min, t_max
|
||||
|
||||
|
||||
def _project_edge_point_at_t(p1, p2, t, calib: ResizedCalib):
|
||||
point_3d = np.asarray(p1, dtype=np.float64) + float(t) * (np.asarray(p2, dtype=np.float64) - np.asarray(p1, dtype=np.float64))
|
||||
point_2d = project_3d_to_2d(point_3d[None, :], calib)[0]
|
||||
return point_3d, point_2d
|
||||
|
||||
|
||||
def _refine_visible_edge_boundary(p1, p2, calib: ResizedCalib, img_w, img_h, t_out, t_in, steps=12):
|
||||
lo, hi = (float(t_out), float(t_in)) if t_out < t_in else (float(t_in), float(t_out))
|
||||
for _ in range(steps):
|
||||
mid = 0.5 * (lo + hi)
|
||||
_, point_2d = _project_edge_point_at_t(p1, p2, mid, calib)
|
||||
if _point_inside_image(point_2d, img_w, img_h):
|
||||
hi = mid
|
||||
else:
|
||||
lo = mid
|
||||
return hi if t_out < t_in else lo
|
||||
|
||||
|
||||
def sample_partial_3d_edge(p1, p2, calib: ResizedCalib, img_w, img_h, num_samples=5, dense_samples=129):
|
||||
endpoints_3d = np.asarray([p1, p2], dtype=np.float64)
|
||||
dense_t = np.linspace(0.0, 1.0, dense_samples, dtype=np.float64)
|
||||
dense_points_3d = endpoints_3d[0:1] + dense_t[:, None] * (endpoints_3d[1:2] - endpoints_3d[0:1])
|
||||
dense_points_2d = project_3d_to_2d(dense_points_3d, calib)
|
||||
visible = np.array([_point_inside_image(point_2d, img_w, img_h) for point_2d in dense_points_2d], dtype=bool)
|
||||
if not visible.any():
|
||||
return None, None
|
||||
|
||||
visible_idx = np.flatnonzero(visible)
|
||||
split_idx = np.where(np.diff(visible_idx) > 1)[0] + 1
|
||||
visible_runs = np.split(visible_idx, split_idx)
|
||||
visible_run = max(visible_runs, key=len)
|
||||
first_idx, last_idx = int(visible_run[0]), int(visible_run[-1])
|
||||
|
||||
t_start = dense_t[first_idx]
|
||||
if first_idx > 0:
|
||||
t_start = _refine_visible_edge_boundary(
|
||||
endpoints_3d[0],
|
||||
endpoints_3d[1],
|
||||
calib,
|
||||
img_w,
|
||||
img_h,
|
||||
dense_t[first_idx - 1],
|
||||
dense_t[first_idx],
|
||||
)
|
||||
|
||||
t_end = dense_t[last_idx]
|
||||
if last_idx < len(dense_t) - 1:
|
||||
t_end = _refine_visible_edge_boundary(
|
||||
endpoints_3d[0],
|
||||
endpoints_3d[1],
|
||||
calib,
|
||||
img_w,
|
||||
img_h,
|
||||
dense_t[last_idx + 1],
|
||||
dense_t[last_idx],
|
||||
)
|
||||
|
||||
if t_end - t_start < 1e-6:
|
||||
return None, None
|
||||
|
||||
sample_t = np.linspace(t_start, t_end, num_samples, dtype=np.float64)
|
||||
sample_points_3d = endpoints_3d[0:1] + sample_t[:, None] * (endpoints_3d[1:2] - endpoints_3d[0:1])
|
||||
sample_points_2d = project_3d_to_2d(sample_points_3d, calib)
|
||||
if np.any(np.isnan(sample_points_2d)):
|
||||
return None, None
|
||||
if not np.all([_point_inside_image(point_2d, img_w, img_h) for point_2d in sample_points_2d]):
|
||||
return None, None
|
||||
|
||||
order = np.argsort(sample_points_2d[:, 0], kind="stable")
|
||||
return sample_points_3d[order], sample_points_2d[order]
|
||||
|
||||
|
||||
def project_3d_box_edges_with_distortion(corners_3d, calib: ResizedCalib, samples_per_edge=10):
|
||||
edges = {
|
||||
"back_0": (4, 5),
|
||||
"back_1": (5, 6),
|
||||
"back_2": (6, 7),
|
||||
"back_3": (7, 4),
|
||||
"connect_0": (0, 4),
|
||||
"connect_1": (1, 5),
|
||||
"connect_2": (2, 6),
|
||||
"connect_3": (3, 7),
|
||||
"front_0": (0, 1),
|
||||
"front_1": (1, 2),
|
||||
"front_2": (2, 3),
|
||||
"front_3": (3, 0),
|
||||
"front_x1": (0, 2),
|
||||
"front_x2": (1, 3),
|
||||
}
|
||||
edge_points_2d = {}
|
||||
for edge_name, (i, j) in edges.items():
|
||||
sampled_3d = sample_3d_edge(corners_3d[i], corners_3d[j], samples_per_edge)
|
||||
edge_points_2d[edge_name] = project_3d_to_2d_with_distortion(sampled_3d, calib)
|
||||
return edge_points_2d
|
||||
|
||||
|
||||
def plot_box3d_on_img_with_distortion(
|
||||
img,
|
||||
edge_points_2d,
|
||||
color_front=(0, 0, 255),
|
||||
color_back=(255, 0, 0),
|
||||
color_side=(255, 255, 0),
|
||||
thickness=1,
|
||||
):
|
||||
front_edges = {"front_0", "front_1", "front_2", "front_3", "front_x1", "front_x2"}
|
||||
back_edges = {"back_0", "back_1", "back_2", "back_3", "back_x1", "back_x2"}
|
||||
for edge_name, points in edge_points_2d.items():
|
||||
if np.any(np.isnan(points)):
|
||||
continue
|
||||
pts = points.astype(np.int32)
|
||||
color = color_front if edge_name in front_edges else color_back if edge_name in back_edges else color_side
|
||||
cv2.polylines(img, [pts], isClosed=False, color=color, thickness=thickness, lineType=cv2.LINE_AA)
|
||||
return img
|
||||
|
||||
|
||||
def plot_box3d_on_img(img, corners_2d, color_front=(0, 0, 255), color_back=(255, 0, 0), color_side=(255, 255, 0), thickness=1):
|
||||
line_indices = (
|
||||
(4, 5),
|
||||
(5, 6),
|
||||
(6, 7),
|
||||
(7, 4),
|
||||
(0, 4),
|
||||
(1, 5),
|
||||
(2, 6),
|
||||
(3, 7),
|
||||
(0, 1),
|
||||
(1, 2),
|
||||
(2, 3),
|
||||
(3, 0),
|
||||
(0, 2),
|
||||
(1, 3),
|
||||
)
|
||||
front_edges = {(0, 1), (1, 2), (2, 3), (3, 0), (0, 2), (1, 3)}
|
||||
back_edges = {(4, 5), (5, 6), (6, 7), (7, 4)}
|
||||
pts = corners_2d.astype(np.int32)
|
||||
for i, j in line_indices:
|
||||
color = color_front if (i, j) in front_edges else color_back if (i, j) in back_edges else color_side
|
||||
cv2.line(img, tuple(pts[i]), tuple(pts[j]), color, thickness, cv2.LINE_AA)
|
||||
return img
|
||||
|
||||
|
||||
def back_project_2d_to_3d(uv, depth, calib: ResizedCalib):
|
||||
if calib is None or depth <= 0:
|
||||
return None
|
||||
fx, fy = calib["fx"], calib["fy"]
|
||||
cx, cy = calib["cx"], calib["cy"]
|
||||
u, v = uv
|
||||
xd = (u - cx) / fx
|
||||
yd = (v - cy) / fy
|
||||
distort_coeffs = calib.get("distort_coeffs", [])
|
||||
if distort_coeffs is not None and len(distort_coeffs) >= 4:
|
||||
xn, yn = remove_fisheye_distortion(xd, yd, distort_coeffs)
|
||||
else:
|
||||
xn, yn = xd, yd
|
||||
return np.array([xn * depth, yn * depth, depth], dtype=np.float64)
|
||||
|
||||
|
||||
def reconstruct_3d_box_from_face(face_uv, face_z, dims, rot_y, face_type, calib: ResizedCalib):
|
||||
if calib is None or face_z <= 0:
|
||||
return None
|
||||
center_3d = back_project_2d_to_3d(face_uv, face_z, calib)
|
||||
if center_3d is None:
|
||||
return None
|
||||
if np.any(np.isnan(np.asarray(dims, dtype=np.float64))) or not np.isfinite(float(rot_y)):
|
||||
return None
|
||||
return compute_3d_box_corners(center_3d, dims, rot_y, face_type)
|
||||
|
||||
|
||||
def reconstruct_3d_box_from_whole(uv, z3d, dims, rot_y, calib: ResizedCalib):
|
||||
if calib is None or z3d <= 0:
|
||||
return None
|
||||
center_3d = back_project_2d_to_3d(uv, z3d, calib)
|
||||
if center_3d is None:
|
||||
return None
|
||||
if np.any(np.isnan(np.asarray(dims, dtype=np.float64))) or not np.isfinite(float(rot_y)):
|
||||
return None
|
||||
return compute_3d_box_corners(center_3d, dims, rot_y, face_type=-1)
|
||||
|
||||
|
||||
def get_face_bottom_edge_points(corners_3d, face_type, num_samples=5):
|
||||
if corners_3d is None or face_type not in FACE_BOTTOM_EDGE_CORNERS:
|
||||
return None
|
||||
start_idx, end_idx = FACE_BOTTOM_EDGE_CORNERS[face_type]
|
||||
return sample_3d_edge(corners_3d[start_idx], corners_3d[end_idx], num_samples=num_samples)
|
||||
|
||||
|
||||
def project_face_bottom_edge(corners_3d, face_type, calib: ResizedCalib, num_samples=5):
|
||||
points_3d = get_face_bottom_edge_points(corners_3d, face_type, num_samples=num_samples)
|
||||
if points_3d is None:
|
||||
return None, None
|
||||
points_2d = project_3d_to_2d(points_3d, calib)
|
||||
if np.any(np.isnan(points_2d)):
|
||||
return points_3d, None
|
||||
order = np.argsort(points_2d[:, 0], kind="stable")
|
||||
return points_3d[order], points_2d[order]
|
||||
|
||||
|
||||
def project_partial_face_bottom_edge(corners_3d, face_type, calib: ResizedCalib, img_w, img_h, num_samples=5):
|
||||
if corners_3d is None or face_type not in FACE_BOTTOM_EDGE_CORNERS:
|
||||
return None, None
|
||||
start_idx, end_idx = FACE_BOTTOM_EDGE_CORNERS[face_type]
|
||||
return sample_partial_3d_edge(corners_3d[start_idx], corners_3d[end_idx], calib, img_w, img_h, num_samples=num_samples)
|
||||
|
||||
|
||||
def collect_face_bottom_edges(corners_3d, face_types, calib: ResizedCalib, num_samples=5):
|
||||
if corners_3d is None:
|
||||
return None, None
|
||||
edge_points_3d, edge_points_2d = [], []
|
||||
for face_type in face_types:
|
||||
points_3d, points_2d = project_face_bottom_edge(corners_3d, face_type, calib, num_samples=num_samples)
|
||||
if points_3d is None or points_2d is None:
|
||||
continue
|
||||
edge_points_3d.append(points_3d.astype(np.float32, copy=False))
|
||||
edge_points_2d.append(points_2d.astype(np.float32, copy=False))
|
||||
if not edge_points_2d:
|
||||
return None, None
|
||||
if len(edge_points_2d) == 1:
|
||||
return edge_points_3d[0], edge_points_2d[0]
|
||||
return np.stack(edge_points_3d, axis=0), np.stack(edge_points_2d, axis=0)
|
||||
|
||||
|
||||
def _edge_batches_to_list(edge_points):
|
||||
if edge_points is None:
|
||||
return []
|
||||
arr = np.asarray(edge_points, dtype=np.float32)
|
||||
if arr.ndim == 2:
|
||||
return [arr]
|
||||
return [arr[i] for i in range(arr.shape[0])]
|
||||
|
||||
|
||||
def _stack_edge_batches(edge_batches):
|
||||
if not edge_batches:
|
||||
return None
|
||||
if len(edge_batches) == 1:
|
||||
return edge_batches[0]
|
||||
return np.stack(edge_batches, axis=0)
|
||||
|
||||
|
||||
def _append_edge_batch(edge_points_3d, edge_points_2d, decoded_edge: DecodedVisibleEdge):
|
||||
if decoded_edge.points_3d is None:
|
||||
return edge_points_3d, edge_points_2d
|
||||
edge3d_list = _edge_batches_to_list(edge_points_3d)
|
||||
edge2d_list = _edge_batches_to_list(edge_points_2d)
|
||||
edge3d_list.append(np.asarray(decoded_edge.points_3d, dtype=np.float32))
|
||||
edge2d_list.append(np.asarray(decoded_edge.points_2d, dtype=np.float32))
|
||||
return _stack_edge_batches(edge3d_list), _stack_edge_batches(edge2d_list)
|
||||
|
||||
|
||||
def decode_visible_face_edge_from_prediction(pred_edge_60, face_type, anchor_xy, stride) -> Optional[DecodedVisibleEdge]:
|
||||
if pred_edge_60 is None or face_type not in range(4):
|
||||
return None
|
||||
off = FACE_EDGE_OFFSETS_60[face_type]
|
||||
face = np.asarray(pred_edge_60[off : off + 15], dtype=np.float32).reshape(5, 3)
|
||||
points_2d = np.empty((5, 2), dtype=np.float32)
|
||||
points_2d[:, 0] = (anchor_xy[0] + face[:, 0]) * stride
|
||||
points_2d[:, 1] = (anchor_xy[1] + face[:, 1]) * stride
|
||||
order = np.argsort(points_2d[:, 0], kind="stable")
|
||||
return DecodedVisibleEdge(
|
||||
face_type=int(face_type),
|
||||
points_2d=points_2d[order],
|
||||
depths=face[order, 2].astype(np.float32),
|
||||
)
|
||||
|
||||
|
||||
def get_cut_side_from_bbox_xyxy(bbox_xyxy, img_w, tol=1.0):
|
||||
if bbox_xyxy is None:
|
||||
return None
|
||||
x1, _, x2, _ = np.asarray(bbox_xyxy, dtype=np.float64)
|
||||
touch_left = x1 <= tol and x2 > tol
|
||||
touch_right = x2 >= img_w - 1 - tol and x1 < img_w - 1 - tol
|
||||
if touch_left == touch_right:
|
||||
return None
|
||||
return "left" if touch_left else "right"
|
||||
|
||||
|
||||
def get_cut_object_side_face(face_type_or_state, cut_side=None):
|
||||
if cut_side not in {"left", "right"}:
|
||||
return None
|
||||
if face_type_or_state not in {CUT_STATE_IN, CUT_STATE_OUT}:
|
||||
return None
|
||||
return 3 if cut_side == "left" else 2
|
||||
|
||||
|
||||
def get_pred_cut_state(pred_41):
|
||||
cut_logits = np.asarray(pred_41[38:41], dtype=np.float32)
|
||||
return int(np.argmax(cut_logits))
|
||||
|
||||
|
||||
def get_pred_cut_primary_face(cut_state):
|
||||
if cut_state == CUT_STATE_IN:
|
||||
return 0
|
||||
if cut_state == CUT_STATE_OUT:
|
||||
return 1
|
||||
return None
|
||||
|
||||
|
||||
def _resolve_pred_cut_state_for_decode(pred_41, bbox_xyxy=None, img_w=None):
|
||||
cut_state = get_pred_cut_state(pred_41)
|
||||
if cut_state == CUT_STATE_NORMAL:
|
||||
return cut_state, None
|
||||
cut_side = None
|
||||
if bbox_xyxy is not None and img_w is not None:
|
||||
cut_side = get_cut_side_from_bbox_xyxy(bbox_xyxy, img_w)
|
||||
if cut_side not in {"left", "right"}:
|
||||
return CUT_STATE_NORMAL, None
|
||||
return cut_state, cut_side
|
||||
|
||||
|
||||
def select_pred_visible_faces(pred_41, score_thr=FACE_VISIBILITY_SCORE_THRESH):
|
||||
selected = []
|
||||
for face_type, off in enumerate(FACE_OFFSETS_41):
|
||||
score = float(pred_41[off + 5])
|
||||
if np.isnan(score) or score < score_thr:
|
||||
continue
|
||||
selected.append((face_type, score))
|
||||
return selected
|
||||
|
||||
|
||||
def _select_best_pred_face_score(pred_41):
|
||||
best_face_type, best_score = None, float("-inf")
|
||||
for face_type, off in enumerate(FACE_OFFSETS_41):
|
||||
score = float(pred_41[off + 5])
|
||||
if not np.isfinite(score):
|
||||
continue
|
||||
if score > best_score:
|
||||
best_face_type = int(face_type)
|
||||
best_score = float(score)
|
||||
if best_face_type is None:
|
||||
return None
|
||||
return best_face_type, best_score
|
||||
|
||||
|
||||
def select_pred_visible_faces_for_decode(pred_41, score_thr=FACE_VISIBILITY_SCORE_THRESH, bbox_xyxy=None, img_w=None):
|
||||
cut_state, _ = _resolve_pred_cut_state_for_decode(pred_41, bbox_xyxy=bbox_xyxy, img_w=img_w)
|
||||
primary_face = get_pred_cut_primary_face(cut_state)
|
||||
if primary_face is not None:
|
||||
off = FACE_OFFSETS_41[primary_face]
|
||||
return [(primary_face, float(pred_41[off + 5]))]
|
||||
visible_faces = list(select_pred_visible_faces(pred_41, score_thr=score_thr))
|
||||
best_face = _select_best_pred_face_score(pred_41)
|
||||
if best_face is None:
|
||||
return visible_faces
|
||||
best_face_type, best_score = best_face
|
||||
if all(int(face_type) != int(best_face_type) for face_type, _ in visible_faces):
|
||||
visible_faces.append((int(best_face_type), float(best_score)))
|
||||
return visible_faces
|
||||
|
||||
|
||||
def decode_cut_partial_side_edge_from_prediction(pred_41, pred_edge_60, anchor_xy, stride, img_w, cut_side=None) -> Optional[DecodedVisibleEdge]:
|
||||
if pred_edge_60 is None:
|
||||
return None
|
||||
cut_state = get_pred_cut_state(pred_41)
|
||||
if cut_state == CUT_STATE_NORMAL:
|
||||
return None
|
||||
side_face_type = get_cut_object_side_face(cut_state, cut_side)
|
||||
if side_face_type is None:
|
||||
return None
|
||||
return decode_visible_face_edge_from_prediction(pred_edge_60, side_face_type, anchor_xy, stride)
|
||||
|
||||
|
||||
def _decoded_edge_to_points_3d(decoded_edge: Optional[DecodedVisibleEdge], calib: ResizedCalib) -> Optional[np.ndarray]:
|
||||
if decoded_edge is None:
|
||||
return None
|
||||
points = [back_project_2d_to_3d(tuple(pt), depth, calib) for pt, depth in zip(decoded_edge.points_2d, decoded_edge.depths)]
|
||||
if any(point is None for point in points):
|
||||
return None
|
||||
return np.asarray(points, dtype=np.float32)
|
||||
|
||||
|
||||
def edge_points_to_yaw(points_3d, face_type):
|
||||
points = np.asarray(points_3d, dtype=np.float32)
|
||||
if points.shape[0] < 2:
|
||||
return float("nan")
|
||||
direction = points[-1] - points[0]
|
||||
yaw = math.atan2(float(direction[0]), float(direction[2]))
|
||||
if face_type == 0:
|
||||
return yaw
|
||||
if face_type == 1:
|
||||
return yaw + np.pi
|
||||
if face_type == 2:
|
||||
return yaw + np.pi / 2
|
||||
if face_type == 3:
|
||||
return yaw - np.pi / 2
|
||||
return float("nan")
|
||||
|
||||
|
||||
def visible_face_edges_to_yaw(face_edges_3d, face_scores=None):
|
||||
if not face_edges_3d:
|
||||
return float("nan")
|
||||
if face_scores:
|
||||
face_type = max(face_edges_3d.keys(), key=lambda ft: face_scores.get(ft, 0.0))
|
||||
return edge_points_to_yaw(face_edges_3d[face_type], face_type)
|
||||
face_type = next(iter(face_edges_3d))
|
||||
return edge_points_to_yaw(face_edges_3d[face_type], face_type)
|
||||
|
||||
|
||||
def _draw_edge_points(img, edge_points_2d=None, edge_color=(0, 255, 0), thickness=1):
|
||||
if edge_points_2d is None:
|
||||
return
|
||||
points = np.asarray(edge_points_2d, dtype=np.float32)
|
||||
if points.ndim == 2:
|
||||
points = points[None, ...]
|
||||
for batch in points:
|
||||
for point in batch:
|
||||
cv2.circle(img, tuple(np.round(point).astype(np.int32)), max(thickness + 1, 2), edge_color, -1, cv2.LINE_AA)
|
||||
|
||||
|
||||
def _decode_yaw_from_prediction(pred_41):
|
||||
yaw_cls_logits = pred_41[30:34]
|
||||
yaw_residual_sin = np.clip(pred_41[34:38], -1.0, 1.0)
|
||||
best_bin = int(np.argmax(yaw_cls_logits))
|
||||
return np.arcsin(yaw_residual_sin[best_bin]) + YAW_BIN_OFFSETS[best_bin]
|
||||
|
||||
|
||||
def decode_3d_prediction(
|
||||
pred_41,
|
||||
anchor_xy,
|
||||
stride,
|
||||
calib,
|
||||
img_w,
|
||||
img_h,
|
||||
face_3d_classes,
|
||||
complete_3d_classes,
|
||||
cls_id,
|
||||
pred_edge_60=None,
|
||||
score_thr=FACE_VISIBILITY_SCORE_THRESH,
|
||||
bbox_xyxy=None,
|
||||
) -> Optional[Decoded3DPrediction]:
|
||||
pred = pred_41
|
||||
rot_y = _decode_yaw_from_prediction(pred)
|
||||
z_whole = pred[24]
|
||||
uv_whole_offset = pred[25:27]
|
||||
dims_whole = pred[27:30]
|
||||
u_whole = (anchor_xy[0] + uv_whole_offset[0]) * stride
|
||||
v_whole = (anchor_xy[1] + uv_whole_offset[1]) * stride
|
||||
|
||||
if cls_id in face_3d_classes:
|
||||
_, cut_side = _resolve_pred_cut_state_for_decode(pred, bbox_xyxy=bbox_xyxy, img_w=img_w)
|
||||
visible_faces = select_pred_visible_faces_for_decode(pred, score_thr=score_thr, bbox_xyxy=bbox_xyxy, img_w=img_w)
|
||||
best_type, _ = (-1, -1.0) if not visible_faces else max(visible_faces, key=lambda item: item[1])
|
||||
if best_type < 0:
|
||||
return None
|
||||
|
||||
off = best_type * 6
|
||||
z_face = pred[off]
|
||||
uv_face_offset = pred[off + 1 : off + 3]
|
||||
u_face = (anchor_xy[0] + uv_face_offset[0]) * stride
|
||||
v_face = (anchor_xy[1] + uv_face_offset[1]) * stride
|
||||
corners = reconstruct_3d_box_from_face((u_face, v_face), z_face, dims_whole, rot_y, best_type, calib)
|
||||
if corners is None:
|
||||
return None
|
||||
|
||||
edge_points_3d, edge_points_2d = collect_face_bottom_edges(
|
||||
corners,
|
||||
[face_type for face_type, _ in visible_faces],
|
||||
calib,
|
||||
num_samples=5,
|
||||
)
|
||||
if pred_edge_60 is not None:
|
||||
pred_edge_points_2d, pred_edge_points_3d = [], []
|
||||
for face_type, _ in visible_faces:
|
||||
pred_edge = decode_visible_face_edge_from_prediction(pred_edge_60, face_type, anchor_xy, stride)
|
||||
if pred_edge is None:
|
||||
continue
|
||||
points_3d = [back_project_2d_to_3d(tuple(pt), depth, calib) for pt, depth in zip(pred_edge.points_2d, pred_edge.depths)]
|
||||
if any(point is None for point in points_3d):
|
||||
continue
|
||||
pred_edge_points_2d.append(pred_edge.points_2d.astype(np.float32, copy=False))
|
||||
pred_edge_points_3d.append(np.asarray(points_3d, dtype=np.float32))
|
||||
if pred_edge_points_2d:
|
||||
edge_points_2d = _stack_edge_batches(pred_edge_points_2d)
|
||||
edge_points_3d = _stack_edge_batches(pred_edge_points_3d)
|
||||
|
||||
partial_edge = decode_cut_partial_side_edge_from_prediction(
|
||||
pred,
|
||||
pred_edge_60,
|
||||
anchor_xy,
|
||||
stride,
|
||||
img_w,
|
||||
cut_side=cut_side,
|
||||
)
|
||||
if partial_edge is not None:
|
||||
partial_points_3d = [back_project_2d_to_3d(tuple(pt), depth, calib) for pt, depth in zip(partial_edge.points_2d, partial_edge.depths)]
|
||||
if all(point is not None for point in partial_points_3d):
|
||||
partial_edge.points_3d = np.asarray(partial_points_3d, dtype=np.float32)
|
||||
visible_face_types = {face_type for face_type, _ in visible_faces}
|
||||
if partial_edge.face_type not in visible_face_types:
|
||||
edge_points_3d, edge_points_2d = _append_edge_batch(edge_points_3d, edge_points_2d, partial_edge)
|
||||
visible_faces = [*visible_faces, (partial_edge.face_type, 1.0)]
|
||||
|
||||
return Decoded3DPrediction(
|
||||
corners_3d=np.asarray(corners, dtype=np.float32),
|
||||
face_center_2d=(u_face, v_face),
|
||||
face_color=FACE_COLORS[best_type],
|
||||
visible_face_type=best_type,
|
||||
visible_face_types=tuple(face_type for face_type, _ in visible_faces),
|
||||
edge_points_2d=None if edge_points_2d is None else np.asarray(edge_points_2d, dtype=np.float32),
|
||||
edge_points_3d=None if edge_points_3d is None else np.asarray(edge_points_3d, dtype=np.float32),
|
||||
cls_id=cls_id,
|
||||
)
|
||||
|
||||
if cls_id in complete_3d_classes:
|
||||
corners = reconstruct_3d_box_from_whole((u_whole, v_whole), z_whole, dims_whole, rot_y, calib)
|
||||
if corners is None:
|
||||
return None
|
||||
return Decoded3DPrediction(
|
||||
corners_3d=np.asarray(corners, dtype=np.float32),
|
||||
face_center_2d=None,
|
||||
face_color=None,
|
||||
visible_face_type=None,
|
||||
visible_face_types=(),
|
||||
edge_points_2d=None,
|
||||
edge_points_3d=None,
|
||||
cls_id=cls_id,
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def draw_3d_box(img, corners_3d, calib: ResizedCalib, face_center_2d=None, face_color=None, edge_points_2d=None, edge_color=(0, 255, 0), thickness=1):
|
||||
corners_3d = corners_3d[[4, 5, 6, 7, 0, 1, 2, 3]]
|
||||
color_front = (0, 0, 255)
|
||||
color_back = (255, 0, 0)
|
||||
color_side = (255, 255, 0)
|
||||
|
||||
distort_coeffs = calib.get("distort_coeffs", []) if calib is not None else []
|
||||
if distort_coeffs is not None and len(distort_coeffs) >= 4:
|
||||
edge_points_2d_box = project_3d_box_edges_with_distortion(corners_3d, calib, samples_per_edge=15)
|
||||
plot_box3d_on_img_with_distortion(
|
||||
img,
|
||||
edge_points_2d_box,
|
||||
color_front=color_front,
|
||||
color_back=color_back,
|
||||
color_side=color_side,
|
||||
thickness=thickness,
|
||||
)
|
||||
else:
|
||||
corners_2d = project_3d_to_2d(corners_3d, calib)
|
||||
if np.any(np.isnan(corners_2d)):
|
||||
return img
|
||||
plot_box3d_on_img(
|
||||
img,
|
||||
corners_2d,
|
||||
color_front=color_front,
|
||||
color_back=color_back,
|
||||
color_side=color_side,
|
||||
thickness=thickness,
|
||||
)
|
||||
|
||||
if face_center_2d is not None and face_color is not None:
|
||||
cv2.circle(img, (int(face_center_2d[0]), int(face_center_2d[1])), 2, face_color, -1, cv2.LINE_AA)
|
||||
|
||||
_draw_edge_points(img, edge_points_2d=edge_points_2d, edge_color=edge_color, thickness=thickness)
|
||||
return img
|
||||
|
||||
|
||||
def decode_visible_face_yaw_from_prediction(pred_41, pred_edge_60, anchor_xy, stride, face_type, calib: ResizedCalib):
|
||||
if pred_edge_60 is None or face_type not in range(4):
|
||||
return float("nan")
|
||||
decoded = decode_visible_face_edge_from_prediction(pred_edge_60, face_type, anchor_xy, stride)
|
||||
points_3d = _decoded_edge_to_points_3d(decoded, calib)
|
||||
if points_3d is None:
|
||||
return float("nan")
|
||||
return edge_points_to_yaw(points_3d, face_type)
|
||||
|
||||
|
||||
def decode_multi_visible_face_yaw_from_prediction(
|
||||
pred_41,
|
||||
pred_edge_60,
|
||||
anchor_xy,
|
||||
stride,
|
||||
calib,
|
||||
fallback_face_type=None,
|
||||
score_thr=FACE_VISIBILITY_SCORE_THRESH,
|
||||
bbox_xyxy=None,
|
||||
img_w=None,
|
||||
):
|
||||
if pred_edge_60 is None:
|
||||
if fallback_face_type in range(4):
|
||||
return decode_visible_face_yaw_from_prediction(pred_41, pred_edge_60, anchor_xy, stride, fallback_face_type, calib)
|
||||
return float("nan")
|
||||
|
||||
inferred_img_w = float(img_w) if img_w is not None else None
|
||||
if inferred_img_w is None:
|
||||
if bbox_xyxy is not None:
|
||||
inferred_img_w = max(float(np.asarray(bbox_xyxy, dtype=np.float64)[2]), 1.0)
|
||||
else:
|
||||
inferred_img_w = max(float((anchor_xy[0] + pred_41[25]) * stride) * 2.0, 1.0)
|
||||
|
||||
cut_state, cut_side = _resolve_pred_cut_state_for_decode(pred_41, bbox_xyxy=bbox_xyxy, img_w=inferred_img_w)
|
||||
face_edges_3d, face_scores = {}, {}
|
||||
for face_type, score in select_pred_visible_faces_for_decode(pred_41, score_thr=score_thr, bbox_xyxy=bbox_xyxy, img_w=inferred_img_w):
|
||||
decoded = decode_visible_face_edge_from_prediction(pred_edge_60, face_type, anchor_xy, stride)
|
||||
points_3d = _decoded_edge_to_points_3d(decoded, calib)
|
||||
if points_3d is None:
|
||||
continue
|
||||
face_edges_3d[face_type] = points_3d
|
||||
face_scores[face_type] = float(score)
|
||||
|
||||
partial_edge = decode_cut_partial_side_edge_from_prediction(
|
||||
pred_41,
|
||||
pred_edge_60,
|
||||
anchor_xy,
|
||||
stride,
|
||||
img_w=inferred_img_w,
|
||||
cut_side=cut_side,
|
||||
)
|
||||
partial_points_3d = _decoded_edge_to_points_3d(partial_edge, calib)
|
||||
if cut_state != CUT_STATE_NORMAL:
|
||||
if partial_edge is not None and partial_points_3d is not None:
|
||||
return edge_points_to_yaw(partial_points_3d, int(partial_edge.face_type))
|
||||
return float("nan")
|
||||
|
||||
if any(face_type in (2, 3) for face_type in face_edges_3d):
|
||||
side_face_type = max(
|
||||
(face_type for face_type in face_edges_3d if face_type in (2, 3)),
|
||||
key=lambda face_type: face_scores.get(face_type, 0.0),
|
||||
)
|
||||
return edge_points_to_yaw(face_edges_3d[side_face_type], side_face_type)
|
||||
|
||||
if partial_points_3d is not None:
|
||||
face_edges_3d[partial_edge.face_type] = partial_points_3d
|
||||
face_scores[partial_edge.face_type] = max(face_scores.get(partial_edge.face_type, 0.0), 1.0)
|
||||
|
||||
if len(face_edges_3d) >= 2:
|
||||
yaw = visible_face_edges_to_yaw(face_edges_3d, face_scores=face_scores)
|
||||
if np.isfinite(yaw):
|
||||
return yaw
|
||||
|
||||
if fallback_face_type in range(4):
|
||||
return decode_visible_face_yaw_from_prediction(pred_41, pred_edge_60, anchor_xy, stride, fallback_face_type, calib)
|
||||
return visible_face_edges_to_yaw(face_edges_3d, face_scores=face_scores)
|
||||
|
||||
|
||||
def _back_project_metric_point(u, v, z, calib: ResizedCalib) -> np.ndarray:
|
||||
if calib is not None and z > 0:
|
||||
center_3d = back_project_2d_to_3d((u, v), z, calib)
|
||||
if center_3d is None:
|
||||
x3d, y3d = float("nan"), float("nan")
|
||||
else:
|
||||
x3d, y3d = center_3d[0], center_3d[1]
|
||||
else:
|
||||
x3d, y3d = float("nan"), float("nan")
|
||||
return np.array([x3d, y3d, z], dtype=np.float32)
|
||||
|
||||
|
||||
def extract_3d_attrs_from_prediction(
|
||||
pred_41,
|
||||
anchor_xy,
|
||||
stride,
|
||||
calib: ResizedCalib,
|
||||
face_type=None,
|
||||
pred_edge_60=None,
|
||||
) -> Optional[Prediction3DAttrs]:
|
||||
pred = pred_41
|
||||
rot_y = _decode_yaw_from_prediction(pred)
|
||||
dims = pred[27:30].astype(np.float32)
|
||||
|
||||
if face_type is None:
|
||||
z = float(pred[24])
|
||||
uv_offset = pred[25:27]
|
||||
edge_yaw = float("nan")
|
||||
else:
|
||||
off = FACE_OFFSETS_41[face_type]
|
||||
z = float(pred[off])
|
||||
uv_offset = pred[off + 1 : off + 3]
|
||||
edge_yaw = decode_multi_visible_face_yaw_from_prediction(
|
||||
pred,
|
||||
pred_edge_60,
|
||||
anchor_xy,
|
||||
stride,
|
||||
calib,
|
||||
fallback_face_type=face_type,
|
||||
)
|
||||
|
||||
u = float((anchor_xy[0] + uv_offset[0]) * stride)
|
||||
v = float((anchor_xy[1] + uv_offset[1]) * stride)
|
||||
center = _back_project_metric_point(u, v, z, calib)
|
||||
return Prediction3DAttrs(
|
||||
center=center,
|
||||
depth=z,
|
||||
dims=dims,
|
||||
yaw=float(rot_y),
|
||||
edge_yaw=float(edge_yaw),
|
||||
uv=np.array([u, v], dtype=np.float32),
|
||||
visible_face_type=None if face_type is None else int(face_type),
|
||||
face_center=None if face_type is None else center,
|
||||
)
|
||||
|
||||
|
||||
def face_center_from_corners(corners_3d, face_type):
|
||||
if corners_3d is None or face_type not in FACE_CORNERS:
|
||||
return None
|
||||
corners = np.asarray(corners_3d, dtype=np.float32)
|
||||
if corners.shape != (8, 3) or not np.isfinite(corners).all():
|
||||
return None
|
||||
return corners[list(FACE_CORNERS[face_type])].mean(axis=0)
|
||||
|
||||
|
||||
def rebuild_box_corners_for_visualization(
|
||||
corners_3d,
|
||||
dims,
|
||||
yaw,
|
||||
visible_face_type=None,
|
||||
face_center_3d=None,
|
||||
box_center_3d=None,
|
||||
):
|
||||
dims_arr = np.asarray(dims, dtype=np.float32)
|
||||
if dims_arr.shape != (3,) or not np.isfinite(dims_arr).all() or not np.isfinite(float(yaw)):
|
||||
return None
|
||||
|
||||
if visible_face_type is not None:
|
||||
if face_center_3d is None:
|
||||
face_center_3d = face_center_from_corners(corners_3d, int(visible_face_type))
|
||||
else:
|
||||
face_center_3d = np.asarray(face_center_3d, dtype=np.float32)
|
||||
if face_center_3d is None or face_center_3d.shape != (3,) or not np.isfinite(face_center_3d).all():
|
||||
return None
|
||||
return compute_3d_box_corners(face_center_3d, dims_arr, float(yaw), face_type=int(visible_face_type))
|
||||
|
||||
if box_center_3d is not None:
|
||||
box_center_3d = np.asarray(box_center_3d, dtype=np.float32)
|
||||
if box_center_3d.shape != (3,) or not np.isfinite(box_center_3d).all():
|
||||
return None
|
||||
return compute_3d_box_corners(box_center_3d, dims_arr, float(yaw), face_type=-1)
|
||||
|
||||
corners = np.asarray(corners_3d, dtype=np.float32)
|
||||
if corners.shape != (8, 3) or not np.isfinite(corners).all():
|
||||
return None
|
||||
return compute_3d_box_corners(corners.mean(axis=0), dims_arr, float(yaw), face_type=-1)
|
||||
1011
tools/model_inference/core/two_roi_infer_utils.py
Executable file
1011
tools/model_inference/core/two_roi_infer_utils.py
Executable file
File diff suppressed because it is too large
Load Diff
175
tools/model_inference/core/two_roi_types.py
Executable file
175
tools/model_inference/core/two_roi_types.py
Executable file
@@ -0,0 +1,175 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Optional, TypedDict
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
ColorBGR = tuple[int, int, int]
|
||||
ImagePoint2D = tuple[float, float]
|
||||
|
||||
|
||||
class RawCameraCalib(TypedDict, total=False):
|
||||
focal_u: float
|
||||
focal_v: float
|
||||
cu: float
|
||||
cv: float
|
||||
roll: float
|
||||
pitch: float
|
||||
yaw: float
|
||||
pos: list[float]
|
||||
distort_coeffs: list[float]
|
||||
image_width: Any
|
||||
image_height: Any
|
||||
source_format: str
|
||||
angle_unit: str
|
||||
|
||||
|
||||
class ROICropCalib(TypedDict):
|
||||
focal_u: float
|
||||
focal_v: float
|
||||
cu: float
|
||||
cv: float
|
||||
src_w: int
|
||||
src_h: int
|
||||
distort_coeffs: list[float]
|
||||
|
||||
|
||||
class ResizedCalib(TypedDict):
|
||||
fx: float
|
||||
fy: float
|
||||
cx: float
|
||||
cy: float
|
||||
distort_coeffs: list[float]
|
||||
depth_scale: float
|
||||
|
||||
|
||||
@dataclass
|
||||
class DecodedVisibleEdge:
|
||||
face_type: int
|
||||
points_2d: np.ndarray
|
||||
depths: np.ndarray
|
||||
points_3d: Optional[np.ndarray] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Decoded3DPrediction:
|
||||
corners_3d: np.ndarray
|
||||
face_center_2d: Optional[ImagePoint2D]
|
||||
face_color: Optional[ColorBGR]
|
||||
visible_face_type: Optional[int]
|
||||
visible_face_types: tuple[int, ...]
|
||||
edge_points_2d: Optional[np.ndarray]
|
||||
edge_points_3d: Optional[np.ndarray]
|
||||
cls_id: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class Prediction3DAttrs:
|
||||
center: np.ndarray
|
||||
depth: float
|
||||
dims: np.ndarray
|
||||
yaw: float
|
||||
edge_yaw: float
|
||||
uv: np.ndarray
|
||||
visible_face_type: Optional[int]
|
||||
face_center: Optional[np.ndarray]
|
||||
|
||||
|
||||
class SerializedPredictionRecord(TypedDict, total=False):
|
||||
bbox_xyxy: Any
|
||||
confidence: float
|
||||
cls_id: int
|
||||
cls_name: str
|
||||
difficulty_logit: Optional[float]
|
||||
difficulty_prob: Optional[float]
|
||||
difficulty_label: Optional[int]
|
||||
difficulty_name: Optional[str]
|
||||
edge_head_available: bool
|
||||
xyzlhwyaw: Any
|
||||
xyzlhwyaw_ego: Any
|
||||
box_center_xyz: Any
|
||||
box_center_xyz_ego: Any
|
||||
depth_m: Optional[float]
|
||||
box_depth_m: Optional[float]
|
||||
lateral_distance_m: Optional[float]
|
||||
euclidean_distance_m: Optional[float]
|
||||
xz_distance_m: Optional[float]
|
||||
attribute: Any
|
||||
yaw_rad: Optional[float]
|
||||
edge_yaw_rad: Optional[float]
|
||||
edge_yaw_confident: bool
|
||||
edge_yaw_lateral_distance_m: Optional[float]
|
||||
edge_yaw_lateral_ok: bool
|
||||
edge_yaw_two_face_eligible: bool
|
||||
edge_yaw_selected_face_types: Any
|
||||
edge_yaw_selected_face_is_partial: Any
|
||||
edge_vs_reg_yaw_rad: Optional[float]
|
||||
selected_edge_direct_box_fit_available: bool
|
||||
selected_edge_direct_box_fit_mean_px: Optional[float]
|
||||
selected_edge_direct_box_fit_max_px: Optional[float]
|
||||
selected_edge_direct_box_fit_per_face_mean_px: Any
|
||||
selected_edge_edgeyaw_box_fit_available: bool
|
||||
selected_edge_edgeyaw_box_fit_mean_px: Optional[float]
|
||||
selected_edge_edgeyaw_box_fit_max_px: Optional[float]
|
||||
selected_edge_edgeyaw_box_fit_per_face_mean_px: Any
|
||||
selected_edge_fit_gain_px: Optional[float]
|
||||
edge_box_center_3d: Any
|
||||
edge_box_dims: Any
|
||||
edge_box_length_m: Optional[float]
|
||||
edge_box_width_m: Optional[float]
|
||||
edge_box_mode: Optional[str]
|
||||
edge_box_length_source: Optional[str]
|
||||
edge_box_width_source: Optional[str]
|
||||
all_edge_predictions: Any
|
||||
edge_selection: Any
|
||||
center_uv: Any
|
||||
center_3d: Any
|
||||
dims: Any
|
||||
cut_cls: Optional[int]
|
||||
roi_id: Optional[int]
|
||||
visible_face_type: Any
|
||||
visible_face_count: int
|
||||
visible_face_types: Any
|
||||
crop_bounds: list[int]
|
||||
original_bbox_xyxy: Any
|
||||
|
||||
|
||||
class SerializedROIPayload(TypedDict):
|
||||
crop_bounds: list[int]
|
||||
vp_x: float
|
||||
vp_y: float
|
||||
crop_center_x: float
|
||||
crop_center_y: float
|
||||
edge_head_available: bool
|
||||
edge_yaw_max_lateral_dist_m: float
|
||||
calib: dict[str, Any]
|
||||
predictions: list[SerializedPredictionRecord]
|
||||
|
||||
|
||||
class SerializedMergedPayload(TypedDict, total=False):
|
||||
method: str
|
||||
edge_head_available: bool
|
||||
roi_bounds: dict[str, list[int]]
|
||||
predictions: list[SerializedPredictionRecord]
|
||||
visualization: str
|
||||
|
||||
|
||||
class SerializedFramePayload(TypedDict, total=False):
|
||||
frame_index: int
|
||||
frame_name: str
|
||||
rois: dict[str, SerializedROIPayload]
|
||||
merged: SerializedMergedPayload
|
||||
merged_vru: SerializedMergedPayload
|
||||
visualization: str
|
||||
|
||||
|
||||
class SerializedPredictionsPayload(TypedDict):
|
||||
case_name: str
|
||||
images_dir: str
|
||||
calib_file: str
|
||||
exported_model_path: str
|
||||
edge_head_available: bool
|
||||
edge_yaw_max_lateral_dist_m: float
|
||||
frames: list[SerializedFramePayload]
|
||||
1
tools/model_inference/data_tools/__init__.py
Executable file
1
tools/model_inference/data_tools/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
"""Small data-preparation helpers for model_inference."""
|
||||
234
tools/model_inference/data_tools/extract_excel_column.py
Executable file
234
tools/model_inference/data_tools/extract_excel_column.py
Executable file
@@ -0,0 +1,234 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from openpyxl import load_workbook
|
||||
except ImportError:
|
||||
load_workbook = None
|
||||
|
||||
|
||||
FILE = Path(__file__).resolve()
|
||||
DEFAULT_INPUT_FILE = FILE.parents[1] / "examples" / "cncap" / "G1M3_AFS1616_CNCAP-2024_11月_0306.xlsx"
|
||||
DEFAULT_COLUMN_NAME = "原始数据地址"
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Extract one column from a CSV/XLSX table and print or save the values."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input-file",
|
||||
type=str,
|
||||
default=str(DEFAULT_INPUT_FILE),
|
||||
help="Path to the input .xlsx or .csv file.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--column-name",
|
||||
type=str,
|
||||
default=DEFAULT_COLUMN_NAME,
|
||||
help="Header name of the target column.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--sheet-name",
|
||||
type=str,
|
||||
default="",
|
||||
help="Worksheet name for .xlsx files. Defaults to the first sheet.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-file",
|
||||
type=str,
|
||||
default="",
|
||||
help="Optional output text file. If omitted, values are written to stdout.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--json-file",
|
||||
type=str,
|
||||
default="",
|
||||
help="Optional output json file. Defaults to a sibling json file next to the input table.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dedupe",
|
||||
action="store_true",
|
||||
help="Remove duplicate values while preserving the original order.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--list-columns",
|
||||
action="store_true",
|
||||
help="List the discovered header names and exit.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def normalize_header(value: str) -> str:
|
||||
return re.sub(r"\s+", "", str(value or "")).strip()
|
||||
|
||||
|
||||
def sanitize_filename(value: str) -> str:
|
||||
sanitized = re.sub(r'[\\/:*?"<>|]+', "_", str(value or "").strip())
|
||||
sanitized = re.sub(r"\s+", "_", sanitized)
|
||||
return sanitized.strip("._") or "column"
|
||||
|
||||
|
||||
def build_default_json_path(input_path: Path, column_name: str) -> Path:
|
||||
return input_path.with_name(f"{input_path.stem}_{sanitize_filename(column_name)}.json")
|
||||
|
||||
|
||||
def load_xlsx_table(path: Path, sheet_name: str) -> tuple[list[str], list[dict[str, str]], str]:
|
||||
if load_workbook is None:
|
||||
raise ImportError("openpyxl is required for .xlsx files. Please install it first.")
|
||||
|
||||
workbook = load_workbook(path, read_only=True, data_only=True)
|
||||
try:
|
||||
if sheet_name:
|
||||
if sheet_name not in workbook.sheetnames:
|
||||
available = ", ".join(workbook.sheetnames)
|
||||
raise ValueError(f"Worksheet {sheet_name!r} not found. Available sheets: {available}")
|
||||
worksheet = workbook[sheet_name]
|
||||
else:
|
||||
worksheet = workbook[workbook.sheetnames[0]]
|
||||
|
||||
header_row_values: list[str] | None = None
|
||||
header_indices: list[int] = []
|
||||
records: list[dict[str, str]] = []
|
||||
|
||||
for row in worksheet.iter_rows(values_only=True):
|
||||
normalized_row = [str(value).strip() if value is not None else "" for value in row]
|
||||
if not any(normalized_row):
|
||||
continue
|
||||
|
||||
if header_row_values is None:
|
||||
header_indices = [index for index, value in enumerate(normalized_row) if value]
|
||||
header_row_values = [normalized_row[index] for index in header_indices]
|
||||
continue
|
||||
|
||||
record = {
|
||||
header_row_values[index]: normalized_row[col_idx] if col_idx < len(normalized_row) else ""
|
||||
for index, col_idx in enumerate(header_indices)
|
||||
}
|
||||
if any(record.values()):
|
||||
records.append(record)
|
||||
|
||||
if header_row_values is None:
|
||||
raise ValueError("The worksheet is empty.")
|
||||
|
||||
return header_row_values, records, worksheet.title
|
||||
finally:
|
||||
workbook.close()
|
||||
|
||||
|
||||
def load_csv_table(path: Path) -> tuple[list[str], list[dict[str, str]], str]:
|
||||
with path.open("r", encoding="utf-8-sig", newline="") as file:
|
||||
sample = file.read(4096)
|
||||
file.seek(0)
|
||||
dialect = csv.Sniffer().sniff(sample) if sample.strip() else csv.excel
|
||||
reader = csv.DictReader(file, dialect=dialect)
|
||||
headers = reader.fieldnames or []
|
||||
records = []
|
||||
for row in reader:
|
||||
normalized_row = {str(key).strip(): str(value or "").strip() for key, value in row.items() if key is not None}
|
||||
if any(normalized_row.values()):
|
||||
records.append(normalized_row)
|
||||
return [str(header).strip() for header in headers], records, ""
|
||||
|
||||
|
||||
def load_table(path: Path, sheet_name: str) -> tuple[list[str], list[dict[str, str]], str]:
|
||||
suffix = path.suffix.lower()
|
||||
if suffix == ".xlsx":
|
||||
return load_xlsx_table(path, sheet_name)
|
||||
if suffix == ".csv":
|
||||
return load_csv_table(path)
|
||||
raise ValueError(f"Unsupported input format: {suffix}. Only .xlsx and .csv are supported.")
|
||||
|
||||
|
||||
def extract_column(records: list[dict[str, str]], column_name: str, dedupe: bool) -> list[str]:
|
||||
if not records:
|
||||
return []
|
||||
|
||||
normalized_to_actual = {normalize_header(name): name for name in records[0].keys()}
|
||||
target_key = normalized_to_actual.get(normalize_header(column_name))
|
||||
if target_key is None:
|
||||
available = ", ".join(records[0].keys())
|
||||
raise ValueError(f"Column {column_name!r} not found. Available columns: {available}")
|
||||
|
||||
values = [record.get(target_key, "").strip() for record in records]
|
||||
values = [value for value in values if value]
|
||||
if not dedupe:
|
||||
return values
|
||||
|
||||
deduped_values: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for value in values:
|
||||
if value in seen:
|
||||
continue
|
||||
seen.add(value)
|
||||
deduped_values.append(value)
|
||||
return deduped_values
|
||||
|
||||
|
||||
def write_output(values: list[str], output_file: str) -> None:
|
||||
content = "\n".join(values)
|
||||
if output_file:
|
||||
output_path = Path(output_file)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text(content + ("\n" if values else ""), encoding="utf-8")
|
||||
print(f"Saved {len(values)} rows to {output_path}", file=sys.stderr)
|
||||
return
|
||||
|
||||
if content:
|
||||
sys.stdout.write(content)
|
||||
sys.stdout.write("\n")
|
||||
|
||||
|
||||
def write_json_output(
|
||||
input_path: Path,
|
||||
resolved_sheet_name: str,
|
||||
column_name: str,
|
||||
values: list[str],
|
||||
json_file: str,
|
||||
) -> Path:
|
||||
json_path = Path(json_file) if json_file else build_default_json_path(input_path, column_name)
|
||||
json_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
payload = {
|
||||
"input_file": str(input_path),
|
||||
"sheet_name": resolved_sheet_name,
|
||||
"column_name": column_name,
|
||||
"num_rows": len(values),
|
||||
"values": values,
|
||||
}
|
||||
json_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"Saved json to {json_path}", file=sys.stderr)
|
||||
return json_path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
input_path = Path(args.input_file)
|
||||
if not input_path.is_file():
|
||||
raise FileNotFoundError(f"Input file not found: {input_path}")
|
||||
|
||||
headers, records, resolved_sheet_name = load_table(input_path, args.sheet_name)
|
||||
if args.list_columns:
|
||||
for header in headers:
|
||||
print(header)
|
||||
return 0
|
||||
|
||||
values = extract_column(records, args.column_name, args.dedupe)
|
||||
write_output(values, args.output_file)
|
||||
json_path = write_json_output(input_path, resolved_sheet_name, args.column_name, values, args.json_file)
|
||||
|
||||
sheet_info = f", sheet={resolved_sheet_name}" if resolved_sheet_name else ""
|
||||
print(
|
||||
f"Extracted {len(values)} rows from column {args.column_name!r} in {input_path}{sheet_info}, json={json_path}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
131
tools/model_inference/data_tools/parse_scene_csv_to_json.py
Executable file
131
tools/model_inference/data_tools/parse_scene_csv_to_json.py
Executable file
@@ -0,0 +1,131 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
FILE = Path(__file__).resolve()
|
||||
DEFAULT_INPUT_FILE = FILE.parents[1] / "examples" / "events" / "G1Q3_场地评测数据集.csv"
|
||||
DEFAULT_SCENE_COLUMN = "scene"
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Parse a CSV table and save a scene-keyed JSON file."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input-file",
|
||||
type=str,
|
||||
default=str(DEFAULT_INPUT_FILE),
|
||||
help="Path to the input CSV file.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--scene-column",
|
||||
type=str,
|
||||
default=DEFAULT_SCENE_COLUMN,
|
||||
help="Column name used as the top-level JSON key.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-file",
|
||||
type=str,
|
||||
default="",
|
||||
help="Optional output JSON path. Defaults to a sibling .json file next to the CSV.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--keep-scene-field",
|
||||
action="store_true",
|
||||
help="Keep the scene column inside each grouped record.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def normalize_row(row: dict[str, str | None]) -> dict[str, str]:
|
||||
return {str(key).strip(): str(value or "").strip() for key, value in row.items() if key is not None}
|
||||
|
||||
|
||||
def resolve_output_path(input_path: Path, output_file: str) -> Path:
|
||||
if output_file:
|
||||
return Path(output_file)
|
||||
return input_path.with_suffix(".json")
|
||||
|
||||
|
||||
def load_csv_rows(path: Path) -> tuple[list[str], list[dict[str, str]]]:
|
||||
with path.open("r", encoding="utf-8-sig", newline="") as file:
|
||||
sample = file.read(4096)
|
||||
file.seek(0)
|
||||
dialect = csv.Sniffer().sniff(sample) if sample.strip() else csv.excel
|
||||
reader = csv.DictReader(file, dialect=dialect)
|
||||
headers = [str(header).strip() for header in (reader.fieldnames or [])]
|
||||
rows: list[dict[str, str]] = []
|
||||
for row in reader:
|
||||
normalized = normalize_row(row)
|
||||
if any(normalized.values()):
|
||||
rows.append(normalized)
|
||||
return headers, rows
|
||||
|
||||
|
||||
def group_rows_by_scene(
|
||||
rows: list[dict[str, str]],
|
||||
scene_column: str,
|
||||
keep_scene_field: bool,
|
||||
) -> OrderedDict[str, list[dict[str, str]]]:
|
||||
grouped: OrderedDict[str, list[dict[str, str]]] = OrderedDict()
|
||||
missing_scene_rows = 0
|
||||
|
||||
for row in rows:
|
||||
scene_value = row.get(scene_column, "").strip()
|
||||
if not scene_value:
|
||||
missing_scene_rows += 1
|
||||
continue
|
||||
|
||||
payload = dict(row)
|
||||
if not keep_scene_field:
|
||||
payload.pop(scene_column, None)
|
||||
|
||||
grouped.setdefault(scene_value, []).append(payload)
|
||||
|
||||
if missing_scene_rows > 0:
|
||||
print(
|
||||
f"Skipped {missing_scene_rows} rows because column {scene_column!r} was empty.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
return grouped
|
||||
|
||||
|
||||
def save_grouped_json(grouped: OrderedDict[str, list[dict[str, str]]], output_path: Path) -> None:
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text(
|
||||
json.dumps(grouped, ensure_ascii=False, indent=2) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
input_path = Path(args.input_file)
|
||||
if not input_path.is_file():
|
||||
raise FileNotFoundError(f"Input file not found: {input_path}")
|
||||
|
||||
headers, rows = load_csv_rows(input_path)
|
||||
if args.scene_column not in headers:
|
||||
available = ", ".join(headers)
|
||||
raise ValueError(f"Column {args.scene_column!r} not found. Available columns: {available}")
|
||||
|
||||
grouped = group_rows_by_scene(rows, args.scene_column, args.keep_scene_field)
|
||||
output_path = resolve_output_path(input_path, args.output_file)
|
||||
save_grouped_json(grouped, output_path)
|
||||
|
||||
print(
|
||||
f"Saved {len(rows)} rows across {len(grouped)} scenes to {output_path}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
48
tools/model_inference/docs/json_format.json
Executable file
48
tools/model_inference/docs/json_format.json
Executable file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"0": {
|
||||
"type": "0",
|
||||
"type_name": "truck",
|
||||
"score": "0.9664586186408997",
|
||||
"roi_id": "0",
|
||||
"box2d": [
|
||||
"1357.25390625",
|
||||
"542.76123046875",
|
||||
"1743.7847290039062",
|
||||
"803.9830627441406"
|
||||
],
|
||||
"xyzlhwyaw": [
|
||||
"3.5862553000515422",
|
||||
"0.6910880269131991",
|
||||
"5.21181583404541",
|
||||
"4.622976303100586",
|
||||
"1.9204307794570923",
|
||||
"1.481898546218872",
|
||||
"-1.5685003995895386"
|
||||
],
|
||||
"face_cls": "tail",
|
||||
"cut_cls": "0"
|
||||
},
|
||||
"1": {
|
||||
"type": "0",
|
||||
"type_name": "truck",
|
||||
"score": "0.9642692804336548",
|
||||
"roi_id": "0",
|
||||
"box2d": [
|
||||
"791.8895263671875",
|
||||
"498.2795104980469",
|
||||
"1162.1598205566406",
|
||||
"816.8395385742188"
|
||||
],
|
||||
"xyzlhwyaw": [
|
||||
"-0.04261477524786694",
|
||||
"0.5091491993856199",
|
||||
"6.116147041320801",
|
||||
"4.321102619171143",
|
||||
"2.0373644828796387",
|
||||
"1.6876970529556274",
|
||||
"-1.5730922222137451"
|
||||
],
|
||||
"face_cls": "tail",
|
||||
"cut_cls": "0"
|
||||
}
|
||||
}
|
||||
9
tools/model_inference/docs/model_inference_cncap2024.md
Executable file
9
tools/model_inference/docs/model_inference_cncap2024.md
Executable file
@@ -0,0 +1,9 @@
|
||||
tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-202411.json文件中记录了一批场地评测数据的路径。
|
||||
|
||||
一组数据路径的示例为:"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_20_5_1_20251115140740/sigmastar.1",查找本地挂载路径时,需替换'hfs/project-G1M3'为'G1M3',同时查找路径下的camera4.bin。
|
||||
|
||||
具体的视频路径为"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_20_5_1_20251115140740/sigmastar.1/camera4.bin"
|
||||
|
||||
另外,其对应的标定参数路径为:"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/test_data/calibs/camera4.json"
|
||||
|
||||
现在期望tools/model_inference/run_two_roi_exported_onnx_infer.py脚本能够接收tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-202411.json的输入,从而对相关的视频数据进行模型推理。
|
||||
5
tools/model_inference/docs/model_inference_through_eventid.md
Executable file
5
tools/model_inference/docs/model_inference_through_eventid.md
Executable file
@@ -0,0 +1,5 @@
|
||||
tools/model_inference/examples/events/G1Q3_场地评测数据集.json文件中记录了不同工况的数据,每个工况下有多组数据,每组数据中的data_path为eventid信息。
|
||||
|
||||
tools/model_inference/adapters/get_clip_by_eventid.py脚本可以用过event_id信息获取clip数据
|
||||
|
||||
现在期望tools/model_inference/run_two_roi_exported_onnx_infer.py脚本能够接收tools/model_inference/examples/events/G1Q3_场地评测数据集.json的输入,从而对相关的clip数据进行模型推理。
|
||||
8
tools/model_inference/docs/model_inference_through_video_dir.md
Executable file
8
tools/model_inference/docs/model_inference_through_video_dir.md
Executable file
@@ -0,0 +1,8 @@
|
||||
/data1/dongying/Mono3d/G1M3/test_data/cncap_20260408
|
||||
|
||||
上述路径中存放了多组测试数据,每组测试数据中有视频数据和标定参数,具体示例路径如下:
|
||||
|
||||
/data1/dongying/Mono3d/G1M3/test_data/cncap_20260408/20260407203248/sigmastar.1/camera4.bin
|
||||
/data1/dongying/Mono3d/G1M3/test_data/cncap_20260408/20260407203248/test_data/calibs/camera4.json
|
||||
|
||||
请对脚本tools/model_inference/run_two_roi_exported_onnx_infer.py的输入接口进行扩展,支持这种视频数据路径的模型推理。
|
||||
654
tools/model_inference/docs/two_roi_model_design.md
Executable file
654
tools/model_inference/docs/two_roi_model_design.md
Executable file
@@ -0,0 +1,654 @@
|
||||
# 双ROI导出模型设计说明(新版)
|
||||
|
||||
> 若当前使用的是带 `difficulty` 分支或 `fake 3D` 分支的新版本双 ROI 合并模型,请优先参考:
|
||||
> `tools/model_inference/docs/two_roi_model_design_with_diff_and_fake3d.md`
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
本文档以 `tools/model_inference/run_two_roi_exported_onnx_infer.py` 和 `tools/model_inference/core/run_two_roi_exported_onnx_infer.py` 的当前实现为准,说明新版双 ROI 导出模型在部署侧的输入约定、前处理、输出张量、后处理、结果序列化方式,以及与旧版说明文档之间的差异。
|
||||
|
||||
本文档关注的是“部署可执行设计”而不是训练侧的完整网络细节。凡与脚本实现冲突之处,以当前推理脚本和其依赖的本地工具模块为准。
|
||||
|
||||
如需查看旧版文档,可参考 `tools/model_inference/docs/two_roi_model_design_bak.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 方案概览
|
||||
|
||||
新版方案仍然采用双 ROI 单目 3D 检测思路,但部署形态已经收敛为一个“自包含的合并导出模型 + Python 侧解码”的运行时:
|
||||
|
||||
1. 同一帧原图按两套 ROI 规则分别裁剪,得到 `ROI0` 和 `ROI1`。
|
||||
2. 两个 ROI 图像分别送入一个合并后的导出模型,模型输出每个 ROI 的原始检测头张量。
|
||||
3. 2D 框解码、Top-K 选择、3D 反归一化、深度恢复、3D 框重建、edge yaw 精化、可视化和 JSON 序列化全部在 Python 侧完成。
|
||||
|
||||
当前实现支持:
|
||||
|
||||
- `ONNX` 推理:通过 `onnxruntime`
|
||||
- `TorchScript` 推理:通过 `torch.jit.load`
|
||||
- 单 case 推理:`--case-dir`
|
||||
- mined eval 数据集批量推理:`--eval-dir`
|
||||
|
||||
当前运行时不依赖 `ultralytics`。
|
||||
|
||||
---
|
||||
|
||||
## 3. 模型与运行时契约
|
||||
|
||||
### 3.1 导出模型形态
|
||||
|
||||
当前脚本只接受双 ROI 合并后的导出模型:
|
||||
|
||||
- 后缀为 `.onnx` 时走 ONNX Runtime
|
||||
- 后缀为 `.torchscript` / `.ts` / `.jit` 时走 TorchScript
|
||||
|
||||
脚本会读取导出清单:
|
||||
|
||||
- ONNX 优先读取同名 sidecar:`merged_model.export.json`
|
||||
- TorchScript 优先读 sidecar,sidecar 不存在时再读模型内嵌的 `config.txt`
|
||||
|
||||
当前实现会显式校验:
|
||||
|
||||
```text
|
||||
export_mode == "raw_head_outputs"
|
||||
```
|
||||
|
||||
也就是说,当前部署脚本只支持“原始检测头输出”模式,不接受 `hybrid_outputs`、`postprocessed_outputs` 等其他导出模式。
|
||||
|
||||
### 3.2 输入输出名称
|
||||
|
||||
若导出清单可用,则直接使用清单中的:
|
||||
|
||||
- `input_names`
|
||||
- `output_names`
|
||||
- `input_sizes_wh`
|
||||
|
||||
若清单缺失,则回退到默认约定:
|
||||
|
||||
- 输入名:`roi0_input`、`roi1_input`
|
||||
- 输出名:
|
||||
- `roi0_boxes_head_raw`
|
||||
- `roi0_scores_head_raw`
|
||||
- `roi0_preds_3d_head_raw`
|
||||
- `roi0_preds_edge_head_raw`
|
||||
- `roi1_boxes_head_raw`
|
||||
- `roi1_scores_head_raw`
|
||||
- `roi1_preds_3d_head_raw`
|
||||
- `roi1_preds_edge_head_raw`
|
||||
|
||||
### 3.3 默认 ROI 配置
|
||||
|
||||
默认 ROI 配置来自 `tools/model_inference/core/two_roi_infer_utils.py` 中的 `DEFAULT_DATASET_CONFIG`:
|
||||
|
||||
| ROI | 裁剪尺寸 `(w, h)` | 裁剪中心模式 | `virtual_fx` | 默认输入尺寸 `(w, h)` |
|
||||
|---|---:|---|---:|---:|
|
||||
| `ROI0` | `1920 x 880` | `cxvy` | `537.0` | `768 x 352` |
|
||||
| `ROI1` | `768 x 352` | `vxvy` | `537.0` | `768 x 352` |
|
||||
|
||||
其中:
|
||||
|
||||
- `cxvy`:裁剪中心 `x` 取原图水平中心,`y` 取灭点 `vp_y`
|
||||
- `vxvy`:裁剪中心 `x` 取灭点 `vp_x`,`y` 取灭点 `vp_y`
|
||||
|
||||
这些默认值可以被 `--data-config`、`--roi0-data`、`--roi1-data` 中的 `roi_configs` 覆盖;若命令行显式传参,也可以进一步覆盖。
|
||||
|
||||
### 3.4 运行时元数据
|
||||
|
||||
推理脚本会从数据配置中加载以下元数据:
|
||||
|
||||
- `class_map`
|
||||
- `face_3d_classes`
|
||||
- `complete_3d_classes`
|
||||
- `norm_scales_3d`
|
||||
|
||||
若没有额外 YAML,使用内置默认值。
|
||||
|
||||
---
|
||||
|
||||
## 4. 前处理设计
|
||||
|
||||
### 4.1 相机标定读取
|
||||
|
||||
当前脚本兼容两种 `camera4.json` 结构:
|
||||
|
||||
1. 扁平格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"focal_u": ...,
|
||||
"focal_v": ...,
|
||||
"cu": ...,
|
||||
"cv": ...,
|
||||
"pitch": ...,
|
||||
"yaw": ...,
|
||||
"distort_coeffs": [...]
|
||||
}
|
||||
```
|
||||
|
||||
2. 合并格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"intrinsics": { "camera4.json": { ... } },
|
||||
"extrinsics": { "camera4.json": { "rpy": [...] } }
|
||||
}
|
||||
```
|
||||
|
||||
脚本会规范化出:
|
||||
|
||||
- `focal_u`, `focal_v`
|
||||
- `cu`, `cv`
|
||||
- `pitch`, `yaw`
|
||||
- `distort_coeffs`
|
||||
- `angle_unit`
|
||||
|
||||
### 4.2 灭点计算
|
||||
|
||||
灭点计算逻辑保持不变:
|
||||
|
||||
```text
|
||||
vp_x = cu + focal_u * tan(yaw)
|
||||
vp_y = cv - focal_v * tan(pitch)
|
||||
```
|
||||
|
||||
其中角度会先根据 `angle_unit` 统一到弧度制。
|
||||
|
||||
### 4.3 ROI 裁剪
|
||||
|
||||
对每一帧原图:
|
||||
|
||||
1. 读取原始宽高 `ori_w`, `ori_h`
|
||||
2. 根据 ROI 配置确定目标裁剪尺寸 `roi_w`, `roi_h`
|
||||
3. 根据 `crop_center_mode` 计算裁剪中心
|
||||
4. 通过 `compute_centered_roi_bounds()` 做边界裁剪
|
||||
|
||||
裁剪边界为:
|
||||
|
||||
```text
|
||||
crop_x1 = clamp(center_x - roi_w / 2, 0, ori_w - roi_w)
|
||||
crop_y1 = clamp(center_y - roi_h / 2, 0, ori_h - roi_h)
|
||||
crop_x2 = crop_x1 + roi_w
|
||||
crop_y2 = crop_y1 + roi_h
|
||||
```
|
||||
|
||||
### 4.4 缩放与标定更新
|
||||
|
||||
这是新版实现中一个关键变化点。
|
||||
|
||||
旧版文档默认把 ROI 裁剪结果直接一次性 resize 到模型输入尺寸;而当前实现使用 `_resize_ground3d_image_in_steps()`,先重复做若干次 `0.5x` 下采样,再做最后一次 resize,以匹配 Ground3D 训练侧的图像缩放行为。
|
||||
|
||||
缩放完成后,相机标定会更新到 ROI-resized 坐标系:
|
||||
|
||||
```text
|
||||
scale_x = target_w / crop_w
|
||||
scale_y = target_h / crop_h
|
||||
|
||||
fx = focal_u * scale_x
|
||||
fy = focal_v * scale_y
|
||||
cx = (cu - crop_x1) * scale_x
|
||||
cy = (cv - crop_y1) * scale_y
|
||||
|
||||
depth_scale = fx / virtual_fx
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- `fx, fy, cx, cy` 是 resized ROI 空间下的标定
|
||||
- `depth_scale` 用于后处理阶段把网络预测深度恢复到真实焦距尺度
|
||||
|
||||
### 4.5 图像张量化
|
||||
|
||||
当前脚本的输入张量构造为:
|
||||
|
||||
```python
|
||||
image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
|
||||
array = image_rgb.transpose(2, 0, 1).astype(np.float32) / 256.0
|
||||
input = array[None, ...]
|
||||
```
|
||||
|
||||
注意这里是:
|
||||
|
||||
```text
|
||||
/ 256.0
|
||||
```
|
||||
|
||||
而不是旧文档中的 `/ 255.0`。
|
||||
|
||||
TorchScript 路径与 ONNX 路径共用同一份前处理逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 5. 输出张量设计
|
||||
|
||||
### 5.1 每个 ROI 的输出分支
|
||||
|
||||
当前部署脚本假设每个 ROI 仍然输出四个分支:
|
||||
|
||||
1. `boxes_head_raw`
|
||||
2. `scores_head_raw`
|
||||
3. `preds_3d_head_raw`
|
||||
4. `preds_edge_head_raw`
|
||||
|
||||
即合并模型总共有 8 个输出张量。
|
||||
|
||||
### 5.2 3D 分支定义(41 维)
|
||||
|
||||
3D 分支通道布局沿用旧版设计:
|
||||
|
||||
| 通道范围 | 含义 |
|
||||
|---|---|
|
||||
| `0-5` | front face:`z3d, u_offset, v_offset, h, w, visible_score` |
|
||||
| `6-11` | rear face:`z3d, u_offset, v_offset, h, w, visible_score` |
|
||||
| `12-17` | left face:`z3d, u_offset, v_offset, l, h, visible_score` |
|
||||
| `18-23` | right face:`z3d, u_offset, v_offset, l, h, visible_score` |
|
||||
| `24` | whole-box `z3d` |
|
||||
| `25-26` | whole-box `u_offset, v_offset` |
|
||||
| `27-29` | whole-box `l, h, w` |
|
||||
| `30-33` | yaw 4-bin 分类 logits |
|
||||
| `34-37` | yaw 残差 `sin(delta)` |
|
||||
| `38-40` | cut state logits |
|
||||
|
||||
### 5.3 Edge 分支定义(60 维)
|
||||
|
||||
Edge 分支依然是四个面的底边缘采样点,每个采样点 3 维:
|
||||
|
||||
```text
|
||||
[du, dv, z]
|
||||
```
|
||||
|
||||
每个面 5 个点,共 `5 x 3 = 15` 维,四个面共 60 维:
|
||||
|
||||
| 面 | 通道范围 |
|
||||
|---|---|
|
||||
| front | `0-14` |
|
||||
| rear | `15-29` |
|
||||
| left | `30-44` |
|
||||
| right | `45-59` |
|
||||
|
||||
### 5.4 默认输出形状
|
||||
|
||||
对默认输入尺寸 `768 x 352`:
|
||||
|
||||
```text
|
||||
A = (352/8 * 768/8) + (352/16 * 768/16) + (352/32 * 768/32)
|
||||
= 4224 + 1056 + 264
|
||||
= 5544
|
||||
```
|
||||
|
||||
因此典型输出为:
|
||||
|
||||
| 输出名 | 形状 | 含义 |
|
||||
|---|---|---|
|
||||
| `roi*_boxes_head_raw` | `[1, 4 * reg_max, 5544]` | 2D 框原始回归输出 |
|
||||
| `roi*_scores_head_raw` | `[1, nc, 5544]` | 分类原始 logits |
|
||||
| `roi*_preds_3d_head_raw` | `[1, 41, 5544]` | 3D 原始预测 |
|
||||
| `roi*_preds_edge_head_raw` | `[1, 60, 5544]` | edge 原始预测 |
|
||||
|
||||
脚本支持 `reg_max > 1` 的通用 DFL 解码;当前导出模型若 `reg_max == 1`,会退化为直接距离回归。
|
||||
|
||||
---
|
||||
|
||||
## 6. 后处理设计
|
||||
|
||||
### 6.1 2D 框解码
|
||||
|
||||
2D 框解码由 `decode_boxes_xyxy()` 完成:
|
||||
|
||||
1. 将 `boxes_head_raw` 还原为 `l, t, r, b`
|
||||
2. 与预先缓存的 anchor 网格中心做几何组合
|
||||
3. 再乘以 stride 还原到 ROI-resized 图像像素坐标
|
||||
|
||||
anchor 由 `build_anchor_cache()` 预生成,默认 stride 为:
|
||||
|
||||
```text
|
||||
(8, 16, 32)
|
||||
```
|
||||
|
||||
### 6.2 Top-K 选择
|
||||
|
||||
当前脚本没有做 NMS,而是严格遵循导出 raw head 的 one-to-one Top-K 路径:
|
||||
|
||||
1. 对分类 logits 做 sigmoid
|
||||
2. 每个 anchor 取最大类别分数
|
||||
3. 先按 anchor 最大分类分数做一轮 Top-K
|
||||
4. 再对 gather 后的 `(anchor, class)` 展平分数做第二轮 Top-K
|
||||
5. 生成 `detections = [x1, y1, x2, y2, conf, cls_id]`
|
||||
|
||||
### 6.3 3D / Edge 反归一化
|
||||
|
||||
`preds_3d_head_raw` 和 `preds_edge_head_raw` 会用 `norm_scales_3d` 做反归一化:
|
||||
|
||||
| 项目 | 反归一化方式 |
|
||||
|---|---|
|
||||
| `z3d` | `raw * z3d_scale + z3d_offset` |
|
||||
| `u/v offset` | `sigmoid(raw) * 16 - 8` |
|
||||
| `size` | `raw * size_scale + size_offset` |
|
||||
| yaw residual | `tanh(raw)` |
|
||||
| edge `z` | `raw * z3d_scale + z3d_offset` |
|
||||
| edge `du/dv` | `sigmoid(raw) * 16 - 8` |
|
||||
|
||||
默认值来自内置配置:
|
||||
|
||||
```text
|
||||
z3d_scale = 24.415
|
||||
z3d_offset = 39.937
|
||||
size_scale = 1.945
|
||||
size_offset = 3.780
|
||||
```
|
||||
|
||||
### 6.4 深度恢复
|
||||
|
||||
由于训练时使用 `virtual_fx`,部署时必须恢复真实焦距尺度:
|
||||
|
||||
```text
|
||||
preds_3d[:, (0, 6, 12, 18, 24)] *= depth_scale
|
||||
preds_edge[:, 2::3] *= depth_scale
|
||||
```
|
||||
|
||||
这里的 `depth_scale = fx / virtual_fx` 是按每个 ROI、每一帧动态计算的。
|
||||
|
||||
### 6.5 置信度与类别过滤
|
||||
|
||||
当前脚本在完成 Top-K 后,再通过 `filter_prediction_rows()` 做最终过滤:
|
||||
|
||||
- `conf >= roi.spec.conf`
|
||||
- 若给了 `--classes`,则再做类别白名单过滤
|
||||
- 最终数量再截断到 `max_det`
|
||||
|
||||
### 6.6 3D 框解码与重建
|
||||
|
||||
#### 6.6.1 面型 3D 类别
|
||||
|
||||
对 `face_3d_classes` 中的类别,当前实现使用“可见面驱动”的 3D 解码:
|
||||
|
||||
1. 根据 `pred_41` 中的 face visibility 选择可见面
|
||||
2. 根据最佳可见面读取 `z_face + uv_face_offset`
|
||||
3. 利用整体尺寸 `dims_whole` 和回归的 `yaw` 重建 3D 框
|
||||
4. 若 `pred_edge_60` 可用,则同时解码可见底边缘点
|
||||
5. 若目标处于 cut 状态,还会尝试解码 partial side edge,并把它补充进可见面集合
|
||||
|
||||
这部分比旧版文档中的描述更具体,已经显式纳入了:
|
||||
|
||||
- cut state 感知
|
||||
- partial edge 补边
|
||||
- 多可见面 edge 采样
|
||||
|
||||
#### 6.6.2 完整体 3D 类别
|
||||
|
||||
对 `complete_3d_classes` 中的类别,直接使用 whole-box 分支:
|
||||
|
||||
- `z_whole`
|
||||
- `uv_whole`
|
||||
- `dims_whole`
|
||||
- `yaw`
|
||||
|
||||
重建完整 3D 包围盒。
|
||||
|
||||
#### 6.6.3 其他类别
|
||||
|
||||
对不属于上述两类集合的类别,脚本通常不会生成可视化 3D 框,但仍会保留 whole-box 分支解码出的:
|
||||
|
||||
- `center_3d`
|
||||
- `dims`
|
||||
- `yaw_rad`
|
||||
|
||||
用于结果序列化。
|
||||
|
||||
### 6.7 Yaw 解码
|
||||
|
||||
Yaw 解码仍是 4-bin 分类 + 残差方式:
|
||||
|
||||
```text
|
||||
best_bin = argmax(pred[30:34])
|
||||
yaw = arcsin(clamp(pred[34 + best_bin], -1, 1)) + yaw_bin_offset[best_bin]
|
||||
```
|
||||
|
||||
### 6.8 Edge Yaw 与 Edge Box 重建
|
||||
|
||||
新版实现中,edge 分支不只是“可选 yaw 精化”,而是形成了一条完整的 edge-based 几何诊断链:
|
||||
|
||||
1. 从 `pred_edge_60` 解码选中的可见底边缘点
|
||||
2. 反投影得到 3D edge points
|
||||
3. 由 `decode_edge_yaw_selection_from_prediction()` 选择最可信的单面或双面组合
|
||||
4. 计算 `edge_yaw_rad`
|
||||
5. 判断横向距离是否满足 `max_lateral_dist_m`
|
||||
6. 基于选中的 edge 几何重建 `edge_box`
|
||||
7. 若重建可信,则生成 `decoded_edge_heading`
|
||||
|
||||
默认横向距离阈值为:
|
||||
|
||||
```text
|
||||
edge_yaw_max_lateral_dist_m = 5.0
|
||||
```
|
||||
|
||||
当前实现额外产出以下诊断信息:
|
||||
|
||||
- `edge_yaw_confident`
|
||||
- `edge_yaw_lateral_distance_m`
|
||||
- `edge_yaw_lateral_ok`
|
||||
- `edge_yaw_two_face_eligible`
|
||||
- `edge_yaw_selected_face_types`
|
||||
- `edge_yaw_selected_face_is_partial`
|
||||
- `edge_vs_reg_yaw_rad`
|
||||
- `edge_box_center_3d`
|
||||
- `edge_box_dims`
|
||||
- `edge_box_mode`
|
||||
- `edge_box_length_source`
|
||||
- `edge_box_width_source`
|
||||
- `selected_edge_direct_box_fit_*`
|
||||
- `selected_edge_edgeyaw_box_fit_*`
|
||||
- `selected_edge_fit_gain_px`
|
||||
|
||||
### 6.9 可视化
|
||||
|
||||
每个 ROI 会输出三张 panel:
|
||||
|
||||
1. `2D`:绘制 ROI-resized 坐标系中的检测框
|
||||
2. `3D`:绘制常规回归 yaw 的 3D 框
|
||||
3. `3D EdgeRecon (1+ face)`:只绘制 `edge_yaw_confident=True` 的 edge 重建结果
|
||||
|
||||
最终按 ROI 拼成一个总览网格图。
|
||||
|
||||
---
|
||||
|
||||
## 7. 输出数据设计
|
||||
|
||||
### 7.1 输出目录结构
|
||||
|
||||
单 case 推理时,输出目录下会生成:
|
||||
|
||||
```text
|
||||
output_dir/
|
||||
├── visualizations/
|
||||
│ ├── *.jpg
|
||||
├── predictions/
|
||||
│ ├── *.json
|
||||
└── predictions.json
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- `visualizations/*.jpg`:每帧一个可视化网格图
|
||||
- `predictions/*.json`:下游消费的简化逐帧结果
|
||||
- `predictions.json`:完整聚合结果
|
||||
|
||||
批量 eval 推理时,会在 `output_dir` 下保留与 `eval_dir` 相同的相对目录层级。
|
||||
|
||||
### 7.2 完整聚合结果 `predictions.json`
|
||||
|
||||
聚合结果顶层结构为:
|
||||
|
||||
```json
|
||||
{
|
||||
"case_name": "...",
|
||||
"images_dir": "...",
|
||||
"calib_file": "...",
|
||||
"exported_model_path": "...",
|
||||
"edge_yaw_max_lateral_dist_m": 5.0,
|
||||
"frames": [
|
||||
{
|
||||
"frame_index": 0,
|
||||
"frame_name": "000000.png",
|
||||
"visualization": ".../visualizations/000000.jpg",
|
||||
"rois": {
|
||||
"roi0": {
|
||||
"crop_bounds": [x1, y1, x2, y2],
|
||||
"vp_x": ...,
|
||||
"vp_y": ...,
|
||||
"crop_center_x": ...,
|
||||
"crop_center_y": ...,
|
||||
"edge_yaw_max_lateral_dist_m": 5.0,
|
||||
"calib": {
|
||||
"fx": ...,
|
||||
"fy": ...,
|
||||
"cx": ...,
|
||||
"cy": ...,
|
||||
"depth_scale": ...
|
||||
},
|
||||
"predictions": [
|
||||
{
|
||||
"bbox_xyxy": [...],
|
||||
"original_bbox_xyxy": [...],
|
||||
"confidence": 0.93,
|
||||
"cls_id": 6,
|
||||
"cls_name": "truck",
|
||||
"center_uv": [...],
|
||||
"center_3d": [...],
|
||||
"dims": [...],
|
||||
"yaw_rad": ...,
|
||||
"edge_yaw_rad": ...,
|
||||
"edge_yaw_confident": true,
|
||||
"cut_cls": 0,
|
||||
"roi_id": 0,
|
||||
"visible_face_type": 1,
|
||||
"visible_face_types": [1, 2]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 简化逐帧结果 `predictions/*.json`
|
||||
|
||||
脚本还会额外导出更接近下游消费格式的逐帧 JSON,例如:
|
||||
|
||||
```json
|
||||
{
|
||||
"0": {
|
||||
"type": "0",
|
||||
"type_name": "truck",
|
||||
"score": "0.9664",
|
||||
"roi_id": "0",
|
||||
"box2d": ["1357.25", "542.76", "1743.78", "803.98"],
|
||||
"xyzlhwyaw": ["3.58", "0.69", "5.21", "4.62", "1.92", "1.48", "-1.57"],
|
||||
"face_cls": "tail",
|
||||
"cut_cls": "0",
|
||||
"edge_yaw_rad": "-1.56",
|
||||
"edge_yaw_confident": true,
|
||||
"edge_vs_reg_yaw_rad": "0.01"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这里有一个新版语义变化:
|
||||
|
||||
- `box2d` 优先使用 `original_bbox_xyxy`
|
||||
- 若原图坐标不可用,才回退到 `bbox_xyxy`
|
||||
|
||||
也就是说,简化逐帧 JSON 里的 2D 框优先是“原图坐标系”。
|
||||
|
||||
### 7.4 坐标系约定
|
||||
|
||||
当前实现涉及四种常见坐标系:
|
||||
|
||||
1. `bbox_xyxy`
|
||||
ROI 裁剪并缩放后的图像坐标系
|
||||
|
||||
2. `original_bbox_xyxy`
|
||||
原始整图坐标系
|
||||
|
||||
3. `center_uv`
|
||||
ROI-resized 图像坐标系下的中心点
|
||||
|
||||
4. `center_3d`
|
||||
相机坐标系,单位米
|
||||
|
||||
旧版文档中“所有二维坐标均在 ROI 坐标系”这一表述对当前实现已不完全成立,因为现在明确同时输出了 `original_bbox_xyxy`。
|
||||
|
||||
---
|
||||
|
||||
## 8. 默认类别配置
|
||||
|
||||
当前运行时默认的 `class_map` 为:
|
||||
|
||||
| `cls_id` | 类别 |
|
||||
|---|---|
|
||||
| `0` | `car` |
|
||||
| `1` | `suv` |
|
||||
| `2` | `pickup` |
|
||||
| `3` | `medium_car` |
|
||||
| `4` | `van` |
|
||||
| `5` | `bus` |
|
||||
| `6` | `truck` / `tanker` / `large_truck` / `construction_vehicle` |
|
||||
| `7` | `special_vehicle` |
|
||||
| `8` | `unknown` |
|
||||
| `9` | `pedestrian` |
|
||||
| `10` | `bicyclist` / `motorcyclist` |
|
||||
| `11` | `bicycle` / `motorcycle` |
|
||||
| `12` | `tricycle` / `tricyclist` |
|
||||
| `13` | `traffic_sign` |
|
||||
| `14` | `wheel` |
|
||||
| `15` | `plate` |
|
||||
| `16` | `face` |
|
||||
|
||||
默认 3D 类别分组为:
|
||||
|
||||
- `face_3d_classes = {0,1,2,3,4,5,6,7,8}`
|
||||
- `complete_3d_classes = {9,10,11,12}`
|
||||
|
||||
因此:
|
||||
|
||||
- `0-8` 使用“可见面驱动”的 3D 解码
|
||||
- `9-12` 使用 whole-box 3D 解码
|
||||
- `13-16` 默认不绘制 3D 框,但仍保留部分序列化属性
|
||||
|
||||
---
|
||||
|
||||
## 9. 新旧版本差异总结
|
||||
|
||||
下表总结了新版实现相对旧版说明文档的主要差异。
|
||||
|
||||
| 项目 | 旧版说明 | 新版实现 |
|
||||
|---|---|---|
|
||||
| 导出模式 | 文档列出了 `raw_head_outputs`、`hybrid_outputs`、`postprocessed_outputs`、`denorm_branch_outputs` | 当前脚本只接受 `raw_head_outputs`,并在启动时校验 |
|
||||
| 后端支持 | 主要按 ONNX 方案描述 | 当前同时支持 `ONNX` 和 `TorchScript`,并自动解析 manifest |
|
||||
| 运行时依赖 | 更偏训练/导出视角 | 当前是完全自包含的部署侧实现,不依赖 `ultralytics` |
|
||||
| ROI 缩放 | 单次 resize 描述 | 当前实现先多次 `0.5x` 下采样,再最终 resize,以贴合训练前处理 |
|
||||
| 图像归一化 | `/255.0` | 当前脚本实际使用 `/256.0` |
|
||||
| 输入尺寸来源 | 假定固定输入尺寸 | 当前优先读 manifest 中的 `input_sizes_wh`,也支持命令行覆盖 |
|
||||
| 标定输入格式 | 主要描述平铺内参格式 | 当前同时兼容 flat `camera4.json` 和 combined calibration |
|
||||
| 类别定义 | 类别表较粗,`face_3d_classes` 和 `complete_3d_classes` 范围较小 | 默认类表扩展到 17 个 id,`face_3d_classes=0-8`,`complete_3d_classes=9-12` |
|
||||
| 3D 解码 | 描述了基础 face / whole 两条路径 | 当前新增 cut-aware partial edge、edge 几何筛选、edge box 重建等更完整逻辑 |
|
||||
| edge yaw | 作为可选精化模块描述 | 当前 edge yaw 已融入主结果结构,带 lateral gating、双面可见判断和拟合残差诊断 |
|
||||
| 输出 JSON | 主要描述聚合 JSON,字段较少 | 当前同时输出完整聚合 JSON 和简化逐帧 JSON,并新增大量 edge 诊断字段 |
|
||||
| 2D 坐标语义 | 默认都在 ROI-resized 坐标系 | 当前同时输出 `bbox_xyxy` 和 `original_bbox_xyxy`,两种坐标系并存 |
|
||||
| 可视化 | 只描述 2D/3D 结果 | 当前每个 ROI 输出 `2D`、`3D`、`3D EdgeRecon` 三个 panel |
|
||||
| 运行模式 | 以单 case 为主 | 当前新增 `--eval-dir`,支持整个 mined eval 数据集复用同一个模型批量跑 |
|
||||
|
||||
### 9.1 对齐建议
|
||||
|
||||
如果后续继续维护部署文档,建议把以下三项视为“新版真值来源”:
|
||||
|
||||
1. `tools/model_inference/run_two_roi_exported_onnx_infer.py`
|
||||
2. `tools/model_inference/core/two_roi_infer_utils.py`
|
||||
3. `tools/model_inference/core/two_roi_3d_utils.py`
|
||||
|
||||
特别是以下内容最容易因实现更新而与文档产生偏差:
|
||||
|
||||
- 输入归一化常数
|
||||
- ROI resize 策略
|
||||
- 类别映射与 3D 类别分组
|
||||
- edge yaw 的筛选和诊断字段
|
||||
- 简化 JSON 中 `box2d` 的坐标系定义
|
||||
385
tools/model_inference/docs/two_roi_model_design_bak.md
Executable file
385
tools/model_inference/docs/two_roi_model_design_bak.md
Executable file
@@ -0,0 +1,385 @@
|
||||
# 双ROI合并模型方案文档
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档描述基于 YOLO26-3D 的双 ROI(Region of Interest)单目3D目标检测方案。该方案将同一张原始图像按两种不同的裁剪策略分别送入两个独立训练的 Detect3D 模型,并将两模型合并导出为单一 ONNX/TorchScript 文件,实现2D检测框与3D属性(深度、尺寸、朝向角)的联合预测。
|
||||
|
||||
---
|
||||
|
||||
## 2. 模型架构
|
||||
|
||||
### 2.1 骨干网络与检测头
|
||||
|
||||
模型基于 `yolo26-3d.yaml` 配置,结构如下:
|
||||
|
||||
```
|
||||
输入 (3 × H × W)
|
||||
├── Backbone: Conv → C3k2 × 2 → Conv → C3k2 × 2 → Conv → C3k2 → Conv → C3k2 → SPPF → C2PSA
|
||||
└── Neck (FPN): Upsample + Concat × 2 → C3k2
|
||||
→ Detect3D(P3/8, P4/16, P5/32)
|
||||
```
|
||||
|
||||
模型使用 `end2end=True`,即训练时启用 one-to-one 分支,推理时直接输出 Top-K 检测结果,无需 NMS。
|
||||
|
||||
### 2.2 Detect3D 检测头
|
||||
|
||||
`Detect3D` 继承自标准 `Detect`,在2D分支(cv2 box、cv3 cls)基础上新增:
|
||||
|
||||
- **cv4(3D预测分支)**:每个 anchor 输出 41 维张量;
|
||||
- **cv5(可见面边缘分支)**:每个 anchor 输出 60 维张量。
|
||||
|
||||
#### 3D预测张量(41维)格式
|
||||
|
||||
| 通道范围 | 含义 |
|
||||
|----------|------|
|
||||
| 0–5 | 前面(Front face): z3d, u_offset, v_offset, h, w, visible_score |
|
||||
| 6–11 | 后面(Rear face): z3d, u_offset, v_offset, h, w, visible_score |
|
||||
| 12–17 | 左面(Left face): z3d, u_offset, v_offset, l, h, visible_score |
|
||||
| 18–23 | 右面(Right face): z3d, u_offset, v_offset, l, h, visible_score |
|
||||
| 24 | 整体 z3d(米) |
|
||||
| 25–26 | 整体 u_offset, v_offset(网格坐标偏移) |
|
||||
| 27–29 | 整体 l, h, w(米) |
|
||||
| 30–33 | 4个朝向 bin 的分类 logits |
|
||||
| 34–37 | 4个朝向 bin 的残差 sin 值 |
|
||||
| 38–40 | cut 状态分类 logits(normal/cut-in/cut-out) |
|
||||
|
||||
#### 可见面边缘张量(60维)格式
|
||||
|
||||
每张可见面对应 5 个采样点 × 3 维(du, dv, z),共 4 个面 × 15 维 = 60 维:
|
||||
|
||||
| 面索引 | 通道范围 |
|
||||
|--------|----------|
|
||||
| 前面 | 0–14 |
|
||||
| 后面 | 15–29 |
|
||||
| 左面 | 30–44 |
|
||||
| 右面 | 45–59 |
|
||||
|
||||
每个采样点格式:`[du (网格偏移), dv (网格偏移), z (米)]`。
|
||||
|
||||
### 2.3 双 ROI 设计
|
||||
|
||||
两个独立模型分别对同一帧图像的不同感兴趣区域进行预测:
|
||||
|
||||
| 参数 | ROI0 | ROI1 |
|
||||
|------|------|------|
|
||||
| 裁剪尺寸(宽×高) | 1920 × 880 | 768 × 352 |
|
||||
| 裁剪中心模式 | `cxvy`(图像水平中心 + 灭点y) | `vxvy`(灭点x + 灭点y) |
|
||||
| 虚拟焦距 virtual_fx | 537.0 | 537.0 |
|
||||
| 模型输入尺寸 | 768 × 352 | 768 × 352 |
|
||||
|
||||
- **ROI0**:以图像水平中心为裁剪中心x,涵盖宽视野,适合远距离大视野检测;
|
||||
- **ROI1**:以灭点为裁剪中心,聚焦正前方,适合近中距离精细检测。
|
||||
|
||||
### 2.4 合并导出
|
||||
|
||||
两模型通过 `merge_models_of_2roi_yolo26.py` 合并为单一模型文件(`merged_model.onnx` 或 `.torchscript`),导出时同时写出 `merged_model.export.json` 元数据 sidecar 文件,记录 input_names、output_names、input_sizes_wh 等信息。
|
||||
|
||||
支持多种导出模式(`--export-mode`):
|
||||
|
||||
| 模式 | 描述 |
|
||||
|------|------|
|
||||
| `raw_head_outputs`(默认) | 输出各分支的原始未后处理张量,所有解码在推理侧完成 |
|
||||
| `hybrid_outputs` | 输出后处理2D检测 + 原始 3D/edge 张量 |
|
||||
| `postprocessed_outputs` | 输出完整后处理结果(含 Top-K 选取) |
|
||||
| `denorm_branch_outputs` | 输出反归一化后、Top-K 选取前的分支张量 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 推理前处理
|
||||
|
||||
### 3.1 加载相机标定
|
||||
|
||||
从 `camera4.json` 读取原始相机内参和外参:
|
||||
|
||||
```
|
||||
RawCameraCalib:
|
||||
focal_u, focal_v — 原始像素焦距
|
||||
cu, cv — 主点 (principal point)
|
||||
pitch, yaw — 相机安装角度(弧度)
|
||||
distort_coeffs — 鱼眼畸变系数 [k1, k2, k3, k4](可选)
|
||||
```
|
||||
|
||||
### 3.2 计算灭点(Vanishing Point)
|
||||
|
||||
根据相机安装姿态计算图像灭点坐标:
|
||||
|
||||
```
|
||||
vp_x = cu + focal_u × tan(yaw)
|
||||
vp_y = cv - focal_v × tan(pitch)
|
||||
```
|
||||
|
||||
### 3.3 ROI 裁剪
|
||||
|
||||
根据 ROI 规格(`roi_size`、`crop_center_mode`)在原图上确定裁剪区域:
|
||||
|
||||
```
|
||||
crop_center_x:
|
||||
cxvy 模式: ori_w / 2
|
||||
vxvy 模式: vp_x
|
||||
|
||||
crop_center_y = vp_y(两种模式均以灭点y为中心)
|
||||
|
||||
crop_bounds [x1, y1, x2, y2]:
|
||||
x1 = clamp(crop_center_x - roi_w/2, 0, ori_w - roi_w)
|
||||
y1 = clamp(crop_center_y - roi_h/2, 0, ori_h - roi_h)
|
||||
```
|
||||
|
||||
裁剪结果为固定尺寸图像块(roi_w × roi_h)。
|
||||
|
||||
### 3.4 缩放与标定更新
|
||||
|
||||
将裁剪图像缩放到模型输入尺寸(768 × 352),同时更新相机内参:
|
||||
|
||||
```
|
||||
scale_x = target_w / crop_w
|
||||
scale_y = target_h / crop_h
|
||||
|
||||
fx = focal_u × scale_x
|
||||
fy = focal_v × scale_y
|
||||
cx = (cu - crop_x1) × scale_x
|
||||
cy = (cv - crop_y1) × scale_y
|
||||
|
||||
depth_scale = fx / virtual_fx # 深度恢复系数
|
||||
```
|
||||
|
||||
`depth_scale` 记录了当前帧缩放后真实焦距与虚拟训练焦距之间的比值,用于后处理阶段的深度恢复。
|
||||
|
||||
### 3.5 图像归一化
|
||||
|
||||
```
|
||||
image_rgb = BGR → RGB 转换
|
||||
tensor = image_rgb.transpose(2,0,1) # HWC → CHW
|
||||
tensor = tensor / 255.0 # 归一化到 [0, 1]
|
||||
input = tensor[None, ...] # 增加 batch 维
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 模型输出格式
|
||||
|
||||
以默认 `raw_head_outputs` 模式为例,合并模型共输出 **8 个张量**(每 ROI 4 个):
|
||||
|
||||
| 输出名 | 形状 | 含义 |
|
||||
|--------|------|------|
|
||||
| `roi0_boxes_head_raw` | `[1, 4×reg_max, A]` | ROI0 DFL box 回归原始 logits |
|
||||
| `roi0_scores_head_raw` | `[1, nc, A]` | ROI0 类别分数原始 logits |
|
||||
| `roi0_preds_3d_head_raw` | `[1, 41, A]` | ROI0 3D 预测原始值 |
|
||||
| `roi0_preds_edge_head_raw` | `[1, 60, A]` | ROI0 可见面边缘原始值 |
|
||||
| `roi1_boxes_head_raw` | `[1, 4×reg_max, A]` | ROI1 DFL box 回归原始 logits |
|
||||
| `roi1_scores_head_raw` | `[1, nc, A]` | ROI1 类别分数原始 logits |
|
||||
| `roi1_preds_3d_head_raw` | `[1, 41, A]` | ROI1 3D 预测原始值 |
|
||||
| `roi1_preds_edge_head_raw` | `[1, 60, A]` | ROI1 可见面边缘原始值 |
|
||||
|
||||
其中 `nc` 为类别数,`A` 为总 anchor 数(三个尺度之和):
|
||||
|
||||
```
|
||||
A = (H/8 × W/8) + (H/16 × W/16) + (H/32 × W/32)
|
||||
对于 352×768: = (44×96) + (22×48) + (11×24) = 4224 + 1056 + 264 = 5544
|
||||
```
|
||||
|
||||
`reg_max=1`(当前配置),因此 box 分支通道数为 4。
|
||||
|
||||
---
|
||||
|
||||
## 5. 后处理步骤
|
||||
|
||||
### 5.1 2D 检测框解码
|
||||
|
||||
**DFL 解码**(分布式焦点损失解码):
|
||||
|
||||
```python
|
||||
# reg_max == 1 时简化为:
|
||||
dist = raw_boxes.reshape(batch, 4, A) # [l, t, r, b] 形式的距离预测
|
||||
|
||||
# 还原为 anchor-relative xyxy:
|
||||
boxes_xyxy[:, 0:2] = anchors - dist[:, 0:2] # x1, y1
|
||||
boxes_xyxy[:, 2:4] = anchors + dist[:, 2:4] # x2, y2
|
||||
|
||||
# 乘以 stride 还原到像素坐标:
|
||||
boxes_xyxy = boxes_xyxy * strides
|
||||
```
|
||||
|
||||
Anchor 坐标为各尺度特征图的网格中心点(0.5 偏移),由 `build_anchor_cache()` 预计算。
|
||||
|
||||
### 5.2 Top-K 选取(无 NMS)
|
||||
|
||||
模型使用 end-to-end one-to-one 训练,推理时直接按类别最高分取 Top-K(默认 K=300),无需 NMS:
|
||||
|
||||
```python
|
||||
# 1. sigmoid 激活类别分数
|
||||
scores = sigmoid(raw_scores) # [1, A, nc]
|
||||
|
||||
# 2. 每个 anchor 取最大分数,选 Top-K anchor
|
||||
anchor_max_scores = scores.max(axis=-1) # [1, A]
|
||||
topk_anchor_indices = argsort(anchor_max_scores)[-K:]
|
||||
|
||||
# 3. 再对 gathered scores 扁平化取 Top-K(双重 Top-K)
|
||||
# 最终输出形状: detections [1, K, 6] (x1,y1,x2,y2, conf, cls_id)
|
||||
```
|
||||
|
||||
### 5.3 3D 预测反归一化
|
||||
|
||||
原始 3D 张量在网络内经过归一化压缩,推理侧需还原为物理量:
|
||||
|
||||
| 通道 | 操作 | 含义 |
|
||||
|------|------|------|
|
||||
| z3d(ch 0,6,12,18,24) | `raw × z3d_scale + z3d_offset` | 深度(米),默认 scale=24.415, offset=39.937 |
|
||||
| UV 偏移(ch 1-2, 7-8, 13-14, 19-20, 25-26) | `sigmoid(raw) × 16 − 8` | 网格坐标偏移(格子数,范围约 [−8, 8]) |
|
||||
| 尺寸 l/h/w(ch 3-4, 9-10, 15-16, 21-22, 27-29) | `raw × size_scale + size_offset` | 尺寸(米),默认 scale=1.945, offset=3.780 |
|
||||
| 朝向 bin logits(ch 30-33) | 保持原始 logits | 4-bin softmax 分类 |
|
||||
| 朝向残差(ch 34-37) | `tanh(raw)` | sin(Δ) in [−1, 1] |
|
||||
| face visibility(ch 5,11,17,23) | 保持原始分数 | 各面可见置信度 |
|
||||
| cut 状态(ch 38-40) | 保持原始 logits | normal/cut-in/cut-out |
|
||||
|
||||
同理,edge 张量(60维)的 UV 偏移和深度 z 也做相同的 sigmoid/线性反归一化。
|
||||
|
||||
### 5.4 深度恢复(Depth Scale 还原)
|
||||
|
||||
由于训练时使用固定 `virtual_fx` 虚拟焦距,而实际推理焦距因裁剪+缩放而变化,需乘以 `depth_scale` 还原真实深度:
|
||||
|
||||
```python
|
||||
preds_3d[:, [0, 6, 12, 18, 24]] *= depth_scale # z3d 通道
|
||||
preds_edge[:, 2::3] *= depth_scale # edge 深度通道
|
||||
```
|
||||
|
||||
其中 `depth_scale = fx_actual / virtual_fx`,每帧根据实际裁剪/缩放参数计算。
|
||||
|
||||
### 5.5 置信度过滤
|
||||
|
||||
按置信度阈值(默认 0.25)和类别白名单过滤低质量检测:
|
||||
|
||||
```python
|
||||
keep = detections[:, 4] >= conf_thres
|
||||
if classes is not None:
|
||||
keep &= cls_id in classes
|
||||
detections = detections[keep][:max_det]
|
||||
```
|
||||
|
||||
### 5.6 朝向角解码
|
||||
|
||||
模型采用 **4-bin 分类 + 残差 sin** 联合解码朝向角:
|
||||
|
||||
```
|
||||
4 个 bin 偏置角: [0°, 90°, −90°, 180°]
|
||||
|
||||
yaw_bin = argmax(logits[30:34])
|
||||
bin_offset = {0: 0, 1: π/2, 2: −π/2, 3: π}[yaw_bin]
|
||||
|
||||
sin_delta = tanh(raw[34 + yaw_bin])
|
||||
delta = arcsin(clamp(sin_delta, −1, 1))
|
||||
|
||||
yaw_reg = bin_offset + delta
|
||||
```
|
||||
|
||||
### 5.7 3D 包围盒重建
|
||||
|
||||
#### 面型类(face_3d_classes):车辆等大目标
|
||||
|
||||
1. 按 face visibility score 选取最高置信可见面(front/rear/left/right);
|
||||
2. 用该面的 UV 偏移 + z 在像素坐标系中反投影,得到 3D 中心点;
|
||||
3. 结合整体尺寸 l/h/w 和朝向角 yaw,计算 8 个角点坐标;
|
||||
4. 若有 edge 预测,用 cv5 中对应面的5个采样点重投影,辅助可视化。
|
||||
|
||||
```python
|
||||
# 面中心 UV → 像素坐标
|
||||
u_face = (anchor_x + u_offset) * stride
|
||||
v_face = (anchor_y + v_offset) * stride
|
||||
|
||||
# 像素坐标 → 相机坐标系 3D 中心
|
||||
X = (u_face - cx) / fx * z_face
|
||||
Y = (v_face - cy) / fy * z_face
|
||||
Z = z_face
|
||||
|
||||
# 基于 3D 中心 + 尺寸 + 朝向重建 8 角点
|
||||
corners = compute_3d_box_corners(center_3d, [l, h, w], yaw, face_type)
|
||||
```
|
||||
|
||||
#### 完整型类(complete_3d_classes):行人、骑手等
|
||||
|
||||
直接使用整体预测(通道 24–29)重建包围盒,无需面选择。
|
||||
|
||||
### 5.8 Edge Yaw 精化(可选)
|
||||
|
||||
对于横向距离 ≤ `edge_yaw_max_lateral_dist_m`(默认 5.0m)的目标,尝试利用可见面底边缘点拟合更精确的朝向角:
|
||||
|
||||
1. 从 cv5 解码可选的1-2个可见面底边缘采样点(2D);
|
||||
2. 结合深度,将采样点反投影到 3D;
|
||||
3. 拟合底边缘方向,得到 `edge_yaw_rad`;
|
||||
4. 若两面同时可见(two-face eligible),优先使用双面拟合结果,置 `edge_yaw_confident=True`。
|
||||
|
||||
---
|
||||
|
||||
## 6. 输出数据格式
|
||||
|
||||
每帧的结构化输出以 JSON 格式保存:
|
||||
|
||||
```json
|
||||
{
|
||||
"frame_index": 0,
|
||||
"frame_name": "000000.png",
|
||||
"rois": {
|
||||
"roi0": {
|
||||
"crop_bounds": [x1, y1, x2, y2],
|
||||
"vp_x": 960.0,
|
||||
"vp_y": 175.0,
|
||||
"calib": { "fx": ..., "fy": ..., "cx": ..., "cy": ..., "depth_scale": ... },
|
||||
"predictions": [
|
||||
{
|
||||
"bbox_xyxy": [x1, y1, x2, y2],
|
||||
"confidence": 0.87,
|
||||
"cls_id": 0,
|
||||
"cls_name": "car",
|
||||
"yaw_rad": -0.32,
|
||||
"edge_yaw_rad": -0.31,
|
||||
"edge_yaw_confident": true,
|
||||
"edge_yaw_lateral_distance_m": 3.2,
|
||||
"edge_yaw_lateral_ok": true,
|
||||
"edge_yaw_two_face_eligible": true,
|
||||
"edge_yaw_selected_face_types": [2, 0],
|
||||
"edge_vs_reg_yaw_rad": 0.01,
|
||||
"center_uv": [u, v],
|
||||
"center_3d": [X, Y, Z],
|
||||
"visible_face_type": 2,
|
||||
"visible_face_types": [2, 0],
|
||||
"crop_bounds": [x1, y1, x2, y2]
|
||||
}
|
||||
]
|
||||
},
|
||||
"roi1": { ... }
|
||||
},
|
||||
"visualization": "/path/to/000000.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
所有二维坐标(`bbox_xyxy`、`center_uv`)均在对应 ROI 裁剪并缩放后的图像坐标系下;`center_3d` 在相机坐标系下,单位为米。
|
||||
|
||||
---
|
||||
|
||||
## 7. 类别定义
|
||||
|
||||
| cls_id | 类别名称(示例) |
|
||||
|--------|-----------------|
|
||||
| 0 | car(含 suv, van 等) |
|
||||
| 1 | bus |
|
||||
| 2 | truck(含 large_truck) |
|
||||
| 3 | tanker / construction_vehicle |
|
||||
| 4 | unknown |
|
||||
| 5 | pedestrian |
|
||||
| 6 | bicycle / motorcycle |
|
||||
| 7 | motorcyclist / bicyclist |
|
||||
| 8 | tricycle / tricyclist |
|
||||
| 9 | traffic_sign |
|
||||
| 10 | wheel |
|
||||
| 11 | plate |
|
||||
| 12 | face |
|
||||
|
||||
类别 0–4 属于 `face_3d_classes`(面型3D重建),类别 5–8 属于 `complete_3d_classes`(整体3D重建)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 鱼眼镜头支持
|
||||
|
||||
若相机标定文件中包含有效的 `distort_coeffs`(4个系数 [k1, k2, k3, k4]),则:
|
||||
- 2D 坐标系下 3D 点投影时使用鱼眼畸变正向模型(`apply_fisheye_distortion`);
|
||||
- 2D → 3D 反投影时使用 Newton 迭代法求解畸变逆映射(`remove_fisheye_distortion`);
|
||||
- 3D 包围盒可视化时对各条棱进行密集采样后逐点投影,确保曲线正确。
|
||||
690
tools/model_inference/docs/two_roi_model_design_with_diff_and_fake3d.md
Executable file
690
tools/model_inference/docs/two_roi_model_design_with_diff_and_fake3d.md
Executable file
@@ -0,0 +1,690 @@
|
||||
# 双ROI导出模型设计说明(Diff 与 Fake3D 版本)
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
本文档说明当前新版双 ROI 合并导出模型在部署侧的输入约定、输出张量、后处理流程,以及 `difficulty` 分支与 `fake 3D` 分支的运行时语义。
|
||||
|
||||
本文档覆盖的对象是:
|
||||
|
||||
- `tools/model_merging/merge_models_of_2roi_yolo26.py`
|
||||
- `tools/model_inference/core/run_two_roi_exported_onnx_infer.py`
|
||||
- `tools/model_inference/core/two_roi_infer_utils.py`
|
||||
- `ultralytics/nn/modules/head.py`
|
||||
|
||||
凡与旧文档冲突之处,以当前代码实现为准。
|
||||
|
||||
如只查看旧版双 ROI 合并模型,请参考:
|
||||
|
||||
- `tools/model_inference/docs/two_roi_model_design.md`
|
||||
|
||||
---
|
||||
|
||||
## 2. 版本背景
|
||||
|
||||
当前仓库中的双 ROI 合并导出模型已经从旧版的:
|
||||
|
||||
- `2D boxes + class scores + 3D branch (+ 可选 edge branch)`
|
||||
|
||||
演进为新版可选扩展的形态:
|
||||
|
||||
- `2D boxes + class scores + 3D branch + difficulty branch`
|
||||
- `2D boxes + class scores + 3D branch + difficulty branch + fake 3D branch`
|
||||
- `(+ 可选 edge branch)`
|
||||
|
||||
其中:
|
||||
|
||||
- `difficulty branch` 用于输出目标 difficulty 二分类 logit
|
||||
- `fake 3D branch` 用于输出 fake class 专用的 3D 预测
|
||||
|
||||
当前合并导出脚本支持以下控制项:
|
||||
|
||||
- `--edge-head-mode keep|drop`
|
||||
- `--fake-3d-branch-mode keep|drop`
|
||||
|
||||
因此新版模型存在两条主要导出变体:
|
||||
|
||||
1. `drop fake_3d`:导出 `3D + diff`
|
||||
2. `keep fake_3d`:导出 `3D + diff + fake_3d`
|
||||
|
||||
---
|
||||
|
||||
## 3. 方案概览
|
||||
|
||||
当前运行时仍然沿用双 ROI 单目 3D 检测的总体思路,但部署形态已经收敛为:
|
||||
|
||||
1. 原图按 `ROI0` 和 `ROI1` 两套规则分别裁剪
|
||||
2. 两个 ROI 图像送入同一个合并导出模型
|
||||
3. 模型输出每个 ROI 的原始检测头张量
|
||||
4. 2D 框解码、Top-K、3D 反归一化、深度恢复、3D 框重建、fake-class 路由、可视化与 JSON 序列化全部在 Python 侧完成
|
||||
|
||||
当前支持:
|
||||
|
||||
- ONNX:`onnxruntime`
|
||||
- TorchScript:`torch.jit.load`
|
||||
- 单 case 推理
|
||||
- mined / eval 数据集批量推理
|
||||
|
||||
当前部署脚本不依赖训练时的 `ultralytics` dataloader,只依赖导出张量契约和运行时元数据。
|
||||
|
||||
---
|
||||
|
||||
## 4. 模型与运行时契约
|
||||
|
||||
### 4.1 导出模型形态
|
||||
|
||||
当前推理脚本只接受双 ROI 合并后的导出模型:
|
||||
|
||||
- `.onnx`
|
||||
- `.torchscript` / `.ts` / `.jit`
|
||||
|
||||
脚本会读取导出清单:
|
||||
|
||||
- ONNX 优先读取 sidecar:`merged_model.export.json`
|
||||
- TorchScript 优先读 sidecar,若 sidecar 缺失再读取模型内嵌 `config.txt`
|
||||
|
||||
当前部署脚本会显式要求:
|
||||
|
||||
```text
|
||||
export_mode == "raw_head_outputs"
|
||||
```
|
||||
|
||||
也就是说,当前文档只讨论原始检测头输出模式,不讨论 `hybrid_outputs`、`postprocessed_outputs` 等其他导出形态。
|
||||
|
||||
### 4.2 输入名称
|
||||
|
||||
默认输入名为:
|
||||
|
||||
- `roi0_input`
|
||||
- `roi1_input`
|
||||
|
||||
默认输入尺寸为:
|
||||
|
||||
- `768 x 352`
|
||||
|
||||
若导出清单里提供了 `input_names` 和 `input_sizes_wh`,运行时以清单为准。
|
||||
|
||||
### 4.3 导出控制开关
|
||||
|
||||
当前导出脚本暴露两个关键开关:
|
||||
|
||||
```bash
|
||||
--edge-head-mode keep|drop
|
||||
--fake-3d-branch-mode keep|drop
|
||||
```
|
||||
|
||||
它们会直接影响导出后的输出张量数量与名称。
|
||||
|
||||
### 4.4 运行时元数据
|
||||
|
||||
运行时会从数据配置 YAML 中读取以下元数据:
|
||||
|
||||
- `class_map`
|
||||
- `face_3d_classes`
|
||||
- `complete_3d_classes`
|
||||
- `fake_3d_classes`
|
||||
- `norm_scales_3d`
|
||||
|
||||
若未提供额外 YAML,则使用 `tools/model_inference/core/two_roi_infer_utils.py` 中的 `DEFAULT_DATASET_CONFIG`。
|
||||
|
||||
当前内置默认值包括:
|
||||
|
||||
- `face_3d_classes = [0,1,2,3,4,5,6,7,8,17]`
|
||||
- `complete_3d_classes = [9,10,11,12,18,19]`
|
||||
- `fake_3d_classes = [17,18,19]`
|
||||
|
||||
对应 fake 类别名称:
|
||||
|
||||
- `car_fake`
|
||||
- `bicyclist_fake`
|
||||
- `pedestrian_fake`
|
||||
|
||||
### 4.5 新旧版本输出类别对比
|
||||
|
||||
当前部署侧的 `cls_id` / `cls_name` 由 `class_map` 决定。
|
||||
旧版与新版的主要差异不只是输出分支数量,还包括默认类别集合本身已经扩展。
|
||||
|
||||
旧版默认类别定义为:
|
||||
|
||||
| `cls_id` | 旧版默认类别 |
|
||||
|---|---|
|
||||
| `0` | `car` |
|
||||
| `1` | `suv` |
|
||||
| `2` | `pickup` |
|
||||
| `3` | `medium_car` |
|
||||
| `4` | `van` |
|
||||
| `5` | `bus` |
|
||||
| `6` | `truck` / `tanker` / `large_truck` / `construction_vehicle` |
|
||||
| `7` | `special_vehicle` |
|
||||
| `8` | `unknown` |
|
||||
| `9` | `pedestrian` |
|
||||
| `10` | `bicyclist` / `motorcyclist` |
|
||||
| `11` | `bicycle` / `motorcycle` |
|
||||
| `12` | `tricycle` / `tricyclist` |
|
||||
| `13` | `traffic_sign` |
|
||||
| `14` | `wheel` |
|
||||
| `15` | `plate` |
|
||||
| `16` | `face` |
|
||||
|
||||
新版默认类别定义为:
|
||||
|
||||
| `cls_id` | 新版默认类别 |
|
||||
|---|---|
|
||||
| `0-16` | 与旧版相同 |
|
||||
| `17` | `car_fake` |
|
||||
| `18` | `bicyclist_fake` |
|
||||
| `19` | `pedestrian_fake` |
|
||||
|
||||
因此默认 `scores_head_raw` 的类别数从旧版的:
|
||||
|
||||
- `nc = 17`
|
||||
|
||||
扩展为新版的:
|
||||
|
||||
- `nc = 20`
|
||||
|
||||
对应的 3D 类别分组也从旧版:
|
||||
|
||||
- `face_3d_classes = [0,1,2,3,4,5,6,7,8]`
|
||||
- `complete_3d_classes = [9,10,11,12]`
|
||||
|
||||
扩展为新版:
|
||||
|
||||
- `face_3d_classes = [0,1,2,3,4,5,6,7,8,17]`
|
||||
- `complete_3d_classes = [9,10,11,12,18,19]`
|
||||
- `fake_3d_classes = [17,18,19]`
|
||||
|
||||
语义上可以理解为:
|
||||
|
||||
- `0-16`:延续旧版类别语义
|
||||
- `17-19`:新增 fake 类别,2D 分类仍走统一 `scores_head_raw`
|
||||
- `17` 会按 face 类路径参与 3D 解码,但在保留 fake 分支时优先读取 `preds_3d_fake_head_raw`
|
||||
- `18-19` 会按 complete 类路径参与 3D 解码,但在保留 fake 分支时同样优先读取 `preds_3d_fake_head_raw`
|
||||
|
||||
---
|
||||
|
||||
## 5. ROI 与前处理设计
|
||||
|
||||
### 5.1 默认 ROI 配置
|
||||
|
||||
默认 ROI 配置来自 `DEFAULT_DATASET_CONFIG["roi_configs"]`:
|
||||
|
||||
| ROI | 裁剪尺寸 `(w, h)` | 裁剪中心模式 | `virtual_fx` | 默认输入尺寸 `(w, h)` |
|
||||
|---|---:|---|---:|---:|
|
||||
| `ROI0` | `1920 x 880` | `cxvy` | `537.0` | `768 x 352` |
|
||||
| `ROI1` | `768 x 352` | `vxvy` | `537.0` | `768 x 352` |
|
||||
|
||||
其中:
|
||||
|
||||
- `cxvy`:裁剪中心 `x` 取图像水平中心,`y` 取灭点 `vp_y`
|
||||
- `vxvy`:裁剪中心 `x` 取灭点 `vp_x`,`y` 取灭点 `vp_y`
|
||||
|
||||
### 5.2 标定与灭点
|
||||
|
||||
当前运行时兼容扁平 `camera4.json` 与合并格式 `camera4.json`。
|
||||
|
||||
灭点计算逻辑:
|
||||
|
||||
```text
|
||||
vp_x = cu + focal_u * tan(yaw)
|
||||
vp_y = cv - focal_v * tan(pitch)
|
||||
```
|
||||
|
||||
### 5.3 ROI 裁剪
|
||||
|
||||
裁剪边界通过 `compute_centered_roi_bounds()` 计算:
|
||||
|
||||
```text
|
||||
crop_x1 = clamp(center_x - roi_w / 2, 0, ori_w - roi_w)
|
||||
crop_y1 = clamp(center_y - roi_h / 2, 0, ori_h - roi_h)
|
||||
crop_x2 = crop_x1 + roi_w
|
||||
crop_y2 = crop_y1 + roi_h
|
||||
```
|
||||
|
||||
### 5.4 resize 与标定更新
|
||||
|
||||
当前脚本会把 ROI 图像 resize 到模型输入尺寸,并同步更新 resized ROI 坐标系下的标定:
|
||||
|
||||
```text
|
||||
fx = focal_u * scale_x
|
||||
fy = focal_v * scale_y
|
||||
cx = (cu - crop_x1) * scale_x
|
||||
cy = (cv - crop_y1) * scale_y
|
||||
depth_scale = fx / virtual_fx
|
||||
```
|
||||
|
||||
其中 `depth_scale` 会在 3D 后处理阶段恢复真实焦距下的深度尺度。
|
||||
|
||||
### 5.5 输入张量化
|
||||
|
||||
输入张量构造方式:
|
||||
|
||||
```python
|
||||
image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
|
||||
array = image_rgb.transpose(2, 0, 1).astype(np.float32) / 256.0
|
||||
input = array[None, ...]
|
||||
```
|
||||
|
||||
注意是:
|
||||
|
||||
```text
|
||||
/ 256.0
|
||||
```
|
||||
|
||||
不是 `/ 255.0`。
|
||||
|
||||
---
|
||||
|
||||
## 6. 输出张量设计
|
||||
|
||||
### 6.1 总体原则
|
||||
|
||||
当前部署脚本只支持每个 ROI 输出原始检测头张量。
|
||||
输出张量是否包含 `preds_edge`、`preds_3d_fake` 由导出开关控制。
|
||||
|
||||
每个 ROI 至少包含:
|
||||
|
||||
1. `boxes_head_raw`
|
||||
2. `scores_head_raw`
|
||||
3. `preds_3d_head_raw`
|
||||
4. `preds_diff_head_raw`
|
||||
|
||||
### 6.2 `drop fake_3d` 且 `drop edge`
|
||||
|
||||
当:
|
||||
|
||||
```bash
|
||||
--fake-3d-branch-mode drop
|
||||
--edge-head-mode drop
|
||||
```
|
||||
|
||||
合并模型总输出为 8 个:
|
||||
|
||||
1. `roi0_boxes_head_raw`
|
||||
2. `roi0_scores_head_raw`
|
||||
3. `roi0_preds_3d_head_raw`
|
||||
4. `roi0_preds_diff_head_raw`
|
||||
5. `roi1_boxes_head_raw`
|
||||
6. `roi1_scores_head_raw`
|
||||
7. `roi1_preds_3d_head_raw`
|
||||
8. `roi1_preds_diff_head_raw`
|
||||
|
||||
### 6.3 `keep fake_3d` 且 `drop edge`
|
||||
|
||||
当:
|
||||
|
||||
```bash
|
||||
--fake-3d-branch-mode keep
|
||||
--edge-head-mode drop
|
||||
```
|
||||
|
||||
合并模型总输出为 10 个:
|
||||
|
||||
1. `roi0_boxes_head_raw`
|
||||
2. `roi0_scores_head_raw`
|
||||
3. `roi0_preds_3d_head_raw`
|
||||
4. `roi0_preds_diff_head_raw`
|
||||
5. `roi0_preds_3d_fake_head_raw`
|
||||
6. `roi1_boxes_head_raw`
|
||||
7. `roi1_scores_head_raw`
|
||||
8. `roi1_preds_3d_head_raw`
|
||||
9. `roi1_preds_diff_head_raw`
|
||||
10. `roi1_preds_3d_fake_head_raw`
|
||||
|
||||
### 6.4 `keep edge` 的扩展
|
||||
|
||||
若再加:
|
||||
|
||||
```bash
|
||||
--edge-head-mode keep
|
||||
```
|
||||
|
||||
则每个 ROI 还会额外多一个:
|
||||
|
||||
- `roi*_preds_edge_head_raw`
|
||||
|
||||
### 6.5 典型 shape
|
||||
|
||||
对默认输入尺寸 `768 x 352`:
|
||||
|
||||
```text
|
||||
A = (352/8 * 768/8) + (352/16 * 768/16) + (352/32 * 768/32)
|
||||
= 4224 + 1056 + 264
|
||||
= 5544
|
||||
```
|
||||
|
||||
所以典型输出 shape 为:
|
||||
|
||||
| 输出名 | 形状 | 含义 |
|
||||
|---|---|---|
|
||||
| `roi*_boxes_head_raw` | `[1, 4, 5544]` 或 `[1, 4*reg_max, 5544]` | 2D 框回归头原始输出 |
|
||||
| `roi*_scores_head_raw` | `[1, nc, 5544]` | 分类原始 logits,旧版默认 `nc=17`,新版默认 `nc=20` |
|
||||
| `roi*_preds_3d_head_raw` | `[1, 41, 5544]` | 常规 3D 分支 |
|
||||
| `roi*_preds_diff_head_raw` | `[1, 1, 5544]` | difficulty 二分类分支 |
|
||||
| `roi*_preds_3d_fake_head_raw` | `[1, 41, 5544]` | fake class 专用 3D 分支 |
|
||||
| `roi*_preds_edge_head_raw` | `[1, 60, 5544]` | edge 分支 |
|
||||
|
||||
注意:
|
||||
|
||||
- 实际 `boxes_head_raw` 通道数取决于 `reg_max`
|
||||
- 旧版本文档里常见的 `[1, 4*reg_max, 5544]` 写法仍然成立
|
||||
- 你当前部分导出模型如果已在导出前把 `reg_max` 相关结构折叠,也可能看到 `[1, 4, 5544]`
|
||||
|
||||
### 6.6 各分支语义
|
||||
|
||||
#### 6.6.1 `boxes_head_raw`
|
||||
|
||||
2D 框回归头的原始输出,逐 anchor 表示边界框回归量。
|
||||
运行时需要结合 anchor 网格与 stride 做 decode,不能直接作为最终 bbox。
|
||||
|
||||
#### 6.6.2 `scores_head_raw`
|
||||
|
||||
分类头的原始 logits,逐 anchor、逐类输出。
|
||||
运行时会先做 sigmoid,再走 one-to-one Top-K 选择。
|
||||
|
||||
#### 6.6.3 `preds_3d_head_raw`
|
||||
|
||||
常规 3D 分支,适用于常规 3D 类别。
|
||||
该分支输出 41 维 3D 表达,后续会按 `norm_scales_3d` 做反归一化。
|
||||
|
||||
#### 6.6.4 `preds_diff_head_raw`
|
||||
|
||||
difficulty 分支输出,每个 anchor 只有 1 维 logit。
|
||||
当前训练逻辑中,difficulty 被视为二分类:
|
||||
|
||||
- `0/1 -> easy-like`
|
||||
- `2/3 -> hard-like`
|
||||
|
||||
部署侧目前保留该分支输出,但默认主推理可视化链路还不会直接把它画到结果图上。
|
||||
|
||||
#### 6.6.5 `preds_3d_fake_head_raw`
|
||||
|
||||
fake class 专用 3D 分支。
|
||||
该分支与常规 3D 分支一样,也是 41 维,但只用于 fake 类别:
|
||||
|
||||
- `car_fake`
|
||||
- `bicyclist_fake`
|
||||
- `pedestrian_fake`
|
||||
|
||||
当导出模型包含这个张量且当前 detection 的 `cls_id` 落在 `fake_3d_classes` 中时,运行时会优先用它,而不是 `preds_3d_head_raw`。
|
||||
|
||||
#### 6.6.6 `preds_edge_head_raw`
|
||||
|
||||
edge 分支输出 60 维。
|
||||
每个面的底边缘由 5 个采样点组成,每个采样点 3 维:
|
||||
|
||||
```text
|
||||
[du, dv, z]
|
||||
```
|
||||
|
||||
4 个面一共 60 维。
|
||||
|
||||
---
|
||||
|
||||
## 7. 3D 分支定义
|
||||
|
||||
### 7.1 常规 3D 分支(41 维)
|
||||
|
||||
通道布局:
|
||||
|
||||
| 通道范围 | 含义 |
|
||||
|---|---|
|
||||
| `0-5` | front face:`z3d, u_offset, v_offset, h, w, visible_score` |
|
||||
| `6-11` | rear face:`z3d, u_offset, v_offset, h, w, visible_score` |
|
||||
| `12-17` | left face:`z3d, u_offset, v_offset, l, h, visible_score` |
|
||||
| `18-23` | right face:`z3d, u_offset, v_offset, l, h, visible_score` |
|
||||
| `24` | whole-box `z3d` |
|
||||
| `25-26` | whole-box `u_offset, v_offset` |
|
||||
| `27-29` | whole-box `l, h, w` |
|
||||
| `30-33` | yaw 4-bin 分类 logits |
|
||||
| `34-37` | yaw 残差 `sin(delta)` |
|
||||
| `38-40` | cut state logits |
|
||||
|
||||
### 7.2 fake 3D 分支(41 维)
|
||||
|
||||
`preds_3d_fake_head_raw` 与 `preds_3d_head_raw` 在张量结构上完全一致,也是 41 维。
|
||||
区别只在于用途:
|
||||
|
||||
- `preds_3d_head_raw`:常规类别使用
|
||||
- `preds_3d_fake_head_raw`:fake class 使用
|
||||
|
||||
### 7.3 edge 分支(60 维)
|
||||
|
||||
| 面 | 通道范围 |
|
||||
|---|---|
|
||||
| front | `0-14` |
|
||||
| rear | `15-29` |
|
||||
| left | `30-44` |
|
||||
| right | `45-59` |
|
||||
|
||||
---
|
||||
|
||||
## 8. 后处理设计
|
||||
|
||||
### 8.1 2D 框解码
|
||||
|
||||
运行时用 `decode_boxes_xyxy()` 对 `boxes_head_raw` 解码:
|
||||
|
||||
1. 还原 `l, t, r, b`
|
||||
2. 与 anchor 网格中心组合
|
||||
3. 乘以 stride 还原到 ROI-resized 图像坐标
|
||||
|
||||
anchor 由 `build_anchor_cache()` 预生成,默认 stride:
|
||||
|
||||
```text
|
||||
(8, 16, 32)
|
||||
```
|
||||
|
||||
### 8.2 Top-K 选择
|
||||
|
||||
当前推理脚本沿用 one-to-one Top-K 路径:
|
||||
|
||||
1. 对分类 logits 做 sigmoid
|
||||
2. 每个 anchor 取最大类别分数
|
||||
3. 做 Top-K
|
||||
4. 生成 `detections = [x1, y1, x2, y2, conf, cls_id]`
|
||||
|
||||
### 8.3 3D / Edge 反归一化
|
||||
|
||||
`preds_3d_head_raw`、`preds_3d_fake_head_raw` 与 `preds_edge_head_raw` 会用 `norm_scales_3d` 做反归一化:
|
||||
|
||||
| 项目 | 反归一化方式 |
|
||||
|---|---|
|
||||
| `z3d` | `raw * z3d_scale + z3d_offset` |
|
||||
| `u/v offset` | `sigmoid(raw) * 16 - 8` |
|
||||
| `size` | `raw * size_scale + size_offset` |
|
||||
| yaw residual | `tanh(raw)` |
|
||||
| edge `z` | `raw * z3d_scale + z3d_offset` |
|
||||
| edge `du/dv` | `sigmoid(raw) * 16 - 8` |
|
||||
|
||||
默认值:
|
||||
|
||||
```text
|
||||
z3d_scale = 24.415
|
||||
z3d_offset = 39.937
|
||||
size_scale = 1.945
|
||||
size_offset = 3.780
|
||||
yaw_scale = 1.5707963
|
||||
```
|
||||
|
||||
### 8.4 深度恢复
|
||||
|
||||
部署时需要按真实焦距恢复深度尺度:
|
||||
|
||||
```text
|
||||
preds_3d[:, (0, 6, 12, 18, 24)] *= depth_scale
|
||||
preds_3d_fake[:, (0, 6, 12, 18, 24)] *= depth_scale
|
||||
preds_edge[:, 2::3] *= depth_scale
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
```text
|
||||
depth_scale = fx / virtual_fx
|
||||
```
|
||||
|
||||
### 8.5 fake class 的 3D 路由
|
||||
|
||||
这是新版运行时与旧版的关键差异之一。
|
||||
|
||||
当前 exported inference 在逐检测框解码时,会做如下判断:
|
||||
|
||||
1. 读取 detection 的 `cls_id`
|
||||
2. 若 `cls_id in fake_3d_classes`
|
||||
3. 且当前导出模型包含 `preds_3d_fake`
|
||||
4. 则用 `preds_3d_fake` 作为该框的 3D 解码输入
|
||||
5. 否则继续使用 `preds_3d`
|
||||
|
||||
也就是说:
|
||||
|
||||
- `keep fake_3d` 时:fake 类别走专用 3D 分支
|
||||
- `drop fake_3d` 时:所有类别都走主 `preds_3d`
|
||||
|
||||
### 8.6 difficulty 分支的使用
|
||||
|
||||
当前部署侧已经能把 `preds_diff` 读入运行时结果结构:
|
||||
|
||||
- `ROISelectedPredictions.preds_diff`
|
||||
|
||||
但默认主推理链路暂未把它用于:
|
||||
|
||||
- 过滤
|
||||
- 合并
|
||||
- 可视化绘制
|
||||
- JSON 输出主字段
|
||||
|
||||
因此当前它的状态是:
|
||||
|
||||
- 已导出
|
||||
- 已可解析
|
||||
- 已可供后续扩展
|
||||
- 默认主链路尚未深度消费
|
||||
|
||||
### 8.7 edge yaw 与 edge box
|
||||
|
||||
若导出模型包含 edge 分支,则运行时可继续执行 edge-based 诊断链:
|
||||
|
||||
1. 反投影可见底边缘点
|
||||
2. 选择单面或双面组合
|
||||
3. 计算 `edge_yaw`
|
||||
4. 约束横向距离阈值
|
||||
5. 重建 `edge_box`
|
||||
6. 生成额外诊断信息
|
||||
|
||||
若使用:
|
||||
|
||||
```bash
|
||||
--edge-head-mode drop
|
||||
```
|
||||
|
||||
则该能力在部署侧被关闭。
|
||||
|
||||
---
|
||||
|
||||
## 9. 下游解析逻辑
|
||||
|
||||
### 9.1 新旧输出协议兼容
|
||||
|
||||
当前 `run_two_roi_exported_onnx_infer.py` 对以下情况都兼容:
|
||||
|
||||
1. 旧版仅 `boxes + scores + preds_3d`
|
||||
2. 新版 `boxes + scores + preds_3d + preds_diff`
|
||||
3. 新版 `boxes + scores + preds_3d + preds_diff + preds_3d_fake`
|
||||
4. 上述版本再叠加 `preds_edge`
|
||||
|
||||
兼容方式为:
|
||||
|
||||
- 必需输出只要求旧版最小集合
|
||||
- 若发现 `preds_3d_fake` / `preds_diff` / `preds_edge` 则自动启用
|
||||
- 若缺失则退化为旧行为
|
||||
|
||||
### 9.2 建议的外部调用方式
|
||||
|
||||
外部调用方不要按固定 output index 写死解析逻辑。
|
||||
推荐使用:
|
||||
|
||||
1. 先读取 `merged_model.export.json`
|
||||
2. 按 `output_names` 解析输出
|
||||
|
||||
原因是:
|
||||
|
||||
- `keep/drop fake_3d_branch` 会改变输出总数
|
||||
- `keep/drop edge_head` 也会改变输出总数
|
||||
|
||||
---
|
||||
|
||||
## 10. 与旧版文档的主要差异
|
||||
|
||||
相对旧版双 ROI 文档,当前新版多出以下变化:
|
||||
|
||||
1. 新增 `preds_diff_head_raw`
|
||||
2. 新增可选 `preds_3d_fake_head_raw`
|
||||
3. 默认输出类别从 `17` 类扩展到 `20` 类,新增:
|
||||
- `car_fake`
|
||||
- `bicyclist_fake`
|
||||
- `pedestrian_fake`
|
||||
4. 运行时引入 `fake_3d_classes`
|
||||
5. fake 类别不再强制走主 `preds_3d`
|
||||
6. 导出 manifest 中新增:
|
||||
- `fake_3d_branch_mode`
|
||||
- `keep_fake_3d_branch`
|
||||
7. 输出总数不再固定为 8
|
||||
|
||||
典型情况:
|
||||
|
||||
- 旧版 no-edge:8 输出
|
||||
- 新版 drop fake + drop edge:8 输出
|
||||
- 新版 keep fake + drop edge:10 输出
|
||||
- 新版 keep fake + keep edge:12 输出
|
||||
|
||||
---
|
||||
|
||||
## 11. 导出示例
|
||||
|
||||
### 11.1 保留 fake 3D 分支
|
||||
|
||||
```bash
|
||||
python tools/model_merging/merge_models_of_2roi_yolo26.py \
|
||||
--roi0-model-path runs/detect/mono3d_roi0_20260506_epoch99.pt \
|
||||
--roi1-model-path runs/detect/mono3d_roi1_20260506_epoch99.pt \
|
||||
--save-dir runs/export/train_mono3d_two_roi_20260506-keep_fake_3d_branch \
|
||||
--imgsz 768 352 \
|
||||
--edge-head-mode drop \
|
||||
--fake-3d-branch-mode keep
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
- `boxes`
|
||||
- `scores`
|
||||
- `preds_3d`
|
||||
- `preds_diff`
|
||||
- `preds_3d_fake`
|
||||
|
||||
### 11.2 去掉 fake 3D 分支
|
||||
|
||||
```bash
|
||||
python tools/model_merging/merge_models_of_2roi_yolo26.py \
|
||||
--roi0-model-path runs/detect/mono3d_roi0_20260506_epoch99.pt \
|
||||
--roi1-model-path runs/detect/mono3d_roi1_20260506_epoch99.pt \
|
||||
--save-dir runs/export/train_mono3d_two_roi_20260506-drop_fake_3d_branch \
|
||||
--imgsz 768 352 \
|
||||
--edge-head-mode drop \
|
||||
--fake-3d-branch-mode drop
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
- `boxes`
|
||||
- `scores`
|
||||
- `preds_3d`
|
||||
- `preds_diff`
|
||||
|
||||
---
|
||||
|
||||
## 12. 建议与注意事项
|
||||
|
||||
1. 如果下游要使用 fake class 的专用 3D 几何,请使用 `--fake-3d-branch-mode keep`。
|
||||
2. 如果只想保持旧版解析复杂度,可使用 `--fake-3d-branch-mode drop`。
|
||||
3. 如果外部部署程序不是本仓库当前的 `run_two_roi_exported_onnx_infer.py`,请务必按 manifest 的 `output_names` 解析。
|
||||
4. `preds_diff` 当前默认未用于主要可视化与合并策略,但导出时建议保留,便于后续直接扩展。
|
||||
5. `keep fake_3d` 与 `drop fake_3d` 的输出总数不同,不能混用固定 index 的后处理脚本。
|
||||
272
tools/model_inference/docs/two_roi_range_oscillation_solution.md
Executable file
272
tools/model_inference/docs/two_roi_range_oscillation_solution.md
Executable file
@@ -0,0 +1,272 @@
|
||||
# 单目3D测距周期性波动问题分析与解决方案
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
本文档聚焦当前双 ROI 单目 3D 检测部署方案中出现的“目标测距周期性波动”问题,结合现有实现分析可能成因,并给出可落地的改进方案与推荐推进顺序。
|
||||
|
||||
本文档不替代 `tools/model_inference/docs/two_roi_model_design.md`。凡涉及当前部署链路的事实性描述,仍以现有推理脚本及其依赖模块为准。
|
||||
|
||||
---
|
||||
|
||||
## 2. 问题描述
|
||||
|
||||
当前模型在部分场景下会出现如下现象:
|
||||
|
||||
- 同一目标在连续帧中的测距结果呈现周期性起伏
|
||||
- 目标实际距离变化不大,但 `z3d` 或 `center_3d.z` 存在明显波动
|
||||
- 波动往往与车辆颠簸、路面不平、减速带、桥头跳车等场景同步出现
|
||||
|
||||
初步分析表明,该问题很可能与自车俯仰姿态变化有关。当自车颠簸时,目标在图像中的垂直位置会发生上下起伏,而当前单帧单目 3D 模型会将这类图像变化部分解释为距离变化。
|
||||
|
||||
---
|
||||
|
||||
## 3. 与当前实现的关系
|
||||
|
||||
### 3.1 当前实现中的关键链路
|
||||
|
||||
结合现有设计与代码实现,测距波动问题存在以下可能传播链路:
|
||||
|
||||
1. 当前灭点计算依赖静态标定中的 `pitch`
|
||||
|
||||
```text
|
||||
vp_y = cv - focal_v * tan(pitch)
|
||||
```
|
||||
|
||||
2. 当前 `camera4.json` 在 case 开始时加载一次,后续帧默认复用同一份标定,不会按帧更新 `pitch / roll`。
|
||||
|
||||
3. 当前 ROI 裁剪在 `y` 方向上直接依赖 `vp_y`,也就是依赖静态俯仰角计算出的灭点位置。
|
||||
|
||||
4. ROI 裁剪和 resize 后,会重新计算 `fx / fy / cx / cy`,后续 3D 回投和深度恢复仍继续使用这套 ROI 坐标系下的标定。
|
||||
|
||||
5. 当真实车身姿态随时间变化、但运行时仍使用静态姿态来解释图像时,目标的上下漂移会被系统误解释为深度变化,最终表现为 `z3d` 周期性波动。
|
||||
|
||||
### 3.2 问题本质
|
||||
|
||||
问题本质可以概括为:
|
||||
|
||||
- 当前实现默认相机姿态在时序上稳定
|
||||
- 实际车辆在颠簸场景下存在动态 `pitch / roll`
|
||||
- 单帧视觉观测中,目标垂直位移与真实深度变化发生耦合
|
||||
|
||||
因此,该问题既是“相机姿态建模不足”的问题,也是“单帧深度估计对图像上下扰动敏感”的问题。
|
||||
|
||||
---
|
||||
|
||||
## 4. 解决方案分层
|
||||
|
||||
从工程与算法角度,可以将方案分为五层:逐帧姿态补偿、时序平滑、ROI 抗扰动、训练增强、几何一致性融合。
|
||||
|
||||
### 4.1 逐帧姿态补偿
|
||||
|
||||
这是最接近根因修复的方案。
|
||||
|
||||
核心思路:
|
||||
|
||||
- 获取逐帧 `pitch / roll`
|
||||
- 按帧更新灭点位置、ROI 裁剪中心和相机姿态
|
||||
- 必要时在进入模型前先完成图像稳定,再执行 ROI 裁剪与推理
|
||||
|
||||
可选实现路径:
|
||||
|
||||
- 接入 `IMU / CAN` 的实时姿态信号
|
||||
- 无额外传感器时,基于地平线、车道线、路面结构、稳定背景点估计视觉姿态
|
||||
|
||||
建议改造点:
|
||||
|
||||
- 将静态 `camera4.json` 扩展为逐帧动态姿态输入
|
||||
- 按帧更新 `vp_y`
|
||||
- 按帧更新 ROI 的 `crop_center_y`
|
||||
- 若结果需要映射到 ego 坐标系,则同步更新相机到 ego 的姿态变换
|
||||
|
||||
优点:
|
||||
|
||||
- 直接处理误差源头
|
||||
- 同时改善 ROI 对位与 3D 回投
|
||||
|
||||
缺点:
|
||||
|
||||
- 依赖新增姿态源或新增视觉姿态估计模块
|
||||
- 集成复杂度最高
|
||||
|
||||
### 4.2 Track 级时序平滑
|
||||
|
||||
这是最适合快速落地的工程方案。
|
||||
|
||||
核心思路:
|
||||
|
||||
- 不直接使用单帧 `z3d` 作为最终结果
|
||||
- 先对目标建立 track
|
||||
- 再对同一目标的连续帧 3D 结果做时序滤波
|
||||
|
||||
推荐方式:
|
||||
|
||||
- 基于 2D/3D 关联建立 tracking
|
||||
- 对 `center_3d.z`、`center_3d.x`、`yaw` 等量做 `EMA`、`Kalman Filter` 或固定窗平滑
|
||||
- 根据类别、置信度、框尺寸、edge 几何一致性等动态调整测量噪声
|
||||
|
||||
优点:
|
||||
|
||||
- 不需要修改训练
|
||||
- 工程改造范围小
|
||||
- 对周期性抖动通常能快速见效
|
||||
|
||||
缺点:
|
||||
|
||||
- 只能抑制表现,不能消除根因
|
||||
- 会引入一定延迟
|
||||
|
||||
### 4.3 降低 ROI 对上下抖动的敏感性
|
||||
|
||||
当前 ROI 在 `y` 方向上缺少独立的稳定策略,因此可以先做轻量改造。
|
||||
|
||||
可选方案:
|
||||
|
||||
- 引入独立的 `crop_center_y_mode`
|
||||
- 支持 `fixed_cy`
|
||||
- 支持 `smoothed_vpy`
|
||||
- 支持 `blend(cv, vp_y)` 形式的加权中心
|
||||
- 对 `crop_center_y` 做低通滤波或逐帧最大步长限制
|
||||
- 适当增大 ROI 高度,降低轻微颠簸引入的相对位置扰动
|
||||
|
||||
优点:
|
||||
|
||||
- 代码改动较小
|
||||
- 便于快速验证问题是否主要由 ROI 跟随静态灭点触发
|
||||
|
||||
缺点:
|
||||
|
||||
- 只能缓解,不能完整表达真实动态姿态
|
||||
|
||||
### 4.4 训练侧抗颠簸增强
|
||||
|
||||
若该问题在量产场景中普遍存在,建议在训练侧显式纳入姿态扰动域。
|
||||
|
||||
建议方向:
|
||||
|
||||
- 增加 `pitch / roll` 扰动增强
|
||||
- 增加垂直平移、轻微透视变化、动态模糊等增强
|
||||
- 对连续帧加入时序一致性约束
|
||||
- 条件允许时,将姿态信息、地平线位置或多帧特征作为额外输入
|
||||
|
||||
进一步方案:
|
||||
|
||||
- 训练轻量多帧模型
|
||||
- 引入显式姿态辅助分支
|
||||
- 增加地平线或路面几何中间量预测
|
||||
|
||||
优点:
|
||||
|
||||
- 可以从模型层面提升鲁棒性
|
||||
|
||||
缺点:
|
||||
|
||||
- 需要重新训练和完整回归验证
|
||||
|
||||
### 4.5 几何一致性融合
|
||||
|
||||
对于车辆类目标,可将网络输出与几何约束融合,以降低单一回归分支对上下抖动的敏感性。
|
||||
|
||||
可利用信息包括:
|
||||
|
||||
- ground plane 或接地点约束
|
||||
- 目标底边缘与 edge 分支几何
|
||||
- 类别尺寸先验
|
||||
- 连续帧运动学先验
|
||||
|
||||
可选策略:
|
||||
|
||||
- 当 `z3d` 与 edge / ground 几何明显冲突时,对该帧深度降权
|
||||
- 将网络回归深度与几何估计深度做加权融合
|
||||
- 将异常跳变作为诊断信号输出
|
||||
|
||||
优点:
|
||||
|
||||
- 提高异常帧下的可解释性
|
||||
- 有助于构建更稳健的诊断链路
|
||||
|
||||
缺点:
|
||||
|
||||
- 依赖额外几何假设,适用范围需要单独验证
|
||||
|
||||
---
|
||||
|
||||
## 5. 推荐推进顺序
|
||||
|
||||
若目标是“先快速抑制线上波动,再逐步修复根因”,建议按以下顺序推进:
|
||||
|
||||
1. 先增加 `track` 级时序平滑,快速压制测距抖动
|
||||
2. 同时引入 ROI `y` 向稳定策略,验证 ROI 机制的敏感性
|
||||
3. 若验证表明问题与车身俯仰强相关,再接入逐帧 `pitch / roll` 补偿
|
||||
4. 在训练侧加入抗颠簸增强,降低模型对垂直扰动的敏感性
|
||||
5. 视业务需要补充 edge / ground / 运动学等几何一致性融合
|
||||
|
||||
该顺序兼顾了:
|
||||
|
||||
- 短期可落地性
|
||||
- 中期定位能力
|
||||
- 长期根因修复效果
|
||||
|
||||
---
|
||||
|
||||
## 6. 推荐实施策略
|
||||
|
||||
从工程收益比看,建议优先采用“两阶段策略”。
|
||||
|
||||
### 6.1 第一阶段:快速止血
|
||||
|
||||
目标:
|
||||
|
||||
- 尽快降低线上测距周期波动
|
||||
- 快速判断问题是否主要与姿态扰动相关
|
||||
|
||||
建议动作:
|
||||
|
||||
- 增加 track 级滤波
|
||||
- 为 ROI 增加 `y` 向平滑或固定策略
|
||||
- 输出更多诊断字段,例如平滑前后深度、ROI 中心变化量、疑似姿态扰动标记
|
||||
|
||||
### 6.2 第二阶段:根因修复
|
||||
|
||||
目标:
|
||||
|
||||
- 将静态姿态假设升级为动态姿态建模
|
||||
|
||||
建议动作:
|
||||
|
||||
- 接入逐帧姿态输入
|
||||
- 按帧更新灭点、裁剪、回投与 ego 变换
|
||||
- 联合训练增强与几何融合进一步提升鲁棒性
|
||||
|
||||
---
|
||||
|
||||
## 7. 验证建议
|
||||
|
||||
为了判断方案是否有效,建议重点关注以下指标:
|
||||
|
||||
- 同一目标连续帧 `center_3d.z` 的标准差
|
||||
- 目标静稳跟车场景下的深度峰峰值
|
||||
- 颠簸场景中深度频谱的主频能量
|
||||
- 引入平滑后的延迟和响应速度
|
||||
- ego 坐标系下 `xyzlhwyaw` 的稳定性
|
||||
|
||||
建议单独构建以下评测子集:
|
||||
|
||||
- 路面平稳场景
|
||||
- 明显颠簸场景
|
||||
- 远距离车辆场景
|
||||
- 近距离跟车场景
|
||||
- 高速桥头或减速带场景
|
||||
|
||||
---
|
||||
|
||||
## 8. 结论
|
||||
|
||||
当前测距周期性波动问题,很大概率与“真实动态俯仰变化”和“运行时静态姿态假设”之间的不一致有关。
|
||||
|
||||
从方案优先级上看:
|
||||
|
||||
- 短期最有效的是 `track` 级时序平滑与 ROI `y` 向稳定
|
||||
- 中长期最关键的是逐帧姿态补偿
|
||||
- 若要进一步提升模型鲁棒性,应结合训练增强与几何一致性融合
|
||||
|
||||
其中,逐帧姿态补偿是最接近根因修复的方案;其余方案更适合作为快速缓解、问题定位和整体稳健性增强手段。
|
||||
3
tools/model_inference/examples/clip_lists/clips_6284.txt
Executable file
3
tools/model_inference/examples/clip_lists/clips_6284.txt
Executable file
@@ -0,0 +1,3 @@
|
||||
019cb7f4-a944-7c22-5427-5b75b25545c7
|
||||
019cb801-e7af-79f1-5756-78ada964e108
|
||||
019cb831-743a-7e7d-478e-b587b7b11f53
|
||||
14
tools/model_inference/examples/clip_lists/clips_aeb.txt
Executable file
14
tools/model_inference/examples/clip_lists/clips_aeb.txt
Executable file
@@ -0,0 +1,14 @@
|
||||
019d2d81-94d4-7ab9-4d65-e90fd652c2c1
|
||||
019d2d86-4a7b-72da-6e09-1e7ab3494d0b
|
||||
019d3285-23db-70e6-514a-74bd4625dccd
|
||||
019d3dd9-a63f-78ce-5b22-266a7341f02c
|
||||
019d2d80-5ea0-7421-4993-4609caa731c7
|
||||
019d2d81-3aff-7084-7647-f535e3cf831c
|
||||
019d2d84-5d15-7481-530d-181d75f140ca
|
||||
019d7126-ada5-7ac0-7bb4-9c43c96dbd18
|
||||
019d7127-b405-7b1a-632a-d71011c12232
|
||||
019d7129-30a7-742e-6bab-6ed6fbc860f0
|
||||
019d7121-321f-7c62-4c7f-0115796fdd98
|
||||
019d3289-e2fb-789e-7f54-e65b10a77f87 CPLA
|
||||
019d3289-8e19-71f0-6d2e-56570badbaa6 CPLA
|
||||
019d328b-bdf7-74fa-6e5c-0da5ff8dab71 CPLA
|
||||
45
tools/model_inference/examples/clip_lists/group_list.txt
Executable file
45
tools/model_inference/examples/clip_lists/group_list.txt
Executable file
@@ -0,0 +1,45 @@
|
||||
019b178d-54a2-78b7-a2d2-0ec63d651a4d
|
||||
019b18ef-ca2b-7e97-8ca5-d4b1d7eefdbb
|
||||
019b29ac-d00b-7e97-96c6-de9573eb6472
|
||||
019b2a13-9af3-7e97-a109-9fb7ba7a8f22
|
||||
019b2a23-9885-7e97-adf6-81bfb1f7f707
|
||||
019b4415-d171-7ae9-88ed-0065c4c6e1e0
|
||||
019b446e-7133-7ae9-a686-034223f9376d
|
||||
019b446e-71c2-71c3-afe1-7f0a988a4261
|
||||
019b4687-0a6c-7c8d-b54e-51b3c5bdc6c2
|
||||
019b471c-84fa-7ae9-9172-add82a30ba76
|
||||
019b4731-38fb-71c3-b0a6-0e90759fc79b
|
||||
019b475a-21db-7ae9-806c-15e4cdf59567
|
||||
019b475e-c8f5-7ae9-b60d-96b5a9e36f3f
|
||||
019b4bbf-a702-7c8d-abee-ec1ec17e66e9
|
||||
019b4c4f-83c5-7aea-b364-cdaf93be8759
|
||||
019b4e2c-f464-7aea-af9f-e61135bb3eed
|
||||
019b661c-eb04-7029-af8c-515fd4d10a05
|
||||
019b662e-49a4-781f-85f5-c2cc76921b63
|
||||
019b6659-e97b-7029-a77a-6df3c01005bf
|
||||
019b6659-ea8d-7029-9614-f067b92a50cf
|
||||
019b674f-ebde-781f-92e8-2fd9efaf4115
|
||||
019b6aa1-a8ed-7029-8b8c-68311394dade
|
||||
019b6aa1-b243-7767-b03e-30423635fae3
|
||||
019b6aa1-b3a5-7820-8fb8-703b5324aa37
|
||||
019b6ba0-6fca-7029-9f49-010991c25574
|
||||
019b6bf2-0124-7820-91b7-c5eb42150cd2
|
||||
019b6bf2-01a6-7029-9232-fce2bbcd2d73
|
||||
019b6c1a-07f7-7029-8dad-b327a960c8ab
|
||||
019b6d98-2e01-7f56-a142-7d10b54b901e
|
||||
019b6f9d-bd6e-7765-b32c-ec6c75945898
|
||||
019b6fa2-e7d8-7765-a96d-d8b341fa1d92
|
||||
019b70f6-7bcc-7765-a5fb-f6338d5d9494
|
||||
019b70f6-7c68-7765-9fbf-fa174798c144
|
||||
019b71ae-35d8-7a2c-816f-fc6cca709e79
|
||||
019b731a-0b43-7a2c-a6de-629a7f8cb7bb
|
||||
019b7850-bfaf-70f1-bdf0-3fa1ba836dee
|
||||
019b7857-33d4-74bc-b492-de067f8e1899
|
||||
019b8ddb-ae8a-70f3-b86f-055894c79724
|
||||
019ba16f-fba6-762c-a961-007f0ce78e19
|
||||
019ba16f-fece-718b-a51d-1bcd2414b52e
|
||||
019ba185-7b16-7866-98a5-c3d5c1b136c0
|
||||
019ba1d6-5faa-762c-9de7-597f2d19d55e
|
||||
019ba1d8-b791-7866-866f-f556fa7405fd
|
||||
019ba1d8-b998-762c-a2b9-92580ee6b16d
|
||||
019ba1d8-c230-762c-9dae-f1b5d391dc04
|
||||
186
tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-202411.json
Executable file
186
tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-202411.json
Executable file
@@ -0,0 +1,186 @@
|
||||
{
|
||||
"input_file": "/deeplearning_team/ydong/dongying/projects/yolo26-3d/tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-2024_11月_0306.xlsx",
|
||||
"sheet_name": "G1M3_AFS1616_CNCAP-2024_11月",
|
||||
"column_name": "原始数据地址",
|
||||
"num_rows": 178,
|
||||
"values": [
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_20_5_1_20251115140740/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_20_5_2_20251115140941/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_20_5_4_20251115141340/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_40_5_1_20251115154533/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_40_5_2_20251115154730/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_AEB_40_5_3_20251115154936/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_AEB_NIGHT_20_2_20251120190340/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_AEB_NIGHT_20_3_20251120190536/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_AEB_NIGHT_20_4_20251120200100/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_AEB_NIGHT_40_1_20251120200307/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_AEB_NIGHT_40_2_20251120200500/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_AEB_NIGHT_40_3_20251120200634/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_FCW_60_5_2_20251115160419/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_FCW_60_5_3_20251115160612/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_FCW_80_5_1_20251115161433/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_FCW_80_5_2_20251115161702/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CPLA_RL_FCW_80_5_3_20251115162115/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_FCW_NIGHT_60_1_20251120201141/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_FCW_NIGHT_60_2_20251120201314/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_FCW_NIGHT_60_3_20251120201458/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_FCW_NIGHT_80_1_20251120202048/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_FCW_NIGHT_80_2_20251120202303/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_FCW_NIGHT_80_3_20251120202606/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_20_1_20251116145122/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_20_2_20251116145250/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_20_3_20251116145409/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_40_1_20251116145541/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_40_2_20251116145658/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_40_3_20251116150142/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_60_1_20251116150405/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_60_2_20251116150531/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPFAO_AEB_60_3_20251116150722/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_20_1_20251120211354/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_20_2_20251120211541/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_20_3_20251120211658/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_40_2_20251120212613/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_40_3_20251120212936/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_40_4_20251120213053/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_60_1_20251120213326/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_60_2_20251120213531/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPFAO_AEB_NIGHT_60_4_20251120214003/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_AEB_20_15_1_20251115164146/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_AEB_20_15_2_20251115164517/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_AEB_20_15_3_20251115164652/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_AEB_40_15_1_20251115165709/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_AEB_40_15_2_20251115165908/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_AEB_40_15_3_20251115170039/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_FCW_60_15_1_20251115171927/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_FCW_60_15_2_20251115172124/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_FCW_60_15_3_20251115172426/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_FCW_80_15_1_20251115172854/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_FCW_80_15_2_20251115173342/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251115/CVE/CBLA_FCW_80_15_5_20251115174113/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_AEB_20_1_20251117112812/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_AEB_20_2_20251117112949/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_AEB_20_3_20251117113128/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_AEB_40_1_20251117113354/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_AEB_40_4_20251117114030/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_AEB_40_5_20251117114211/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_FCW_60_1_20251117114410/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_FCW_60_2_20251117114541/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251117/CVE/CCRS_FCW_60_3_20251117114726/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_FCW_80_1_20251118165115/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_FCW_80_2_20251118165417/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_FCW_80_3_20251118165714/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_AEB_30_1_20251118171813/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_AEB_30_2_20251118171927/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_AEB_30_3_20251118172047/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_FCW_50_1_20251118172359/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_FCW_50_2_20251118172529/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_FCW_50_3_20251118172648/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_FCW_70_1_20251118173427/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_FCW_70_2_20251118173727/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CCRS_RR_FCW_70_5_20251118174256/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_20_1_20251116115843/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_20_3_20251116120432/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_40_2_20251116162411/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_40_3_20251116162528/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_40_4_20251116162828/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_60_1_20251116163110/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_60_2_20251116163314/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CBNAO_AEB_60_3_20251116163456/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_20_1_20251116094544/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_20_2_20251116094807/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_20_3_20251116095003/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_40_1_20251116111946/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_40_2_20251116112240/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_40_3_20251116112403/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_60_5_20251116113407/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_60_6_20251116113532/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPNCO_AEB_60_7_20251116113702/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_AEB_30_1_20251120125750/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_AEB_30_2_20251120131043/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_AEB_30_3_20251120131354/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_AEB_40_1_20251120133202/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_AEB_40_2_20251120135059/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_AEB_40_3_20251120135316/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_50_1_20251120140205/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_50_2_20251120141420/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_50_3_20251120141611/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_50_4_20251120141754/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_50_5_20251120143758/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_50_6_20251120143949/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_60_1_20251121132303/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_60_2_20251121132531/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/C2CSCP_FCW_60_3_20251120145205/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCRH_FCW_120_1_20251121142329/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCRH_FCW_120_2_20251121142615/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCRH_FCW_120_3_20251121142858/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCRH_FCW_80_1_20251121134351/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCRH_FCW_80_2_20251121134820/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCRH_FCW_80_3_20251121135124/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LF_AEB_10_1_20251116165509/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LF_AEB_10_2_20251116165624/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LF_AEB_10_3_20251116165726/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LF_AEB_20_1_20251116170243/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LF_AEB_20_2_20251116170440/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LF_AEB_20_3_20251116170553/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LF_AEB_20_4_20251116170703/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LN_AEB_10_1_20251116153118/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LN_AEB_10_2_20251116153233/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LN_AEB_10_3_20251116153353/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LN_AEB_20_1_20251116154321/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LN_AEB_20_2_20251116154424/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251116/CVE/CPTA_LN_AEB_20_3_20251116154522/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTA-RF_AEB_10_2_20251118152341/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTA-RF_AEB_10_3_20251118152502/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTA-RF_AEB_10_4_20251118152627/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTA-RF_AEB_20_1_20251118153924/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTA-RF_AEB_20_2_20251118154118/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTA-RF_AEB_20_3_20251118154310/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LF_AEB_30_1_20251118162051/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LF_AEB_30_2_20251118162258/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LF_AEB_30_3_20251118162502/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LF_AEB_30_4_20251118162753/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LN_AEB_30_1_20251118155909/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LN_AEB_30_2_20251118160410/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LN_AEB_30_3_20251118160701/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LN_AEB_30_4_20251118160910/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_20_1_20251118100252/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_20_2_20251118100507/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_20_3_20251118100811/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_20_4_20251118100943/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_40_1_20251118101132/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_40_2_20251118101308/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_40_3_20251118101449/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_40_4_20251118102012/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_60_1_20251118102439/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_60_2_20251118102648/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSFAO_AEB_60_3_20251118102842/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_10_1_20251118135544/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_10_2_20251118140105/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_10_3_20251118141436/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_10_4_20251118141606/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_10_5_20251118141805/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_20_1_20251118142701/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_20_2_20251118142901/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA-RN_AEB_20_3_20251118143114/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_10_1_20251118125212/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_10_2_20251118125425/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_10_3_20251118125731/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_20_1_20251118130844/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_20_2_20251118131325/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_20_3_20251118131506/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_20_4_20251118131706/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_30_1_20251118132854/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_30_2_20251118133333/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CSTA_LN_AEB_30_3_20251118133500/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_10_1_20251120111329/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_10_2_20251120111531/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_10_3_20251120111715/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_20_1_20251120112848/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_20_2_20251120113358/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_20_3_20251120113552/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_20_4_20251120114255/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_30_1_20251120115726/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_30_2_20251120115936/sigmastar.1",
|
||||
"/mnt/hfs/project-G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CCFT_AEB_30_3_20251120120135/sigmastar.1"
|
||||
]
|
||||
}
|
||||
BIN
tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-2024_11月_0306.xlsx
Executable file
BIN
tools/model_inference/examples/cncap/G1M3_AFS1616_CNCAP-2024_11月_0306.xlsx
Executable file
Binary file not shown.
7165
tools/model_inference/examples/cncap/aeb_clips-20260422.json
Executable file
7165
tools/model_inference/examples/cncap/aeb_clips-20260422.json
Executable file
File diff suppressed because it is too large
Load Diff
7165
tools/model_inference/examples/cncap/aeb_clips-20260429.json
Executable file
7165
tools/model_inference/examples/cncap/aeb_clips-20260429.json
Executable file
File diff suppressed because it is too large
Load Diff
401
tools/model_inference/examples/events/G1Q3_场地评测数据集.csv
Executable file
401
tools/model_inference/examples/events/G1Q3_场地评测数据集.csv
Executable file
@@ -0,0 +1,401 @@
|
||||
datetime,rawid,scene,offset,gvt_speed,vut_speed,event_uuid
|
||||
20260322175850,ADAS_S751NX0Y800506T_20260402120500514190_df44c7e0f558,CPNA,75,5.0,30,019dba8a-6dba-7ea7-6158-864c5ca840b5
|
||||
20260322175649,ADAS_S751NX0Y800506T_20260402120500514190_41bdeb4dc9c9,CPNA,75,5.0,30,019dba8a-71d2-7c37-57c9-fee30c51daac
|
||||
20260322175205,ADAS_S751NX0Y800506T_20260402120500514190_7a0cbe1afafb,CPNA,75,5.0,30,019dba8a-7550-7db2-7ed3-f5ff17d3dbb3
|
||||
20260322174325,ADAS_S751NX0Y800506T_20260402120500514190_5827b3b5ec93,CPNA,75,5.0,20,019dba8a-78d3-7e4e-43e2-b7d0566ecb42
|
||||
20260322174119,ADAS_S751NX0Y800506T_20260402120500514190_17aba2ec3a91,CPNA,75,5.0,20,019dba8a-7cae-78df-6969-b210ce359472
|
||||
20260322173859,ADAS_S751NX0Y800506T_20260402120500514190_d05ce02d8128,CPNA,75,5.0,20,019dba8a-80ea-73d0-72cf-d3e25d54aa43
|
||||
20260322173530,ADAS_S751NX0Y800506T_20260402120500514190_4d885636e544,CPNA,25,5.0,40,019dba8a-84b3-7685-4ee6-1a776977717b
|
||||
20260322173110,ADAS_S751NX0Y800506T_20260402120500514190_3121fd72c10e,CPNA,25,5.0,40,019dba8a-8899-75c9-41d2-637c2d1013d4
|
||||
20260322172726,ADAS_S751NX0Y800506T_20260402120500514190_160bff7a0258,CPNA,25,5.0,40,019dba8a-8c0e-7024-6dce-aab8c15b5a8c
|
||||
20260322163631,ADAS_S751NX0Y800506T_20260402120500514190_f38d79224c9b,CPNA,25,5.0,30,019dba8a-8fc2-7d9e-66f9-9066d8c47e71
|
||||
20260322163412,ADAS_S751NX0Y800506T_20260402120500514190_188bbc4fd7cd,CPNA,25,5.0,30,019dba8a-94be-7449-4666-31c9070bae44
|
||||
20260322162901,ADAS_S751NX0Y800506T_20260402120500514190_9ec9c9547f85,CPNA,25,5.0,30,019dba8a-983d-7c1a-6e21-ae950e359c19
|
||||
20260322162319,ADAS_S751NX0Y800506T_20260402120500514190_1ae2913db09c,CPNA,25,5.0,20,019dba8a-9b90-7e99-7cce-bfabafff8ab9
|
||||
20260322161344,ADAS_S751NX0Y800506T_20260402120500514190_e9e3c9e67eac,CPNA,25,5.0,20,019dba8a-9f8f-78ba-56f9-9aaccfc0a68b
|
||||
20260322160034,ADAS_S751NX0Y800506T_20260402120500514190_e774fbfe04b5,CPNA,25,5.0,20,019dba8a-a2fd-7cd8-507b-748aecd99ee6
|
||||
20260322154206,ADAS_S751NX0Y800506T_20260402120500514190_2cae2b77af35,CPFA,50,6.5,30,019dba8a-a68f-72a6-62e6-1f870ef06880
|
||||
20260322154017,ADAS_S751NX0Y800506T_20260402120500514190_18742842430a,CPFA,50,6.5,30,019dba8a-aa11-7937-7299-50e612807225
|
||||
20260322153820,ADAS_S751NX0Y800506T_20260402120500514190_88239721e460,CPFA,50,6.5,30,019dba8a-adb4-7008-5783-6777b442c00d
|
||||
20260322153301,ADAS_S751NX0Y800506T_20260402120500514190_e843fb7f3356,CPFA,50,6.5,20,019dba8a-b4fd-7bcc-5eea-3ebd69418d2f
|
||||
20260322152819,ADAS_S751NX0Y800506T_20260402120500514190_56ffe9a635e2,CPFA,50,6.5,20,019dba8a-b873-76a5-53f9-b587a63998f5
|
||||
20260322152509,ADAS_S751NX0Y800506T_20260402120500514190_55e385cadd8f,CPFA,50,6.5,20,019dba8a-bcaa-7a83-65a1-b4e2be991e90
|
||||
20260323151226,ADAS_S751NX0Y800506T_20260402120500514190_9bfcc283ca9f,CPFA,25,6.5,60,019dba8b-9d64-76b1-7952-46899675e6b7
|
||||
20260323150956,ADAS_S751NX0Y800506T_20260402120500514190_3f67a521af37,CPFA,25,6.5,60,019dba8b-a4d0-7f78-4e07-171b4b6fd04f
|
||||
20260323150051,ADAS_S751NX0Y800506T_20260402120500514190_832aca065af3,CPFA,25,6.5,60,019dba8b-a980-7e97-6891-d9404946ad3a
|
||||
20260323142614,ADAS_S751NX0Y800506T_20260402120500514190_b840a33bb533,CPFA,25,6.5,50,019dba8b-ae8d-7ddb-5b73-ea9d44b373b4
|
||||
20260323142435,ADAS_S751NX0Y800506T_20260402120500514190_0cd79bd65838,CPFA,25,6.5,50,019dba8b-b507-7f98-7702-b7db890c40fe
|
||||
20260323142206,ADAS_S751NX0Y800506T_20260402120500514190_8509ac645d11,CPFA,25,6.5,50,019dba8b-ba4e-7c3e-655e-0ce237eebf1c
|
||||
20260323141946,ADAS_S751NX0Y800506T_20260402120500514190_257c4d40a320,CPFA,25,6.5,40,019dba8b-bd96-7937-6b97-d81bf764b42f
|
||||
20260323140816,ADAS_S751NX0Y800506T_20260402120500514190_5852cf241628,CPFA,25,6.5,40,019dba8b-c31a-7327-6f84-61b66598e4de
|
||||
20260323140108,ADAS_S751NX0Y800506T_20260402120500514190_084f8d8a14ff,CPFA,25,6.5,40,019dba8b-c81f-7e39-6bf6-b163da68789b
|
||||
20260323114938,ADAS_S751NX0Y800506T_20260402120500514190_a004524019b0,CPFA,25,6.5,30,019dba8b-cef9-7fc3-5d3a-e566162fb14d
|
||||
20260323114629,ADAS_S751NX0Y800506T_20260402120500514190_ab11efa628ee,CPFA,25,6.5,30,019dba8b-d39b-7461-6911-f8fa3c698828
|
||||
20260323113832,ADAS_S751NX0Y800506T_20260402120500514190_36dade09baea,CPFA,25,6.5,20,019dba8b-d733-7158-7322-b3a79ad240b5
|
||||
20260323113612,ADAS_S751NX0Y800506T_20260402120500514190_68e77ef5aa44,CPFA,25,6.5,20,019dba8b-dc52-725a-6164-f54217be3322
|
||||
20260323113249,ADAS_S751NX0Y800506T_20260402120500514190_91fe5e43236d,CPFA,50,6.5,60,019dba8b-e0ec-7898-41fe-2e7c99bfa4c5
|
||||
20260323113007,ADAS_S751NX0Y800506T_20260402120500514190_4c9b9263a276,CPFA,50,6.5,60,019dba8b-e560-71f5-47d1-9a47f71d2486
|
||||
20260323112758,ADAS_S751NX0Y800506T_20260402120500514190_119e9e58e546,CPFA,50,6.5,60,019dba8b-e928-7b8b-45d9-bd5a3aa357d0
|
||||
20260323112515,ADAS_S751NX0Y800506T_20260402120500514190_f6dcf99a5ca1,CPFA,50,6.5,50,019dba8b-ece3-737b-4212-613b8128cd83
|
||||
20260323112255,ADAS_S751NX0Y800506T_20260402120500514190_7d7a31a63e86,CPFA,50,6.5,50,019dba8b-f27e-7117-5f7c-1486db8bf775
|
||||
20260323112055,ADAS_S751NX0Y800506T_20260402120500514190_532d066d050d,CPFA,50,6.5,50,019dba8b-f6eb-7b46-450e-a2c071792e36
|
||||
20260323111755,ADAS_S751NX0Y800506T_20260402120500514190_79b8ac183c24,CPFA,50,6.5,40,019dba8b-fa4f-7ce8-4bff-9e568881e959
|
||||
20260323111522,ADAS_S751NX0Y800506T_20260402120500514190_b93edaab8c70,CPFA,50,6.5,40,019dba8b-fe00-75ac-746e-1462d5eba7c5
|
||||
20260323111334,ADAS_S751NX0Y800506T_20260402120500514190_af02999872b1,CPFA,50,6.5,40,019dba8c-0165-7dda-56fe-5447b413082e
|
||||
20260324174238,ADAS_S751NX0Y800506T_20260402120500514190_e113d246ac8a,CPNA,75,5.0,60,019dba8c-3c06-7577-515d-1b415add0b64
|
||||
20260324173924,ADAS_S751NX0Y800506T_20260402120500514190_747514674cb5,CPNA,75,5.0,60,019dba8c-4003-71d1-4be4-60e61f8ee1d6
|
||||
20260324173139,ADAS_S751NX0Y800506T_20260402120500514190_ba8b47506266,CPNA,75,5.0,60,019dba8c-441c-7a49-4b3e-c7b3cc2f455a
|
||||
20260324172833,ADAS_S751NX0Y800506T_20260402120500514190_20ff1981dcd9,CPNA,75,5.0,50,019dba8c-4a81-79ea-530a-6d8e24f8fa55
|
||||
20260324172558,ADAS_S751NX0Y800506T_20260402120500514190_fc2ec8859218,CPNA,75,5.0,50,019dba8c-8a61-70ac-48b6-aad76a1df1bc
|
||||
20260324172350,ADAS_S751NX0Y800506T_20260402120500514190_6d1f2fdaffe1,CPNA,75,5.0,50,019dba8c-9193-7803-50c3-051a99f1a74f
|
||||
20260324172117,ADAS_S751NX0Y800506T_20260402120500514190_14bcdf9bf591,CPNA,75,5.0,40,019dba8c-9744-7a3f-72a5-7a3769d61b3a
|
||||
20260324171844,ADAS_S751NX0Y800506T_20260402120500514190_fc3b19e58c4b,CPNA,75,5.0,40,019dba8c-9ccc-7acb-4242-cb82cba15ffc
|
||||
20260324165218,ADAS_S751NX0Y800506T_20260402120500514190_2c6193e79a1b,CPNA,25,5.0,60,019dba8c-a624-7342-681f-72a187ecd3e1
|
||||
20260324164151,ADAS_S751NX0Y800506T_20260402120500514190_765b60cf1fe3,CPNA,25,5.0,60,019dba8c-a971-747a-6253-d7b5cbdeca3f
|
||||
20260324161933,ADAS_S751NX0Y800506T_20260402120500514190_25c2f29a8f42,CPNA,25,5.0,50,019dba8c-adc3-7e77-6900-8ee40e9167de
|
||||
20260325181249,ADAS_S751NX0Y800506T_20260402120500514190_a6bb10ce6479,CPLA,25,5.0,30,019dba8c-df89-7a07-4c90-6c1384a83f89
|
||||
20260325180857,ADAS_S751NX0Y800506T_20260402120500514190_6033ca518600,CPLA,25,5.0,30,019dba8c-e80f-7a40-7545-8778073cd4a9
|
||||
20260325180602,ADAS_S751NX0Y800506T_20260402120500514190_04ab6361c6f8,CPLA,25,5.0,30,019dba8c-efc0-729a-4ed1-bfc4765a8b8a
|
||||
20260325180337,ADAS_S751NX0Y800506T_20260402120500514190_e463db00873c,CPLA,25,5.0,20,019dba8c-fac6-78fe-66f5-8c188d47193d
|
||||
20260325180145,ADAS_S751NX0Y800506T_20260402120500514190_c2c07583877e,CPLA,25,5.0,20,019dba8c-ff1a-78b1-45c0-c3cb9b7fe17b
|
||||
20260325175106,ADAS_S751NX0Y800506T_20260402120500514190_30ce60e0d63d,CPLA,25,5.0,20,019dba8d-03ff-7dbb-7726-6072569fdbdb
|
||||
20260325172254,ADAS_S751NX0Y800506T_20260402120500514190_072cb4411b63,CSFA,50,20.0,60,019dba8d-0c92-72be-5401-d3b6c808e155
|
||||
20260325171905,ADAS_S751NX0Y800506T_20260402120500514190_dfbc1dbd393c,CSFA,50,20.0,60,019dba8d-1377-7a61-6259-ee58519c1f2c
|
||||
20260325170448,ADAS_S751NX0Y800506T_20260402120500514190_f83a9601f577,CSFA,50,20.0,60,019dba8d-1900-7e31-7e13-939985c88c24
|
||||
20260325170106,ADAS_S751NX0Y800506T_20260402120500514190_2c54e25cb32f,CSFA,50,20.0,50,019dba8d-1cc8-72b5-4762-d7ce61ca9a8f
|
||||
20260325165620,ADAS_S751NX0Y800506T_20260402120500514190_7389767ab909,CSFA,50,20.0,50,019dba8d-2045-72c5-603a-af19182d9279
|
||||
20260325165344,ADAS_S751NX0Y800506T_20260402120500514190_e95155ae8f08,CSFA,50,20.0,50,019dba8d-27ad-72af-7a44-61659faf5fd2
|
||||
20260325165101,ADAS_S751NX0Y800506T_20260402120500514190_1fe6d0c95742,CSFA,50,20.0,40,019dba8d-3aa4-7535-74b5-40c2664d916c
|
||||
20260325164557,ADAS_S751NX0Y800506T_20260402120500514190_5779b22a5c73,CSFA,50,20.0,40,019dba8d-4432-72b9-65bf-a7469b53e92a
|
||||
20260325164019,ADAS_S751NX0Y800506T_20260402120500514190_b224bea0ddbb,CSFA,50,20.0,40,019dba8d-49da-791e-6a8d-888d048776f6
|
||||
20260325163640,ADAS_S751NX0Y800506T_20260402120500514190_d6f39345461f,CSFA,50,20.0,30,019dba8d-4e2d-766f-41ef-a9d706dd6b14
|
||||
20260325163344,ADAS_S751NX0Y800506T_20260402120500514190_12f793d51613,CSFA,50,20.0,30,019dba8d-5244-7c4b-5154-8f67232a9fcf
|
||||
20260325160450,ADAS_S751NX0Y800506T_20260402120500514190_e2efe25a6880,CSFA,50,20.0,30,019dba8d-57ff-7056-6808-a60b07d1a70d
|
||||
20260325153627,ADAS_S751NX0Y800506T_20260402120500514190_a2ca26a51193,CBNA,50,15.0,60,019dba8d-5f80-702b-57d2-52dcd6e8f914
|
||||
20260325153201,ADAS_S751NX0Y800506T_20260402120500514190_bf145238287f,CBNA,50,15.0,60,019dba8d-6933-7d3e-7039-92af7f4913aa
|
||||
20260325151329,ADAS_S751NX0Y800506T_20260402120500514190_0b861057a7d9,CBNA,50,15.0,50,019dba8d-6e1b-735a-70ad-b297ffc7c1c8
|
||||
20260325150516,ADAS_S751NX0Y800506T_20260402120500514190_26d04cf53d23,CBNA,50,15.0,50,019dba8d-7231-77a8-5c8f-c9953ee04d96
|
||||
20260325150059,ADAS_S751NX0Y800506T_20260402120500514190_1aa11c5aeba7,CBNA,50,15.0,50,019dba8d-7a28-7d05-7761-8f8c6f7d40a2
|
||||
20260325145759,ADAS_S751NX0Y800506T_20260402120500514190_38491776ee5a,CBNA,50,15.0,40,019dba8d-7ec0-71b4-4e23-8212e624c34e
|
||||
20260325145539,ADAS_S751NX0Y800506T_20260402120500514190_a05517753a60,CBNA,50,15.0,40,019dba8d-82b2-7fc4-7b6d-63cbb1ce20e6
|
||||
20260325145316,ADAS_S751NX0Y800506T_20260402120500514190_a5d59f3e0de2,CBNA,50,15.0,40,019dba8d-8775-7f47-5f49-4b816ccfa55f
|
||||
20260325144443,ADAS_S751NX0Y800506T_20260402120500514190_8991319529c4,CBNA,50,15.0,30,019dba8d-8d91-76bd-5bac-05a1c88be6e1
|
||||
20260325144228,ADAS_S751NX0Y800506T_20260402120500514190_154ac0410795,CBNA,50,15.0,30,019dba8d-9280-78e1-4f43-21e7f891ef13
|
||||
20260325142826,ADAS_S751NX0Y800506T_20260402120500514190_25b1c474d0bb,CBNA,50,15.0,30,019dba8d-9876-75ca-6228-3852a33be169
|
||||
20260325142109,ADAS_S751NX0Y800506T_20260402120500514190_83ab0ea00dc7,CBNA,50,15.0,20,019dba8d-9f36-7a3c-5528-a3e87a3ff57a
|
||||
20260325141355,ADAS_S751NX0Y800506T_20260402120500514190_369491fcade7,CBNA,50,15.0,20,019dba8d-a510-7f61-6e11-41b6a1365217
|
||||
20260325140126,ADAS_S751NX0Y800506T_20260402120500514190_57283841b369,CBNA,50,15.0,20,019dba8d-ab06-74df-7b01-7fe7576c7888
|
||||
20260326181430,ADAS_S751NX0Y601865J_20260328113450259688_1e9541a7d2c7,CPLA,50,5.0,50,019dba8d-bf15-777f-4952-c6680aca4c1e
|
||||
20260326180301,ADAS_S751NX0Y601865J_20260328113450259688_713766bcf1f2,CPLA,50,5.0,50,019dba8d-c3ff-7f5b-7ced-a19828dbdd94
|
||||
20260326175733,ADAS_S751NX0Y601865J_20260328113450259688_43fbd00148aa,CPLA,50,5.0,50,019dba8d-c87a-70bc-480f-e37a9c2c6a0c
|
||||
20260326174803,ADAS_S751NX0Y601865J_20260328113450259688_1ced9e7a5ff4,CBLA-CN21,50,15.0,60,019dba8d-cd58-783e-5ef9-fd9c655a8ada
|
||||
20260326174513,ADAS_S751NX0Y601865J_20260328113450259688_183e46d60337,CBLA-CN21,50,15.0,60,019dba8d-d21e-7ef7-5e82-6e0df2672823
|
||||
20260326173610,ADAS_S751NX0Y601865J_20260328113450259688_559e79696f59,CBLA-CN21,50,15.0,60,019dba8d-d707-7b92-796c-e9efb20c179d
|
||||
20260326171109,ADAS_S751NX0Y601865J_20260328113450259688_490ba9b95ba9,CBLA-CN21,50,15.0,50,019dba8d-dc89-7f13-493e-ca1d492ad142
|
||||
20260326170202,ADAS_S751NX0Y601865J_20260328113450259688_347a11543c73,CBLA-CN21,50,15.0,50,019dba8d-e0ff-731d-6ee9-b6d77b1a89f4
|
||||
20260326164438,ADAS_S751NX0Y601865J_20260328113450259688_5241e2ff36e4,CBLA-CN21,50,15.0,50,019dba8d-e717-74bc-7616-4cd4feb90dea
|
||||
20260326164202,ADAS_S751NX0Y601865J_20260328113450259688_10e68e264ee3,CBLA-CN21,50,15.0,40,019dba8d-ec33-75e6-784b-6b652685bd1a
|
||||
20260326162358,ADAS_S751NX0Y601865J_20260328113450259688_2b77ce9a349e,CBLA-CN21,50,15.0,40,019dba8d-f191-7302-7488-9f1fda4f8bba
|
||||
20260326162136,ADAS_S751NX0Y601865J_20260328113450259688_900166524e3b,CBLA-CN21,50,15.0,40,019dba8d-f5ec-756f-7f21-3367acc845a3
|
||||
20260326161852,ADAS_S751NX0Y601865J_20260328113450259688_67fd2a079d1d,CBLA-CN21,50,15.0,30,019dba8d-fc3c-73dd-582b-1399182fd5bc
|
||||
20260326161642,ADAS_S751NX0Y601865J_20260328113450259688_fd8ae38ed3ef,CBLA-CN21,50,15.0,30,019dba8e-02d0-7c88-49fb-085e3437eada
|
||||
20260326161154,ADAS_S751NX0Y601865J_20260328113450259688_8d0bdc3af3ad,CBLA-CN21,50,15.0,30,019dba8e-08e7-7519-7dc7-f4a077a7a73d
|
||||
20260326160814,ADAS_S751NX0Y601865J_20260328113450259688_46197d491ed8,CBLA-CN21,50,15.0,20,019dba8e-1062-7f53-702d-ff7c593e020e
|
||||
20260326155847,ADAS_S751NX0Y601865J_20260328113450259688_f55db8debcca,CBLA-CN21,50,15.0,20,019dba8e-189b-72b8-612a-9504d52fab99
|
||||
20260326153031,ADAS_S751NX0Y601865J_20260328113450259688_336615afba11,CPLA,50,5.0,60,019dba8e-1ea1-709e-52ed-95d228e800d1
|
||||
20260326152808,ADAS_S751NX0Y601865J_20260328113450259688_740131f6e72c,CPLA,50,5.0,60,019dba8e-274b-75e0-7f9e-adfd1a86b923
|
||||
20260326152355,ADAS_S751NX0Y601865J_20260328113450259688_1f80da22f45a,CPLA,50,5.0,60,019dba8e-3255-7ba6-689e-0df1a6329004
|
||||
20260326144728,ADAS_S751NX0Y601865J_20260328113450259688_010690530eb1,CPLA,50,5.0,40,019dba8e-4d61-717b-5331-405c302917da
|
||||
20260326144521,ADAS_S751NX0Y601865J_20260328113450259688_88f480b20482,CPLA,50,5.0,40,019dba8e-53ad-7fc8-4112-5fec894af7d9
|
||||
20260326144301,ADAS_S751NX0Y601865J_20260328113450259688_11edf0db8552,CPLA,50,5.0,40,019dba8e-5864-761c-7e3c-6778151f6515
|
||||
20260326143953,ADAS_S751NX0Y601865J_20260328113450259688_31374e23ea52,CPLA,50,5.0,30,019dba8e-5e3e-7f71-4bf4-42d174dda454
|
||||
20260326143553,ADAS_S751NX0Y601865J_20260328113450259688_208c31032ab7,CPLA,50,5.0,30,019dba8e-653e-7350-7f96-54bf58ecd18d
|
||||
20260326143325,ADAS_S751NX0Y601865J_20260328113450259688_890e13a19330,CPLA,50,5.0,30,019dba8e-6bcb-7b38-42f0-821b34cf3881
|
||||
20260326143002,ADAS_S751NX0Y601865J_20260328113450259688_253cc2246a46,CPLA,50,5.0,20,019dba8e-7358-7062-6dc4-6d75f763f51c
|
||||
20260326141816,ADAS_S751NX0Y601865J_20260328113450259688_968bbf10d481,CPLA,50,5.0,20,019dba8e-7ecd-7010-765a-37ff228578bb
|
||||
20260326141456,ADAS_S751NX0Y601865J_20260328113450259688_7089abe3283f,CPLA,50,5.0,20,019dba8e-8260-7436-7560-c44860a34ddb
|
||||
20260326121348,ADAS_S751NX0Y601865J_20260328113450259688_434da435af46,CPLA,25,5.0,40,019dba8e-892e-7527-59df-97eb0cd6ba13
|
||||
20260326120929,ADAS_S751NX0Y601865J_20260328113450259688_19aa5768291c,CPLA,25,5.0,40,019dba8e-8e70-7609-6e15-004dd8b4e3c5
|
||||
20260326113327,ADAS_S751NX0Y601865J_20260328113450259688_cf29bc58f910,CPLA,25,5.0,40,019dba8e-9518-7a09-599b-5064d89540f2
|
||||
20260327164844,ADAS_S751NX0Y601739V_20260330104120600319_b8ffb91ad5b3,CCRS,-50,0.0,20,019dba8e-a1eb-759c-5e99-d91414dbcb65
|
||||
20260327164715,ADAS_S751NX0Y601739V_20260330104120600319_25960516b170,CCRS,-50,0.0,20,019dba8e-a70f-72ac-7996-79cec1bab193
|
||||
20260327163408,ADAS_S751NX0Y601739V_20260330104120600319_2bcd36764fdc,CCRS,-50,0.0,20,019dba8e-adc1-7a3f-4e2a-bdfa804aa9a1
|
||||
20260327160636,ADAS_S751NX0Y601739V_20260330104120600319_5e14779592f2,CCRS,100,0.0,40,019dba8e-b4be-739a-5297-d7b60f37f030
|
||||
20260327155725,ADAS_S751NX0Y601739V_20260330104120600319_44d7b1f69620,CCRS,100,0.0,40,019dba8e-b913-7be7-4071-4e349a8bb241
|
||||
20260327155538,ADAS_S751NX0Y601739V_20260330104120600319_eb4efa485513,CCRS,100,0.0,40,019dba8e-be43-7519-589e-a06a5e71a75d
|
||||
20260327153617,ADAS_S751NX0Y601739V_20260330104120600319_4f029dbe74a6,CCRS,100,0.0,30,019dba8e-c22f-7a21-4b8c-a4828bc3bd5a
|
||||
20260327152708,ADAS_S751NX0Y601739V_20260330104120600319_c84cd8106f77,CCRS,100,0.0,30,019dba8e-c6ac-7d85-7c7d-64e4dfb6b36a
|
||||
20260327151710,ADAS_S751NX0Y601739V_20260330104120600319_eb5e6353a9b5,CCRS,100,0.0,30,019dba8e-cccf-7893-48ea-3325a5c5ab52
|
||||
20260327150850,ADAS_S751NX0Y601739V_20260330104120600319_96c7a7f2338c,CCRS,100,0.0,20,019dba8e-d206-713a-69d8-0c350ff48f24
|
||||
20260327150639,ADAS_S751NX0Y601739V_20260330104120600319_c06f5150f502,CCRS,100,0.0,20,019dba8e-d61d-7256-536b-e6b1dbf769c4
|
||||
20260327150038,ADAS_S751NX0Y601739V_20260330104120600319_4b079fa4769c,CCRS,100,0.0,20,019dba8e-dae4-7c57-40c8-da652cb563eb
|
||||
20260327115408,ADAS_S751NX0Y601739V_20260330104120600319_89971a38a795,CCRM,100,20.0,40,019dba8e-dfa7-79b3-76d7-ea9ef016e0fe
|
||||
20260327115052,ADAS_S751NX0Y601739V_20260330104120600319_9fde171dd0c5,CCRM,100,20.0,40,019dba8e-e685-75e5-5a4e-a0555eecf3aa
|
||||
20260327113709,ADAS_S751NX0Y601739V_20260330104120600319_310c2fb9e063,CCRM,100,20.0,40,019dba8e-eb36-79a9-56dc-5a777e892f92
|
||||
20260327112148,ADAS_S751NX0Y601739V_20260330104120600319_71c00fa5c46c,CCRM,100,20.0,30,019dba8e-effd-731c-481d-0e8c2bd318e3
|
||||
20260327111430,ADAS_S751NX0Y601739V_20260330104120600319_49f67f0f4c84,CCRM,100,20.0,30,019dba8e-f43e-7095-4bd1-83e7a1623df2
|
||||
20260327110922,ADAS_S751NX0Y601739V_20260330104120600319_d9c5e242cd43,CCRM,100,20.0,30,019dba8e-f9e8-7230-7426-8beae71bc750
|
||||
20260329154913,ADAS_S5STNF0T504465N_20260330162214124146_0491e7efbd55,CCRS,100,0.0,60,019dba8e-fe8c-74b0-5020-04219d015632
|
||||
20260329154719,ADAS_S5STNF0T504465N_20260330162214124146_6bc547d69cf8,CCRS,100,0.0,60,019dba8f-036c-7eaf-6636-653468b7bb3b
|
||||
20260329154536,ADAS_S5STNF0T504465N_20260330162214124146_a82545a4fac4,CCRS,100,0.0,50,019dba8f-0896-7317-6a4e-ae75c0ebab7c
|
||||
20260329154203,ADAS_S5STNF0T504465N_20260330162214124146_e0dfc76d03a5,CCRS,100,0.0,50,019dba8f-0ccb-71d4-5be7-b8cfb15bb6f0
|
||||
20260329142003,ADAS_S5STNF0T504465N_20260330162214124146_c74af4cc5253,CCRS,-50,0.0,40,019dba8f-3e92-70ab-408c-7ffce13cd657
|
||||
20260329141813,ADAS_S5STNF0T504465N_20260330162214124146_370de986d132,CCRS,-50,0.0,40,019dba8f-4244-7d9f-6c58-6888367f5ffd
|
||||
20260329120223,ADAS_S5STNF0T504465N_20260330162214124146_28f2102c8b7d,CCRS,-50,0.0,40,019dba8f-4864-7226-6921-6248ac3e0cb7
|
||||
20260329115326,ADAS_S5STNF0T504465N_20260330162214124146_73d6bf86aabf,CCRS,50,0.0,30,019dba8f-54d6-7cdf-4702-c00b0e1ee340
|
||||
20260329115057,ADAS_S5STNF0T504465N_20260330162214124146_22ec55135ffb,CCRS,50,0.0,30,019dba8f-5945-75a8-6bf2-ecd05a34755f
|
||||
20260329114336,ADAS_S5STNF0T504465N_20260330162214124146_c68c2ee15588,CCRS,50,0.0,30,019dba8f-5d2f-7a1d-6bad-78ead7afc89d
|
||||
20260331175331,ADAS_S5STNF0T406280R_20260402104850269428_d22b22f0957c,CPNA,25,5.0,60,019dba8f-873f-7bba-6f02-448274ca1cfd
|
||||
20260331163715,ADAS_S5STNF0T406280R_20260402104850269428_53960b821f6f,CPNA,75,5.0,40,019dba8f-a46a-7861-45f4-4366c3a1851c
|
||||
20260331151454,ADAS_S5STNF0T406280R_20260402104850269428_98e24c39222d,CPNA,25,5.0,50,019dba8f-d397-79d5-7e79-cdb2b84dd620
|
||||
20260331151250,ADAS_S5STNF0T406280R_20260402104850269428_f0cf082bc503,CPNA,25,5.0,50,019dba8f-d8e8-7886-5c86-b70a49d7cf07
|
||||
20260401105643,ADAS_S5STNF0T504465N_20260402191154995992_22c18553e90d,CBNA,50,15.0,60,019dba7e-fede-7b33-5088-856cadb9f663
|
||||
20260402163705,ADAS_S751NX0Y601865J_20260404102607981812_a61254e06e07,CCRM,100,20.0,FCW70,019dba82-192f-7a87-5d00-ab7caf376a6c
|
||||
20260402161029,ADAS_S751NX0Y601865J_20260404102607981812_8e62c1e285e4,CCRM,50,20.0,50,019dba82-21c1-7551-4315-9753aaf80d19
|
||||
20260402160740,ADAS_S751NX0Y601865J_20260404102607981812_88676757d6a7,CCRM,50,20.0,50,019dba82-2bc2-7045-7f2d-3471a81da6c5
|
||||
20260402160313,ADAS_S751NX0Y601865J_20260404102607981812_85683577a86c,CCRM,50,20.0,50,019dba82-3312-7a73-670b-b0a071570a7c
|
||||
20260402155719,ADAS_S751NX0Y601865J_20260404102607981812_59d8b2bb7b26,CCRM,100,20.0,50,019dba82-3db1-7c70-7f71-00aac10e069f
|
||||
20260402155441,ADAS_S751NX0Y601865J_20260404102607981812_83a21145e104,CCRM,100,20.0,50,019dba82-474f-7d9b-4930-a6da99da2524
|
||||
20260402140527,ADAS_S751NX0Y601865J_20260404102607981812_94a82a4fc7ed,CCRM,100,20.0,50,019dba82-4fbc-7403-457b-29842a656fa3
|
||||
20260402112926,ADAS_S751NX0Y601865J_20260404102607981812_9d1774bc6384,CCRM,-50,20.0,40,019dba82-761b-7d10-4499-5a77b88cc146
|
||||
20260402112746,ADAS_S751NX0Y601865J_20260404102607981812_66692e40d317,CCRM,-50,20.0,40,019dba82-7c59-76ec-5d20-6327cf819094
|
||||
20260402112422,ADAS_S751NX0Y601865J_20260404102607981812_169c8d652d38,CCRM,-50,20.0,40,019dba82-81a0-7252-43d2-9f4b1d9a497f
|
||||
20260402104850,ADAS_S751NX0Y601865J_20260404102607981812_9d2cab2c0acc,CCRM,50,20.0,30,019dba82-9f89-728e-7730-8c6a71cdd37f
|
||||
20260402104654,ADAS_S751NX0Y601865J_20260404102607981812_6dc1ef0b9205,CCRM,50,20.0,30,019dba82-a6d3-73e1-7ec1-32c4a371507d
|
||||
20260402104227,ADAS_S751NX0Y601865J_20260404102607981812_440893f8545b,CCRM,50,20.0,30,019dba82-acf6-7c89-6855-f1d4920fcacc
|
||||
20260403111717,ADAS_S751NX0Y601739V_20260404180449233610_5e1c121e3173,CPLA,25,5.0,FCW80,019dba84-a4fc-793c-5e97-c56d370aa46f
|
||||
20260403111530,ADAS_S751NX0Y601739V_20260404180449233610_60322c693233,CPLA,25,5.0,FCW80,019dba84-a828-7b0b-6dbb-5426ddd3f782
|
||||
20260403111209,ADAS_S751NX0Y601739V_20260404180449233610_0090dd8e218e,CPLA,25,5.0,FCW80,019dba84-ac55-7507-793f-6b1b83c171c9
|
||||
20260403110410,ADAS_S751NX0Y601739V_20260404180449233610_5e216b122d19,CPLA,25,5.0,FCW70,019dba84-afb5-7412-6f5a-0f209e51e0be
|
||||
20260403110146,ADAS_S751NX0Y601739V_20260404180449233610_0af677bafa70,CPLA,25,5.0,FCW70,019dba84-b302-7a2f-55b1-55d74ca34b97
|
||||
20260403105607,ADAS_S751NX0Y601739V_20260404180449233610_77171219d205,CPLA,25,5.0,FCW70,019dba84-b659-73f9-6f2d-2bfbf4e2b661
|
||||
20260403105245,ADAS_S751NX0Y601739V_20260404180449233610_d69464e39b14,CPLA,25,5.0,FCW60,019dba84-ba6b-76da-4ccc-99233bcff685
|
||||
20260403105025,ADAS_S751NX0Y601739V_20260404180449233610_e29f23ae0340,CPLA,25,5.0,FCW60,019dba84-bd90-70bc-619f-b8dde6b730e8
|
||||
20260403104553,ADAS_S751NX0Y601739V_20260404180449233610_2bcd8b998839,CPLA,25,5.0,FCW60,019dba84-c0c7-7183-5e8d-870fc4d04964
|
||||
20260403104107,ADAS_S751NX0Y601739V_20260404180449233610_c1e13502a0e1,CPLA,25,5.0,FCW50,019dba84-c4af-7d97-7e6d-b6239722ec96
|
||||
20260403103901,ADAS_S751NX0Y601739V_20260404180449233610_9ba0984bad5a,CPLA,25,5.0,FCW50,019dba84-c809-743e-5080-1de74eb35b5a
|
||||
20260403103238,ADAS_S751NX0Y601739V_20260404180449233610_349b6b6c98d3,CPLA,25,5.0,FCW50,019dba84-cb24-71cb-47cf-0fb636fe7071
|
||||
20260407235712,ADAS_S5STNF0T406280R_20260409152111002995_efab4f9a5f9e,CPLA-夜晚,50.0,5.0,40,019d9aa9-076e-7b24-5f16-a4774edf4093
|
||||
20260407235601,ADAS_S5STNF0T406280R_20260409152111002995_cfeadccd6caf,CPLA-夜晚,50.0,5.0,40,019d9aa9-0f61-7497-7d99-c5748212bfc8
|
||||
20260407235425,ADAS_S5STNF0T406280R_20260409152111002995_49e7f088e808,CPLA-夜晚,50.0,5.0,30,019d9aa9-15e1-7e51-41cc-c6a705f1dd9a
|
||||
20260407235247,ADAS_S5STNF0T406280R_20260409152111002995_3c85c3558988,CPLA-夜晚,50.0,5.0,30,019d9aa9-1b86-72f8-5625-626e1d10850a
|
||||
20260407235041,ADAS_S5STNF0T406280R_20260409152111002995_24f188716448,CPLA-夜晚,50.0,5.0,20,019d9aa9-21b4-7853-54b1-bf3e6771ffc2
|
||||
20260407234858,ADAS_S5STNF0T406280R_20260409152111002995_5b39e9130eb2,CPLA-夜晚,50.0,5.0,20,019d9aa9-26b6-7452-51e8-a185ef8f03f9
|
||||
20260407234222,ADAS_S5STNF0T406280R_20260409152111002995_425ba64c99f3,CPLA-夜晚,25.0,5.0,FCW80,019d9aa9-2b19-73e6-4765-3c7d280b3ee6
|
||||
20260407234024,ADAS_S5STNF0T406280R_20260409152111002995_bb954963fead,CPLA-夜晚,25.0,5.0,FCW80,019d9aa9-30c5-7636-549f-81144cc4f62e
|
||||
20260407233737,ADAS_S5STNF0T406280R_20260409152111002995_409f58cad2b1,CPLA-夜晚,25.0,5.0,FCW70,019d9aa9-3496-7948-5037-2a02204cc43e
|
||||
20260407233549,ADAS_S5STNF0T406280R_20260409152111002995_dd98b096d792,CPLA-夜晚,25.0,5.0,FCW70,019d9aa9-3977-7d5b-652d-66a266e6c60a
|
||||
20260407233339,ADAS_S5STNF0T406280R_20260409152111002995_c105bad6812b,CPLA-夜晚,25.0,5.0,FCW60,019d9aa9-4051-7b14-5e87-20cd3532ef90
|
||||
20260407233159,ADAS_S5STNF0T406280R_20260409152111002995_8065a4b59db6,CPLA-夜晚,25.0,5.0,FCW60,019d9aa9-4536-7af2-6562-40e4b9c89ccc
|
||||
20260407232758,ADAS_S5STNF0T406280R_20260409152111002995_851306838843,CPLA-夜晚,25.0,5.0,FCW50,019d9aa9-48a9-7e39-6d1d-9ed1732bfbb9
|
||||
20260407232406,ADAS_S5STNF0T406280R_20260409152111002995_877fb48c53e8,CPLA-夜晚,25.0,5.0,FCW50,019d9aa9-4cd4-77d7-7aa5-0b4314a7fd3e
|
||||
20260407231753,ADAS_S5STNF0T406280R_20260409152111002995_d89ac36f740c,CPLA-夜晚,25.0,5.0,FCW50,019d9aa9-5140-7c6c-5cc1-ae1058843056
|
||||
20260407225130,ADAS_S5STNF0T406280R_20260409152111002995_92dd871fc3bd,CPFAO-夜晚,25.0,6.5,60,019d9aa9-556c-7ab5-5d3f-6e63014ce80b
|
||||
20260407224321,ADAS_S5STNF0T406280R_20260409152111002995_797f2a520f7f,CPFAO-夜晚,25.0,6.5,60,019d9aa9-5aaa-7b33-6455-8489710518a9
|
||||
20260407224125,ADAS_S5STNF0T406280R_20260409152111002995_955748274b43,CPFAO-夜晚,25.0,6.5,60,019d9aa9-6119-7cc4-7699-7f644dc2a964
|
||||
20260407223853,ADAS_S5STNF0T406280R_20260409152111002995_f5829f94e220,CPFAO-夜晚,25.0,6.5,40,019d9aa9-65aa-7748-63fd-6b9ada70eef2
|
||||
20260407223726,ADAS_S5STNF0T406280R_20260409152111002995_9dd57efb9e3f,CPFAO-夜晚,25.0,6.5,40,019d9aa9-6a50-79cf-76fd-a98eb8d5f5a8
|
||||
20260407223528,ADAS_S5STNF0T406280R_20260409152111002995_53a024ff00b0,CPFAO-夜晚,25.0,6.5,40,019d9aa9-7016-793e-44de-b79af7e1456b
|
||||
20260407223054,ADAS_S5STNF0T406280R_20260409152111002995_1f4fb829d5c1,CPFAO-夜晚,25.0,6.5,20,019d9aa9-7472-764a-545a-99cbb25f9835
|
||||
20260407222854,ADAS_S5STNF0T406280R_20260409152111002995_65df5c754a08,CPFAO-夜晚,25.0,6.5,20,019d9aa9-7865-74d7-7e59-093438dc3388
|
||||
20260407222417,ADAS_S5STNF0T406280R_20260409152111002995_cf1dfc5751fb,CPFAO-夜晚,25.0,6.5,20,019d9aa9-7c27-729c-4d7b-3713e76ef75b
|
||||
20260407221421,ADAS_S5STNF0T406280R_20260409152111002995_79ead953a267,CPFA-夜晚,25.0,6.5,60,019d9aa9-827d-7a37-78e5-4ea0ec992c77
|
||||
20260407215247,ADAS_S5STNF0T406280R_20260409152111002995_a345faf933c1,CPFA-夜晚,25.0,6.5,60,019d9aa9-8986-7e12-6f1c-7b4541a5c438
|
||||
20260407214759,ADAS_S5STNF0T406280R_20260409152111002995_3c626bbc7af6,CPFA-夜晚,25.0,6.5,50,019d9aa9-8e5d-7bae-7fa6-a1243ad252b1
|
||||
20260407214009,ADAS_S5STNF0T406280R_20260409152111002995_bc6c0c01e193,CPFA-夜晚,25.0,6.5,50,019d9aa9-91e3-7a04-77dd-d1fec1704486
|
||||
20260407213801,ADAS_S5STNF0T406280R_20260409152111002995_48410cc6c373,CPFA-夜晚,25.0,6.5,50,019d9aa9-9842-7b06-643f-a6d3c27fdb4a
|
||||
20260407212845,ADAS_S5STNF0T406280R_20260409152111002995_f81455ea3eed,CPFA-夜晚,25.0,6.5,40,019d9aa9-9e5a-761b-71ee-2c0daebc363a
|
||||
20260407211000,ADAS_S5STNF0T406280R_20260409152111002995_bc6ff7c44071,CPFA-夜晚,25.0,6.5,40,019d9aa9-a2ea-729b-61da-46dc65e0f2c9
|
||||
20260407210630,ADAS_S5STNF0T406280R_20260409152111002995_aa33868a5965,CPFA-夜晚,25.0,6.5,30,019d9aa9-a8a0-748d-612c-77c42f99428c
|
||||
20260407205653,ADAS_S5STNF0T406280R_20260409152111002995_2264933415a6,CPFA-夜晚,25.0,6.5,30,019d9aa9-b0a4-7dd1-5fb1-4bd3842b0a0d
|
||||
20260407203248,ADAS_S5STNF0T406280R_20260409152111002995_51b93fb7cf53,CPFA-夜晚,25.0,6.5,30,019d9aa9-b6b3-7abb-6f43-815eb75834a8
|
||||
20260407203003,ADAS_S5STNF0T406280R_20260409152111002995_ddada7c982c6,CPFA-夜晚,25.0,6.5,20,019d9aa9-bd6e-746b-556d-0c089251cc57
|
||||
20260407202812,ADAS_S5STNF0T406280R_20260409152111002995_4779e10c3a5b,CPFA-夜晚,25.0,6.5,20,019d9aa9-c38e-7e79-70b1-615b22a4f86b
|
||||
20260407202502,ADAS_S5STNF0T406280R_20260409152111002995_bf0967499ed6,CPFA-夜晚,25.0,6.5,20,019d9aa9-c752-7a92-44e6-69411b6e44aa
|
||||
20260407182536,ADAS_S5STNF0T406280R_20260409152111002995_4f1437a97128,CPFAO,25.0,6.5,60,019d9aa9-cb33-7375-4f41-2a8282140d9a
|
||||
20260407181809,ADAS_S5STNF0T406280R_20260409152111002995_bfa7f306290b,CPFAO,25.0,6.5,60,019d9aa9-cff8-7e52-4e27-eecdd74e70c4
|
||||
20260407181450,ADAS_S5STNF0T406280R_20260409152111002995_716c2b09c740,CPFAO,25.0,6.5,40,019d9aa9-d4d7-7a5d-7eac-fadf6fb9d2ea
|
||||
20260407181122,ADAS_S5STNF0T406280R_20260409152111002995_da621561033c,CPFAO,25.0,6.5,40,019d9aa9-ecfb-73fb-4b6b-743b7bbb2b08
|
||||
20260407180720,ADAS_S5STNF0T406280R_20260409152111002995_9f26c651c46d,CPFAO,25.0,6.5,40,019d9aa9-f13a-7b1a-5760-09e35fc5d834
|
||||
20260407150403,ADAS_S5STNF0T406280R_20260409152111002995_9c12dd965fc5,CPFAO,25.0,6.5,20,019d9aaa-0ccb-70bc-45e1-85a75961a5ee
|
||||
20260407145705,ADAS_S5STNF0T406280R_20260409152111002995_eb1aa8b08248,CPFAO,25.0,6.5,20,019d9aaa-127b-78ef-57df-f568d78eeab5
|
||||
20260407115528,ADAS_S5STNF0T406280R_20260409152111002995_7254e457ef67,CBLA,25.0,15.0,FCW80,019d9aaa-18f2-75d9-59e2-25649bb25498
|
||||
20260407115335,ADAS_S5STNF0T406280R_20260409152111002995_6325ec39b751,CBLA,25.0,15.0,FCW80,019d9aaa-1ccc-70e2-4a60-07216d9dd359
|
||||
20260407115155,ADAS_S5STNF0T406280R_20260409152111002995_b51fdac11ab8,CBLA,25.0,15.0,FCW80,019d9aaa-21bb-7429-6b35-a725a9993bdd
|
||||
20260407114731,ADAS_S5STNF0T406280R_20260409152111002995_44c27781ddc3,CBLA,25.0,15.0,FCW70,019d9aaa-2891-7960-7681-84be2eac02d1
|
||||
20260407114555,ADAS_S5STNF0T406280R_20260409152111002995_33b078bf6216,CBLA,25.0,15.0,FCW70,019d9aaa-2d9b-7b10-54bd-88503a0ed61b
|
||||
20260407114352,ADAS_S5STNF0T406280R_20260409152111002995_ecfd3b259961,CBLA,25.0,15.0,FCW60,019d9aaa-3150-7366-774b-946d68a529f8
|
||||
20260407114204,ADAS_S5STNF0T406280R_20260409152111002995_562404e71005,CBLA,25.0,15.0,FCW60,019d9aaa-37bb-7b90-788b-66a42a574474
|
||||
20260407114023,ADAS_S5STNF0T406280R_20260409152111002995_7071743abdf9,CBLA,25.0,15.0,FCW60,019d9aaa-3d58-7acb-73f3-444d666e03e7
|
||||
20260407113824,ADAS_S5STNF0T406280R_20260409152111002995_f016eafc886a,CBLA,25.0,15.0,FCW50,019d9aaa-4167-7eeb-4715-7892f58a5271
|
||||
20260407113633,ADAS_S5STNF0T406280R_20260409152111002995_14b6fffb9346,CBLA,25.0,15.0,FCW50,019d9aaa-48af-7840-4f34-59a83f60ae4f
|
||||
20260407113402,ADAS_S5STNF0T406280R_20260409152111002995_2db981f7c452,CBLA,25.0,15.0,FCW50,019d9aaa-4e92-743e-673b-19ca695f6571
|
||||
20260407112549,ADAS_S5STNF0T406280R_20260409152111002995_915cffcc1584,CBLA,50.0,15.0,60,019d9aaa-524c-7950-5d38-965c8a7044b5
|
||||
20260407112334,ADAS_S5STNF0T406280R_20260409152111002995_72cb0932d90e,CBLA,50.0,15.0,60,019d9aaa-590d-77a4-7db2-923118c55be9
|
||||
20260407112214,ADAS_S5STNF0T406280R_20260409152111002995_2ac2047ca290,CBLA,50.0,15.0,60,019d9aaa-5e44-7fc5-6e5b-8c43a352ccb7
|
||||
20260407112037,ADAS_S5STNF0T406280R_20260409152111002995_3aaeea19a547,CBLA,50.0,15.0,50,019d9aaa-630d-77f1-5bdd-d09431e1e161
|
||||
20260407111922,ADAS_S5STNF0T406280R_20260409152111002995_4deb6874a615,CBLA,50.0,15.0,50,019d9aaa-67ec-7410-5d97-7f3371866c7c
|
||||
20260407111812,ADAS_S5STNF0T406280R_20260409152111002995_d39a5d1c908f,CBLA,50.0,15.0,50,019d9aaa-6b63-73bf-73bb-5a3f96ace7b3
|
||||
20260407111307,ADAS_S5STNF0T406280R_20260409152111002995_7a5e67352e0e,CBLA,50.0,15.0,40,019d9aaa-70a3-748e-6d05-0c2d1a31dcae
|
||||
20260407111122,ADAS_S5STNF0T406280R_20260409152111002995_d3ab196e744a,CBLA,50.0,15.0,40,019d9aaa-88a0-7970-4ceb-15bb8ab3b1ff
|
||||
20260407110751,ADAS_S5STNF0T406280R_20260409152111002995_5c50e575f464,CBLA,50.0,15.0,40,019d9aaa-8fd9-7ab1-6a49-72b63397588c
|
||||
20260407110422,ADAS_S5STNF0T406280R_20260409152111002995_4045be63fc22,CBLA,50.0,15.0,30,019d9aaa-b385-753d-5faa-1ad2759f5a5f
|
||||
20260407110300,ADAS_S5STNF0T406280R_20260409152111002995_ea8e031bb31e,CBLA,50.0,15.0,30,019d9aaa-b8bb-7da2-4d44-23f067e0d663
|
||||
20260407110130,ADAS_S5STNF0T406280R_20260409152111002995_6e0a4c97c8c1,CBLA,50.0,15.0,30,019d9aaa-bee0-7dab-4651-4c3915a8c5cd
|
||||
20260407105941,ADAS_S5STNF0T406280R_20260409152111002995_621325fdf415,CBLA,50.0,15.0,20,019d9aaa-c31f-7e26-75c6-e02b1700a8a8
|
||||
20260407105753,ADAS_S5STNF0T406280R_20260409152111002995_069a2c13319e,CBLA,50.0,15.0,20,019d9aaa-c7f4-7027-50c2-58b40e941188
|
||||
20260407105535,ADAS_S5STNF0T406280R_20260409152111002995_0e1ce93501ef,CBLA,50.0,15.0,20,019d9aaa-cb54-7853-7393-0d3928f895f9
|
||||
20260407102008,ADAS_S5STNF0T406280R_20260409152111002995_ef2816221a27,CPLA,50.0,5.0,60,019d9aaa-cf01-761f-690c-7f2090d7277d
|
||||
20260407101706,ADAS_S5STNF0T406280R_20260409152111002995_2249a6c9c868,CPLA,50.0,5.0,60,019d9aaa-d4af-7f14-5347-005312fcbb02
|
||||
20260407101455,ADAS_S5STNF0T406280R_20260409152111002995_3aec82d2ae5b,CPLA,50.0,5.0,60,019d9aaa-dc19-7189-7ea1-1c6b2bb3a963
|
||||
20260407100842,ADAS_S5STNF0T406280R_20260409152111002995_a33d9aa63d97,CPLA,50.0,5.0,50,019d9aaa-df67-7cea-7ac6-b5783b3aeab8
|
||||
20260407100530,ADAS_S5STNF0T406280R_20260409152111002995_a3fd722c219d,CPLA,50.0,5.0,50,019d9aaa-e4a6-7293-71ed-bd5ffeae3cbf
|
||||
20260407100321,ADAS_S5STNF0T406280R_20260409152111002995_0a59f61cc73e,CPLA,50.0,5.0,50,019d9aaa-e9bc-72a1-511e-051af8249f39
|
||||
20260407095827,ADAS_S5STNF0T406280R_20260409152111002995_522b6859b7cc,CPLA,50.0,5.0,40,019d9aaa-ed4f-7c64-734b-853b64feafdf
|
||||
20260407095546,ADAS_S5STNF0T406280R_20260409152111002995_f45e8cd87f19,CPLA,50.0,5.0,40,019d9aaa-f24d-7e7f-513b-50bbd4dde342
|
||||
20260407095253,ADAS_S5STNF0T406280R_20260409152111002995_d635dca3a188,CPLA,50.0,5.0,40,019d9aaa-f79c-7528-63f5-3d6592aedbfb
|
||||
20260408161638,ADAS_S5STNF0T504465N_20260409152139658693_8dbfcbfeb5ee,CBNAO,50.0,15.0,60,019d9aa4-e596-73a3-563e-91eff907fc5f
|
||||
20260408161312,ADAS_S5STNF0T504465N_20260409152139658693_552b57bd437a,CBNAO,50.0,15.0,60,019d9aa4-e97b-7f4c-71fe-27fb3e92820c
|
||||
20260408161043,ADAS_S5STNF0T504465N_20260409152139658693_159245c0434e,CBNAO,50.0,15.0,60,019d9aa4-eddd-77f5-6ce3-9eb75c9e126c
|
||||
20260408160836,ADAS_S5STNF0T504465N_20260409152139658693_235d852f9406,CBNAO,50.0,15.0,40,019d9aa4-f55c-7254-6da3-9371446494a2
|
||||
20260408160613,ADAS_S5STNF0T504465N_20260409152139658693_dbb8344a1203,CBNAO,50.0,15.0,40,019d9aa4-fa8b-7cdf-51c3-118b7c34368e
|
||||
20260408160358,ADAS_S5STNF0T504465N_20260409152139658693_6c96ac950cc5,CBNAO,50.0,15.0,40,019d9aa4-ff05-79fb-58c4-c719f7dc6e07
|
||||
20260408160123,ADAS_S5STNF0T504465N_20260409152139658693_259ff1913329,CBNAO,50.0,15.0,20,019d9aa5-049f-7bb1-5e03-978f6b092895
|
||||
20260408155917,ADAS_S5STNF0T504465N_20260409152139658693_7f68037838f3,CBNAO,50.0,15.0,20,019d9aa5-09c3-78fc-73b5-7aa4c811f39a
|
||||
20260408155451,ADAS_S5STNF0T504465N_20260409152139658693_0a7f2b349464,CBNAO,50.0,15.0,20,019d9aa5-0dcf-7135-4e96-d516559ebc9e
|
||||
20260408152655,ADAS_S5STNF0T504465N_20260409152139658693_6d37a9755ccc,CPNCO,25.0,5.0,60,019d9aa5-11b0-7f7b-79ff-9a433fc42aef
|
||||
20260408151807,ADAS_S5STNF0T504465N_20260409152139658693_0d829e9357a4,CPNCO,25.0,5.0,60,019d9aa5-18c9-724e-7f73-8fe42bd39b5b
|
||||
20260408150258,ADAS_S5STNF0T504465N_20260409152139658693_7a94940f5d03,CPNCO,25.0,5.0,60,019d9aa5-1d67-79ab-6805-059001b21a42
|
||||
20260408145812,ADAS_S5STNF0T504465N_20260409152139658693_750011a9dfe4,CPNCO,25.0,5.0,40,019d9aa5-24e4-79fe-549c-19e449a23c53
|
||||
20260408145424,ADAS_S5STNF0T504465N_20260409152139658693_ea7728a2697d,CPNCO,25.0,5.0,40,019d9aa5-2aa5-7d7c-75b8-2b60ef3eed08
|
||||
20260408145214,ADAS_S5STNF0T504465N_20260409152139658693_4948b709cf5d,CPNCO,25.0,5.0,40,019d9aa5-31da-7d88-4f99-11dd0d0f8499
|
||||
20260408141857,ADAS_S5STNF0T504465N_20260409152139658693_4eb92c8fee57,CPNCO,25.0,5.0,20,019d9aa5-4eca-7f08-635b-2fa3bc598c09
|
||||
20260408141334,ADAS_S5STNF0T504465N_20260409152139658693_b0faffa9dc30,CPNCO,25.0,5.0,20,019d9aa5-538a-772a-494d-35f736399e65
|
||||
20260408134743,ADAS_S5STNF0T504465N_20260409152139658693_b5876596c9d1,CPNCO,25.0,5.0,20,019d9aa5-5802-7924-6ce0-ffb4967f13bd
|
||||
20260408002949,ADAS_S5STNF0T406280R_20260409152111002995_45d2787fbc67,CPLA-夜晚,25.0,5.0,FCW80,019d9aa5-5bf7-7fb2-6efc-6d8161e18c1b
|
||||
20260408002550,ADAS_S5STNF0T406280R_20260409152111002995_5e07f54bbb10,CPLA-夜晚,25.0,5.0,FCW60,019d9aa5-63e8-711a-417e-c616fe4e5eda
|
||||
20260408002023,ADAS_S5STNF0T406280R_20260409152111002995_0b5d60209c57,CPLA-夜晚,25.0,5.0,40,019d9aa5-6c4f-7ebf-5b32-53e5c680be0a
|
||||
20260408001902,ADAS_S5STNF0T406280R_20260409152111002995_edda23ef80bd,CPLA-夜晚,25.0,5.0,40,019d9aa5-701a-7bf6-4e38-45d884353a70
|
||||
20260408001653,ADAS_S5STNF0T406280R_20260409152111002995_b29f5723b2c0,CPLA-夜晚,25.0,5.0,20,019d9aa5-735a-75f3-5ba4-93902a277d59
|
||||
20260408001434,ADAS_S5STNF0T406280R_20260409152111002995_c14dc9bae519,CPLA-夜晚,25.0,5.0,20,019d9aa5-76fe-7d1f-598b-5e7dd61280e9
|
||||
20260408000623,ADAS_S5STNF0T406280R_20260409152111002995_46815deac491,CPLA-夜晚,50.0,5.0,60,019d9aa5-7b0e-75c8-4334-61c3ab70abbb
|
||||
20260408000446,ADAS_S5STNF0T406280R_20260409152111002995_c62ef90d053e,CPLA-夜晚,50.0,5.0,60,019d9aa5-7e74-7664-6f81-427fa818ade0
|
||||
20260408000248,ADAS_S5STNF0T406280R_20260409152111002995_543e826a5e70,CPLA-夜晚,50.0,5.0,50,019d9aa5-8200-7f80-46a0-02307e146cfa
|
||||
20260408000108,ADAS_S5STNF0T406280R_20260409152111002995_4086a9a63200,CPLA-夜晚,50.0,5.0,50,019d9aa5-8a5a-7798-53ee-8ebecd6efac0
|
||||
20260410183944,ADAS_S751NX0Y601865J_20260412195842469563_433f140b95d6,CCRS,-50.0,0.0,FCW80,019d9a96-c1d6-7326-728e-02a54fd8e225
|
||||
20260410183322,ADAS_S751NX0Y601865J_20260412195842469563_a7973f1e9bb1,CCRS,100.0,0.0,FCW80,019d9a96-cb3d-7c97-7ea5-b3f748d9eb5e
|
||||
20260410183032,ADAS_S751NX0Y601865J_20260412195842469563_ef2acadfb2bd,CCRS,100.0,0.0,FCW80,019d9a96-d38c-7078-46fe-d780744cb909
|
||||
20260410182651,ADAS_S751NX0Y601865J_20260412195842469563_62b3ba276352,CCRS,50.0,0.0,FCW70,019d9a96-da33-7c3b-6246-61da039dfa20
|
||||
20260410182102,ADAS_S751NX0Y601865J_20260412195842469563_cbcfff9884b1,CCRS,50.0,0.0,FCW70,019d9a96-dff9-7b8f-4705-38c5c58c2599
|
||||
20260410180809,ADAS_S751NX0Y601865J_20260412195842469563_1f2727954bca,CCRS,50.0,0.0,FCW70,019d9a96-e5e5-782c-65d1-48036de2d14a
|
||||
20260410180043,ADAS_S751NX0Y601865J_20260412195842469563_9e2611ec8323,CCRS,100.0,0.0,FCW70,019d9a97-02a2-7ad2-6658-aa217ab89e55
|
||||
20260410175829,ADAS_S751NX0Y601865J_20260412195842469563_042f5636d4f4,CCRS,100.0,0.0,FCW70,019d9a97-08a2-71ca-7a1a-4bec6e69a901
|
||||
20260410175602,ADAS_S751NX0Y601865J_20260412195842469563_7787aecfa77f,CCRS,100.0,0.0,FCW70,019d9a97-0d8d-7a20-489c-f90e4ce10e22
|
||||
20260410175256,ADAS_S751NX0Y601865J_20260412195842469563_13f6d65d0058,CCRS,-50.0,0.0,FCW60,019d9a97-11c1-742b-5d71-2074250c8b5f
|
||||
20260410174813,ADAS_S751NX0Y601865J_20260412195842469563_74864ef9dfac,CCRS,100.0,0.0,FCW60,019d9a97-1719-70e0-6008-7ca16945ea6b
|
||||
20260410174417,ADAS_S751NX0Y601865J_20260412195842469563_fb97c4371e87,CCRS,100.0,0.0,FCW60,019d9a97-1c3b-74fa-4273-514b875c17ad
|
||||
20260410172805,ADAS_S751NX0Y601865J_20260412195842469563_ca74d9bf7865,CCRS,100.0,0.0,FCW60,019d9a97-1fe2-7480-417b-a86fbb036b09
|
||||
20260410171831,ADAS_S751NX0Y601865J_20260412195842469563_3299757de161,CCRS,-50.0,0.0,FCW60,019d9a97-2bee-7107-401d-4d872729a179
|
||||
20260410171425,ADAS_S751NX0Y601865J_20260412195842469563_9cae1d226719,CCRS,-50.0,0.0,FCW60,019d9a97-3091-7993-662c-cd6a5a2ec208
|
||||
20260410135043,ADAS_S751NX0Y601865J_20260412195842469563_5a853fcb203a,CCRS,50.0,0.0,FCW50,019d9a97-5715-7df7-79f8-bee1114b0445
|
||||
20260410134822,ADAS_S751NX0Y601865J_20260412195842469563_32bc05a9d954,CCRS,50.0,0.0,FCW50,019d9a97-5b96-76ad-6af6-261e504f4b6a
|
||||
20260410134541,ADAS_S751NX0Y601865J_20260412195842469563_7110684c2ec6,CCRS,50.0,0.0,FCW50,019d9a97-5f4c-7d07-6fd5-6301296712e0
|
||||
20260410121059,ADAS_S751NX0Y601865J_20260412195842469563_2f056f43e537,CCRS,100.0,0.0,FCW50,019d9a97-646e-749d-78fc-7c1177a082e4
|
||||
20260410120748,ADAS_S751NX0Y601865J_20260412195842469563_f719a9f14f03,CCRS,100.0,0.0,FCW50,019d9a97-6c15-71d7-7ca4-8aa861b4f657
|
||||
20260410120327,ADAS_S751NX0Y601865J_20260412195842469563_b1089228c2a7,CCRS,100.0,0.0,FCW50,019d9a97-707f-7b4c-6f73-bfdca7b99135
|
||||
20260410111646,ADAS_S751NX0Y601865J_20260412195842469563_c5d7494583d0,CSFAO,50.0,20.0,60,019d9a97-7721-744b-6f9d-3e7f33022481
|
||||
20260410104110,ADAS_S751NX0Y601865J_20260412195842469563_99948185a04d,CSFAO,50.0,20.0,60,019d9a97-7c0c-7a18-6c44-0245ab8bf1ad
|
||||
20260410103025,ADAS_S751NX0Y601865J_20260412195842469563_09a490787dad,CSFAO,50.0,20.0,60,019d9a97-8221-7aa2-49ac-411ab9a7b24a
|
||||
20260410102715,ADAS_S751NX0Y601865J_20260412195842469563_5e4f95ca5ba9,CSFAO,50.0,20.0,40,019d9a97-86f6-711a-68e0-69a9b8e9b359
|
||||
20260410102527,ADAS_S751NX0Y601865J_20260412195842469563_e88c82463dde,CSFAO,50.0,20.0,40,019d9a97-8bb3-7007-7c41-c7edd0edb95e
|
||||
20260410102252,ADAS_S751NX0Y601865J_20260412195842469563_e12a5bd21c7b,CSFAO,50.0,20.0,40,019d9a97-9152-7292-7210-da999124e35f
|
||||
20260410102018,ADAS_S751NX0Y601865J_20260412195842469563_02d5dd72de6e,CSFAO,50.0,20.0,20,019d9a97-96f8-7f2d-7675-481089eac2c7
|
||||
20260410101810,ADAS_S751NX0Y601865J_20260412195842469563_f4a683d9d4db,CSFAO,50.0,20.0,20,019d9a97-9ba9-75da-6e53-b4e8575ac660
|
||||
20260410101534,ADAS_S751NX0Y601865J_20260412195842469563_cda9e45c8fd1,CSFAO,50.0,20.0,20,019d9a97-9fb4-76a5-5fa4-3bdfcdf3da32
|
||||
20260411183829,ADAS_S751NX0Y601739V_20260413155723466116_a04db0919eec,CCRS,-50.0,0.0,FCW80,019d9a7c-a893-7ebe-44fc-88658f70c9a2
|
||||
20260411182247,ADAS_S751NX0Y601739V_20260413155723466116_d1186bf4a065,CCRS,-50.0,0.0,FCW80,019d9a7c-af31-7626-5765-81fc0f62c50b
|
||||
20260411180919,ADAS_S751NX0Y601739V_20260413155723466116_9a6876a65dca,CCRS,100.0,0.0,FCW80,019d9a7c-b749-77a4-57a0-8db9b20ff808
|
||||
20260411175300,ADAS_S751NX0Y601739V_20260413155723466116_d852ebd5465e,CCRM,-50.0,20.0,FCW80,019d9a7c-c5e4-7e00-7abc-0b61af7b34d2
|
||||
20260411174303,ADAS_S751NX0Y601739V_20260413155723466116_434fdd766056,CCRM,-50.0,20.0,FCW80,019d9a7c-c955-7e81-4d13-eb44371e532a
|
||||
20260411173124,ADAS_S751NX0Y601739V_20260413155723466116_97ec63da982a,CCRM,-50.0,20.0,FCW80,019d9a7c-cd7f-78f7-5c70-131af26cc440
|
||||
20260411172605,ADAS_S751NX0Y601739V_20260413155723466116_71bcb435e71c,CCRM,100.0,20.0,FCW80,019d9a7c-d846-741b-7597-41b66b95e10a
|
||||
20260411172410,ADAS_S751NX0Y601739V_20260413155723466116_6d8d13f750fc,CCRM,100.0,20.0,FCW80,019d9a7c-dc76-7635-5934-90774c92ed6d
|
||||
20260411172142,ADAS_S751NX0Y601739V_20260413155723466116_723bebf4506d,CCRM,100.0,20.0,FCW80,019d9a7c-e374-7a08-41df-cb22895e85e9
|
||||
20260411171702,ADAS_S751NX0Y601739V_20260413155723466116_8f574aa74cca,CCRM,50.0,20.0,FCW70,019d9a7c-e985-7d35-73d6-3c32a44ef500
|
||||
20260411171447,ADAS_S751NX0Y601739V_20260413155723466116_5c3cb97938c5,CCRM,50.0,20.0,FCW70,019d9a7c-ed45-704a-56af-2fee6afc2bb7
|
||||
20260411171038,ADAS_S751NX0Y601739V_20260413155723466116_d8fc43891af6,CCRM,50.0,20.0,FCW70,019d9a7c-f0ef-7ec9-5285-16661cc3be7c
|
||||
20260411170537,ADAS_S751NX0Y601739V_20260413155723466116_0c1194076828,CCRM,100.0,20.0,FCW70,019d9a7c-f5c8-76c5-5dcb-0ab62615959e
|
||||
20260411170231,ADAS_S751NX0Y601739V_20260413155723466116_4f8d3c73fffa,CCRM,100.0,20.0,FCW70,019d9a7c-fb91-766b-4c07-18323de8251c
|
||||
20260411165955,ADAS_S751NX0Y601739V_20260413155723466116_a3fe89de5059,CCRM,100.0,20.0,FCW70,019d9a7d-0105-7b5e-4b10-da65ba7b2306
|
||||
20260411165255,ADAS_S751NX0Y601739V_20260413155723466116_2481817963a5,CCRM,-50.0,20.0,FCW60,019d9a7d-04b7-74fb-75ff-d8cc08b2e6b5
|
||||
20260411164856,ADAS_S751NX0Y601739V_20260413155723466116_a591780712a5,CCRM,-50.0,20.0,FCW60,019d9a7d-0989-7b0c-46a1-e621003a415e
|
||||
20260411164604,ADAS_S751NX0Y601739V_20260413155723466116_a570cbea0f8c,CCRM,-50.0,20.0,FCW60,019d9a7d-0e02-7c5f-4163-756d1d22c96b
|
||||
20260411164110,ADAS_S751NX0Y601739V_20260413155723466116_1c8ce6be64a0,CCRM,100.0,20.0,FCW60,019d9a7d-12b7-7c15-46a5-256d59cba379
|
||||
20260411163351,ADAS_S751NX0Y601739V_20260413155723466116_c5c8b22ad3dc,CCRM,100.0,20.0,FCW60,019d9a7d-16fa-7aaf-44ff-9516a0d5684e
|
||||
20260411162856,ADAS_S751NX0Y601739V_20260413155723466116_45a1708bd6e7,CCRM,100.0,20.0,FCW60,019d9a7d-1ba0-7648-61c9-bcc36579b627
|
||||
20260413184006,ADAS_S5STNF0T504465N_20260414163318204977_94d493ef794c,CPTA-LN,50.0,5.0,20,019d9a5d-b50f-75d1-79cd-6450dfebdd5d
|
||||
20260413182950,ADAS_S5STNF0T504465N_20260414163318204977_65588ce02434,CPTA-LF,50.0,6.5,20,019d9a5d-bc97-7015-4292-587775914bad
|
||||
20260413182735,ADAS_S5STNF0T504465N_20260414163318204977_e9c68de37ce5,CPTA-LF,50.0,6.5,20,019d9a5d-c404-7ec9-463d-bc3ccd120447
|
||||
20260413181209,ADAS_S5STNF0T504465N_20260414163318204977_731fe43b77a4,CPTA-LF,50.0,6.5,10,019d9a5d-ca7c-7e1c-5065-445b231ab139
|
||||
20260413180557,ADAS_S5STNF0T504465N_20260414163318204977_ab161275fcdd,CPTA-LF,50.0,6.5,10,019d9a5d-cf2a-700e-426b-4834795e46e4
|
||||
20260413155722,ADAS_S5STNF0T504465N_20260414163318204977_de1770ab54a4,CPTA-LF,50.0,6.5,10,019d9a5d-d6a3-7582-7ec1-e15fbd30314f
|
||||
20260413152044,ADAS_S5STNF0T504465N_20260414163318204977_2c16f786a458,CPTA-LN,50.0,5.0,20,019d9a5d-daa6-7d0b-6040-634b0adc26d5
|
||||
20260413144918,ADAS_S5STNF0T504465N_20260414163318204977_311e2e4f3469,CPTA-LN,50.0,5.0,20,019d9a5d-e12b-77ed-795b-a177a975d2d8
|
||||
20260413143117,ADAS_S5STNF0T504465N_20260414163318204977_912131df3c3f,CPTA-LN,50.0,5.0,10,019d9a5d-e9f7-75fb-70c7-d966c6229458
|
||||
20260413142635,ADAS_S5STNF0T504465N_20260414163318204977_c83b9a3226dd,CPTA-LN,50.0,5.0,10,019d9a5d-f0bf-7b9f-40d2-7e37931ed680
|
||||
20260413141932,ADAS_S5STNF0T504465N_20260414163318204977_0c640c814bc3,CPTA-LN,50.0,5.0,10,019d9a5d-f609-786e-7cac-da37ebc1ae67
|
||||
20260414182041,ADAS_S5STNF0T406280R_20260415153614565776_6717025a2999,CPTA-RF,50.0,6.5,20,019d9a51-ae0f-7c50-6dfb-9ebe3bd45849
|
||||
20260414181827,ADAS_S5STNF0T406280R_20260415153614565776_a6af70bdfa52,CPTA-RF,50.0,6.5,20,019d9a51-b50b-7acf-6c49-f52dc69a2850
|
||||
20260414181027,ADAS_S5STNF0T406280R_20260415153614565776_ac6a27726e5c,CPTA-RF,50.0,6.5,20,019d9a51-b8cf-7339-595c-1dde3419ee32
|
||||
20260414175932,ADAS_S5STNF0T406280R_20260415153614565776_641a01713a60,CPTA-RF,50.0,6.5,10,019d9a51-cc24-7989-4be4-e3ad8d2aa724
|
||||
20260414175703,ADAS_S5STNF0T406280R_20260415153614565776_2ddbe4a780d2,CPTA-RF,50.0,6.5,10,019d9a51-d078-7764-4942-78794b5f6907
|
||||
20260414175324,ADAS_S5STNF0T406280R_20260415153614565776_423750bdef2c,CPTA-RF,50.0,6.5,10,019d9a51-d672-7605-4f29-b37caa9eae1c
|
||||
20260414173141,ADAS_S5STNF0T406280R_20260415153614565776_6304fc524d71,CSTA-LN,50.0,20.0,10,019d9a51-de91-792b-5301-78dc8837a22a
|
||||
20260414172819,ADAS_S5STNF0T406280R_20260415153614565776_7b6bcdb90977,CSTA-LN,50.0,20.0,10,019d9a51-e518-7bef-6d16-c7ba8b8a2aab
|
||||
20260414171833,ADAS_S5STNF0T406280R_20260415153614565776_0ae4e25121ec,CSTA-LN,50.0,20.0,20,019d9a51-e91f-7b43-7e4d-c687d932dba0
|
||||
20260414170603,ADAS_S5STNF0T406280R_20260415153614565776_c66607e24083,CSTA-LN,50.0,20.0,20,019d9a51-ef9e-7b48-4a73-df674f472c55
|
||||
20260414170224,ADAS_S5STNF0T406280R_20260415153614565776_db50a7ab7485,CSTA-LN,50.0,20.0,20,019d9a51-f683-7a5e-5364-1896e1ca6598
|
||||
20260414165228,ADAS_S5STNF0T406280R_20260415153614565776_94db38de8391,CSTA-LN,50.0,20.0,30,019d9a51-ff2c-7cc2-58c8-05cae8d4ec9e
|
||||
20260414164728,ADAS_S5STNF0T406280R_20260415153614565776_c0b75572b138,CSTA-LN,50.0,20.0,30,019d9a52-04fd-75e5-57f7-54b7dc96246c
|
||||
20260414151451,ADAS_S5STNF0T406280R_20260415153614565776_672a18ed480a,CSTA-LN,50.0,20.0,30,019d9a52-0afa-71e8-6e1c-e534a2850eff
|
||||
20260414141804,ADAS_S5STNF0T406280R_20260415153614565776_593e8310f18f,CSTA-LN,50.0,20.0,10,019d9a52-2237-7843-4407-6cac5ae39635
|
||||
20260414103823,ADAS_S5STNF0T406280R_20260415153614565776_e3a569188ace,CPTA-LF,50.0,6.5,30,019d9a52-5247-719d-6774-a834bc949e33
|
||||
20260414103041,ADAS_S5STNF0T406280R_20260415153614565776_d357ca15a359,CPTA-LF,50.0,6.5,30,019d9a52-5694-7c91-7a0e-072b54ee0879
|
||||
20260414101728,ADAS_S5STNF0T406280R_20260415153614565776_8b3b17c2bee2,CPTA-LN,50.0,5.0,30,019d9a52-5a9a-738a-531b-2e60fa91338a
|
||||
20260414100312,ADAS_S5STNF0T406280R_20260415153614565776_1cd9b9feba23,CPTA-LN,50.0,5.0,30,019d9a52-5e3c-77fc-7644-8b46ab7c192f
|
||||
20260415182950,ADAS_S751NX0Y601865J_20260417101159978228_f3c4f45b6d78,SCPO,无,40.0,FCW50,019d9ad0-974c-72b2-6576-d90453782b51
|
||||
20260415181728,ADAS_S751NX0Y601865J_20260417101159978228_2dcca16a3b4a,SCPO,无,50.0,FCW60,019d9ad0-9f8a-791b-47b1-572744314e8d
|
||||
20260415181449,ADAS_S751NX0Y601865J_20260417101159978228_349202d868d0,SCPO,无,50.0,FCW60,019d9ad0-a733-7e52-4dc3-5974dde5ad99
|
||||
20260415181218,ADAS_S751NX0Y601865J_20260417101159978228_8f80b1fd043d,SCPO,无,50.0,FCW60,019d9ad0-c235-74dc-4c71-dbd7bf6a42fb
|
||||
20260415175852,ADAS_S751NX0Y601865J_20260417101159978228_9ec3b55f6845,SCPO,无,40.0,FCW50,019d9ad0-c6b4-75f7-49ac-215a534b203e
|
||||
20260415175352,ADAS_S751NX0Y601865J_20260417101159978228_66569e4b4cb2,SCPO,无,40.0,FCW50,019d9ad0-cd9a-7dbf-49b5-3f9fb8a2b943
|
||||
20260415170215,ADAS_S751NX0Y601865J_20260417101159978228_a058dd06c98c,SCP,无,40.0,FCW50,019d9ad0-d40c-7f86-4f01-c92465e0cde5
|
||||
20260415161100,ADAS_S751NX0Y601865J_20260417101159978228_56ea31bafe02,SCP,无,50.0,FCW60,019d9ad0-da51-773d-557f-4684de8f8593
|
||||
20260415160711,ADAS_S751NX0Y601865J_20260417101159978228_46aa39158604,SCP,无,50.0,FCW60,019d9ad0-df57-78ff-4590-ebcaaec53aab
|
||||
20260415160405,ADAS_S751NX0Y601865J_20260417101159978228_bee8068c98fc,SCP,无,50.0,FCW60,019d9ad0-e30f-79ed-7a0d-884a4f6c1cd0
|
||||
20260415154024,ADAS_S751NX0Y601865J_20260417101159978228_2f1ade039337,SCP,无,40.0,FCW50,019d9ad0-e757-741a-5156-6385fc72f938
|
||||
20260415153332,ADAS_S751NX0Y601865J_20260417101159978228_3af6ab7e3d9d,SCP,无,40.0,FCW50,019d9ad0-ff56-74ec-7f7a-ca0ea75f8957
|
||||
20260415152337,ADAS_S751NX0Y601865J_20260417101159978228_04a9c20fdd89,SCP,无,30.0,40,019d9ad1-02de-7ebf-7adf-a12148a9ee51
|
||||
20260415152009,ADAS_S751NX0Y601865J_20260417101159978228_6d4572f106f9,SCP,无,30.0,40,019d9ad1-06e0-7a20-4613-411bd3ac6621
|
||||
20260415151432,ADAS_S751NX0Y601865J_20260417101159978228_747d58ffa48f,SCP,无,20.0,30,019d9ad1-0a91-71ea-5da9-c9d7d7dc91b8
|
||||
20260415150905,ADAS_S751NX0Y601865J_20260417101159978228_3e31d0688fc8,SCP,无,20.0,30,019d9ad1-11d0-7099-76b0-aaf48cfd3794
|
||||
20260415104410,ADAS_S751NX0Y601865J_20260417101159978228_ba06434aae58,SCP,无,30.0,40,019d9ad1-1ba5-730a-4504-896c892f8486
|
||||
20260415102130,ADAS_S751NX0Y601865J_20260417101159978228_01906cac8a3a,SCP,无,20.0,30,019d9ad1-300a-7509-7f94-984b56ab2f8b
|
||||
20260416151630,ADAS_S751NX0Y601739V_20260418160638633646_496ebb0a2ff1,CBLA-CN24,25,15.0,FCW80,019db3f6-1d15-718a-724d-bed4c91ba628
|
||||
20260416151431,ADAS_S751NX0Y601739V_20260418160638633646_22612682b9c9,CBLA-CN24,25,15.0,FCW80,019db3f6-2443-7632-47c8-410071836c58
|
||||
20260416151047,ADAS_S751NX0Y601739V_20260418160638633646_8a773af16606,CBLA-CN24,25,15.0,FCW80,019db3f6-2b30-79d4-708d-4b239be1acf2
|
||||
20260416150314,ADAS_S751NX0Y601739V_20260418160638633646_ae0b94f3324a,CBLA-CN24,25,15.0,FCW60,019db3f6-4031-7053-6ba9-b9ff190b8f0c
|
||||
20260416145925,ADAS_S751NX0Y601739V_20260418160638633646_05bb8a06451c,CBLA-CN24,25,15.0,FCW60,019db3f6-47d7-75e8-6251-fd30d96e2abc
|
||||
20260416145727,ADAS_S751NX0Y601739V_20260418160638633646_3a1fb37781a4,CBLA-CN24,25,15.0,FCW60,019db3f6-5171-7b48-5c29-f20016206acf
|
||||
20260416143538,ADAS_S751NX0Y601739V_20260418160638633646_74c05ab76327,CBLA-CN21,25,15.0,FCW80,019db3f6-58e5-767b-72c7-ea46de3a19fe
|
||||
20260416143214,ADAS_S751NX0Y601739V_20260418160638633646_b5a9cd0663a3,CBLA-CN21,25,15.0,FCW80,019db3f6-646a-7e0b-54b1-c6f31a4bc344
|
||||
20260416142947,ADAS_S751NX0Y601739V_20260418160638633646_b4ba81b4492d,CBLA-CN21,25,15.0,FCW80,019db3f6-6db0-70b6-5602-b61e51fb6b00
|
||||
20260416142739,ADAS_S751NX0Y601739V_20260418160638633646_d007dbd1fef6,CBLA-CN21,25,15.0,FCW70,019db3f6-768c-7955-4db7-82fcdc8ecf11
|
||||
20260416142527,ADAS_S751NX0Y601739V_20260418160638633646_cea22e9fc4b2,CBLA-CN21,25,15.0,FCW70,019db3f6-7ceb-7b0d-513e-ddfafe62acc2
|
||||
20260416142206,ADAS_S751NX0Y601739V_20260418160638633646_cea65402d2f0,CBLA-CN21,25,15.0,FCW70,019db3f6-868f-7ceb-6169-86d01d3e09ae
|
||||
20260416141321,ADAS_S751NX0Y601739V_20260418160638633646_9b2070e30a94,CBLA-CN21,25,15.0,FCW60,019db3f6-9c95-7da4-5f42-a598dee5935c
|
||||
20260416141056,ADAS_S751NX0Y601739V_20260418160638633646_05e29a63c4c5,CBLA-CN21,25,15.0,FCW60,019db3f6-a785-77de-6fd3-f841e40d90d9
|
||||
20260416140906,ADAS_S751NX0Y601739V_20260418160638633646_443fc0fdce22,CBLA-CN21,25,15.0,FCW60,019db3f6-b875-77ad-533c-dc77dc3745a2
|
||||
20260416140653,ADAS_S751NX0Y601739V_20260418160638633646_915c24c91174,CBLA-CN21,25,15.0,FCW50,019db3f6-c0e8-714a-7ead-cf6fa750249c
|
||||
20260416140423,ADAS_S751NX0Y601739V_20260418160638633646_3727f5ceb78c,CBLA-CN21,25,15.0,FCW50,019db3f6-c84c-7b3a-4cf3-65ebf97ca2db
|
||||
20260416140135,ADAS_S751NX0Y601739V_20260418160638633646_aad58490855a,CBLA-CN21,25,15.0,FCW50,019db3f6-ce3f-707c-718b-b7c1cd4c072b
|
||||
|
3248
tools/model_inference/examples/events/G1Q3_场地评测数据集.json
Executable file
3248
tools/model_inference/examples/events/G1Q3_场地评测数据集.json
Executable file
File diff suppressed because it is too large
Load Diff
109
tools/model_inference/examples/events/G1Q3_场地评测数据集_0418.csv
Executable file
109
tools/model_inference/examples/events/G1Q3_场地评测数据集_0418.csv
Executable file
@@ -0,0 +1,109 @@
|
||||
datetime,rawid,scene,offset,gvt_speed,vut_speed,event_uuid
|
||||
20260421165302,ADAS_S5STNF0T406280R_20260424143102910957_204c5679f12e,CCRH,1,0,FCW120,019dbea9-1a38-7b40-7f39-314eb07bb76d
|
||||
20260421165124,ADAS_S5STNF0T406280R_20260424143102910957_9ee9ec2148e8,CCRH,1,0,FCW120,019dbea9-3cdf-7953-719f-bdd635eaffa4
|
||||
20260421164943,ADAS_S5STNF0T406280R_20260424143102910957_860409653c26,CCRH,1,0,FCW120,019dbea9-53fc-75a6-6178-0696b63de01b
|
||||
20260421163804,ADAS_S5STNF0T406280R_20260424143102910957_0939f3645d9c,CCRH,1,0,FCW80,019dbea9-6851-7511-44ce-36554aac6a91
|
||||
20260421163319,ADAS_S5STNF0T406280R_20260424143102910957_7a307c148cd7,CCRH,1,0,FCW80,019dbea9-7ef5-73fd-5eb4-5761dd42efa8
|
||||
20260421163154,ADAS_S5STNF0T406280R_20260424143102910957_8af71c24686e,CCRH,1,0,FCW80,019dbea9-9726-776f-7b82-5e47ac6e3e1a
|
||||
20260422170800,ADAS_S5STNF0T406280R_20260424143102910957_3528d22515d5,CCRS,100,0,60,019dbeaf-da0e-7a1f-6a2a-969f12e4f13a
|
||||
20260422170403,ADAS_S5STNF0T406280R_20260424143102910957_4f20967658ae,CCRS,100,0,60,019dbeaf-dee9-741e-7ca9-1ba865c1f42e
|
||||
20260422170238,ADAS_S5STNF0T406280R_20260424143102910957_ce36b7f1153a,CCRS,100,0,60,019dbea9-b946-7511-43c3-dfbbbf251e52
|
||||
20260422170012,ADAS_S5STNF0T406280R_20260424143102910957_6a5f70646a16,CCRS,100,0,50,019dbea9-cf85-7fad-5974-6901a134cd38
|
||||
20260422165842,ADAS_S5STNF0T406280R_20260424143102910957_e674d9eb9568,CCRS,100,0,50,019dbea9-e0b6-7c9b-7aae-71cf080d1d3f
|
||||
20260422165644,ADAS_S5STNF0T406280R_20260424143102910957_80c60d6f3899,CCRS,100,0,50,019dbea9-f321-7d7d-7907-7306457108bf
|
||||
20260422164009,ADAS_S5STNF0T406280R_20260424143102910957_aa662fd0c24f,CCRS,100,0,40,019dbeaf-e3a0-756b-569d-fa627af56012
|
||||
20260422163835,ADAS_S5STNF0T406280R_20260424143102910957_d284665c509f,CCRS,100,0,40,019dbeaf-e894-7f6a-7124-e8d7fbb05a27
|
||||
20260422163615,ADAS_S5STNF0T406280R_20260424143102910957_b29f69764a66,CCRS,100,0,40,019dbeaa-1d36-77ee-4f61-80890f46d39c
|
||||
20260422161227,ADAS_S5STNF0T406280R_20260424143102910957_62a21a126fce,CCFT,50,20,10,019dbeaa-32bf-7cb9-6e82-d07fcb21f35a
|
||||
20260422160038,ADAS_S5STNF0T406280R_20260424143102910957_756cc10c0a71,CCFT,50,50,30,019dbeaa-413d-75ab-4282-686838393490
|
||||
20260422144136,ADAS_S5STNF0T406280R_20260424143102910957_25e2161254d7,CCFT,50,50,30,019dbeaa-4c1f-7c61-7690-6cfd14ef779c
|
||||
20260422143535,ADAS_S5STNF0T406280R_20260424143102910957_938ec4fd825a,CCFT,50,40,20,019dbeaa-58a1-7223-5799-940f1fab38ba
|
||||
20260422143045,ADAS_S5STNF0T406280R_20260424143102910957_8ccfd8c3fadd,CCFT,50,40,20,019dbeaa-707b-7bc3-778f-bed824c3f151
|
||||
20260422141143,ADAS_S5STNF0T406280R_20260424143102910957_6e6acb788fea,CCFT,50,20,10,019dbeaa-80d4-7a80-6d84-b805e7b8c0e6
|
||||
20260422114602,ADAS_S5STNF0T406280R_20260424143102910957_b52d53dd07cb,CCFT,50,20,10,019dbeaa-966c-7486-4d54-8856c274ce50
|
||||
20260423165539,ADAS_S751NX0Y601865J_20260425160638282353_5bdad74f0035,CBLA-CN21,25,15,FCW70,019dccc4-42ba-78f2-437c-cead7d452568
|
||||
20260423165159,ADAS_S751NX0Y601865J_20260425160638282353_a75bd09b1591,CBLA-CN21,25,15,FCW70,019dccc4-4f20-74d5-5edf-eb7d119270f6
|
||||
20260423164643,ADAS_S751NX0Y601865J_20260425160638282353_f02011f6fb51,CBLA-CN21,25,15,FCW50,019dccc4-5631-7267-6580-8f55c03f3269
|
||||
20260423164406,ADAS_S751NX0Y601865J_20260425160638282353_33f47ad79ea4,CBLA-CN21,25,15,FCW50,019dccc4-5b35-7459-4097-554fc6c58621
|
||||
20260423164220,ADAS_S751NX0Y601865J_20260425160638282353_3422d076b4b4,CBLA-cn21,50,15,60,019dccc9-2623-7a08-5135-e78a8ece105c
|
||||
20260423163827,ADAS_S751NX0Y601865J_20260425160638282353_8552d0859d87,CBLA-cn21,50,15,60,019dccc9-2d6d-799b-6d2d-6bb572d2a18a
|
||||
20260423163640,ADAS_S751NX0Y601865J_20260425160638282353_2516f29f235f,CBLA-cn21,50,15,50,019dccc9-33f1-7629-4370-462c8a5453ab
|
||||
20260423162521,ADAS_S751NX0Y601865J_20260425160638282353_44e04f0525e9,CBLA-cn21,50,15,50,019dccc9-3a1c-7c5c-67aa-40d06b7b2555
|
||||
20260423161011,ADAS_S751NX0Y601865J_20260425160638282353_3c486812721a,CBLA-cn24,25,15,40,019dccc9-4260-7ada-54fb-d395c275092b
|
||||
20260423160753,ADAS_S751NX0Y601865J_20260425160638282353_eb521054a5e7,CBLA-cn24,25,15,40,019dccc9-46d3-7e58-5c42-8ee8778fb98b
|
||||
20260423160611,ADAS_S751NX0Y601865J_20260425160638282353_805ec2d6dfb9,CBLA-cn24,25,15,40,019dccc9-4aeb-7fdf-5a01-1c4da8d9c268
|
||||
20260423160427,ADAS_S751NX0Y601865J_20260425160638282353_45d1afad713c,CBLA-cn24,25,15,20,019dccc9-4f0c-7a16-6f4a-8d9801f93347
|
||||
20260423160241,ADAS_S751NX0Y601865J_20260425160638282353_6281b7a1ec03,CBLA-cn24,25,15,20,019dccc9-5ab3-7a88-4fb6-fafd066195ae
|
||||
20260423160005,ADAS_S751NX0Y601865J_20260425160638282353_3499529a30c5,CBLA-cn24,25,15,20,019dccc9-6081-76fa-6fe3-3bc9870efadd
|
||||
20260423152501,ADAS_S751NX0Y601865J_20260425160638282353_7fe834d1e141,CCRM,-50,20,FCW80,019dccc9-64bd-760d-5587-e2d5c0557773
|
||||
20260423152049,ADAS_S751NX0Y601865J_20260425160638282353_5583953c59cd,CCRM,-50,20,FCW80,019dccc9-6b06-7bac-7867-82ff6caf6f8b
|
||||
20260423151903,ADAS_S751NX0Y601865J_20260425160638282353_45bdf88fa7e2,CCRM,-50,20,FCW80,019dccc9-6f22-7790-538b-7eb0bba8e8a7
|
||||
20260423151053,ADAS_S751NX0Y601865J_20260425160638282353_6921d44c9df1,CCRS,-50,0,FCW80,019dccc9-74e3-781f-5d3f-70bdb67ec4b6
|
||||
20260423145748,ADAS_S751NX0Y601865J_20260425160638282353_2a6786176fb4,CCRS,-50,0,FCW80,019dccc9-78c5-7a99-44c5-20d499c1ad1b
|
||||
20260424165609,ADAS_S751NX0Y601739V_20260426105646474483_8e3ef1dd2b95,CPLA,50,5,50,019dccc9-a412-7274-4b69-3dfcf9b1c751
|
||||
20260424165355,ADAS_S751NX0Y601739V_20260426105646474483_d71e1fcdd716,CPLA,50,5,50,019dccc9-a7c9-7911-6c96-1b3a8e53e08a
|
||||
20260424164838,ADAS_S751NX0Y601739V_20260426105646474483_8674df9f7e6c,CPLA,25,5,FCW50,019dccc9-abad-7dc9-5311-d4b4cfc6c996
|
||||
20260424163138,ADAS_S751NX0Y601739V_20260426105646474483_d56ab481858d,CPLA,25,5,FCW50,019dccc9-b70a-7a64-79d4-7d74b3c29504
|
||||
20260424161735,ADAS_S751NX0Y601739V_20260426105646474483_f40e70b67ad5,CPLA-cn24,25,5,FCW80,019dccda-0a48-775a-4b49-31e4f52ac800
|
||||
20260424160918,ADAS_S751NX0Y601739V_20260426105646474483_c3ab74ad2582,CPLA-cn24,25,5,FCW80,019dccda-0fb5-7040-60fb-5b6eb0340c90
|
||||
20260424160557,ADAS_S751NX0Y601739V_20260426105646474483_280ec474f1e7,CPLA-cn24,25,5,FCW80,019dccda-1b52-7d2c-4e20-ba87c5fb8906
|
||||
20260424160317,ADAS_S751NX0Y601739V_20260426105646474483_3c471e2b551e,CPLA-cn24,25,5,FCW60,019dccda-22b4-7590-5a90-9d93d91a62a2
|
||||
20260424155607,ADAS_S751NX0Y601739V_20260426105646474483_b13af5e369e4,CPLA-cn24,25,5,FCW60,019dccda-2b1b-7ce0-5f11-067ff68c180c
|
||||
20260424155333,ADAS_S751NX0Y601739V_20260426105646474483_37703d761455,CPLA-cn24,25,5,FCW60,019dccda-2fa3-7c8a-5efc-9c1a06ab60df
|
||||
20260424151547,ADAS_S751NX0Y601739V_20260426105646474483_9c30cae5f806,CPLA-cn24,25,5,40,019dccda-3b7a-7225-6d4a-3549aec142a2
|
||||
20260424151208,ADAS_S751NX0Y601739V_20260426105646474483_03d95f1a0bea,CPLA-cn24,25,5,40,019dccda-4335-7c87-6432-c8a061772dcf
|
||||
20260424150237,ADAS_S751NX0Y601739V_20260426105646474483_68b9be51b240,CPLA-cn24,25,5,40,019dccda-4853-7b14-79a3-686c976fec99
|
||||
20260424145815,ADAS_S751NX0Y601739V_20260426105646474483_ab99d7f496b7,CPLA-cn24,25,5,20,019dccda-4be8-7f2e-474c-83483bb86d61
|
||||
20260424145646,ADAS_S751NX0Y601739V_20260426105646474483_9d9f4f81d58b,CPLA-cn24,25,5,20,019dccda-4ff1-7e09-79bc-0248f385c3a3
|
||||
20260424145409,ADAS_S751NX0Y601739V_20260426105646474483_6ed854132275,CPLA-cn24,25,5,20,019dccda-56e1-74eb-59b8-bbdef5b2eebd
|
||||
20260424103224,ADAS_S751NX0Y601739V_20260426105646474483_dea4e64065d5,SCP,无,20,30,019dccc9-bc95-7c6f-7252-394628471d0b
|
||||
20260425170806,ADAS_S5STNF0T504465N_20260427141205368130_fa832c22f1d0,CPTA-LN,50,5,20,019dd420-c6c2-730a-6c14-f4513669fe8d
|
||||
20260425170149,ADAS_S5STNF0T504465N_20260427141205368130_a199460fdb86,CPTA-LN,50,5,20,019dd420-cbaa-7367-5680-dd3cbbebfabc
|
||||
20260425150005,ADAS_S5STNF0T504465N_20260427141205368130_66e67c5c39be,SCP,无,20,30,019dd420-d37c-7f00-7fa5-b50f8ed72220
|
||||
20260425145813,ADAS_S5STNF0T504465N_20260427141205368130_67fee0b894e5,SCP,无,20,30,019dd420-dbca-73d4-632b-e5f65ee08add
|
||||
20260425144953,ADAS_S5STNF0T504465N_20260427141205368130_30d3364724be,SCP,无,50,FCW60,019dd420-e730-7c1b-6a2a-1f28c5abdb31
|
||||
20260425144737,ADAS_S5STNF0T504465N_20260427141205368130_50a3ef4039ec,SCP,无,50,FCW60,019dd420-ebf5-7295-7605-ee83309a5f9a
|
||||
20260425114942,ADAS_S5STNF0T504465N_20260427141205368130_3f7cd5c01537,SCP,无,40,FCW50,019dd420-f18a-7452-7541-0c5b8d67bfd8
|
||||
20260425111856,ADAS_S5STNF0T504465N_20260427141205368130_992eed63acec,SCP,无,40,FCW50,019dd420-f854-7547-7783-f5ea609d92ca
|
||||
20260425111443,ADAS_S5STNF0T504465N_20260427141205368130_de3c37dc6e75,SCP,无,30,40,019dd420-fd1f-7b3c-6e3f-8f7bcea6321a
|
||||
20260425111027,ADAS_S5STNF0T504465N_20260427141205368130_2cc5c5469141,SCP,无,30,40,019dd421-0260-749a-7b6a-5fdac9e9be44
|
||||
20260425105940,ADAS_S5STNF0T504465N_20260427141205368130_680a33a5f78d,SCP,无,30,40,019dd421-0cb0-7578-62fc-7c2e0d42510b
|
||||
20260426161459,ADAS_S751NX0Y800506T_20260428123042509470_29327584d51d,CBLA-CN21,25,15,FCW70,019dd421-4b69-71ac-6a32-ec788393fe4f
|
||||
20260426160008,ADAS_S751NX0Y800506T_20260428123042509470_d69768e25615,CBLA-CN21,25,15,FCW50,019dd421-645f-739b-4fcb-863735ace841
|
||||
20260426154615,ADAS_S751NX0Y800506T_20260428123042509470_f2c5d47738ad,CBLA-cn21,50,15,60,019dd421-8101-7018-57ce-9bcae8c008fc
|
||||
20260426153534,ADAS_S751NX0Y800506T_20260428123042509470_0b8deed3ca4d,CBLA-cn21,50,15,50,019dd421-94b9-7cd3-4834-5592601312c0
|
||||
20260426141443,ADAS_S751NX0Y800506T_20260428123042509470_4f816e7e320a,CCFT,50,50,30,019dd421-bf6a-74e2-68ca-a2909e8b8a35
|
||||
20260426114522,ADAS_S751NX0Y800506T_20260428123042509470_3d725df8d10d,CCFT,50,40,20,019dd421-e1cb-7419-51dc-df1018d64664
|
||||
20260426104816,ADAS_S751NX0Y800506T_20260428123042509470_a7a13aaeb441,CCRS,-50,0,FCW80,019dd422-12d1-70f3-6418-629a09bf7d03
|
||||
20260429180444,ADAS_S751NX0Y601739V_20260503105236841267_2c1473b10dc6,CPLA,25,5,FCW50,019df6ed-cd2f-7d2a-688c-713c0cd6307b
|
||||
20260429165306,ADAS_S751NX0Y601739V_20260503105236841267_f18094de4d8a,CPLA,50,5,50,019df6ed-e11b-7e3b-5f6b-0f23c224f66a
|
||||
20260429161841,ADAS_S751NX0Y601739V_20260503105236841267_8e07fc3208b9,CPTA-LF,50,6.5,10,019df6ee-0264-79f2-57fd-83608f1eaac6
|
||||
20260429161528,ADAS_S751NX0Y601739V_20260503105236841267_7123bd12f35b,CPTA-LF,50,6.5,10,019df6ee-0867-7e44-5000-7873beef8dbf
|
||||
20260429161021,ADAS_S751NX0Y601739V_20260503105236841267_f06682f85f33,CPTA-LF,50,6.5,10,019df6ee-0f73-7c90-6196-7fc08cad2f73
|
||||
20260429155038,ADAS_S751NX0Y601739V_20260503105236841267_4ef26aabdfae,CPTA-RF,50,6.5,20,019df6ee-14d6-7a13-44dc-63f353943186
|
||||
20260429154600,ADAS_S751NX0Y601739V_20260503105236841267_0d79d3d7a9d6,CPTA-RF,50,6.5,20,019df6ee-1d07-776e-72ed-af1ba59c76cd
|
||||
20260429153237,ADAS_S751NX0Y601739V_20260503105236841267_9d1716a5f582,CPTA-RF,50,6.5,20,019df6ee-24e0-776f-7ddd-0c65b8c01d24
|
||||
20260429144733,ADAS_S751NX0Y601739V_20260503105236841267_6f3c74447dec,CPTA-RF,50,6.5,10,019df6ee-35ea-7bb1-6be8-2497aa23f1ad
|
||||
20260429114321,ADAS_S751NX0Y601739V_20260503105236841267_6ffeb9a156eb,CPTA-RF,50,6.5,10,019df6ee-4aa8-7aa6-5523-8d0fa6384228
|
||||
20260429113635,ADAS_S751NX0Y601739V_20260503105236841267_5b68e94bafac,CPTA-RF,50,6.5,10,019df6ee-540f-7bcc-5f7d-7ef249177de0
|
||||
20260429111506,ADAS_S751NX0Y601739V_20260503105236841267_0457ce74ada2,CPTA-LF,50,6.5,30,019df6ee-5ba6-7db0-7a20-561fe03286eb
|
||||
20260429110130,ADAS_S751NX0Y601739V_20260503105236841267_f41dbf7a1fe0,CPTA-LF,50,6.5,30,019df6ee-60a1-77ad-4835-dc7259d65576
|
||||
20260429105306,ADAS_S751NX0Y601739V_20260503105236841267_ffd6b1c17fb7,CPTA-LF,50,6.5,20,019df6ee-6875-7fd8-75de-9bf342def9c8
|
||||
20260429105051,ADAS_S751NX0Y601739V_20260503105236841267_5f6244be6752,CPTA-LF,50,6.5,20,019df6ee-6e42-74f3-5be5-ca793f9ee226
|
||||
20260429104840,ADAS_S751NX0Y601739V_20260503105236841267_040dab1b6462,CPTA-LF,50,6.5,20,019df6ee-7437-7302-4e6b-706646d57c53
|
||||
20260430005758,ADAS_S751NX0Y601739V_20260503105236841267_d43542536f95,CPLA-夜晚CN24,25,5,FCW80,019df6ee-a134-7901-60db-81d81b60998d
|
||||
20260430005628,ADAS_S751NX0Y601739V_20260503105236841267_068362143e80,CPLA-夜晚CN24,25,5,FCW80,019df6ee-a686-7c25-563d-67b25298af0b
|
||||
20260430005353,ADAS_S751NX0Y601739V_20260503105236841267_4e13f3cedc71,CPLA-夜晚CN24,25,5,FCW80,019df6ee-ab74-7a6c-4f75-97bcb5245fda
|
||||
20260430005034,ADAS_S751NX0Y601739V_20260503105236841267_99a915ec4784,CPLA-夜晚CN24,25,5,FCW60,019df6ee-b2f0-7a73-74c6-80c472bcc5df
|
||||
20260430004703,ADAS_S751NX0Y601739V_20260503105236841267_0061760569c9,CPLA-夜晚CN24,25,5,FCW60,019df6ee-b7ee-78e6-7ae0-3ae241457e06
|
||||
20260430004432,ADAS_S751NX0Y601739V_20260503105236841267_07bca13ed759,CPLA-夜晚CN24,25,5,FCW60,019df6ee-be7e-7a34-61e5-b77877c546eb
|
||||
20260430004247,ADAS_S751NX0Y601739V_20260503105236841267_1f3320ce38ac,CPLA-夜晚CN24,25,5,40,019df6ee-c4de-7e59-4f5c-16b4261d77f4
|
||||
20260430003934,ADAS_S751NX0Y601739V_20260503105236841267_82443933fdee,CPLA-夜晚CN24,25,5,40,019df6ee-d00c-7e28-45c3-b1d1890ec640
|
||||
20260430003725,ADAS_S751NX0Y601739V_20260503105236841267_bd901e7e8041,CPLA-夜晚CN24,25,5,20,019df6ee-d6e5-7e20-642d-7921e54619e2
|
||||
20260430003547,ADAS_S751NX0Y601739V_20260503105236841267_070e814ef27e,CPLA-夜晚CN24,25,5,20,019df6ee-db3c-764a-46e5-5a2a8495b08a
|
||||
20260430003302,ADAS_S751NX0Y601739V_20260503105236841267_dc73a4d2ec69,CPLA-夜晚CN24,25,5,20,019df6ee-e1ba-7c15-7559-2f32ecf76326
|
||||
20260430002426,ADAS_S751NX0Y601739V_20260503105236841267_1506a8d8eda5,CPLA-夜晚,25,5,FCW80,019df6ee-e7fc-785e-65c0-39403838db31
|
||||
20260430002127,ADAS_S751NX0Y601739V_20260503105236841267_04b9a81743fc,CPLA-夜晚,25,5,FCW80,019df6ee-efae-7fed-7023-82bf07447393
|
||||
20260430001509,ADAS_S751NX0Y601739V_20260503105236841267_6df59d151cb4,CPLA-夜晚,25,5,FCW70,019df6ee-f551-7a5b-78c6-4f03848a2b68
|
||||
20260430001258,ADAS_S751NX0Y601739V_20260503105236841267_8b8b37938873,CPLA-夜晚,25,5,FCW70,019df6ee-f985-7317-4f86-c5fdd56f8f48
|
||||
20260430000414,ADAS_S751NX0Y601739V_20260503105236841267_b8fed19cc042,CPLA-夜晚,25,5,FCW60,019df6ee-fef4-7d3c-4a4c-c52f722c8e00
|
||||
|
896
tools/model_inference/examples/events/G1Q3_场地评测数据集_0418.json
Executable file
896
tools/model_inference/examples/events/G1Q3_场地评测数据集_0418.json
Executable file
@@ -0,0 +1,896 @@
|
||||
{
|
||||
"CCRH": [
|
||||
{
|
||||
"datetime": "20260421165302",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_204c5679f12e",
|
||||
"offset": "1",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW120",
|
||||
"event_uuid": "019dbea9-1a38-7b40-7f39-314eb07bb76d"
|
||||
},
|
||||
{
|
||||
"datetime": "20260421165124",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_9ee9ec2148e8",
|
||||
"offset": "1",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW120",
|
||||
"event_uuid": "019dbea9-3cdf-7953-719f-bdd635eaffa4"
|
||||
},
|
||||
{
|
||||
"datetime": "20260421164943",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_860409653c26",
|
||||
"offset": "1",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW120",
|
||||
"event_uuid": "019dbea9-53fc-75a6-6178-0696b63de01b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260421163804",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_0939f3645d9c",
|
||||
"offset": "1",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dbea9-6851-7511-44ce-36554aac6a91"
|
||||
},
|
||||
{
|
||||
"datetime": "20260421163319",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_7a307c148cd7",
|
||||
"offset": "1",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dbea9-7ef5-73fd-5eb4-5761dd42efa8"
|
||||
},
|
||||
{
|
||||
"datetime": "20260421163154",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_8af71c24686e",
|
||||
"offset": "1",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dbea9-9726-776f-7b82-5e47ac6e3e1a"
|
||||
}
|
||||
],
|
||||
"CCRS": [
|
||||
{
|
||||
"datetime": "20260422170800",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_3528d22515d5",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "60",
|
||||
"event_uuid": "019dbeaf-da0e-7a1f-6a2a-969f12e4f13a"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422170403",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_4f20967658ae",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "60",
|
||||
"event_uuid": "019dbeaf-dee9-741e-7ca9-1ba865c1f42e"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422170238",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_ce36b7f1153a",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "60",
|
||||
"event_uuid": "019dbea9-b946-7511-43c3-dfbbbf251e52"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422170012",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_6a5f70646a16",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dbea9-cf85-7fad-5974-6901a134cd38"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422165842",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_e674d9eb9568",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dbea9-e0b6-7c9b-7aae-71cf080d1d3f"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422165644",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_80c60d6f3899",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dbea9-f321-7d7d-7907-7306457108bf"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422164009",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_aa662fd0c24f",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dbeaf-e3a0-756b-569d-fa627af56012"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422163835",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_d284665c509f",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dbeaf-e894-7f6a-7124-e8d7fbb05a27"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422163615",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_b29f69764a66",
|
||||
"offset": "100",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dbeaa-1d36-77ee-4f61-80890f46d39c"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423151053",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_6921d44c9df1",
|
||||
"offset": "-50",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccc9-74e3-781f-5d3f-70bdb67ec4b6"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423145748",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_2a6786176fb4",
|
||||
"offset": "-50",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccc9-78c5-7a99-44c5-20d499c1ad1b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260426104816",
|
||||
"rawid": "ADAS_S751NX0Y800506T_20260428123042509470_a7a13aaeb441",
|
||||
"offset": "-50",
|
||||
"gvt_speed": "0",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dd422-12d1-70f3-6418-629a09bf7d03"
|
||||
}
|
||||
],
|
||||
"CCFT": [
|
||||
{
|
||||
"datetime": "20260422161227",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_62a21a126fce",
|
||||
"offset": "50",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019dbeaa-32bf-7cb9-6e82-d07fcb21f35a"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422160038",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_756cc10c0a71",
|
||||
"offset": "50",
|
||||
"gvt_speed": "50",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019dbeaa-413d-75ab-4282-686838393490"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422144136",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_25e2161254d7",
|
||||
"offset": "50",
|
||||
"gvt_speed": "50",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019dbeaa-4c1f-7c61-7690-6cfd14ef779c"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422143535",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_938ec4fd825a",
|
||||
"offset": "50",
|
||||
"gvt_speed": "40",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dbeaa-58a1-7223-5799-940f1fab38ba"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422143045",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_8ccfd8c3fadd",
|
||||
"offset": "50",
|
||||
"gvt_speed": "40",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dbeaa-707b-7bc3-778f-bed824c3f151"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422141143",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_6e6acb788fea",
|
||||
"offset": "50",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019dbeaa-80d4-7a80-6d84-b805e7b8c0e6"
|
||||
},
|
||||
{
|
||||
"datetime": "20260422114602",
|
||||
"rawid": "ADAS_S5STNF0T406280R_20260424143102910957_b52d53dd07cb",
|
||||
"offset": "50",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019dbeaa-966c-7486-4d54-8856c274ce50"
|
||||
},
|
||||
{
|
||||
"datetime": "20260426141443",
|
||||
"rawid": "ADAS_S751NX0Y800506T_20260428123042509470_4f816e7e320a",
|
||||
"offset": "50",
|
||||
"gvt_speed": "50",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019dd421-bf6a-74e2-68ca-a2909e8b8a35"
|
||||
},
|
||||
{
|
||||
"datetime": "20260426114522",
|
||||
"rawid": "ADAS_S751NX0Y800506T_20260428123042509470_3d725df8d10d",
|
||||
"offset": "50",
|
||||
"gvt_speed": "40",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dd421-e1cb-7419-51dc-df1018d64664"
|
||||
}
|
||||
],
|
||||
"CBLA-CN21": [
|
||||
{
|
||||
"datetime": "20260423165539",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_5bdad74f0035",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "FCW70",
|
||||
"event_uuid": "019dccc4-42ba-78f2-437c-cead7d452568"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423165159",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_a75bd09b1591",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "FCW70",
|
||||
"event_uuid": "019dccc4-4f20-74d5-5edf-eb7d119270f6"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423164643",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_f02011f6fb51",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019dccc4-5631-7267-6580-8f55c03f3269"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423164406",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_33f47ad79ea4",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019dccc4-5b35-7459-4097-554fc6c58621"
|
||||
},
|
||||
{
|
||||
"datetime": "20260426161459",
|
||||
"rawid": "ADAS_S751NX0Y800506T_20260428123042509470_29327584d51d",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "FCW70",
|
||||
"event_uuid": "019dd421-4b69-71ac-6a32-ec788393fe4f"
|
||||
},
|
||||
{
|
||||
"datetime": "20260426160008",
|
||||
"rawid": "ADAS_S751NX0Y800506T_20260428123042509470_d69768e25615",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019dd421-645f-739b-4fcb-863735ace841"
|
||||
}
|
||||
],
|
||||
"CBLA-cn21": [
|
||||
{
|
||||
"datetime": "20260423164220",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_3422d076b4b4",
|
||||
"offset": "50",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "60",
|
||||
"event_uuid": "019dccc9-2623-7a08-5135-e78a8ece105c"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423163827",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_8552d0859d87",
|
||||
"offset": "50",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "60",
|
||||
"event_uuid": "019dccc9-2d6d-799b-6d2d-6bb572d2a18a"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423163640",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_2516f29f235f",
|
||||
"offset": "50",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dccc9-33f1-7629-4370-462c8a5453ab"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423162521",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_44e04f0525e9",
|
||||
"offset": "50",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dccc9-3a1c-7c5c-67aa-40d06b7b2555"
|
||||
},
|
||||
{
|
||||
"datetime": "20260426154615",
|
||||
"rawid": "ADAS_S751NX0Y800506T_20260428123042509470_f2c5d47738ad",
|
||||
"offset": "50",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "60",
|
||||
"event_uuid": "019dd421-8101-7018-57ce-9bcae8c008fc"
|
||||
},
|
||||
{
|
||||
"datetime": "20260426153534",
|
||||
"rawid": "ADAS_S751NX0Y800506T_20260428123042509470_0b8deed3ca4d",
|
||||
"offset": "50",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dd421-94b9-7cd3-4834-5592601312c0"
|
||||
}
|
||||
],
|
||||
"CBLA-cn24": [
|
||||
{
|
||||
"datetime": "20260423161011",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_3c486812721a",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dccc9-4260-7ada-54fb-d395c275092b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423160753",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_eb521054a5e7",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dccc9-46d3-7e58-5c42-8ee8778fb98b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423160611",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_805ec2d6dfb9",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dccc9-4aeb-7fdf-5a01-1c4da8d9c268"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423160427",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_45d1afad713c",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dccc9-4f0c-7a16-6f4a-8d9801f93347"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423160241",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_6281b7a1ec03",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dccc9-5ab3-7a88-4fb6-fafd066195ae"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423160005",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_3499529a30c5",
|
||||
"offset": "25",
|
||||
"gvt_speed": "15",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dccc9-6081-76fa-6fe3-3bc9870efadd"
|
||||
}
|
||||
],
|
||||
"CCRM": [
|
||||
{
|
||||
"datetime": "20260423152501",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_7fe834d1e141",
|
||||
"offset": "-50",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccc9-64bd-760d-5587-e2d5c0557773"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423152049",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_5583953c59cd",
|
||||
"offset": "-50",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccc9-6b06-7bac-7867-82ff6caf6f8b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260423151903",
|
||||
"rawid": "ADAS_S751NX0Y601865J_20260425160638282353_45bdf88fa7e2",
|
||||
"offset": "-50",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccc9-6f22-7790-538b-7eb0bba8e8a7"
|
||||
}
|
||||
],
|
||||
"CPLA": [
|
||||
{
|
||||
"datetime": "20260424165609",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_8e3ef1dd2b95",
|
||||
"offset": "50",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dccc9-a412-7274-4b69-3dfcf9b1c751"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424165355",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_d71e1fcdd716",
|
||||
"offset": "50",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019dccc9-a7c9-7911-6c96-1b3a8e53e08a"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424164838",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_8674df9f7e6c",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019dccc9-abad-7dc9-5311-d4b4cfc6c996"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424163138",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_d56ab481858d",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019dccc9-b70a-7a64-79d4-7d74b3c29504"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429180444",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_2c1473b10dc6",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019df6ed-cd2f-7d2a-688c-713c0cd6307b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429165306",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_f18094de4d8a",
|
||||
"offset": "50",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "50",
|
||||
"event_uuid": "019df6ed-e11b-7e3b-5f6b-0f23c224f66a"
|
||||
}
|
||||
],
|
||||
"CPLA-cn24": [
|
||||
{
|
||||
"datetime": "20260424161735",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_f40e70b67ad5",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccda-0a48-775a-4b49-31e4f52ac800"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424160918",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_c3ab74ad2582",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccda-0fb5-7040-60fb-5b6eb0340c90"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424160557",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_280ec474f1e7",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019dccda-1b52-7d2c-4e20-ba87c5fb8906"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424160317",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_3c471e2b551e",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019dccda-22b4-7590-5a90-9d93d91a62a2"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424155607",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_b13af5e369e4",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019dccda-2b1b-7ce0-5f11-067ff68c180c"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424155333",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_37703d761455",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019dccda-2fa3-7c8a-5efc-9c1a06ab60df"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424151547",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_9c30cae5f806",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dccda-3b7a-7225-6d4a-3549aec142a2"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424151208",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_03d95f1a0bea",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dccda-4335-7c87-6432-c8a061772dcf"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424150237",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_68b9be51b240",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dccda-4853-7b14-79a3-686c976fec99"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424145815",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_ab99d7f496b7",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dccda-4be8-7f2e-474c-83483bb86d61"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424145646",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_9d9f4f81d58b",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dccda-4ff1-7e09-79bc-0248f385c3a3"
|
||||
},
|
||||
{
|
||||
"datetime": "20260424145409",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_6ed854132275",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dccda-56e1-74eb-59b8-bbdef5b2eebd"
|
||||
}
|
||||
],
|
||||
"SCP": [
|
||||
{
|
||||
"datetime": "20260424103224",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260426105646474483_dea4e64065d5",
|
||||
"offset": "无",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019dccc9-bc95-7c6f-7252-394628471d0b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425150005",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_66e67c5c39be",
|
||||
"offset": "无",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019dd420-d37c-7f00-7fa5-b50f8ed72220"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425145813",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_67fee0b894e5",
|
||||
"offset": "无",
|
||||
"gvt_speed": "20",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019dd420-dbca-73d4-632b-e5f65ee08add"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425144953",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_30d3364724be",
|
||||
"offset": "无",
|
||||
"gvt_speed": "50",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019dd420-e730-7c1b-6a2a-1f28c5abdb31"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425144737",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_50a3ef4039ec",
|
||||
"offset": "无",
|
||||
"gvt_speed": "50",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019dd420-ebf5-7295-7605-ee83309a5f9a"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425114942",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_3f7cd5c01537",
|
||||
"offset": "无",
|
||||
"gvt_speed": "40",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019dd420-f18a-7452-7541-0c5b8d67bfd8"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425111856",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_992eed63acec",
|
||||
"offset": "无",
|
||||
"gvt_speed": "40",
|
||||
"vut_speed": "FCW50",
|
||||
"event_uuid": "019dd420-f854-7547-7783-f5ea609d92ca"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425111443",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_de3c37dc6e75",
|
||||
"offset": "无",
|
||||
"gvt_speed": "30",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dd420-fd1f-7b3c-6e3f-8f7bcea6321a"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425111027",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_2cc5c5469141",
|
||||
"offset": "无",
|
||||
"gvt_speed": "30",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dd421-0260-749a-7b6a-5fdac9e9be44"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425105940",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_680a33a5f78d",
|
||||
"offset": "无",
|
||||
"gvt_speed": "30",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019dd421-0cb0-7578-62fc-7c2e0d42510b"
|
||||
}
|
||||
],
|
||||
"CPTA-LN": [
|
||||
{
|
||||
"datetime": "20260425170806",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_fa832c22f1d0",
|
||||
"offset": "50",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dd420-c6c2-730a-6c14-f4513669fe8d"
|
||||
},
|
||||
{
|
||||
"datetime": "20260425170149",
|
||||
"rawid": "ADAS_S5STNF0T504465N_20260427141205368130_a199460fdb86",
|
||||
"offset": "50",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019dd420-cbaa-7367-5680-dd3cbbebfabc"
|
||||
}
|
||||
],
|
||||
"CPTA-LF": [
|
||||
{
|
||||
"datetime": "20260429161841",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_8e07fc3208b9",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019df6ee-0264-79f2-57fd-83608f1eaac6"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429161528",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_7123bd12f35b",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019df6ee-0867-7e44-5000-7873beef8dbf"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429161021",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_f06682f85f33",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019df6ee-0f73-7c90-6196-7fc08cad2f73"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429111506",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_0457ce74ada2",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019df6ee-5ba6-7db0-7a20-561fe03286eb"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429110130",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_f41dbf7a1fe0",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "30",
|
||||
"event_uuid": "019df6ee-60a1-77ad-4835-dc7259d65576"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429105306",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_ffd6b1c17fb7",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-6875-7fd8-75de-9bf342def9c8"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429105051",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_5f6244be6752",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-6e42-74f3-5be5-ca793f9ee226"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429104840",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_040dab1b6462",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-7437-7302-4e6b-706646d57c53"
|
||||
}
|
||||
],
|
||||
"CPTA-RF": [
|
||||
{
|
||||
"datetime": "20260429155038",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_4ef26aabdfae",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-14d6-7a13-44dc-63f353943186"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429154600",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_0d79d3d7a9d6",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-1d07-776e-72ed-af1ba59c76cd"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429153237",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_9d1716a5f582",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-24e0-776f-7ddd-0c65b8c01d24"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429144733",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_6f3c74447dec",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019df6ee-35ea-7bb1-6be8-2497aa23f1ad"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429114321",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_6ffeb9a156eb",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019df6ee-4aa8-7aa6-5523-8d0fa6384228"
|
||||
},
|
||||
{
|
||||
"datetime": "20260429113635",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_5b68e94bafac",
|
||||
"offset": "50",
|
||||
"gvt_speed": "6.5",
|
||||
"vut_speed": "10",
|
||||
"event_uuid": "019df6ee-540f-7bcc-5f7d-7ef249177de0"
|
||||
}
|
||||
],
|
||||
"CPLA-夜晚CN24": [
|
||||
{
|
||||
"datetime": "20260430005758",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_d43542536f95",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019df6ee-a134-7901-60db-81d81b60998d"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430005628",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_068362143e80",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019df6ee-a686-7c25-563d-67b25298af0b"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430005353",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_4e13f3cedc71",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019df6ee-ab74-7a6c-4f75-97bcb5245fda"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430005034",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_99a915ec4784",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019df6ee-b2f0-7a73-74c6-80c472bcc5df"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430004703",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_0061760569c9",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019df6ee-b7ee-78e6-7ae0-3ae241457e06"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430004432",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_07bca13ed759",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019df6ee-be7e-7a34-61e5-b77877c546eb"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430004247",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_1f3320ce38ac",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019df6ee-c4de-7e59-4f5c-16b4261d77f4"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430003934",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_82443933fdee",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "40",
|
||||
"event_uuid": "019df6ee-d00c-7e28-45c3-b1d1890ec640"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430003725",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_bd901e7e8041",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-d6e5-7e20-642d-7921e54619e2"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430003547",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_070e814ef27e",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-db3c-764a-46e5-5a2a8495b08a"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430003302",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_dc73a4d2ec69",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "20",
|
||||
"event_uuid": "019df6ee-e1ba-7c15-7559-2f32ecf76326"
|
||||
}
|
||||
],
|
||||
"CPLA-夜晚": [
|
||||
{
|
||||
"datetime": "20260430002426",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_1506a8d8eda5",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019df6ee-e7fc-785e-65c0-39403838db31"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430002127",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_04b9a81743fc",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW80",
|
||||
"event_uuid": "019df6ee-efae-7fed-7023-82bf07447393"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430001509",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_6df59d151cb4",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW70",
|
||||
"event_uuid": "019df6ee-f551-7a5b-78c6-4f03848a2b68"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430001258",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_8b8b37938873",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW70",
|
||||
"event_uuid": "019df6ee-f985-7317-4f86-c5fdd56f8f48"
|
||||
},
|
||||
{
|
||||
"datetime": "20260430000414",
|
||||
"rawid": "ADAS_S751NX0Y601739V_20260503105236841267_b8fed19cc042",
|
||||
"offset": "25",
|
||||
"gvt_speed": "5",
|
||||
"vut_speed": "FCW60",
|
||||
"event_uuid": "019df6ee-fef4-7d3c-4a4c-c52f722c8e00"
|
||||
}
|
||||
]
|
||||
}
|
||||
1038
tools/model_inference/examples/events/G1Q3_场地评测数据集_part.json
Executable file
1038
tools/model_inference/examples/events/G1Q3_场地评测数据集_part.json
Executable file
File diff suppressed because it is too large
Load Diff
159
tools/model_inference/examples/events/G1Q3_场地评测数据集_v1.csv
Executable file
159
tools/model_inference/examples/events/G1Q3_场地评测数据集_v1.csv
Executable file
@@ -0,0 +1,159 @@
|
||||
scene,offset,gvt_speed,vut_speed,datetime,rawid,data_path
|
||||
CPFA,25,6.5,20,20260323113612 ,ADAS_S751NX0Y800506T_20260327120535206279_a18b17bc1454,019d4e3a-78d3-7dc4-4e33-e871f9c3e15a
|
||||
CPFA,25,6.5,20,20260323113832 ,ADAS_S751NX0Y800506T_20260327120535206279_ff61c208d184,019d4e3a-8f48-77d9-5f70-43bee3eab1c5
|
||||
CPFA,25,6.5,30,20260323114629 ,ADAS_S751NX0Y800506T_20260327120535206279_2f11a63355c7,019d4e3a-90ad-7f00-7798-5551095fb4b5
|
||||
CPFA,25,6.5,30,20260323114938 ,ADAS_S751NX0Y800506T_20260327120535206279_eba8998fb8a3,019d4e3a-9441-7d17-63dc-b773bd467ae5
|
||||
CPFA,25,6.5,40,20260323140108 ,ADAS_S751NX0Y800506T_20260327120535206279_6429dd74f911,019d4e3a-974f-751c-5b3b-46c0a9364466
|
||||
CPFA,25,6.5,40,20260323140816 ,ADAS_S751NX0Y800506T_20260327120535206279_2a6aca204419,019d4e3a-99de-7e5a-56d4-83547bd8ac34
|
||||
CPFA,25,6.5,40,20260323141946 ,ADAS_S751NX0Y800506T_20260327120535206279_b527f4357559,019d4e3a-9bb0-7755-66c9-8fdd3770f67f
|
||||
CPFA,25,6.5,50,20260323142206 ,ADAS_S751NX0Y800506T_20260327120535206279_468f64aaaaed,019d4e3a-9cf4-7d35-4e0c-52952c05537d
|
||||
CPFA,25,6.5,50,20260323142435 ,ADAS_S751NX0Y800506T_20260327120535206279_72e20dc77396,019d4e3a-9f08-7500-6382-44bacad5f1ed
|
||||
CPFA,25,6.5,50,20260323142614 ,ADAS_S751NX0Y800506T_20260327120535206279_f0a4e2c2f8de,019d4e3a-a07a-7aa1-5981-8977d03402dc
|
||||
CPFA,25,6.5,60,20260323150051 ,ADAS_S751NX0Y800506T_20260327120535206279_8c30e32b75da,019d4e3a-ac12-74ae-5d1b-7ddca8db7feb
|
||||
CPFA,25,6.5,60,20260323150956 ,ADAS_S751NX0Y800506T_20260327120535206279_597b22308c0c,019d4e3a-af07-7d2b-79ed-cce2054427b2
|
||||
CPFA,25,6.5,60,20260323151226 ,ADAS_S751NX0Y800506T_20260327120535206279_920d06aa0c83,019d4e3a-b05e-7499-7cc0-c3b75d576e8c
|
||||
CPFA,50,6.5,20,20260322152509 ,ADAS_S751NX0Y800506T_20260327120535206279_1b6644577499,019d4e3a-b72a-702f-7485-de4f36c19291
|
||||
CPFA,50,6.5,20,20260322152819 ,ADAS_S751NX0Y800506T_20260327120535206279_3f4043e7c43b,019d4e3a-b87b-7ba7-770a-56ab7e461dd2
|
||||
CPFA,50,6.5,20,20260322153301 ,ADAS_S751NX0Y800506T_20260327120535206279_f00ed7674617,019d4e3a-bb94-77e0-6de8-aa85930f28e8
|
||||
CPFA,50,6.5,30,20260322153555 ,ADAS_S751NX0Y800506T_20260327120535206279_8fc6b6b738b3,019d4e3a-c417-7fe5-7eea-e1096344665b
|
||||
CPFA,50,6.5,30,20260322153820 ,ADAS_S751NX0Y800506T_20260327120535206279_55177e3ae374,019d4e3a-c676-76d2-77b1-d498fad94160
|
||||
CPFA,50,6.5,30,20260322154017 ,ADAS_S751NX0Y800506T_20260327120535206279_82b9ead31ef0,019d4e3a-c989-7b2f-67f3-08cabcfa7a97
|
||||
CPFA,50,6.5,40,20260323111334 ,ADAS_S751NX0Y800506T_20260327120535206279_7ec23297755f,019d4e3a-d5b5-7cbb-7add-b81d9d6da22f
|
||||
CPFA,50,6.5,40,20260323111522 ,ADAS_S751NX0Y800506T_20260327120535206279_2f655a7f3faa,019d4e3a-d858-72f8-6e5a-4de5471314f0
|
||||
CPFA,50,6.5,40,20260323111755 ,ADAS_S751NX0Y800506T_20260327120535206279_00dd9a4dda13,019d4e3a-db87-7799-66c7-96a11b425725
|
||||
CPFA,50,6.5,50,20260323112055 ,ADAS_S751NX0Y800506T_20260327120535206279_08404d05ab99,019d4e3a-ddc1-749a-523f-bfa54c6ab4b9
|
||||
CPFA,50,6.5,50,20260323112255 ,ADAS_S751NX0Y800506T_20260327120535206279_7bda3d59284b,019d4e3a-e154-7114-4619-a60849eb771a
|
||||
CPFA,50,6.5,50,20260323112515 ,ADAS_S751NX0Y800506T_20260327120535206279_523828701c91,019d4e3a-e764-7634-765c-6178bb27739d
|
||||
CPFA,50,6.5,60,20260323112758 ,ADAS_S751NX0Y800506T_20260327120535206279_5c77b0c2fc61,019d4e3a-ea48-7eb9-6720-7ba5e0a38877
|
||||
CPFA,50,6.5,60,20260323113007 ,ADAS_S751NX0Y800506T_20260327120535206279_16986d99d73c,019d4e3a-ed5d-7426-7143-8cb7870c8a53
|
||||
CPFA,50,6.5,60,20260323113249 ,ADAS_S751NX0Y800506T_20260327120535206279_7fa179422fa9,019d4e3a-f0d1-760d-64c4-0bf331a399f7
|
||||
CPNA,25,5,20,20260322160034 ,ADAS_S751NX0Y800506T_20260327120535206279_bfa3bdb3ecfa,019d4e3a-f35c-7f56-6350-fdae7d030520
|
||||
CPNA,25,5,20,20260322161344 ,ADAS_S751NX0Y800506T_20260327120535206279_4d845a8f0558,019d4e3a-f744-7cd1-7260-2a17dc2fd996
|
||||
CPNA,25,5,20,20260322162319 ,ADAS_S751NX0Y800506T_20260327120535206279_bb2b77bf7e71,019d4e3a-fa3c-7bc2-75b0-d676f2d12eaa
|
||||
CPNA,25,5,30,20260322162901 ,ADAS_S751NX0Y800506T_20260327120535206279_a4e2d3b50dfc,019d4e3b-0c47-76bc-6f13-9bac1a818536
|
||||
CPNA,25,5,30,20260322163412 ,ADAS_S751NX0Y800506T_20260327120535206279_34ec8bc7c628,019d4e3b-0e7c-7347-49c1-b70b0caa6010
|
||||
CPNA,25,5,30,20260322163631 ,ADAS_S751NX0Y800506T_20260327120535206279_a398a2f1d31d,019d4e3b-1077-77d3-570a-71463fe4e9c8
|
||||
CPNA,25,5,40,20260322172726 ,ADAS_S751NX0Y800506T_20260327120535206279_62a7fe51f78a,019d4e3b-2f89-775e-6fb8-1de28a664495
|
||||
CPNA,25,5,40,20260322173110 ,ADAS_S751NX0Y800506T_20260327120535206279_525d3358ef99,019d4e3b-337f-714b-60b4-8e87df7f7a51
|
||||
CPNA,25,5,40,20260322173530 ,ADAS_S751NX0Y800506T_20260327120535206279_2926f0bbdeb6,019d4e3b-3606-7e91-7816-2b9d0ad07dcd
|
||||
CPNA,25,5,50,20260324161933 ,ADAS_S751NX0Y800506T_20260327120535206279_d74d2d3f578d,019d4e3b-4fba-707b-4a28-1ac6277145ba
|
||||
CPNA,25,5,50,20260331151009 ,ADAS_S5STNF0T406280R_20260402104850269428_0785a9b23943,019d4e3b-5213-7f0d-7fc9-18a3051690f7
|
||||
CPNA,25,5,50,20260331151250 ,ADAS_S5STNF0T406280R_20260402104850269428_f0cf082bc503,019d4e3b-541b-787d-6ae6-3da8fb8e1139
|
||||
CPNA,25,5,60,20260324164151 ,ADAS_S751NX0Y800506T_20260327120535206279_7b3031a15f43,019d4e3b-5bf2-7e3a-49df-56bc4f07fb62
|
||||
CPNA,25,5,60,20260324165218 ,ADAS_S751NX0Y800506T_20260327120535206279_ef49250e9812,019d4e3b-5e24-7249-4bb6-bdd243110001
|
||||
CPNA,25,5,60,20260331151834 ,ADAS_S5STNF0T406280R_20260402104850269428_f8705c0133fa,019d4e3b-6076-7ede-73a3-afdfd283b7b4
|
||||
CPNA,75,5,20,20260322173859 ,ADAS_S751NX0Y800506T_20260327120535206279_f91ce01108fe,019d4e3b-6900-71f3-4685-a4332df5f883
|
||||
CPNA,75,5,20,20260322174119 ,ADAS_S751NX0Y800506T_20260327120535206279_ab63c70e43b8,019d4e3b-6b7c-72e8-56ea-2d6eac52ab30
|
||||
CPNA,75,5,20,20260322174325 ,ADAS_S751NX0Y800506T_20260327120535206279_56c1d30ff57b,019d4e3b-70f6-76a1-5812-f8db1c73e627
|
||||
CPNA,75,5,30,20260322175205 ,ADAS_S751NX0Y800506T_20260327120535206279_fdada52e9fa5,019d4e3b-92d0-7fd2-66c2-f2a1d1e81e6f
|
||||
CPNA,75,5,30,20260322175649 ,ADAS_S751NX0Y800506T_20260327120535206279_89d41fb8d2e8,019d4e3b-9663-7d48-55b8-2af349c18284
|
||||
CPNA,75,5,30,20260322175850 ,ADAS_S751NX0Y800506T_20260327120535206279_bbe31db90e0a,019d4e3b-9acb-7387-6b18-466c0534a3bc
|
||||
CPNA,75,5,40,20260324171844 ,ADAS_S751NX0Y800506T_20260327120535206279_44a743580dac,019d4e3b-a6ff-7af5-6b3b-38fcdf52e12b
|
||||
CPNA,75,5,40,20260324172117 ,ADAS_S751NX0Y800506T_20260327120535206279_51afa9e84ca0,019d4e3b-a8c6-736e-7dea-bfbdd73fd93a
|
||||
CPNA,75,5,40,20260331163021 ,ADAS_S5STNF0T406280R_20260402104850269428_5c97beda0356,019d4e3b-ac9d-7dd8-41a7-f7c7838e4471
|
||||
CPNA,75,5,50,20260324172350 ,ADAS_S751NX0Y800506T_20260327120535206279_1e84d8ee3c5e,019d4e3b-b426-7c52-70ec-4433ffa93589
|
||||
CPNA,75,5,50,20260324172558 ,ADAS_S751NX0Y800506T_20260327120535206279_e9d1fb808bed,019d4e3b-b6ec-74ca-533a-d50dd4c6bc76
|
||||
CPNA,75,5,50,20260324172833 ,ADAS_S751NX0Y800506T_20260327120535206279_16007a77b8e3,019d4e3b-cd62-7eb6-7a95-60a64da7c7ce
|
||||
CPNA,75,5,60,20260324173139 ,ADAS_S751NX0Y800506T_20260327120535206279_ef6e0008db8a,019d4e3b-da82-7e0d-4d74-b59da953ecff
|
||||
CPNA,75,5,60,20260324173924 ,ADAS_S751NX0Y800506T_20260327120535206279_84ce75f29b5b,019d4e3b-df7a-7e7b-44a7-226205b4213f
|
||||
CPNA,75,5,60,20260324174238 ,ADAS_S751NX0Y800506T_20260327120535206279_76553de00e52,019d4e3b-e195-75cc-687b-e6c9c642ee54
|
||||
CBNA,50,15,20,20260325112105 ,ADAS_S751NX0Y800506T_20260327120535206279_c7ff38958fa1,019d4e3b-ea01-7a92-63ee-4854e139ed23
|
||||
CBNA,50,15,20,20260325120919 ,ADAS_S751NX0Y800506T_20260327120535206279_aaa5e92f1b8d,019d4e3b-ee98-7208-7e05-184f40aad9c6
|
||||
CBNA,50,15,20,20260325140126 ,ADAS_S751NX0Y800506T_20260327120535206279_72d0b390d41b,019d4e3b-f52d-702d-49bd-86c2a007937f
|
||||
CBNA,50,15,30,20260325142826 ,ADAS_S751NX0Y800506T_20260327120535206279_d3da82eff0a1,019d4e3c-03d5-72ff-5fdc-d798dafc0689
|
||||
CBNA,50,15,30,20260325144228 ,ADAS_S751NX0Y800506T_20260327120535206279_81bd7a6856f8,019d4e3c-06ff-7af8-4b52-45705976b906
|
||||
CBNA,50,15,30,20260325144443 ,ADAS_S751NX0Y800506T_20260327120535206279_e07712df8814,019d4e3c-08e9-72f3-721c-460d3da8b41c
|
||||
CBNA,50,15,40,20260325145316 ,ADAS_S751NX0Y800506T_20260327120535206279_5f75b8004ae5,019d4e3c-39e9-760e-428f-80a856bbb683
|
||||
CBNA,50,15,40,20260325145539 ,ADAS_S751NX0Y800506T_20260327120535206279_b3de854ceea1,019d4e3c-3e78-765c-5f1c-672330e51957
|
||||
CBNA,50,15,40,20260325145759 ,ADAS_S751NX0Y800506T_20260327120535206279_4c2cc3a4581f,019d4e3c-403d-73af-7310-dc91edbc687a
|
||||
CBNA,50,15,50,20260325150059 ,ADAS_S751NX0Y800506T_20260327120535206279_3ab5c9fb09e8,019d4e3c-4a59-70ac-5799-76424e4a5926
|
||||
CBNA,50,15,50,20260325150516 ,ADAS_S751NX0Y800506T_20260327120535206279_c548265438c0,019d4e3c-4cce-7267-5cab-81c5a8147465
|
||||
CBNA,50,15,50,20260325151329 ,ADAS_S751NX0Y800506T_20260327120535206279_56ec7f3f0a9f,019d4e3c-5023-7469-594c-0aca8726e58f
|
||||
CBNA,50,15,60,20260325153201 ,ADAS_S751NX0Y800506T_20260327120535206279_079e46de1e69,019d4e3c-5bee-7dd7-5ca1-d6bc06862db6
|
||||
CBNA,50,15,60,20260325153627 ,ADAS_S751NX0Y800506T_20260327120535206279_e7bd46fa5526,019d4e3c-5dc6-710b-616c-56a91c34b928
|
||||
CBNA,50,15,60,20260401105118 ,ADAS_S5STNF0T504465N_20260402191154995992_98b65d35a0e8,019d4e3c-60fa-7d56-61ab-078cd6e38af5
|
||||
CSFA,50,20,30,20260325160450 ,ADAS_S751NX0Y800506T_20260327120535206279_3db3d3c5f75e,019d4e3c-6e6e-7d1a-79af-39cd8a4a54d8
|
||||
CSFA,50,20,30,20260325163344 ,ADAS_S751NX0Y800506T_20260327120535206279_8b26b8678563,019d4e3c-70c7-7a72-5dac-25eb86983968
|
||||
CSFA,50,20,30,20260325163640 ,ADAS_S751NX0Y800506T_20260327120535206279_048ca75c2b68,019d4e3c-7352-738d-47ab-2ea8eca8d7ad
|
||||
CSFA,50,20,30,20260401112255 ,ADAS_S5STNF0T504465N_20260402191154995992_8c840c39ed44,019d4e3c-7a18-7597-71b1-31f9ece82944
|
||||
CSFA,50,20,40,20260325164019 ,ADAS_S751NX0Y800506T_20260327120535206279_71ba721054d2,019d4e3c-7cd2-7485-64a3-52d954e956fe
|
||||
CSFA,50,20,40,20260325164557 ,ADAS_S751NX0Y800506T_20260327120535206279_101c937f632e,019d4e3c-8191-7c57-64a2-b21ce84ecc08
|
||||
CSFA,50,20,40,20260325165101 ,ADAS_S751NX0Y800506T_20260327120535206279_0039e9c4f44c,019d4e3c-84d1-7496-4cf5-55f849f06c6d
|
||||
CSFA,50,20,50,20260325165344 ,ADAS_S751NX0Y800506T_20260327120535206279_35f7055b3936,019d4e3c-9254-795a-5d2c-e1c38b47f6f1
|
||||
CSFA,50,20,50,20260325165620 ,ADAS_S751NX0Y800506T_20260327120535206279_cae0b056a639,019d4e3c-95e3-7c5c-6c3e-0d97a6aa300e
|
||||
CSFA,50,20,50,20260325170106 ,ADAS_S751NX0Y800506T_20260327120535206279_a3b60a4417f1,019d4e3c-9881-768a-447c-063b27c49a4d
|
||||
CSFA,50,20,60,20260325170448 ,ADAS_S751NX0Y800506T_20260327120535206279_9cf23dfe1aa7,019d4e3c-a794-7de1-70b6-cf64d043298a
|
||||
CSFA,50,20,60,20260325171905 ,ADAS_S751NX0Y800506T_20260327120535206279_f05823ea3fb0,019d4e3c-aa4d-7285-60da-b503786e136d
|
||||
CSFA,50,20,60,20260325172254 ,ADAS_S751NX0Y800506T_20260327120535206279_095c61152216,019d4e3c-ae93-7858-6a24-810c5f1e62db
|
||||
CCRM,100,20,30,20260327110922 ,ADAS_S751NX0Y601739V_20260330104120600319_d9c5e242cd43,019d4e3c-bb28-73bc-5211-83d63bdf0ca9
|
||||
CCRM,100,20,30,20260327111430 ,ADAS_S751NX0Y601739V_20260330104120600319_49f67f0f4c84,019d4e3c-becf-7df4-6697-fd1e7359b44e
|
||||
CCRM,100,20,30,20260327112148 ,ADAS_S751NX0Y601739V_20260330104120600319_71c00fa5c46c,019d4e3c-c0e6-7ada-63e8-f2e7cd2ee7fa
|
||||
CCRM,100,20,40,20260327113709 ,ADAS_S751NX0Y601739V_20260330104120600319_310c2fb9e063,019d4e3c-c8a5-7b63-5fb9-f9847ca1baa9
|
||||
CCRM,100,20,40,20260327115052 ,ADAS_S751NX0Y601739V_20260330104120600319_9fde171dd0c5,019d4e3c-cb80-712f-46e5-36af2aad17f8
|
||||
CCRM,100,20,40,20260327115408 ,ADAS_S751NX0Y601739V_20260330104120600319_89971a38a795,019d4e3c-cd63-776f-7608-9f922d1902d2
|
||||
CPLA,25,5,20,20260325175106 ,ADAS_S751NX0Y800506T_20260327120535206279_67c2c4cfdcfa,019d4e3c-d4b2-79f9-4ed1-4ecb7b0194c8
|
||||
CPLA,25,5,20,20260325180145 ,ADAS_S751NX0Y800506T_20260327120535206279_6c216f1d5e73,019d4e3c-d864-7799-5a0b-28bb4f33acb4
|
||||
CPLA,25,5,20,20260325180337 ,ADAS_S751NX0Y800506T_20260327120535206279_42d78cae79e4,019d4e3c-da58-73c5-491e-6974c7368238
|
||||
CPLA,25,5,30,20260325180602 ,ADAS_S751NX0Y800506T_20260327120535206279_305900bb160b,019d4e3c-dc9f-704f-5b1a-2fe724439ca6
|
||||
CPLA,25,5,30,20260325180857 ,ADAS_S751NX0Y800506T_20260327120535206279_d72d2f1eab33,019d4e3c-df35-7734-69cb-a4d0c67e80d9
|
||||
CPLA,25,5,30,20260325181249 ,ADAS_S751NX0Y800506T_20260327120535206279_e65e2e8bb2c3,019d4e3c-e27f-739a-7823-ae3a8cf49aba
|
||||
CPLA,25,5,40,20260326112939 ,ADAS_S751NX0Y601865J_20260328113450259688_7e273228d47b,019d4e3c-e3c2-73ee-6b22-fb2ac8a75c73
|
||||
CPLA,25,5,40,20260326113327 ,ADAS_S751NX0Y601865J_20260328113450259688_cf29bc58f910,019d4e3c-e511-7249-7c25-e69e8452d486
|
||||
CPLA,25,5,40,20260326120929 ,ADAS_S751NX0Y601865J_20260328113450259688_19aa5768291c,019d4e3c-e781-7c8d-4873-f1d931f483d6
|
||||
CPLA,50,5,20,20260326141456 ,ADAS_S751NX0Y601865J_20260328113450259688_7089abe3283f,019d4e3c-ee0a-7f12-6936-b8f2fd8f17ad
|
||||
CPLA,50,5,20,20260326141816 ,ADAS_S751NX0Y601865J_20260328113450259688_968bbf10d481,
|
||||
CPLA,50,5,20,20260326143002 ,ADAS_S751NX0Y601865J_20260328113450259688_253cc2246a46,019d4e3c-f166-7b61-46eb-6b2c216bfff8
|
||||
CPLA,50,5,30,20260326143325 ,ADAS_S751NX0Y601865J_20260328113450259688_890e13a19330,019d4e3c-f4c9-7b4a-4c86-0ffd3898c96f
|
||||
CPLA,50,5,30,20260326143553 ,ADAS_S751NX0Y601865J_20260328113450259688_208c31032ab7,019d4e3c-f78b-77e7-53c3-ae06b3ae3b66
|
||||
CPLA,50,5,30,20260326143953 ,ADAS_S751NX0Y601865J_20260328113450259688_31374e23ea52,019d4e3c-f8e0-74f6-461a-e2b03ec26f0b
|
||||
CPLA,50,5,40,20260326144301 ,ADAS_S751NX0Y601865J_20260328113450259688_11edf0db8552,019d4e3c-fac9-7171-6894-a4a295f2aee3
|
||||
CPLA,50,5,40,20260326144521 ,ADAS_S751NX0Y601865J_20260328113450259688_88f480b20482,019d4e3c-fc5e-76c8-783e-c95921d6db7c
|
||||
CPLA,50,5,40,20260326144728 ,ADAS_S751NX0Y601865J_20260328113450259688_010690530eb1,019d4e3c-fe9d-7724-5895-96d271ac56b4
|
||||
CPLA,50,5,50,20260326145318 ,ADAS_S751NX0Y601865J_20260328113450259688_e8f3c0c2d8e7,019d4e3d-0304-7a98-47bf-a2123c57756e
|
||||
CPLA,50,5,50,20260326150327 ,ADAS_S751NX0Y601865J_20260328113450259688_a44f950ae272,019d4e3d-0714-7346-4218-45001f0df930
|
||||
CPLA,50,5,50,20260326152042 ,ADAS_S751NX0Y601865J_20260328113450259688_13132ea06b7c,019d4e3d-097c-7c4e-6f7a-a5514e19ae85
|
||||
CPLA,50,5,60,20260326152355 ,ADAS_S751NX0Y601865J_20260328113450259688_1f80da22f45a,019d4e3d-1265-72f9-5136-f47ea119947d
|
||||
CPLA,50,5,60,20260326152808 ,ADAS_S751NX0Y601865J_20260328113450259688_740131f6e72c,019d4e3d-1648-7d56-6fed-02716eb149a1
|
||||
CPLA,50,5,60,20260326153031 ,ADAS_S751NX0Y601865J_20260328113450259688_336615afba11,019d4e3d-1868-7ca0-40e5-9ff09ddffe7f
|
||||
CBLA,50,15,20,20260326155847 ,ADAS_S751NX0Y601865J_20260328113450259688_f55db8debcca,019d4e3d-19f8-705e-4947-c5c339ea3a7e
|
||||
CBLA,50,15,20,20260326160617 ,ADAS_S751NX0Y601865J_20260328113450259688_399b4adafe58,
|
||||
CBLA,50,15,20,20260326160814 ,ADAS_S751NX0Y601865J_20260328113450259688_46197d491ed8,019d4e3d-1df4-7038-410e-a74a438c8492
|
||||
CBLA,50,15,30,20260326161154 ,ADAS_S751NX0Y601865J_20260328113450259688_8d0bdc3af3ad,019d4e3d-2067-7e9f-5385-c9f53102dc7a
|
||||
CBLA,50,15,30,20260326161642 ,ADAS_S751NX0Y601865J_20260328113450259688_fd8ae38ed3ef,019d4e3d-21e5-7ba9-4216-1c9ec4f957b1
|
||||
CBLA,50,15,30,20260326161852 ,ADAS_S751NX0Y601865J_20260328113450259688_67fd2a079d1d,019d4e3d-252c-767d-6427-7d463f865b10
|
||||
CBLA,50,15,40,20260326162136 ,ADAS_S751NX0Y601865J_20260328113450259688_900166524e3b,019d4e3d-26b5-7856-4050-a96f6d200ebf
|
||||
CBLA,50,15,40,20260326162358 ,ADAS_S751NX0Y601865J_20260328113450259688_2b77ce9a349e,019d4e3d-285b-7116-6873-8216f98b58eb
|
||||
CBLA,50,15,40,20260326164202 ,ADAS_S751NX0Y601865J_20260328113450259688_10e68e264ee3,019d4e3d-2cb1-710f-7f59-be9ef1322f47
|
||||
CBLA,50,15,50,20260326164438 ,ADAS_S751NX0Y601865J_20260328113450259688_5241e2ff36e4,019d4e3d-2fbc-7e19-4ed4-c295ad9c20ac
|
||||
CBLA,50,15,50,20260326170202 ,ADAS_S751NX0Y601865J_20260328113450259688_347a11543c73,019d4e3d-31d4-71d1-4caa-34a546a296d1
|
||||
CBLA,50,15,50,20260326171109 ,ADAS_S751NX0Y601865J_20260328113450259688_490ba9b95ba9,019d4e3d-34d6-7187-7af0-e97fe079a772
|
||||
CBLA,50,15,60,20260326173610 ,ADAS_S751NX0Y601865J_20260328113450259688_559e79696f59,019d4e3d-36bf-7f87-6320-146481b08c2d
|
||||
CBLA,50,15,60,20260326174513 ,ADAS_S751NX0Y601865J_20260328113450259688_183e46d60337,019d4e3d-3da9-79fc-4523-a80b6d5d9bb9
|
||||
CBLA,50,15,60,20260326174803 ,ADAS_S751NX0Y601865J_20260328113450259688_1ced9e7a5ff4,019d4e3d-3f8f-7736-5f1c-ce5b7bebe985
|
||||
CCRS,100,0,20,20260327150038 ,ADAS_S751NX0Y601739V_20260330104120600319_4b079fa4769c,019d4e3d-40e4-7952-5bb1-61a7bcc26ffb
|
||||
CCRS,100,0,20,20260327150639 ,ADAS_S751NX0Y601739V_20260330104120600319_c06f5150f502,019d4e3d-44be-7fc4-47b9-93647ce7ba13
|
||||
CCRS,100,0,20,20260327150850 ,ADAS_S751NX0Y601739V_20260330104120600319_96c7a7f2338c,019d4e3d-468a-7907-7be3-089462e21801
|
||||
CCRS,100,0,30,20260327151710 ,ADAS_S751NX0Y601739V_20260330104120600319_eb5e6353a9b5,019d4e3d-47c3-75b5-4f06-ccfaddeea596
|
||||
CCRS,100,0,30,20260327152708 ,ADAS_S751NX0Y601739V_20260330104120600319_c84cd8106f77,019d4e3d-494d-7344-74d1-727fd772dcc1
|
||||
CCRS,100,0,30,20260327153617 ,ADAS_S751NX0Y601739V_20260330104120600319_4f029dbe74a6,019d4e3d-4a66-7f48-67ca-80af46768fe1
|
||||
CCRS,100,0,40,20260327155538 ,ADAS_S751NX0Y601739V_20260330104120600319_eb4efa485513,019d4e3d-4c25-7fba-5495-c3c37583bbd8
|
||||
CCRS,100,0,40,20260327155725 ,ADAS_S751NX0Y601739V_20260330104120600319_44d7b1f69620,019d4e3d-4d42-7371-68d9-ca2c9aabf4e1
|
||||
CCRS,100,0,40,20260327160636 ,ADAS_S751NX0Y601739V_20260330104120600319_5e14779592f2,019d4e3d-4f36-7b47-646a-e95d51125e0a
|
||||
CCRS,-50,0,20,20260327163408 ,ADAS_S751NX0Y601739V_20260330104120600319_2bcd36764fdc,019d4e3d-508d-7ec6-7cfd-29f4aa246b5c
|
||||
CCRS,-50,0,20,20260327164715 ,ADAS_S751NX0Y601739V_20260330104120600319_25960516b170,019d4e3d-51ce-7b1d-4f14-d1d4fad73a00
|
||||
CCRS,-50,0,20,20260327164844 ,ADAS_S751NX0Y601739V_20260330104120600319_b8ffb91ad5b3,019d4e3d-531b-7ae0-4080-72022af1d85c
|
||||
CCRS,50,0,30,20260329094430 ,ADAS_S5STNF0T504465N_20260330162214124146_420efd665249,019d4e3d-54d6-7380-7e9d-11e13181980b
|
||||
CCRS,50,0,30,20260329100613 ,ADAS_S5STNF0T504465N_20260330162214124146_64601c7323b8,019d4e3d-5668-7402-6156-3331c9cbb71f
|
||||
CCRS,50,0,30,20260329114336 ,ADAS_S5STNF0T504465N_20260330162214124146_c68c2ee15588,019d4e3d-5960-7d08-58b4-2f72cd3c7b77
|
||||
CCRS,50,0,30,20260329115057 ,ADAS_S5STNF0T504465N_20260330162214124146_22ec55135ffb,019d4e3d-5bec-763f-663a-7dd9be2d546c
|
||||
CCRS,50,0,30,20260329115326 ,ADAS_S5STNF0T504465N_20260330162214124146_73d6bf86aabf,019d4e3d-5d6d-7c5c-479c-7e86d4ab824a
|
||||
CCRS,-50,0,40,20260329115744 ,ADAS_S5STNF0T504465N_20260330162214124146_7d8bc5e99bd8,019d4e3d-605b-75a0-68cb-347da7344e2d
|
||||
CCRS,-50,0,40,20260329115942 ,ADAS_S5STNF0T504465N_20260330162214124146_544d794c895a,019d4e3d-629e-78d2-5f06-c7a8339aa887
|
||||
CCRS,-50,0,40,20260329120223 ,ADAS_S5STNF0T504465N_20260330162214124146_28f2102c8b7d,019d4e3d-65e2-71da-7a8a-bf3a11b84ea4
|
||||
CCRS,100,0,40,20260329152947 ,ADAS_S5STNF0T504465N_20260330162214124146_8dcc9b350e60,019d4e3d-6cae-7d7f-4116-51f1ad23650e
|
||||
CCRS,100,0,40,20260329153103 ,ADAS_S5STNF0T504465N_20260330162214124146_d0ab7bbf15e6,019d4e3d-6f92-7051-57ea-3a0ab52f7f9b
|
||||
CCRS,100,0,40,20260329153211 ,ADAS_S5STNF0T504465N_20260330162214124146_942230bcc8f5,019d4e3d-714a-7d3e-400a-a13ca0391193
|
||||
CCRS,100,0,50,20260329154203 ,ADAS_S5STNF0T504465N_20260330162214124146_e0dfc76d03a5,019d4e3d-7594-7679-5955-52a47aa749a2
|
||||
CCRS,100,0,50,20260329154536 ,ADAS_S5STNF0T504465N_20260330162214124146_a82545a4fac4,019d4e3d-78ea-7eb9-6861-84dec1bda1a5
|
||||
CCRS,100,0,60,20260329154719 ,ADAS_S5STNF0T504465N_20260330162214124146_6bc547d69cf8,019d4e3d-7f2a-7f1f-5631-91ff2c42af27
|
||||
CCRS,100,0,60,20260329154913 ,ADAS_S5STNF0T504465N_20260330162214124146_0491e7efbd55,019d4e3d-8410-77cd-6dae-e0bf501b5304
|
||||
|
1282
tools/model_inference/examples/events/G1Q3_场地评测数据集_v1.json
Executable file
1282
tools/model_inference/examples/events/G1Q3_场地评测数据集_v1.json
Executable file
File diff suppressed because it is too large
Load Diff
67
tools/model_inference/scripts/run_evalset_infer.sh
Executable file
67
tools/model_inference/scripts/run_evalset_infer.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
# Batch inference over all cases in a mined eval dataset directory.
|
||||
#
|
||||
# Directory layout expected (produced by mine_balanced_eval_subset.py):
|
||||
# EVAL_DIR/<date>/<case_uuid>/images/
|
||||
# EVAL_DIR/<date>/<case_uuid>/calib/L2_calib/camera4.json
|
||||
#
|
||||
# Output mirrors the same structure under OUTPUT_DIR:
|
||||
# OUTPUT_DIR/<date>/<case_uuid>/visualizations/
|
||||
# OUTPUT_DIR/<date>/<case_uuid>/predictions/
|
||||
# OUTPUT_DIR/<date>/<case_uuid>/predictions.json
|
||||
#
|
||||
# Usage:
|
||||
# bash tools/model_inference/scripts/run_evalset_infer.sh
|
||||
#
|
||||
# Override defaults with environment variables:
|
||||
# EVAL_DIR=... EXPORTED_MODEL=... OUTPUT_DIR=... bash tools/model_inference/scripts/run_evalset_infer.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
EVAL_DIR="${EVAL_DIR:-/data1/dongying/Mono3d/G1M3/data_for_alignment/mono3d_mining_val300}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_202603291430-raw-fuse/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-${PROJECT_ROOT}/runs/test/evalset_infer_$(basename "${EVAL_DIR}")_new}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-1}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-0}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-1}"
|
||||
|
||||
if [[ ! -d "${EVAL_DIR}" ]]; then
|
||||
echo "ERROR: EVAL_DIR does not exist: ${EVAL_DIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${EXPORTED_MODEL}" ]]; then
|
||||
echo "ERROR: EXPORTED_MODEL does not exist: ${EXPORTED_MODEL}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Eval dir: ${EVAL_DIR}"
|
||||
echo "Model : ${EXPORTED_MODEL}"
|
||||
echo "Output : ${OUTPUT_DIR}"
|
||||
echo ""
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--eval-dir "${EVAL_DIR}"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
)
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
"${CMD[@]}"
|
||||
61
tools/model_inference/scripts/run_extract_excel_column.sh
Executable file
61
tools/model_inference/scripts/run_extract_excel_column.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for Excel/CSV column extraction.
|
||||
#
|
||||
# Usage:
|
||||
# bash tools/model_inference/scripts/run_extract_excel_column.sh
|
||||
#
|
||||
# Common env overrides:
|
||||
# INPUT_FILE, COLUMN_NAME, SHEET_NAME, OUTPUT_FILE, JSON_FILE,
|
||||
# DEDUPE, LIST_COLUMNS, EXTRA_ARGS
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
INPUT_FILE="${INPUT_FILE:-${MODEL_INFERENCE_DIR}/examples/cncap/G1M3_AFS1616_CNCAP-2024_11月_0306.xlsx}"
|
||||
COLUMN_NAME="${COLUMN_NAME:-原始数据地址}"
|
||||
SHEET_NAME="${SHEET_NAME:-}"
|
||||
OUTPUT_FILE="${OUTPUT_FILE:-}"
|
||||
JSON_FILE="${JSON_FILE:-}"
|
||||
DEDUPE="${DEDUPE:-0}"
|
||||
LIST_COLUMNS="${LIST_COLUMNS:-0}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/data_tools/extract_excel_column.py"
|
||||
--input-file "${INPUT_FILE}"
|
||||
--column-name "${COLUMN_NAME}"
|
||||
)
|
||||
|
||||
if [[ -n "${SHEET_NAME}" ]]; then
|
||||
CMD+=(--sheet-name "${SHEET_NAME}")
|
||||
fi
|
||||
|
||||
if [[ -n "${OUTPUT_FILE}" ]]; then
|
||||
CMD+=(--output-file "${OUTPUT_FILE}")
|
||||
fi
|
||||
|
||||
if [[ -n "${JSON_FILE}" ]]; then
|
||||
CMD+=(--json-file "${JSON_FILE}")
|
||||
fi
|
||||
|
||||
if [[ "${DEDUPE}" == "1" ]]; then
|
||||
CMD+=(--dedupe)
|
||||
fi
|
||||
|
||||
if [[ "${LIST_COLUMNS}" == "1" ]]; then
|
||||
CMD+=(--list-columns)
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
|
||||
"${CMD[@]}"
|
||||
45
tools/model_inference/scripts/run_parse_scene_csv_to_json.sh
Executable file
45
tools/model_inference/scripts/run_parse_scene_csv_to_json.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for scene-keyed CSV -> JSON conversion.
|
||||
#
|
||||
# Usage:
|
||||
# bash tools/model_inference/scripts/run_parse_scene_csv_to_json.sh
|
||||
#
|
||||
# Common env overrides:
|
||||
# INPUT_FILE, SCENE_COLUMN, OUTPUT_FILE, KEEP_SCENE_FIELD, EXTRA_ARGS
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
INPUT_FILE="${INPUT_FILE:-${MODEL_INFERENCE_DIR}/examples/events/G1Q3_场地评测数据集_0418.csv}"
|
||||
SCENE_COLUMN="${SCENE_COLUMN:-scene}"
|
||||
OUTPUT_FILE="${OUTPUT_FILE:-}"
|
||||
KEEP_SCENE_FIELD="${KEEP_SCENE_FIELD:-0}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/data_tools/parse_scene_csv_to_json.py"
|
||||
--input-file "${INPUT_FILE}"
|
||||
--scene-column "${SCENE_COLUMN}"
|
||||
)
|
||||
|
||||
if [[ -n "${OUTPUT_FILE}" ]]; then
|
||||
CMD+=(--output-file "${OUTPUT_FILE}")
|
||||
fi
|
||||
|
||||
if [[ "${KEEP_SCENE_FIELD}" == "1" ]]; then
|
||||
CMD+=(--keep-scene-field)
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
|
||||
"${CMD[@]}"
|
||||
27
tools/model_inference/scripts/run_two_roi_exported_onnx_infer.sh
Executable file
27
tools/model_inference/scripts/run_two_roi_exported_onnx_infer.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# Navigation launcher kept for convenience.
|
||||
#
|
||||
# Prefer using one of the mode-specific scripts directly:
|
||||
# bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_case.sh
|
||||
# bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_clip_list.sh
|
||||
# bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_cncap_json.sh
|
||||
# bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_event_json.sh
|
||||
# bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_video_case.sh
|
||||
# bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_video_root.sh
|
||||
# bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_mcap.sh
|
||||
|
||||
cat <<'EOF'
|
||||
Available launchers:
|
||||
1. run_two_roi_exported_onnx_infer_case.sh
|
||||
2. run_two_roi_exported_onnx_infer_clip_list.sh
|
||||
3. run_two_roi_exported_onnx_infer_cncap_json.sh
|
||||
4. run_two_roi_exported_onnx_infer_event_json.sh
|
||||
5. run_two_roi_exported_onnx_infer_video_case.sh
|
||||
6. run_two_roi_exported_onnx_infer_video_root.sh
|
||||
7. run_two_roi_exported_onnx_infer_mcap.sh
|
||||
EOF
|
||||
461
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_case.sh
Executable file
461
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_case.sh
Executable file
@@ -0,0 +1,461 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for single case / eval-dir inference.
|
||||
#
|
||||
# Supported modes:
|
||||
# 1. CASE_DIR=<case-dir>
|
||||
# 2. EVAL_DIR=<eval-root>
|
||||
# 3. INPUT_DIR=<case-dir-or-eval-root>
|
||||
# 4. POSTPROCESS_ONLY=1 OUTPUT_DIR=<inference-output-root>
|
||||
# 5. ENABLE_PARALLEL=1 GPU_IDS="0 1" INPUT_DIR=<eval-root>
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
CASE_DIR="${CASE_DIR:-}"
|
||||
EVAL_DIR="${EVAL_DIR:-}"
|
||||
|
||||
# /data1/dongying/Mono3d/G1Q3/dataset_for_evaluation/DL_KPI_SCENE
|
||||
# /data1/dongying/Mono3d/G1Q3/dataset_for_evaluation/OP_KPI_SCENE
|
||||
# /data1/dongying/Mono3d/G1Q3/dataset_for_evaluation/OP_KPI_TRAFFIC_SCENARIO
|
||||
# /data1/xdzhu/Testdata_0129
|
||||
# /data1/xdzhu/Testdata_0129019b4415-d171-7ae9-88ed-0065c4c6e1e0
|
||||
|
||||
INPUT_DIR="${INPUT_DIR:-${EVAL_DIR:-/data1/dongying/Mono3d/G1Q3/dataset_for_evaluation/OP_KPI_SCENE}}"
|
||||
# INPUT_DIR="${INPUT_DIR:-${CASE_DIR}}"
|
||||
# The core inference script now auto-detects whether the exported model keeps the edge branch.
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_20260506-keep_fake_3d_branch/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/KPI/OP_KPI_SCENE/model_20260506_all_cases}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-1}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-0}"
|
||||
DEVICE="${DEVICE:-}"
|
||||
ATTR_DEVICE="${ATTR_DEVICE:-}"
|
||||
VIS_CLASSES="${VIS_CLASSES:-}"
|
||||
VIS_CLASS_NAMES="${VIS_CLASS_NAMES:-}"
|
||||
SAVE_VISUALIZATION="${SAVE_VISUALIZATION:-0}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
POSTPROCESS_ONLY="${POSTPROCESS_ONLY:-1}"
|
||||
ENABLE_PARALLEL="${ENABLE_PARALLEL:-0}"
|
||||
GPU_IDS="${GPU_IDS:-}"
|
||||
NUM_SHARDS="${NUM_SHARDS:-1}"
|
||||
SHARD_INDEX="${SHARD_INDEX:-0}"
|
||||
SHARD_STRATEGY="${SHARD_STRATEGY:-round_robin}"
|
||||
CASE_INDEX_START="${CASE_INDEX_START:-}"
|
||||
CASE_INDEX_END="${CASE_INDEX_END:-}"
|
||||
PARALLEL_LOG_DIR="${PARALLEL_LOG_DIR:-${OUTPUT_DIR%/}/parallel_logs}"
|
||||
FORWARD_ARGS=("$@")
|
||||
|
||||
# Optional post-inference tracking stage. When enabled, the launcher reuses
|
||||
# the exported-inference tracking wrapper, which runs track_objects.py over
|
||||
# predictions/{roi0,roi1,merge} and merges the results per case.
|
||||
ENABLE_TRACKING="${ENABLE_TRACKING:-0}"
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING:-0}"
|
||||
TRACK_STRICT="${TRACK_STRICT:-1}"
|
||||
TRACK_RESULTS_ROOT="${TRACK_RESULTS_ROOT:-${OUTPUT_DIR}}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12}"
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH:-0.3}"
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE:-5}"
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS:-1}"
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH:-100}"
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D:-0}"
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE:-10.0}"
|
||||
TRACK_MAX_FRAMES="${TRACK_MAX_FRAMES:-}"
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION:-20260506}"
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN:-*.json}"
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME:-combined_tracking.json}"
|
||||
TRACK_PARALLEL_JOBS="${TRACK_PARALLEL_JOBS:-4}"
|
||||
TRACKING_WRAPPER="${PROJECT_ROOT}/tools/temporal_analysis/track_objects_exported_onnx_infer_case.sh"
|
||||
|
||||
# Optional post-tracking protocol-conversion stage.
|
||||
# Runs convert_merge_tracking_exported_onnx_infer_case.sh on the tracked
|
||||
# case/eval-root output tree. By default, each case writes converted protocol
|
||||
# artifacts into its own objectlist/ subdirectory. Set CONVERT_OUTPUT_ROOT to
|
||||
# write only converted artifacts into a separate root while preserving case
|
||||
# relative paths.
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT:-1}"
|
||||
CONVERT_STRICT="${CONVERT_STRICT:-1}"
|
||||
CONVERT_RESULTS_ROOT="${CONVERT_RESULTS_ROOT:-${TRACK_RESULTS_ROOT}}"
|
||||
CONVERT_OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT:-/data1/dongying/Mono3d/G1Q3/model_inference/KPI/OP_KPI_SCENE/model_20260506_objectlist}"
|
||||
if [[ -z "${CONVERT_OUTPUT_LAYOUT+x}" ]]; then
|
||||
if [[ -n "${CONVERT_OUTPUT_ROOT}" ]]; then
|
||||
CONVERT_OUTPUT_LAYOUT="parallel_root"
|
||||
else
|
||||
CONVERT_OUTPUT_LAYOUT="case_subdir"
|
||||
fi
|
||||
else
|
||||
CONVERT_OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT:-case_subdir}"
|
||||
fi
|
||||
CONVERT_OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME:-objectlist}"
|
||||
CONVERT_MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME:-${TRACK_MERGE_OUTPUT_NAME}}"
|
||||
CONVERT_CAM_ID="${CONVERT_CAM_ID:-}"
|
||||
CONVERT_CASE_LIST_FILE="${CONVERT_CASE_LIST_FILE:-}"
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS:-8}"
|
||||
CONVERT_WRAPPER="${PROJECT_ROOT}/tools/convert_merge_tracking_bundle/convert_merge_tracking_exported_onnx_infer_case.sh"
|
||||
|
||||
is_eval_case_dir() {
|
||||
local case_dir="$1"
|
||||
|
||||
[[ -d "${case_dir}/images" ]] || return 1
|
||||
[[ -f "${case_dir}/calib/L2_calib/camera4.json" || -f "${case_dir}/calib/camera4.json" ]]
|
||||
}
|
||||
|
||||
collect_eval_case_dirs() {
|
||||
local eval_root="${1%/}"
|
||||
local first_level_dir
|
||||
local second_level_dir
|
||||
|
||||
while IFS= read -r -d '' first_level_dir; do
|
||||
if is_eval_case_dir "${first_level_dir}"; then
|
||||
printf '%s\n' "${first_level_dir}"
|
||||
continue
|
||||
fi
|
||||
|
||||
while IFS= read -r -d '' second_level_dir; do
|
||||
if is_eval_case_dir "${second_level_dir}"; then
|
||||
printf '%s\n' "${second_level_dir}"
|
||||
fi
|
||||
done < <(find "${first_level_dir}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
|
||||
done < <(find "${eval_root}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)
|
||||
}
|
||||
|
||||
write_convert_case_list() {
|
||||
local target_mode="$1"
|
||||
local convert_root="${2%/}"
|
||||
local list_file="$3"
|
||||
local eval_root="${EVAL_DIR:-${INPUT_DIR}}"
|
||||
local -a case_dirs=()
|
||||
local case_index_start="${CASE_INDEX_START:-0}"
|
||||
local case_index_end="${CASE_INDEX_END:-}"
|
||||
local total_cases
|
||||
local relative_case_dir
|
||||
local case_dir
|
||||
local index
|
||||
|
||||
mkdir -p "$(dirname "${list_file}")"
|
||||
: > "${list_file}"
|
||||
|
||||
if [[ "${target_mode}" == "case" ]]; then
|
||||
printf '%s\n' "${convert_root}" > "${list_file}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mapfile -t case_dirs < <(collect_eval_case_dirs "${eval_root}")
|
||||
total_cases="${#case_dirs[@]}"
|
||||
if [[ -z "${case_index_end}" ]]; then
|
||||
case_index_end="${total_cases}"
|
||||
fi
|
||||
|
||||
for ((index = case_index_start; index < case_index_end; index++)); do
|
||||
case_dir="${case_dirs[${index}]}"
|
||||
relative_case_dir="${case_dir#${eval_root%/}/}"
|
||||
printf '%s\n' "${convert_root}/${relative_case_dir}" >> "${list_file}"
|
||||
done
|
||||
}
|
||||
|
||||
resolve_target_mode() {
|
||||
if [[ -n "${CASE_DIR}" ]]; then
|
||||
printf 'case\n'
|
||||
elif [[ -n "${EVAL_DIR}" ]]; then
|
||||
printf 'eval\n'
|
||||
elif [[ -d "${INPUT_DIR}/images" ]]; then
|
||||
printf 'case\n'
|
||||
else
|
||||
printf 'eval\n'
|
||||
fi
|
||||
}
|
||||
|
||||
launch_parallel_eval_workers() {
|
||||
local target_mode="$1"
|
||||
local num_shards="${NUM_SHARDS}"
|
||||
local failed=0
|
||||
local -a gpu_ids_arr=()
|
||||
local -a pids=()
|
||||
local -a log_files=()
|
||||
|
||||
if [[ "${target_mode}" != "eval" ]]; then
|
||||
echo "ENABLE_PARALLEL=1 only supports eval-root inference." >&2
|
||||
echo "Please point INPUT_DIR/EVAL_DIR to an eval root instead of a single case." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "${GPU_IDS}" ]]; then
|
||||
echo "ENABLE_PARALLEL=1 requires GPU_IDS, for example: GPU_IDS=\"0 1 2 3\"." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2206
|
||||
gpu_ids_arr=(${GPU_IDS})
|
||||
if [[ "${num_shards}" == "1" ]]; then
|
||||
num_shards="${#gpu_ids_arr[@]}"
|
||||
fi
|
||||
if [[ "${num_shards}" -lt 2 ]]; then
|
||||
echo "Parallel mode requires at least 2 shards, got NUM_SHARDS=${num_shards}." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${#gpu_ids_arr[@]}" -ne "${num_shards}" ]]; then
|
||||
echo "GPU_IDS count (${#gpu_ids_arr[@]}) must match NUM_SHARDS (${num_shards}) in ENABLE_PARALLEL mode." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${PARALLEL_LOG_DIR}"
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Parallel eval-dir inference"
|
||||
echo "######################################################################"
|
||||
echo "Eval root : ${INPUT_DIR}"
|
||||
echo "Output root : ${OUTPUT_DIR}"
|
||||
echo "Shards : ${num_shards}"
|
||||
echo "Shard strategy : ${SHARD_STRATEGY}"
|
||||
echo "GPU ids : ${GPU_IDS}"
|
||||
echo "Worker logs : ${PARALLEL_LOG_DIR}"
|
||||
|
||||
for shard_index in "${!gpu_ids_arr[@]}"; do
|
||||
local gpu_id="${gpu_ids_arr[${shard_index}]}"
|
||||
local device="cuda:${gpu_id}"
|
||||
local attr_device="${ATTR_DEVICE:-${device}}"
|
||||
local log_file="${PARALLEL_LOG_DIR}/shard_${shard_index}_gpu_${gpu_id}.log"
|
||||
|
||||
echo "Launching shard ${shard_index}/${num_shards} on ${device} -> ${log_file}"
|
||||
ENABLE_PARALLEL=0 \
|
||||
ENABLE_TRACKING=0 \
|
||||
ENABLE_CONVERT=0 \
|
||||
NUM_SHARDS="${num_shards}" \
|
||||
SHARD_INDEX="${shard_index}" \
|
||||
SHARD_STRATEGY="${SHARD_STRATEGY}" \
|
||||
DEVICE="${device}" \
|
||||
ATTR_DEVICE="${attr_device}" \
|
||||
bash "${BASH_SOURCE[0]}" "${FORWARD_ARGS[@]}" >"${log_file}" 2>&1 &
|
||||
|
||||
pids+=("$!")
|
||||
log_files+=("${log_file}")
|
||||
done
|
||||
|
||||
for shard_index in "${!pids[@]}"; do
|
||||
if wait "${pids[${shard_index}]}"; then
|
||||
echo "Shard ${shard_index}/${num_shards} finished successfully. Log: ${log_files[${shard_index}]}"
|
||||
else
|
||||
echo "[ERROR] Shard ${shard_index}/${num_shards} failed. Log: ${log_files[${shard_index}]}" >&2
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${failed}" == "1" ]]; then
|
||||
echo "Parallel inference did not finish cleanly. Postprocess was skipped." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
)
|
||||
|
||||
if [[ -n "${DEVICE}" ]]; then
|
||||
CMD+=(--device "${DEVICE}")
|
||||
fi
|
||||
|
||||
if [[ -n "${ATTR_DEVICE}" ]]; then
|
||||
CMD+=(--attr-device "${ATTR_DEVICE}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CASE_INDEX_START}" ]]; then
|
||||
CMD+=(--case-index-start "${CASE_INDEX_START}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CASE_INDEX_END}" ]]; then
|
||||
CMD+=(--case-index-end "${CASE_INDEX_END}")
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASSES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASSES_ARR=(${VIS_CLASSES})
|
||||
CMD+=(--vis-classes "${VIS_CLASSES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASS_NAMES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASS_NAMES_ARR=(${VIS_CLASS_NAMES})
|
||||
CMD+=(--vis-class-names "${VIS_CLASS_NAMES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${NUM_SHARDS}" != "1" ]] || [[ "${SHARD_INDEX}" != "0" ]] || [[ "${SHARD_STRATEGY}" != "round_robin" ]]; then
|
||||
CMD+=(--num-shards "${NUM_SHARDS}" --shard-index "${SHARD_INDEX}" --shard-strategy "${SHARD_STRATEGY}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CASE_DIR}" ]]; then
|
||||
CMD+=(--case-dir "${CASE_DIR}")
|
||||
elif [[ -n "${EVAL_DIR}" ]]; then
|
||||
CMD+=(--eval-dir "${EVAL_DIR}")
|
||||
elif [[ -d "${INPUT_DIR}/images" ]]; then
|
||||
CMD+=(--case-dir "${INPUT_DIR}")
|
||||
else
|
||||
CMD+=(--eval-dir "${INPUT_DIR}")
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${SAVE_VISUALIZATION}" != "1" ]]; then
|
||||
CMD+=(--skip-visualizations)
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
|
||||
TARGET_MODE="$(resolve_target_mode)"
|
||||
|
||||
if [[ "${ENABLE_PARALLEL}" == "1" ]] && [[ "${POSTPROCESS_ONLY}" != "1" ]]; then
|
||||
launch_parallel_eval_workers "${TARGET_MODE}"
|
||||
POSTPROCESS_ONLY="1"
|
||||
fi
|
||||
|
||||
if [[ "${POSTPROCESS_ONLY}" == "1" ]]; then
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# POSTPROCESS_ONLY=1, skipping inference"
|
||||
echo "######################################################################"
|
||||
echo "Postprocess root: ${OUTPUT_DIR}"
|
||||
else
|
||||
"${CMD[@]}"
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_TRACKING}" == "1" ]]; then
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-inference tracking for exported case/eval-root outputs"
|
||||
echo "######################################################################"
|
||||
echo "Tracking root: ${TRACK_RESULTS_ROOT}"
|
||||
|
||||
if [[ "${TRACK_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
TRACK_PARALLEL_JOBS="${TRACK_PARALLEL_JOBS}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
TRACK_PARALLEL_JOBS="${TRACK_PARALLEL_JOBS}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Tracking failed, but inference outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
elif [[ "${ENABLE_CONVERT}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CONVERT}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="${CONVERT_OUTPUT_ROOT}"
|
||||
CONVERT_OUTPUT_LAYOUT_EFFECTIVE="${CONVERT_OUTPUT_LAYOUT}"
|
||||
CONVERT_CASE_LIST_FILE_EFFECTIVE="${CONVERT_CASE_LIST_FILE}"
|
||||
|
||||
case "${CONVERT_OUTPUT_LAYOUT}" in
|
||||
same_dir)
|
||||
if [[ -f "${CONVERT_RESULTS_ROOT}" ]] || [[ "$(basename "${CONVERT_RESULTS_ROOT}")" == "${CONVERT_MERGE_JSON_NAME}" ]]; then
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="$(dirname "${CONVERT_RESULTS_ROOT}")"
|
||||
else
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="${CONVERT_RESULTS_ROOT%/}"
|
||||
fi
|
||||
CONVERT_OUTPUT_LAYOUT_EFFECTIVE="parallel_root"
|
||||
;;
|
||||
case_subdir|parallel_root)
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported CONVERT_OUTPUT_LAYOUT: ${CONVERT_OUTPUT_LAYOUT}" >&2
|
||||
echo "Expected one of: same_dir, case_subdir, parallel_root" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-tracking protocol conversion for exported case/eval-root outputs"
|
||||
echo "######################################################################"
|
||||
echo "Conversion target: ${CONVERT_RESULTS_ROOT}"
|
||||
echo "Conversion layout: ${CONVERT_OUTPUT_LAYOUT}"
|
||||
|
||||
if [[ "${CONVERT_OUTPUT_LAYOUT}" == "same_dir" ]]; then
|
||||
echo "Conversion output: same directory as tracking results"
|
||||
elif [[ "${CONVERT_OUTPUT_LAYOUT}" == "case_subdir" ]]; then
|
||||
echo "Conversion subdir: ${CONVERT_OUTPUT_DIR_NAME}"
|
||||
elif [[ -n "${CONVERT_OUTPUT_ROOT_EFFECTIVE}" ]]; then
|
||||
echo "Conversion output root: ${CONVERT_OUTPUT_ROOT_EFFECTIVE}"
|
||||
fi
|
||||
|
||||
if [[ -z "${CONVERT_CASE_LIST_FILE_EFFECTIVE}" ]]; then
|
||||
CONVERT_CASE_LIST_FILE_EFFECTIVE="${OUTPUT_DIR%/}/_status/convert_case_list.txt"
|
||||
fi
|
||||
|
||||
if [[ -d "${CONVERT_RESULTS_ROOT}" ]]; then
|
||||
write_convert_case_list "${TARGET_MODE}" "${CONVERT_RESULTS_ROOT}" "${CONVERT_CASE_LIST_FILE_EFFECTIVE}"
|
||||
echo "Conversion case list: ${CONVERT_CASE_LIST_FILE_EFFECTIVE}"
|
||||
fi
|
||||
|
||||
if [[ "${CONVERT_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
CASE_LIST_FILE="${CONVERT_CASE_LIST_FILE_EFFECTIVE}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT_EFFECTIVE}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT_EFFECTIVE}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
CASE_LIST_FILE="${CONVERT_CASE_LIST_FILE_EFFECTIVE}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT_EFFECTIVE}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT_EFFECTIVE}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Protocol conversion failed, but tracking outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
77
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_clip_list.sh
Executable file
77
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_clip_list.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for PDCL clip-list batch inference.
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
CLIP_LIST_FILE="${CLIP_LIST_FILE:-${MODEL_INFERENCE_DIR}/examples/clip_lists/clips_aeb.txt}"
|
||||
EXPORT_ROOT="${EXPORT_ROOT:-/data1/dongying/Mono3d/G1Q3/model_inference/test/clips_aeb_export}"
|
||||
OUTPUT_PREFIX="${OUTPUT_PREFIX:-clip_export}"
|
||||
CAMERA_TOPIC="${CAMERA_TOPIC:-camera4}"
|
||||
MAX_FRAMES_PER_CLIP="${MAX_FRAMES_PER_CLIP:-0}"
|
||||
LIMIT_CLIPS="${LIMIT_CLIPS:-0}"
|
||||
SKIP_DONE="${SKIP_DONE:-1}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_20260413-raw/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/test/clips_aeb_no_cls}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-0}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-1}"
|
||||
VIS_CLASSES="${VIS_CLASSES:-9 10 11 12}"
|
||||
VIS_CLASS_NAMES="${VIS_CLASS_NAMES:-}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--clip-list-file "${CLIP_LIST_FILE}"
|
||||
--export-root "${EXPORT_ROOT}"
|
||||
--output-prefix "${OUTPUT_PREFIX}"
|
||||
--camera-topic "${CAMERA_TOPIC}"
|
||||
--max-frames-per-clip "${MAX_FRAMES_PER_CLIP}"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
)
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASSES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASSES_ARR=(${VIS_CLASSES})
|
||||
CMD+=(--vis-classes "${VIS_CLASSES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASS_NAMES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASS_NAMES_ARR=(${VIS_CLASS_NAMES})
|
||||
CMD+=(--vis-class-names "${VIS_CLASS_NAMES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${LIMIT_CLIPS}" != "0" ]]; then
|
||||
CMD+=(--limit-clips "${LIMIT_CLIPS}")
|
||||
fi
|
||||
|
||||
if [[ "${SKIP_DONE}" == "1" ]]; then
|
||||
CMD+=(--skip-done)
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
"${CMD[@]}"
|
||||
141
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_cncap_json.sh
Executable file
141
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_cncap_json.sh
Executable file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for CNCAP JSON batch video inference.
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
CNCAP_JSON_FILE="${CNCAP_JSON_FILE:-${MODEL_INFERENCE_DIR}/examples/cncap/G1M3_AFS1616_CNCAP-202411.json}"
|
||||
CNCAP_VALUES_KEY="${CNCAP_VALUES_KEY:-values}"
|
||||
CNCAP_PATH_PREFIX_SRC="${CNCAP_PATH_PREFIX_SRC:-/mnt/hfs/project-G1M3}"
|
||||
CNCAP_PATH_PREFIX_DST="${CNCAP_PATH_PREFIX_DST:-/mnt/G1M3}"
|
||||
VIDEO_STRIDE="${VIDEO_STRIDE:-1}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_20260506-keep_fake_3d_branch/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/cncap_2024_with_cls_ego/model_20260506_keep_fake3d_validate}"
|
||||
MAX_IMAGES="${MAX_IMAGES:-0}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-1}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-0}"
|
||||
DEVICE="${DEVICE:-cuda:2}"
|
||||
VIS_CLASSES="${VIS_CLASSES:-}"
|
||||
VIS_CLASS_NAMES="${VIS_CLASS_NAMES:-}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Auto-tracking: run tracking immediately after inference completes.
|
||||
# Set AUTO_TRACK=1 to enable. All TRACK_* variables mirror the defaults in
|
||||
# track_objects_exported_onnx_infer_cncap_json.sh and can be overridden.
|
||||
# ---------------------------------------------------------------------------
|
||||
AUTO_TRACK="${AUTO_TRACK:-1}"
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING:-0}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12 17 18 19}"
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH:-0.3}"
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE:-5}"
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS:-1}"
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH:-100}"
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE:-10.0}"
|
||||
TRACK_MAX_FRAMES="${TRACK_MAX_FRAMES:-}"
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION:-20260506}"
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN:-*.json}"
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D:-0}"
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME:-combined_tracking.json}"
|
||||
|
||||
if [[ -z "${CNCAP_JSON_FILE}" ]]; then
|
||||
echo "CNCAP_JSON_FILE is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# /data1/dongying/Mono3d/G1Q3/model_inference/cncap/cncap_2024_with_cls_ego/model_20260407/20251115/CVE/CPLA_RL_AEB_20_5_1_20251115140740/predictions/roi0/camera4_345630.json
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--cncap-json-file "${CNCAP_JSON_FILE}"
|
||||
--cncap-values-key "${CNCAP_VALUES_KEY}"
|
||||
--cncap-path-prefix-src "${CNCAP_PATH_PREFIX_SRC}"
|
||||
--cncap-path-prefix-dst "${CNCAP_PATH_PREFIX_DST}"
|
||||
--video-stride "${VIDEO_STRIDE}"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
--device "${DEVICE}"
|
||||
)
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASSES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASSES_ARR=(${VIS_CLASSES})
|
||||
CMD+=(--vis-classes "${VIS_CLASSES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASS_NAMES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASS_NAMES_ARR=(${VIS_CLASS_NAMES})
|
||||
CMD+=(--vis-class-names "${VIS_CLASS_NAMES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${MAX_IMAGES}" != "0" ]]; then
|
||||
CMD+=(--max-images "${MAX_IMAGES}")
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
"${CMD[@]}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Auto-tracking step
|
||||
# ---------------------------------------------------------------------------
|
||||
if [[ "${AUTO_TRACK}" == "1" ]]; then
|
||||
TRACKING_SCRIPT="${PROJECT_ROOT}/tools/temporal_analysis/track_objects_exported_onnx_infer_cncap_json.sh"
|
||||
if [[ ! -f "${TRACKING_SCRIPT}" ]]; then
|
||||
echo "[AUTO_TRACK] ERROR: tracking script not found: ${TRACKING_SCRIPT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# AUTO_TRACK=1 — starting CNCAP tracking on ${OUTPUT_DIR}"
|
||||
echo "######################################################################"
|
||||
|
||||
TRACK_ENV=(
|
||||
PYTHON_BIN="${PYTHON_BIN}"
|
||||
RESULTS_ROOT="${OUTPUT_DIR}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES}"
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}"
|
||||
MAX_AGE="${TRACK_MAX_AGE}"
|
||||
MIN_HITS="${TRACK_MIN_HITS}"
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}"
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}"
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}"
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}"
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}"
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}"
|
||||
)
|
||||
|
||||
if [[ -n "${TRACK_MAX_FRAMES}" ]]; then
|
||||
TRACK_ENV+=(MAX_FRAMES="${TRACK_MAX_FRAMES}")
|
||||
fi
|
||||
|
||||
if [[ -n "${TRACK_MODEL_VERSION}" ]]; then
|
||||
TRACK_ENV+=(MODEL_VERSION="${TRACK_MODEL_VERSION}")
|
||||
fi
|
||||
|
||||
env "${TRACK_ENV[@]}" bash "${TRACKING_SCRIPT}"
|
||||
fi
|
||||
218
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_cncap_scene.sh
Executable file
218
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_cncap_scene.sh
Executable file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
BASE_SCRIPT="${SCRIPT_DIR}/run_two_roi_exported_onnx_infer_event_json.sh"
|
||||
|
||||
# Launcher for CNCAP scene/rawid batch inference based on scene-grouped JSON
|
||||
# records that contain direct clip-id lists.
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
EVENT_JSON_FILE="${EVENT_JSON_FILE:-${MODEL_INFERENCE_DIR}/examples/cncap/aeb_clips-20260429.json}"
|
||||
SCENE="${SCENE:-SCP}"
|
||||
EVENT_ID_FIELD="${EVENT_ID_FIELD:-rawid}"
|
||||
EVENT_CLIP_IDS_FIELD="${EVENT_CLIP_IDS_FIELD:-clips}"
|
||||
CONDITION_FIELDS="${CONDITION_FIELDS:-偏置 目标速度 自车速度}"
|
||||
MAX_RECORDS_PER_CONDITION="${MAX_RECORDS_PER_CONDITION:-1}"
|
||||
CONDITION_SELECT_STRATEGY="${CONDITION_SELECT_STRATEGY:-first}"
|
||||
SELECTION_ONLY="${SELECTION_ONLY:-0}"
|
||||
MAX_EVENTS="${MAX_EVENTS:-0}"
|
||||
EVENT_CACHE_FILE="${EVENT_CACHE_FILE:-${MODEL_INFERENCE_DIR}/.cache/event_clip_cache.json}"
|
||||
EVENT_RESOLVE_WORKERS="${EVENT_RESOLVE_WORKERS:-4}"
|
||||
EVENT_REQUEST_TIMEOUT="${EVENT_REQUEST_TIMEOUT:-60}"
|
||||
EVENT_REQUEST_RETRIES="${EVENT_REQUEST_RETRIES:-3}"
|
||||
EVENT_REQUEST_RETRY_BACKOFF_SEC="${EVENT_REQUEST_RETRY_BACKOFF_SEC:-2.0}"
|
||||
EXPORT_ROOT="${EXPORT_ROOT:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/aeb_clips_20260429_selected/event_exports}"
|
||||
OUTPUT_PREFIX="${OUTPUT_PREFIX:-clip}"
|
||||
CAMERA_TOPIC="${CAMERA_TOPIC:-camera4}"
|
||||
MAX_FRAMES_PER_CLIP="${MAX_FRAMES_PER_CLIP:-0}"
|
||||
LIMIT_CLIPS="${LIMIT_CLIPS:-0}"
|
||||
SKIP_DONE="${SKIP_DONE:-1}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${MODEL_INFERENCE_DIR}/../../runs/export/train_mono3d_two_roi_20260506-drop_fake_3d_branch/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/aeb_clips_20260429_selected/model_20260506_vis_distance}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-0}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
SHOW_DISTANCE_LABEL="${SHOW_DISTANCE_LABEL:-1}"
|
||||
DISTANCE_LABEL_MODE="${DISTANCE_LABEL_MODE:-depth_lateral}"
|
||||
DISTANCE_LABEL_PANELS="${DISTANCE_LABEL_PANELS:-3d}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
# Optional rawid L2 package download through mdi.
|
||||
ENABLE_RAW_L2_DOWNLOAD="${ENABLE_RAW_L2_DOWNLOAD:-1}"
|
||||
RAW_L2_DOWNLOAD_ONLY="${RAW_L2_DOWNLOAD_ONLY:-0}"
|
||||
RAW_L2_DOWNLOAD_ROOT="${RAW_L2_DOWNLOAD_ROOT:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/aeb_clips_20260429_selected/raw_l2}"
|
||||
RAW_L2_DOWNLOAD_MANIFEST="${RAW_L2_DOWNLOAD_MANIFEST:-${RAW_L2_DOWNLOAD_ROOT}/download_manifest.json}"
|
||||
RAW_L2_DOWNLOAD_DRY_RUN="${RAW_L2_DOWNLOAD_DRY_RUN:-0}"
|
||||
RAW_L2_DOWNLOAD_SKIP_DONE="${RAW_L2_DOWNLOAD_SKIP_DONE:-1}"
|
||||
RAW_L2_DOWNLOAD_STRICT="${RAW_L2_DOWNLOAD_STRICT:-1}"
|
||||
|
||||
# Auto-tracking is delegated to the shared event-json launcher.
|
||||
# Set TRACK_ONLY=1 to skip clip export/inference and run tracking on OUTPUT_DIR.
|
||||
# Set CONVERT_ONLY=1 to skip clip export/inference and tracking, then convert.
|
||||
TRACK_ONLY="${TRACK_ONLY:-0}"
|
||||
CONVERT_ONLY="${CONVERT_ONLY:-0}"
|
||||
AUTO_TRACK="${AUTO_TRACK:-1}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12 17 18 19}"
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH:-0.3}"
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE:-5}"
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS:-1}"
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH:-100}"
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE:-10.0}"
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION:-20260506}"
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN:-*.json}"
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D:-0}"
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME:-combined_tracking.json}"
|
||||
TRACK_MANIFEST_NAME="${TRACK_MANIFEST_NAME:-frame_order_manifest.json}"
|
||||
TRACK_EVENT_TRACKING_DIRNAME="${TRACK_EVENT_TRACKING_DIRNAME:-}"
|
||||
|
||||
# Post-tracking protocol conversion. This scene launcher converts only the
|
||||
# event-level merge.json by default.
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT:-1}"
|
||||
CONVERT_STRICT="${CONVERT_STRICT:-1}"
|
||||
CONVERT_RESULTS_ROOT="${CONVERT_RESULTS_ROOT:-${OUTPUT_DIR}}"
|
||||
CONVERT_OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT:-${OUTPUT_DIR%/}_objectlist}"
|
||||
CONVERT_OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT:-parallel_root}"
|
||||
CONVERT_OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME:-objectlist}"
|
||||
CONVERT_MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME:-merge.json}"
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS:-4}"
|
||||
CONVERT_CAM_ID="${CONVERT_CAM_ID:-}"
|
||||
|
||||
if [[ ! -f "${BASE_SCRIPT}" ]]; then
|
||||
echo "Base launcher not found: ${BASE_SCRIPT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run_raw_l2_download() {
|
||||
local downloader="${MODEL_INFERENCE_DIR}/core/download_rawid_l2_by_event_json.py"
|
||||
if [[ ! -f "${downloader}" ]]; then
|
||||
echo "Raw L2 downloader not found: ${downloader}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local -a cmd=(
|
||||
"${PYTHON_BIN}" "${downloader}"
|
||||
--event-json-file "${EVENT_JSON_FILE}"
|
||||
--event-id-field "${EVENT_ID_FIELD}"
|
||||
--event-clip-ids-field "${EVENT_CLIP_IDS_FIELD}"
|
||||
--event-cache-file "${EVENT_CACHE_FILE}"
|
||||
--event-resolve-workers "${EVENT_RESOLVE_WORKERS}"
|
||||
--event-request-timeout "${EVENT_REQUEST_TIMEOUT}"
|
||||
--event-request-retries "${EVENT_REQUEST_RETRIES}"
|
||||
--event-request-retry-backoff-sec "${EVENT_REQUEST_RETRY_BACKOFF_SEC}"
|
||||
--output-root "${RAW_L2_DOWNLOAD_ROOT}"
|
||||
--manifest-path "${RAW_L2_DOWNLOAD_MANIFEST}"
|
||||
)
|
||||
|
||||
if [[ -n "${SCENE}" ]]; then
|
||||
cmd+=(--scene "${SCENE}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CONDITION_FIELDS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
CONDITION_FIELDS_ARR=(${CONDITION_FIELDS})
|
||||
cmd+=(--condition-fields "${CONDITION_FIELDS_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${MAX_RECORDS_PER_CONDITION}" != "0" ]]; then
|
||||
cmd+=(--max-records-per-condition "${MAX_RECORDS_PER_CONDITION}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CONDITION_SELECT_STRATEGY}" ]]; then
|
||||
cmd+=(--condition-select-strategy "${CONDITION_SELECT_STRATEGY}")
|
||||
fi
|
||||
|
||||
if [[ "${MAX_EVENTS}" != "0" ]]; then
|
||||
cmd+=(--max-events "${MAX_EVENTS}")
|
||||
fi
|
||||
|
||||
if [[ "${RAW_L2_DOWNLOAD_DRY_RUN}" == "1" ]]; then
|
||||
cmd+=(--dry-run)
|
||||
fi
|
||||
|
||||
if [[ "${RAW_L2_DOWNLOAD_SKIP_DONE}" == "1" ]]; then
|
||||
cmd+=(--skip-done)
|
||||
fi
|
||||
|
||||
if [[ "${RAW_L2_DOWNLOAD_STRICT}" == "1" ]]; then
|
||||
cmd+=(--strict)
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Rawid L2 package download through mdi"
|
||||
echo "######################################################################"
|
||||
echo "Download root : ${RAW_L2_DOWNLOAD_ROOT}"
|
||||
echo "Manifest : ${RAW_L2_DOWNLOAD_MANIFEST}"
|
||||
"${cmd[@]}"
|
||||
}
|
||||
|
||||
if [[ "${ENABLE_RAW_L2_DOWNLOAD}" == "1" || "${RAW_L2_DOWNLOAD_ONLY}" == "1" ]]; then
|
||||
if [[ "${RAW_L2_DOWNLOAD_STRICT}" == "1" ]]; then
|
||||
run_raw_l2_download
|
||||
else
|
||||
if ! run_raw_l2_download; then
|
||||
echo "[WARN] Raw L2 download failed, continuing because RAW_L2_DOWNLOAD_STRICT=0" >&2
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${RAW_L2_DOWNLOAD_ONLY}" == "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
env \
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
EVENT_JSON_FILE="${EVENT_JSON_FILE}" \
|
||||
SCENE="${SCENE}" \
|
||||
EVENT_ID_FIELD="${EVENT_ID_FIELD}" \
|
||||
EVENT_CLIP_IDS_FIELD="${EVENT_CLIP_IDS_FIELD}" \
|
||||
CONDITION_FIELDS="${CONDITION_FIELDS}" \
|
||||
MAX_RECORDS_PER_CONDITION="${MAX_RECORDS_PER_CONDITION}" \
|
||||
CONDITION_SELECT_STRATEGY="${CONDITION_SELECT_STRATEGY}" \
|
||||
SELECTION_ONLY="${SELECTION_ONLY}" \
|
||||
MAX_EVENTS="${MAX_EVENTS}" \
|
||||
EVENT_CACHE_FILE="${EVENT_CACHE_FILE}" \
|
||||
EVENT_RESOLVE_WORKERS="${EVENT_RESOLVE_WORKERS}" \
|
||||
EVENT_REQUEST_TIMEOUT="${EVENT_REQUEST_TIMEOUT}" \
|
||||
EVENT_REQUEST_RETRIES="${EVENT_REQUEST_RETRIES}" \
|
||||
EVENT_REQUEST_RETRY_BACKOFF_SEC="${EVENT_REQUEST_RETRY_BACKOFF_SEC}" \
|
||||
EXPORT_ROOT="${EXPORT_ROOT}" \
|
||||
OUTPUT_PREFIX="${OUTPUT_PREFIX}" \
|
||||
CAMERA_TOPIC="${CAMERA_TOPIC}" \
|
||||
MAX_FRAMES_PER_CLIP="${MAX_FRAMES_PER_CLIP}" \
|
||||
LIMIT_CLIPS="${LIMIT_CLIPS}" \
|
||||
SKIP_DONE="${SKIP_DONE}" \
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL}" \
|
||||
OUTPUT_DIR="${OUTPUT_DIR}" \
|
||||
ENABLE_ATTR="${ENABLE_ATTR}" \
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR}" \
|
||||
SHOW_DISTANCE_LABEL="${SHOW_DISTANCE_LABEL}" \
|
||||
DISTANCE_LABEL_MODE="${DISTANCE_LABEL_MODE}" \
|
||||
DISTANCE_LABEL_PANELS="${DISTANCE_LABEL_PANELS}" \
|
||||
EXTRA_ARGS="${EXTRA_ARGS}" \
|
||||
TRACK_ONLY="${TRACK_ONLY}" \
|
||||
CONVERT_ONLY="${CONVERT_ONLY}" \
|
||||
AUTO_TRACK="${AUTO_TRACK}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
TRACK_MANIFEST_NAME="${TRACK_MANIFEST_NAME}" \
|
||||
TRACK_EVENT_TRACKING_DIRNAME="${TRACK_EVENT_TRACKING_DIRNAME}" \
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT}" \
|
||||
CONVERT_STRICT="${CONVERT_STRICT}" \
|
||||
CONVERT_RESULTS_ROOT="${CONVERT_RESULTS_ROOT}" \
|
||||
CONVERT_OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT}" \
|
||||
CONVERT_OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT}" \
|
||||
CONVERT_OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
CONVERT_MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS}" \
|
||||
CONVERT_CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${BASE_SCRIPT}" "$@"
|
||||
287
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_event_json.sh
Executable file
287
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_event_json.sh
Executable file
@@ -0,0 +1,287 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for scene event-json batch inference.
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
EVENT_JSON_FILE="${EVENT_JSON_FILE:-${MODEL_INFERENCE_DIR}/examples/events/G1Q3_场地评测数据集.json}"
|
||||
SCENE="${SCENE:-}"
|
||||
EVENT_ID_FIELD="${EVENT_ID_FIELD:-data_path}"
|
||||
EVENT_CLIP_IDS_FIELD="${EVENT_CLIP_IDS_FIELD:-clips}"
|
||||
CONDITION_FIELDS="${CONDITION_FIELDS:-}"
|
||||
MAX_RECORDS_PER_CONDITION="${MAX_RECORDS_PER_CONDITION:-0}"
|
||||
CONDITION_SELECT_STRATEGY="${CONDITION_SELECT_STRATEGY:-first}"
|
||||
SELECTION_ONLY="${SELECTION_ONLY:-0}"
|
||||
MAX_EVENTS="${MAX_EVENTS:-0}"
|
||||
EVENT_CACHE_FILE="${EVENT_CACHE_FILE:-${MODEL_INFERENCE_DIR}/.cache/event_clip_cache.json}"
|
||||
EVENT_RESOLVE_WORKERS="${EVENT_RESOLVE_WORKERS:-4}"
|
||||
EVENT_REQUEST_TIMEOUT="${EVENT_REQUEST_TIMEOUT:-60}"
|
||||
EVENT_REQUEST_RETRIES="${EVENT_REQUEST_RETRIES:-3}"
|
||||
EVENT_REQUEST_RETRY_BACKOFF_SEC="${EVENT_REQUEST_RETRY_BACKOFF_SEC:-2.0}"
|
||||
EXPORT_ROOT="${EXPORT_ROOT:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/cncap_2021_with_cls_ego/event_exports}"
|
||||
OUTPUT_PREFIX="${OUTPUT_PREFIX:-clip}"
|
||||
CAMERA_TOPIC="${CAMERA_TOPIC:-camera4}"
|
||||
MAX_FRAMES_PER_CLIP="${MAX_FRAMES_PER_CLIP:-0}"
|
||||
LIMIT_CLIPS="${LIMIT_CLIPS:-0}"
|
||||
SKIP_DONE="${SKIP_DONE:-1}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_20260506-keep_fake_3d_branch/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/cncap_2021_with_cls_ego/model_20260506_keep_fake3d_validate}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-1}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-0}"
|
||||
VIS_CLASSES="${VIS_CLASSES:-}"
|
||||
VIS_CLASS_NAMES="${VIS_CLASS_NAMES:-}"
|
||||
SHOW_DISTANCE_LABEL="${SHOW_DISTANCE_LABEL:-0}"
|
||||
DISTANCE_LABEL_MODE="${DISTANCE_LABEL_MODE:-depth}"
|
||||
DISTANCE_LABEL_PANELS="${DISTANCE_LABEL_PANELS:-3d}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Auto-tracking: run tracking immediately after inference completes, or set
|
||||
# TRACK_ONLY=1 to skip clip export/inference and run tracking on OUTPUT_DIR.
|
||||
# Set CONVERT_ONLY=1 to skip clip export/inference and tracking, then convert.
|
||||
# Set AUTO_TRACK=1 to enable. All TRACK_* variables mirror the defaults in
|
||||
# track_objects_exported_onnx_infer_event_json.sh and can be overridden.
|
||||
# ---------------------------------------------------------------------------
|
||||
TRACK_ONLY="${TRACK_ONLY:-0}"
|
||||
CONVERT_ONLY="${CONVERT_ONLY:-0}"
|
||||
AUTO_TRACK="${AUTO_TRACK:-1}"
|
||||
if [[ "${TRACK_ONLY}" == "1" ]] && [[ "${CONVERT_ONLY}" != "1" ]]; then
|
||||
AUTO_TRACK="1"
|
||||
fi
|
||||
if [[ "${CONVERT_ONLY}" == "1" ]]; then
|
||||
AUTO_TRACK="0"
|
||||
fi
|
||||
TRACK_CLASSES="${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12 17 18 19}"
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH:-0.3}"
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE:-5}"
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS:-1}"
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH:-100}"
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE:-10.0}"
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION:-20260506}"
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN:-*.json}"
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D:-0}"
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME:-combined_tracking.json}"
|
||||
TRACK_MANIFEST_NAME="${TRACK_MANIFEST_NAME:-frame_order_manifest.json}"
|
||||
TRACK_EVENT_TRACKING_DIRNAME="${TRACK_EVENT_TRACKING_DIRNAME:-}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Post-tracking protocol conversion.
|
||||
# Only merge.json is converted by default; override CONVERT_MERGE_JSON_NAME if
|
||||
# another tracking result needs conversion.
|
||||
# ---------------------------------------------------------------------------
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT:-0}"
|
||||
if [[ "${CONVERT_ONLY}" == "1" ]]; then
|
||||
ENABLE_CONVERT="1"
|
||||
fi
|
||||
CONVERT_STRICT="${CONVERT_STRICT:-1}"
|
||||
CONVERT_RESULTS_ROOT="${CONVERT_RESULTS_ROOT:-${OUTPUT_DIR}}"
|
||||
CONVERT_OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT:-${OUTPUT_DIR%/}_objectlist}"
|
||||
CONVERT_OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT:-parallel_root}"
|
||||
CONVERT_OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME:-objectlist}"
|
||||
CONVERT_MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME:-merge.json}"
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS:-4}"
|
||||
CONVERT_CAM_ID="${CONVERT_CAM_ID:-}"
|
||||
CONVERT_WRAPPER="${PROJECT_ROOT}/tools/convert_merge_tracking_bundle/convert_merge_tracking_exported_onnx_infer_case.sh"
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--event-json-file "${EVENT_JSON_FILE}"
|
||||
--event-id-field "${EVENT_ID_FIELD}"
|
||||
--event-clip-ids-field "${EVENT_CLIP_IDS_FIELD}"
|
||||
--event-cache-file "${EVENT_CACHE_FILE}"
|
||||
--event-resolve-workers "${EVENT_RESOLVE_WORKERS}"
|
||||
--event-request-timeout "${EVENT_REQUEST_TIMEOUT}"
|
||||
--event-request-retries "${EVENT_REQUEST_RETRIES}"
|
||||
--event-request-retry-backoff-sec "${EVENT_REQUEST_RETRY_BACKOFF_SEC}"
|
||||
--export-root "${EXPORT_ROOT}"
|
||||
--output-prefix "${OUTPUT_PREFIX}"
|
||||
--camera-topic "${CAMERA_TOPIC}"
|
||||
--max-frames-per-clip "${MAX_FRAMES_PER_CLIP}"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
)
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASSES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASSES_ARR=(${VIS_CLASSES})
|
||||
CMD+=(--vis-classes "${VIS_CLASSES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASS_NAMES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASS_NAMES_ARR=(${VIS_CLASS_NAMES})
|
||||
CMD+=(--vis-class-names "${VIS_CLASS_NAMES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${SHOW_DISTANCE_LABEL}" == "1" ]]; then
|
||||
CMD+=(--show-distance-label)
|
||||
if [[ -n "${DISTANCE_LABEL_MODE}" ]]; then
|
||||
CMD+=(--distance-label-mode "${DISTANCE_LABEL_MODE}")
|
||||
fi
|
||||
if [[ -n "${DISTANCE_LABEL_PANELS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
DISTANCE_LABEL_PANELS_ARR=(${DISTANCE_LABEL_PANELS})
|
||||
CMD+=(--distance-label-panels "${DISTANCE_LABEL_PANELS_ARR[@]}")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "${SCENE}" ]]; then
|
||||
CMD+=(--scene "${SCENE}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CONDITION_FIELDS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
CONDITION_FIELDS_ARR=(${CONDITION_FIELDS})
|
||||
CMD+=(--condition-fields "${CONDITION_FIELDS_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${MAX_RECORDS_PER_CONDITION}" != "0" ]]; then
|
||||
CMD+=(--max-records-per-condition "${MAX_RECORDS_PER_CONDITION}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CONDITION_SELECT_STRATEGY}" ]]; then
|
||||
CMD+=(--condition-select-strategy "${CONDITION_SELECT_STRATEGY}")
|
||||
fi
|
||||
|
||||
if [[ "${SELECTION_ONLY}" == "1" ]]; then
|
||||
CMD+=(--selection-only)
|
||||
fi
|
||||
|
||||
if [[ "${MAX_EVENTS}" != "0" ]]; then
|
||||
CMD+=(--max-events "${MAX_EVENTS}")
|
||||
fi
|
||||
|
||||
if [[ "${LIMIT_CLIPS}" != "0" ]]; then
|
||||
CMD+=(--limit-clips "${LIMIT_CLIPS}")
|
||||
fi
|
||||
|
||||
if [[ "${SKIP_DONE}" == "1" ]]; then
|
||||
CMD+=(--skip-done)
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
|
||||
if [[ "${CONVERT_ONLY}" == "1" ]]; then
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# CONVERT_ONLY=1, skipping event-json clip export/inference and tracking"
|
||||
echo "######################################################################"
|
||||
echo "Conversion target: ${CONVERT_RESULTS_ROOT}"
|
||||
elif [[ "${TRACK_ONLY}" == "1" ]]; then
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# TRACK_ONLY=1, skipping event-json clip export/inference"
|
||||
echo "######################################################################"
|
||||
echo "Tracking root: ${OUTPUT_DIR}"
|
||||
else
|
||||
"${CMD[@]}"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Auto-tracking step
|
||||
# ---------------------------------------------------------------------------
|
||||
if [[ "${AUTO_TRACK}" == "1" ]]; then
|
||||
TRACKING_SCRIPT="${PROJECT_ROOT}/tools/temporal_analysis/track_objects_exported_onnx_infer_event_json.sh"
|
||||
if [[ ! -f "${TRACKING_SCRIPT}" ]]; then
|
||||
echo "[AUTO_TRACK] ERROR: tracking script not found: ${TRACKING_SCRIPT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# AUTO_TRACK=1 — starting event-level tracking on ${OUTPUT_DIR}"
|
||||
echo "######################################################################"
|
||||
|
||||
TRACK_ENV=(
|
||||
PYTHON_BIN="${PYTHON_BIN}"
|
||||
RESULTS_ROOT="${OUTPUT_DIR}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES}"
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}"
|
||||
MAX_AGE="${TRACK_MAX_AGE}"
|
||||
MIN_HITS="${TRACK_MIN_HITS}"
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}"
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}"
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}"
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}"
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}"
|
||||
MANIFEST_NAME="${TRACK_MANIFEST_NAME}"
|
||||
)
|
||||
|
||||
if [[ -n "${TRACK_MODEL_VERSION}" ]]; then
|
||||
TRACK_ENV+=(MODEL_VERSION="${TRACK_MODEL_VERSION}")
|
||||
fi
|
||||
|
||||
if [[ -n "${TRACK_EVENT_TRACKING_DIRNAME}" ]]; then
|
||||
TRACK_ENV+=(EVENT_TRACKING_DIRNAME="${TRACK_EVENT_TRACKING_DIRNAME}")
|
||||
fi
|
||||
|
||||
# Propagate SCENE as SCENE_FILTER so tracking processes only the same scene.
|
||||
if [[ -n "${SCENE}" ]]; then
|
||||
TRACK_ENV+=(SCENE_FILTER="${SCENE}")
|
||||
fi
|
||||
|
||||
env "${TRACK_ENV[@]}" bash "${TRACKING_SCRIPT}"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Post-tracking protocol conversion step
|
||||
# ---------------------------------------------------------------------------
|
||||
if [[ "${ENABLE_CONVERT}" == "1" ]]; then
|
||||
if [[ ! -f "${CONVERT_WRAPPER}" ]]; then
|
||||
echo "[ENABLE_CONVERT] ERROR: conversion script not found: ${CONVERT_WRAPPER}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# ENABLE_CONVERT=1 — converting tracking ${CONVERT_MERGE_JSON_NAME}"
|
||||
echo "######################################################################"
|
||||
echo "Conversion target: ${CONVERT_RESULTS_ROOT}"
|
||||
echo "Conversion layout: ${CONVERT_OUTPUT_LAYOUT}"
|
||||
if [[ "${CONVERT_OUTPUT_LAYOUT}" == "case_subdir" ]]; then
|
||||
echo "Conversion subdir: ${CONVERT_OUTPUT_DIR_NAME}"
|
||||
elif [[ -n "${CONVERT_OUTPUT_ROOT}" ]]; then
|
||||
echo "Conversion output root: ${CONVERT_OUTPUT_ROOT}"
|
||||
fi
|
||||
|
||||
CONVERT_ENV=(
|
||||
PYTHON_BIN="${PYTHON_BIN}"
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT}"
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT}"
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}"
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}"
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS}"
|
||||
CAM_ID="${CONVERT_CAM_ID}"
|
||||
)
|
||||
|
||||
if [[ "${CONVERT_STRICT}" == "1" ]]; then
|
||||
env "${CONVERT_ENV[@]}" bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"
|
||||
else
|
||||
if ! env "${CONVERT_ENV[@]}" bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Protocol conversion failed, but tracking outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,307 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Parallel launcher for event-json inference by scene.
|
||||
#
|
||||
# Strategy:
|
||||
# 1. Read scene names from the top-level keys of EVENT_JSON_FILE.
|
||||
# 2. Distribute scenes across GPU_IDS using round-robin or contiguous mode.
|
||||
# 3. Each scene runs the existing event-json launcher in an isolated temp root.
|
||||
# 4. After a scene succeeds, move scene artifacts into the final roots.
|
||||
#
|
||||
# This avoids concurrent writes to the same root-level manifest/status files while
|
||||
# preserving the existing single-scene inference, tracking, and conversion logic.
|
||||
|
||||
WORKER_SCRIPT="${SCRIPT_DIR}/run_two_roi_exported_onnx_infer_event_json.sh"
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
EVENT_JSON_FILE="${EVENT_JSON_FILE:-${MODEL_INFERENCE_DIR}/examples/events/G1Q3_场地评测数据集.json}"
|
||||
EVENT_ID_FIELD="${EVENT_ID_FIELD:-event_uuid}"
|
||||
EVENT_CLIP_IDS_FIELD="${EVENT_CLIP_IDS_FIELD:-clips}"
|
||||
GPU_IDS="${GPU_IDS:-0 1}"
|
||||
SCENES="${SCENES:-}"
|
||||
SCENE_REGEX="${SCENE_REGEX:-}"
|
||||
MAX_SCENES="${MAX_SCENES:-0}"
|
||||
SCENE_DISTRIBUTION="${SCENE_DISTRIBUTION:-round_robin}"
|
||||
DRY_RUN="${DRY_RUN:-0}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/cncap_2021_with_cls_ego/model_20260506_keep_fake3d_validate}"
|
||||
EXPORT_ROOT="${EXPORT_ROOT:-/data1/dongying/Mono3d/G1Q3/model_inference/cncap/cncap_2021_with_cls_ego/event_exports_new}"
|
||||
CONVERT_OUTPUT_ROOT_BASE="${CONVERT_OUTPUT_ROOT:-${OUTPUT_DIR%/}_objectlist}"
|
||||
PARALLEL_RUN_ID="${PARALLEL_RUN_ID:-$(date +%Y%m%d_%H%M%S)}"
|
||||
PARALLEL_TMP_ROOT="${PARALLEL_TMP_ROOT:-${OUTPUT_DIR%/}/_parallel_scene_tmp/${PARALLEL_RUN_ID}}"
|
||||
PARALLEL_LOG_DIR="${PARALLEL_LOG_DIR:-${OUTPUT_DIR%/}/parallel_scene_logs/${PARALLEL_RUN_ID}}"
|
||||
SKIP_EXISTING_SCENES="${SKIP_EXISTING_SCENES:-0}"
|
||||
FORWARD_ARGS=("$@")
|
||||
|
||||
discover_scenes() {
|
||||
if [[ -n "${SCENES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
DISCOVERED_SCENES=(${SCENES})
|
||||
else
|
||||
mapfile -t DISCOVERED_SCENES < <(
|
||||
"${PYTHON_BIN}" - "${EVENT_JSON_FILE}" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
json_path = sys.argv[1]
|
||||
with open(json_path, encoding="utf-8") as file:
|
||||
payload = json.load(file)
|
||||
if not isinstance(payload, dict):
|
||||
raise SystemExit(f"Expected top-level object in {json_path}, got {type(payload).__name__}")
|
||||
for scene_name in sorted(payload):
|
||||
print(scene_name)
|
||||
PY
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ -n "${SCENE_REGEX}" ]]; then
|
||||
local -a filtered_scenes=()
|
||||
local scene_name
|
||||
for scene_name in "${DISCOVERED_SCENES[@]}"; do
|
||||
if [[ "${scene_name}" =~ ${SCENE_REGEX} ]]; then
|
||||
filtered_scenes+=("${scene_name}")
|
||||
fi
|
||||
done
|
||||
DISCOVERED_SCENES=("${filtered_scenes[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${MAX_SCENES}" != "0" ]] && [[ "${MAX_SCENES}" -lt "${#DISCOVERED_SCENES[@]}" ]]; then
|
||||
DISCOVERED_SCENES=("${DISCOVERED_SCENES[@]:0:${MAX_SCENES}}")
|
||||
fi
|
||||
|
||||
if [[ "${#DISCOVERED_SCENES[@]}" -eq 0 ]]; then
|
||||
echo "No scenes selected from ${EVENT_JSON_FILE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
scene_assigned_to_worker() {
|
||||
local scene_index="$1"
|
||||
local worker_index="$2"
|
||||
local worker_count="$3"
|
||||
|
||||
case "${SCENE_DISTRIBUTION}" in
|
||||
round_robin)
|
||||
(( scene_index % worker_count == worker_index ))
|
||||
;;
|
||||
contiguous)
|
||||
local start=$(( ${#DISCOVERED_SCENES[@]} * worker_index / worker_count ))
|
||||
local end=$(( ${#DISCOVERED_SCENES[@]} * (worker_index + 1) / worker_count ))
|
||||
(( scene_index >= start && scene_index < end ))
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported SCENE_DISTRIBUTION: ${SCENE_DISTRIBUTION}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
print_scene_plan() {
|
||||
local worker_count="$1"
|
||||
local worker_index
|
||||
local scene_index
|
||||
local scene_name
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Dry Run: scene to GPU assignment"
|
||||
echo "######################################################################"
|
||||
echo "Event JSON : ${EVENT_JSON_FILE}"
|
||||
echo "Event id field : ${EVENT_ID_FIELD}"
|
||||
echo "Clip ids field : ${EVENT_CLIP_IDS_FIELD}"
|
||||
echo "Scenes : ${#DISCOVERED_SCENES[@]}"
|
||||
echo "GPU ids : ${GPU_IDS}"
|
||||
echo "Distribution : ${SCENE_DISTRIBUTION}"
|
||||
echo "Output root : ${OUTPUT_DIR}"
|
||||
echo "Export root : ${EXPORT_ROOT}"
|
||||
echo "Convert root : ${CONVERT_OUTPUT_ROOT_BASE}"
|
||||
echo "Temp root : ${PARALLEL_TMP_ROOT}"
|
||||
echo "Worker logs : ${PARALLEL_LOG_DIR}"
|
||||
|
||||
for worker_index in "${!GPU_IDS_ARR[@]}"; do
|
||||
echo ""
|
||||
echo "[worker ${worker_index}] gpu=${GPU_IDS_ARR[${worker_index}]}"
|
||||
for scene_index in "${!DISCOVERED_SCENES[@]}"; do
|
||||
if ! scene_assigned_to_worker "${scene_index}" "${worker_index}" "${worker_count}"; then
|
||||
continue
|
||||
fi
|
||||
scene_name="${DISCOVERED_SCENES[${scene_index}]}"
|
||||
echo " - ${scene_name}"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
move_scene_tree() {
|
||||
local src_dir="$1"
|
||||
local dst_dir="$2"
|
||||
|
||||
[[ -d "${src_dir}" ]] || return 0
|
||||
if [[ -e "${dst_dir}" ]]; then
|
||||
echo "Target already exists, refusing to overwrite: ${dst_dir}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${dst_dir}")"
|
||||
mv "${src_dir}" "${dst_dir}"
|
||||
}
|
||||
|
||||
run_one_scene() {
|
||||
local gpu_id="$1"
|
||||
local worker_index="$2"
|
||||
local scene_name="$3"
|
||||
local scene_tmp_root="${PARALLEL_TMP_ROOT%/}/worker_${worker_index}_gpu_${gpu_id}/${scene_name}"
|
||||
local worker_output_root="${scene_tmp_root}/output_root"
|
||||
local worker_export_root="${scene_tmp_root}/export_root"
|
||||
local worker_convert_root="${scene_tmp_root}/convert_root"
|
||||
local final_scene_output_dir="${OUTPUT_DIR%/}/${scene_name}"
|
||||
local final_scene_export_dir="${EXPORT_ROOT%/}/${scene_name}"
|
||||
local final_scene_convert_dir="${CONVERT_OUTPUT_ROOT_BASE%/}/${scene_name}"
|
||||
local output_status_dir="${OUTPUT_DIR%/}/_status"
|
||||
|
||||
if [[ "${SKIP_EXISTING_SCENES}" == "1" ]] && [[ -d "${final_scene_output_dir}" ]]; then
|
||||
echo "[GPU ${gpu_id}] skip existing scene: ${scene_name}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "${scene_tmp_root}"
|
||||
echo "[GPU ${gpu_id}] start scene: ${scene_name}"
|
||||
|
||||
CUDA_VISIBLE_DEVICES="${gpu_id}" \
|
||||
SCENE="${scene_name}" \
|
||||
EVENT_ID_FIELD="${EVENT_ID_FIELD}" \
|
||||
EVENT_CLIP_IDS_FIELD="${EVENT_CLIP_IDS_FIELD}" \
|
||||
OUTPUT_DIR="${worker_output_root}" \
|
||||
EXPORT_ROOT="${worker_export_root}" \
|
||||
CONVERT_OUTPUT_ROOT="${worker_convert_root}" \
|
||||
bash "${WORKER_SCRIPT}" "${FORWARD_ARGS[@]}"
|
||||
|
||||
move_scene_tree "${worker_output_root}/${scene_name}" "${final_scene_output_dir}"
|
||||
move_scene_tree "${worker_export_root}/${scene_name}" "${final_scene_export_dir}"
|
||||
|
||||
if [[ "${CONVERT_OUTPUT_LAYOUT:-parallel_root}" == "parallel_root" ]]; then
|
||||
move_scene_tree "${worker_convert_root}/${scene_name}" "${final_scene_convert_dir}"
|
||||
fi
|
||||
|
||||
if [[ -f "${worker_output_root}/_status/event_scene_manifest.json" ]]; then
|
||||
mkdir -p "${output_status_dir}"
|
||||
cp "${worker_output_root}/_status/event_scene_manifest.json" \
|
||||
"${output_status_dir}/${scene_name}_event_scene_manifest.json"
|
||||
fi
|
||||
|
||||
echo "[GPU ${gpu_id}] finished scene: ${scene_name}"
|
||||
}
|
||||
|
||||
launch_worker() {
|
||||
local worker_index="$1"
|
||||
local gpu_id="$2"
|
||||
local worker_count="$3"
|
||||
local log_file="${PARALLEL_LOG_DIR%/}/worker_${worker_index}_gpu_${gpu_id}.log"
|
||||
local scene_index
|
||||
local scene_name
|
||||
local worker_failed=0
|
||||
local worker_scene_count=0
|
||||
|
||||
for scene_index in "${!DISCOVERED_SCENES[@]}"; do
|
||||
if scene_assigned_to_worker "${scene_index}" "${worker_index}" "${worker_count}"; then
|
||||
((worker_scene_count+=1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Launch worker ${worker_index} on GPU ${gpu_id}: ${worker_scene_count} scenes -> ${log_file}"
|
||||
(
|
||||
echo "Worker index : ${worker_index}"
|
||||
echo "GPU id : ${gpu_id}"
|
||||
echo "Scene count : ${worker_scene_count}"
|
||||
echo "Distribution : ${SCENE_DISTRIBUTION}"
|
||||
echo "Event JSON : ${EVENT_JSON_FILE}"
|
||||
echo "Event id field : ${EVENT_ID_FIELD}"
|
||||
echo "Clip ids field : ${EVENT_CLIP_IDS_FIELD}"
|
||||
echo "Output root : ${OUTPUT_DIR}"
|
||||
echo "Export root : ${EXPORT_ROOT}"
|
||||
echo "Convert root : ${CONVERT_OUTPUT_ROOT_BASE}"
|
||||
echo "Temp root : ${PARALLEL_TMP_ROOT}"
|
||||
|
||||
for scene_index in "${!DISCOVERED_SCENES[@]}"; do
|
||||
if ! scene_assigned_to_worker "${scene_index}" "${worker_index}" "${worker_count}"; then
|
||||
continue
|
||||
fi
|
||||
scene_name="${DISCOVERED_SCENES[${scene_index}]}"
|
||||
if ! run_one_scene "${gpu_id}" "${worker_index}" "${scene_name}"; then
|
||||
worker_failed=1
|
||||
echo "[GPU ${gpu_id}] failed scene: ${scene_name}" >&2
|
||||
fi
|
||||
done
|
||||
|
||||
exit "${worker_failed}"
|
||||
) >"${log_file}" 2>&1 &
|
||||
|
||||
WORKER_PIDS+=("$!")
|
||||
WORKER_LOGS+=("${log_file}")
|
||||
}
|
||||
|
||||
if [[ ! -f "${WORKER_SCRIPT}" ]]; then
|
||||
echo "Worker script not found: ${WORKER_SCRIPT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
discover_scenes
|
||||
|
||||
# shellcheck disable=SC2206
|
||||
GPU_IDS_ARR=(${GPU_IDS})
|
||||
if [[ "${#GPU_IDS_ARR[@]}" -lt 1 ]]; then
|
||||
echo "GPU_IDS must contain at least one GPU id." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
worker_count="${#GPU_IDS_ARR[@]}"
|
||||
|
||||
if [[ "${DRY_RUN}" == "1" ]]; then
|
||||
print_scene_plan "${worker_count}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${PARALLEL_LOG_DIR}" "${OUTPUT_DIR}" "${EXPORT_ROOT}"
|
||||
if [[ "${CONVERT_OUTPUT_LAYOUT:-parallel_root}" == "parallel_root" ]]; then
|
||||
mkdir -p "${CONVERT_OUTPUT_ROOT_BASE}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Parallel event-json inference by scene"
|
||||
echo "######################################################################"
|
||||
echo "Event JSON : ${EVENT_JSON_FILE}"
|
||||
echo "Event id field : ${EVENT_ID_FIELD}"
|
||||
echo "Clip ids field : ${EVENT_CLIP_IDS_FIELD}"
|
||||
echo "Scenes : ${#DISCOVERED_SCENES[@]}"
|
||||
echo "GPU ids : ${GPU_IDS}"
|
||||
echo "Distribution : ${SCENE_DISTRIBUTION}"
|
||||
echo "Output root : ${OUTPUT_DIR}"
|
||||
echo "Export root : ${EXPORT_ROOT}"
|
||||
echo "Convert root : ${CONVERT_OUTPUT_ROOT_BASE}"
|
||||
echo "Temp root : ${PARALLEL_TMP_ROOT}"
|
||||
echo "Worker logs : ${PARALLEL_LOG_DIR}"
|
||||
|
||||
WORKER_PIDS=()
|
||||
WORKER_LOGS=()
|
||||
for worker_index in "${!GPU_IDS_ARR[@]}"; do
|
||||
launch_worker "${worker_index}" "${GPU_IDS_ARR[${worker_index}]}" "${worker_count}"
|
||||
done
|
||||
|
||||
failed=0
|
||||
for worker_index in "${!WORKER_PIDS[@]}"; do
|
||||
if wait "${WORKER_PIDS[${worker_index}]}"; then
|
||||
echo "Worker ${worker_index}/${worker_count} finished successfully. Log: ${WORKER_LOGS[${worker_index}]}"
|
||||
else
|
||||
echo "[ERROR] Worker ${worker_index}/${worker_count} failed. Log: ${WORKER_LOGS[${worker_index}]}" >&2
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${failed}" == "1" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All scene workers finished successfully."
|
||||
280
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_mcap.sh
Executable file
280
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_mcap.sh
Executable file
@@ -0,0 +1,280 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for one local .mcap file.
|
||||
#
|
||||
# Example:
|
||||
# MCAP_FILE=/path/to/case.mcap bash tools/model_inference/scripts/run_two_roi_exported_onnx_infer_mcap.sh
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
MCAP_FILE="${MCAP_FILE:-/data1/dongying/Mono3d/G1Q3/tmp/mcap/20260428201929.mcap}"
|
||||
MCAP_CLIP_ID="${MCAP_CLIP_ID:-}"
|
||||
MCAP_DATE_NAME="${MCAP_DATE_NAME:-}"
|
||||
MCAP_VEHICLE_NAME="${MCAP_VEHICLE_NAME:-local_mcap}"
|
||||
EXPORT_ROOT="${EXPORT_ROOT:-/data1/dongying/Mono3d/G1Q3/model_inference/mcap/exports}"
|
||||
OUTPUT_PREFIX="${OUTPUT_PREFIX:-mcap}"
|
||||
CAMERA_TOPIC="${CAMERA_TOPIC:-camera4}"
|
||||
CALIB_FILE="${CALIB_FILE:-}"
|
||||
MAX_FRAMES_PER_CLIP="${MAX_FRAMES_PER_CLIP:-0}"
|
||||
MAX_IMAGES="${MAX_IMAGES:-0}"
|
||||
SKIP_DONE="${SKIP_DONE:-1}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_20260423-raw_no_edge/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/mcap/model_20260423}"
|
||||
DEVICE="${DEVICE:-}"
|
||||
ATTR_DEVICE="${ATTR_DEVICE:-}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-0}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-1}"
|
||||
VIS_CLASSES="${VIS_CLASSES:-}"
|
||||
VIS_CLASS_NAMES="${VIS_CLASS_NAMES:-}"
|
||||
SAVE_VISUALIZATION="${SAVE_VISUALIZATION:-1}"
|
||||
SAVE_AGGREGATE_PREDICTIONS="${SAVE_AGGREGATE_PREDICTIONS:-0}"
|
||||
SHOW_DISTANCE_LABEL="${SHOW_DISTANCE_LABEL:-1}"
|
||||
DISTANCE_LABEL_MODE="${DISTANCE_LABEL_MODE:-depth}"
|
||||
DISTANCE_LABEL_PANELS="${DISTANCE_LABEL_PANELS:-3d}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
# Optional post-inference tracking stage.
|
||||
ENABLE_TRACKING="${ENABLE_TRACKING:-1}"
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING:-1}"
|
||||
TRACK_STRICT="${TRACK_STRICT:-1}"
|
||||
TRACK_RESULTS_ROOT="${TRACK_RESULTS_ROOT:-${OUTPUT_DIR}}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12}"
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH:-0.3}"
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE:-5}"
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS:-1}"
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH:-100}"
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D:-0}"
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE:-10.0}"
|
||||
TRACK_MAX_FRAMES="${TRACK_MAX_FRAMES:-}"
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION:-20260427}"
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN:-*.json}"
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME:-combined_tracking.json}"
|
||||
TRACK_PARALLEL_JOBS="${TRACK_PARALLEL_JOBS:-1}"
|
||||
TRACKING_WRAPPER="${PROJECT_ROOT}/tools/temporal_analysis/track_objects_exported_onnx_infer_case.sh"
|
||||
|
||||
# Optional post-tracking protocol conversion stage.
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT:-1}"
|
||||
CONVERT_STRICT="${CONVERT_STRICT:-1}"
|
||||
CONVERT_RESULTS_ROOT="${CONVERT_RESULTS_ROOT:-${TRACK_RESULTS_ROOT}}"
|
||||
CONVERT_OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT:-}"
|
||||
CONVERT_OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT:-case_subdir}"
|
||||
CONVERT_OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME:-objectlist}"
|
||||
CONVERT_MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME:-${TRACK_MERGE_OUTPUT_NAME}}"
|
||||
CONVERT_CAM_ID="${CONVERT_CAM_ID:-}"
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS:-1}"
|
||||
CONVERT_WRAPPER="${PROJECT_ROOT}/tools/convert_merge_tracking_bundle/convert_merge_tracking_exported_onnx_infer_case.sh"
|
||||
|
||||
if [[ -z "${MCAP_FILE}" ]]; then
|
||||
echo "MCAP_FILE is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--mcap-file "${MCAP_FILE}"
|
||||
--export-root "${EXPORT_ROOT}"
|
||||
--output-prefix "${OUTPUT_PREFIX}"
|
||||
--camera-topic "${CAMERA_TOPIC}"
|
||||
--max-frames-per-clip "${MAX_FRAMES_PER_CLIP}"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
)
|
||||
|
||||
if [[ -n "${MCAP_CLIP_ID}" ]]; then
|
||||
CMD+=(--mcap-clip-id "${MCAP_CLIP_ID}")
|
||||
fi
|
||||
|
||||
if [[ -n "${MCAP_DATE_NAME}" ]]; then
|
||||
CMD+=(--mcap-date-name "${MCAP_DATE_NAME}")
|
||||
fi
|
||||
|
||||
if [[ -n "${MCAP_VEHICLE_NAME}" ]]; then
|
||||
CMD+=(--mcap-vehicle-name "${MCAP_VEHICLE_NAME}")
|
||||
fi
|
||||
|
||||
if [[ -n "${CALIB_FILE}" ]]; then
|
||||
CMD+=(--calib-file "${CALIB_FILE}")
|
||||
fi
|
||||
|
||||
if [[ -n "${DEVICE}" ]]; then
|
||||
CMD+=(--device "${DEVICE}")
|
||||
fi
|
||||
|
||||
if [[ -n "${ATTR_DEVICE}" ]]; then
|
||||
CMD+=(--attr-device "${ATTR_DEVICE}")
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASSES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASSES_ARR=(${VIS_CLASSES})
|
||||
CMD+=(--vis-classes "${VIS_CLASSES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASS_NAMES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASS_NAMES_ARR=(${VIS_CLASS_NAMES})
|
||||
CMD+=(--vis-class-names "${VIS_CLASS_NAMES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${SHOW_DISTANCE_LABEL}" == "1" ]]; then
|
||||
CMD+=(--show-distance-label)
|
||||
CMD+=(--distance-label-mode "${DISTANCE_LABEL_MODE}")
|
||||
|
||||
if [[ -n "${DISTANCE_LABEL_PANELS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
DISTANCE_LABEL_PANELS_ARR=(${DISTANCE_LABEL_PANELS})
|
||||
CMD+=(--distance-label-panels "${DISTANCE_LABEL_PANELS_ARR[@]}")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${MAX_IMAGES}" != "0" ]]; then
|
||||
CMD+=(--max-images "${MAX_IMAGES}")
|
||||
fi
|
||||
|
||||
if [[ "${SKIP_DONE}" == "1" ]]; then
|
||||
CMD+=(--skip-done)
|
||||
fi
|
||||
|
||||
if [[ "${SAVE_VISUALIZATION}" != "1" ]]; then
|
||||
CMD+=(--skip-visualizations)
|
||||
fi
|
||||
|
||||
if [[ "${SAVE_AGGREGATE_PREDICTIONS}" == "1" ]]; then
|
||||
CMD+=(--save-aggregate-predictions)
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
"${CMD[@]}"
|
||||
|
||||
if [[ "${ENABLE_TRACKING}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-inference tracking for exported mcap output"
|
||||
echo "######################################################################"
|
||||
echo "Tracking target: ${TRACK_RESULTS_ROOT}"
|
||||
|
||||
if [[ "${TRACK_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
TRACK_PARALLEL_JOBS="${TRACK_PARALLEL_JOBS}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
TRACK_PARALLEL_JOBS="${TRACK_PARALLEL_JOBS}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Tracking failed, but inference outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CONVERT}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="${CONVERT_OUTPUT_ROOT}"
|
||||
CONVERT_OUTPUT_LAYOUT_EFFECTIVE="${CONVERT_OUTPUT_LAYOUT}"
|
||||
|
||||
case "${CONVERT_OUTPUT_LAYOUT}" in
|
||||
same_dir)
|
||||
if [[ -f "${CONVERT_RESULTS_ROOT}" ]] || [[ "$(basename "${CONVERT_RESULTS_ROOT}")" == "${CONVERT_MERGE_JSON_NAME}" ]]; then
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="$(dirname "${CONVERT_RESULTS_ROOT}")"
|
||||
else
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="${CONVERT_RESULTS_ROOT%/}"
|
||||
fi
|
||||
CONVERT_OUTPUT_LAYOUT_EFFECTIVE="parallel_root"
|
||||
;;
|
||||
case_subdir|parallel_root)
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported CONVERT_OUTPUT_LAYOUT: ${CONVERT_OUTPUT_LAYOUT}" >&2
|
||||
echo "Expected one of: same_dir, case_subdir, parallel_root" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-tracking protocol conversion for exported mcap output"
|
||||
echo "######################################################################"
|
||||
echo "Conversion target: ${CONVERT_RESULTS_ROOT}"
|
||||
echo "Conversion layout: ${CONVERT_OUTPUT_LAYOUT}"
|
||||
|
||||
if [[ "${CONVERT_OUTPUT_LAYOUT}" == "same_dir" ]]; then
|
||||
echo "Conversion output: same directory as tracking results"
|
||||
elif [[ "${CONVERT_OUTPUT_LAYOUT}" == "case_subdir" ]]; then
|
||||
echo "Conversion subdir: ${CONVERT_OUTPUT_DIR_NAME}"
|
||||
elif [[ -n "${CONVERT_OUTPUT_ROOT_EFFECTIVE}" ]]; then
|
||||
echo "Conversion output root: ${CONVERT_OUTPUT_ROOT_EFFECTIVE}"
|
||||
fi
|
||||
|
||||
if [[ "${CONVERT_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT_EFFECTIVE}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT_EFFECTIVE}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT_EFFECTIVE}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT_EFFECTIVE}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CONVERT_PARALLEL_JOBS="${CONVERT_PARALLEL_JOBS}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Protocol conversion failed, but tracking outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
232
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_video_case.sh
Executable file
232
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_video_case.sh
Executable file
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for single video-case inference.
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
VIDEO_CASE_DIR="${VIDEO_CASE_DIR:-/data1/dongying/Mono3d/G1Q3/tmp/20260507/20260507165034/sigmastar.1/camera4.bin}"
|
||||
# VIDEO_CASE_DIR="${VIDEO_CASE_DIR:-/mnt/G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LF_AEB_30_4_20251118162753/sigmastar.1/camera4.bin}"
|
||||
# VIDEO_CASE_DIR="${VIDEO_CASE_DIR:-/mnt/G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251118/CVE/CPTN_LN_AEB_30_1_20251118155909/sigmastar.1/camera4.bin}"
|
||||
# VIDEO_CASE_DIR="${VIDEO_CASE_DIR:-/mnt/G1M3/gt_org_data/G1M3_AFS1616/CNCAP2024数采/20251121/CVE/CPLA_RL_FCW_NIGHT_60_1_20251120201141/sigmastar.1/camera4.bin}"
|
||||
VIDEO_STRIDE="${VIDEO_STRIDE:-1}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_20260427-raw_no_edge/merged_model.torchscript}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/tmp/20260507_results/model_20260427/20260507165034}"
|
||||
# OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/tmp/20260416/CPLA_RL_FCW_NIGHT_60_1_20251120201141}"
|
||||
MAX_IMAGES="${MAX_IMAGES:-1000}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-0}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-1}"
|
||||
VIS_CLASSES="${VIS_CLASSES:-}"
|
||||
VIS_CLASS_NAMES="${VIS_CLASS_NAMES:-}"
|
||||
SHOW_DISTANCE_LABEL="${SHOW_DISTANCE_LABEL:-1}"
|
||||
DISTANCE_LABEL_MODE="${DISTANCE_LABEL_MODE:-depth}"
|
||||
DISTANCE_LABEL_PANELS="${DISTANCE_LABEL_PANELS:-3d}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
|
||||
# Optional post-inference tracking stage. When enabled, the launcher reuses
|
||||
# the exported-inference tracking wrapper, which runs track_objects.py over
|
||||
# predictions/{roi0,roi1,merge} and merges the results for this case.
|
||||
ENABLE_TRACKING="${ENABLE_TRACKING:-1}"
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING:-1}"
|
||||
TRACK_STRICT="${TRACK_STRICT:-1}"
|
||||
TRACK_RESULTS_ROOT="${TRACK_RESULTS_ROOT:-${OUTPUT_DIR}}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12 17 18 19}"
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH:-0.3}"
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE:-5}"
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS:-1}"
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH:-100}"
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D:-0}"
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE:-10.0}"
|
||||
TRACK_MAX_FRAMES="${TRACK_MAX_FRAMES:-}"
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION:-20260506}"
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN:-*.json}"
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME:-combined_tracking.json}"
|
||||
TRACKING_WRAPPER="${PROJECT_ROOT}/tools/temporal_analysis/track_objects_exported_onnx_infer_case.sh"
|
||||
|
||||
# Optional post-tracking protocol-conversion stage.
|
||||
# Runs convert_merge_tracking_exported_onnx_infer_case.sh on the case output
|
||||
# directory to produce ObjectPerceptionObjectList.{data.json,bin,index.json}.
|
||||
# By default, converted protocol files are written into the same directory as
|
||||
# the tracking result. Override CONVERT_OUTPUT_LAYOUT=case_subdir to emit into
|
||||
# {case_dir}/{CONVERT_OUTPUT_DIR_NAME}/, or use parallel_root with an explicit
|
||||
# CONVERT_OUTPUT_ROOT to mirror outputs into another root.
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT:-1}"
|
||||
CONVERT_STRICT="${CONVERT_STRICT:-1}"
|
||||
CONVERT_RESULTS_ROOT="${CONVERT_RESULTS_ROOT:-${OUTPUT_DIR}}"
|
||||
CONVERT_OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT:-}"
|
||||
CONVERT_OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT:-case_subdir}"
|
||||
CONVERT_OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME:-objectlist}"
|
||||
CONVERT_MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME:-${TRACK_MERGE_OUTPUT_NAME}}"
|
||||
CONVERT_CAM_ID="${CONVERT_CAM_ID:-}"
|
||||
CONVERT_WRAPPER="${PROJECT_ROOT}/tools/convert_merge_tracking_bundle/convert_merge_tracking_exported_onnx_infer_case.sh"
|
||||
|
||||
if [[ -z "${VIDEO_CASE_DIR}" ]]; then
|
||||
echo "VIDEO_CASE_DIR is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--video-case-dir "${VIDEO_CASE_DIR}"
|
||||
--video-stride "${VIDEO_STRIDE}"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
)
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASSES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASSES_ARR=(${VIS_CLASSES})
|
||||
CMD+=(--vis-classes "${VIS_CLASSES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASS_NAMES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASS_NAMES_ARR=(${VIS_CLASS_NAMES})
|
||||
CMD+=(--vis-class-names "${VIS_CLASS_NAMES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${SHOW_DISTANCE_LABEL}" == "1" ]]; then
|
||||
CMD+=(--show-distance-label)
|
||||
CMD+=(--distance-label-mode "${DISTANCE_LABEL_MODE}")
|
||||
|
||||
if [[ -n "${DISTANCE_LABEL_PANELS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
DISTANCE_LABEL_PANELS_ARR=(${DISTANCE_LABEL_PANELS})
|
||||
CMD+=(--distance-label-panels "${DISTANCE_LABEL_PANELS_ARR[@]}")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${MAX_IMAGES}" != "0" ]]; then
|
||||
CMD+=(--max-images "${MAX_IMAGES}")
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
"${CMD[@]}"
|
||||
|
||||
if [[ "${ENABLE_TRACKING}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-inference tracking for exported video-case output"
|
||||
echo "######################################################################"
|
||||
echo "Tracking target: ${TRACK_RESULTS_ROOT}"
|
||||
|
||||
if [[ "${TRACK_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Tracking failed, but inference outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CONVERT}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="${CONVERT_OUTPUT_ROOT}"
|
||||
CONVERT_OUTPUT_LAYOUT_EFFECTIVE="${CONVERT_OUTPUT_LAYOUT}"
|
||||
|
||||
case "${CONVERT_OUTPUT_LAYOUT}" in
|
||||
same_dir)
|
||||
if [[ -f "${CONVERT_RESULTS_ROOT}" ]] || [[ "$(basename "${CONVERT_RESULTS_ROOT}")" == "${CONVERT_MERGE_JSON_NAME}" ]]; then
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="$(dirname "${CONVERT_RESULTS_ROOT}")"
|
||||
else
|
||||
CONVERT_OUTPUT_ROOT_EFFECTIVE="${CONVERT_RESULTS_ROOT%/}"
|
||||
fi
|
||||
CONVERT_OUTPUT_LAYOUT_EFFECTIVE="parallel_root"
|
||||
;;
|
||||
case_subdir|parallel_root)
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported CONVERT_OUTPUT_LAYOUT: ${CONVERT_OUTPUT_LAYOUT}" >&2
|
||||
echo "Expected one of: same_dir, case_subdir, parallel_root" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-tracking protocol conversion for exported video-case output"
|
||||
echo "######################################################################"
|
||||
echo "Conversion target: ${CONVERT_RESULTS_ROOT}"
|
||||
echo "Conversion layout: ${CONVERT_OUTPUT_LAYOUT}"
|
||||
|
||||
if [[ "${CONVERT_OUTPUT_LAYOUT}" == "same_dir" ]]; then
|
||||
echo "Conversion output: same directory as tracking results"
|
||||
elif [[ "${CONVERT_OUTPUT_LAYOUT}" == "case_subdir" ]]; then
|
||||
echo "Conversion subdir: ${CONVERT_OUTPUT_DIR_NAME}"
|
||||
elif [[ -n "${CONVERT_OUTPUT_ROOT_EFFECTIVE}" ]]; then
|
||||
echo "Conversion output root: ${CONVERT_OUTPUT_ROOT_EFFECTIVE}"
|
||||
fi
|
||||
|
||||
if [[ "${CONVERT_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT_EFFECTIVE}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT_EFFECTIVE}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT_EFFECTIVE}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT_EFFECTIVE}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Protocol conversion failed, but tracking outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
262
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_video_root.sh
Executable file
262
tools/model_inference/scripts/run_two_roi_exported_onnx_infer_video_root.sh
Executable file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
|
||||
# Launcher for batch video-root inference.
|
||||
#
|
||||
# Supported postprocess-only mode:
|
||||
# POSTPROCESS_ONLY=1 OUTPUT_DIR=<inference-output-root> bash run_two_roi_exported_onnx_infer_video_root.sh
|
||||
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
VIDEO_ROOT_DIR="${VIDEO_ROOT_DIR:-/data1/dongying/Mono3d/G1Q3/tmp/20260507}"
|
||||
# VIDEO_ROOT_DIR="${VIDEO_ROOT_DIR:-/data1/dongying/Mono3d/G1Q3/dataset_for_evaluation/CNCAP/CSTA_LN}"
|
||||
VIDEO_STRIDE="${VIDEO_STRIDE:-1}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-${PROJECT_ROOT}/runs/export/train_mono3d_two_roi_20260506-drop_fake_3d_branch/merged_model.torchscript}"
|
||||
# OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1M3/test_outputs/video_case_model_20260416_with_cls}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/tmp/20260507_results/model_20260507_drop_fake3d}"
|
||||
MAX_IMAGES="${MAX_IMAGES:-0}"
|
||||
ENABLE_ATTR="${ENABLE_ATTR:-1}"
|
||||
ENABLE_CROSS_CLASS_MERGE_PRIOR="${ENABLE_CROSS_CLASS_MERGE_PRIOR:-1}"
|
||||
ENABLE_VRU_MERGE="${ENABLE_VRU_MERGE:-1}"
|
||||
VIS_CLASSES="${VIS_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12 17 18 19}"
|
||||
VIS_CLASS_NAMES="${VIS_CLASS_NAMES:-}"
|
||||
SHOW_DISTANCE_LABEL="${SHOW_DISTANCE_LABEL:-1}"
|
||||
# depth_lateral keeps the existing longitudinal z label and adds signed
|
||||
# camera-frame lateral x offset. Override with depth/lateral/xz/etc if needed.
|
||||
DISTANCE_LABEL_MODE="${DISTANCE_LABEL_MODE:-depth_lateral}"
|
||||
DISTANCE_LABEL_PANELS="${DISTANCE_LABEL_PANELS:-3d}"
|
||||
EXTRA_ARGS="${EXTRA_ARGS:-}"
|
||||
POSTPROCESS_ONLY="${POSTPROCESS_ONLY:-0}"
|
||||
|
||||
# Optional post-inference tracking stage. When enabled, the launcher reuses
|
||||
# the exported-inference tracking wrapper, which runs track_objects.py over
|
||||
# predictions/{roi0,roi1,merge} and merges the results per case.
|
||||
ENABLE_TRACKING="${ENABLE_TRACKING:-1}"
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING:-0}"
|
||||
TRACK_STRICT="${TRACK_STRICT:-1}"
|
||||
TRACK_RESULTS_ROOT="${TRACK_RESULTS_ROOT:-${OUTPUT_DIR}}"
|
||||
TRACK_CLASSES="${TRACK_CLASSES:-0 1 2 3 4 5 6 7 8 9 10 11 12 17 18 19}"
|
||||
TRACK_IOU_THRESH="${TRACK_IOU_THRESH:-0.3}"
|
||||
TRACK_MAX_AGE="${TRACK_MAX_AGE:-5}"
|
||||
TRACK_MIN_HITS="${TRACK_MIN_HITS:-1}"
|
||||
TRACK_DIST_THRESH="${TRACK_DIST_THRESH:-100}"
|
||||
TRACK_ENABLE_USE_3D="${TRACK_ENABLE_USE_3D:-0}"
|
||||
TRACK_MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE:-10.0}"
|
||||
TRACK_MAX_FRAMES="${TRACK_MAX_FRAMES:-}"
|
||||
TRACK_MODEL_VERSION="${TRACK_MODEL_VERSION:-20260427}"
|
||||
TRACK_FILE_PATTERN="${TRACK_FILE_PATTERN:-*.json}"
|
||||
TRACK_MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME:-combined_tracking.json}"
|
||||
TRACKING_WRAPPER="${PROJECT_ROOT}/tools/temporal_analysis/track_objects_exported_onnx_infer_case.sh"
|
||||
|
||||
# Optional post-tracking protocol-conversion stage.
|
||||
# Runs convert_merge_tracking_exported_onnx_infer_case.sh on the tracked
|
||||
# video-root output tree. By default, each case writes converted protobuf
|
||||
# artifacts into its own objectlist/ subdirectory.
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT:-1}"
|
||||
CONVERT_STRICT="${CONVERT_STRICT:-1}"
|
||||
CONVERT_RESULTS_ROOT="${CONVERT_RESULTS_ROOT:-${TRACK_RESULTS_ROOT}}"
|
||||
CONVERT_OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT:-}"
|
||||
CONVERT_OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT:-case_subdir}"
|
||||
CONVERT_OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME:-objectlist}"
|
||||
CONVERT_MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME:-${TRACK_MERGE_OUTPUT_NAME}}"
|
||||
CONVERT_CAM_ID="${CONVERT_CAM_ID:-}"
|
||||
CONVERT_WRAPPER="${PROJECT_ROOT}/tools/convert_merge_tracking_bundle/convert_merge_tracking_exported_onnx_infer_case.sh"
|
||||
ENABLE_CONVERT_VRU="${ENABLE_CONVERT_VRU:-0}"
|
||||
CONVERT_VRU_OUTPUT_ROOT="${CONVERT_VRU_OUTPUT_ROOT:-}"
|
||||
CONVERT_VRU_OUTPUT_LAYOUT="${CONVERT_VRU_OUTPUT_LAYOUT:-case_subdir}"
|
||||
CONVERT_VRU_OUTPUT_DIR_NAME="${CONVERT_VRU_OUTPUT_DIR_NAME:-objectlist_vru}"
|
||||
CONVERT_VRU_MERGE_JSON_NAME="${CONVERT_VRU_MERGE_JSON_NAME:-merge_vru.json}"
|
||||
|
||||
if [[ "${POSTPROCESS_ONLY}" != "1" && -z "${VIDEO_ROOT_DIR}" ]]; then
|
||||
echo "VIDEO_ROOT_DIR is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CMD=(
|
||||
"${PYTHON_BIN}" "${MODEL_INFERENCE_DIR}/core/run_two_roi_exported_onnx_infer.py"
|
||||
--video-root-dir "${VIDEO_ROOT_DIR}"
|
||||
--video-stride "${VIDEO_STRIDE}"
|
||||
--exported-model "${EXPORTED_MODEL}"
|
||||
--output-dir "${OUTPUT_DIR}"
|
||||
)
|
||||
|
||||
if [[ "${ENABLE_ATTR}" == "1" ]]; then
|
||||
CMD+=(--enable-attr)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CROSS_CLASS_MERGE_PRIOR}" == "1" ]]; then
|
||||
CMD+=(--enable-cross-class-merge-prior)
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_VRU_MERGE}" == "1" ]]; then
|
||||
CMD+=(--enable-vru-merge)
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASSES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASSES_ARR=(${VIS_CLASSES})
|
||||
CMD+=(--vis-classes "${VIS_CLASSES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n "${VIS_CLASS_NAMES}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
VIS_CLASS_NAMES_ARR=(${VIS_CLASS_NAMES})
|
||||
CMD+=(--vis-class-names "${VIS_CLASS_NAMES_ARR[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${SHOW_DISTANCE_LABEL}" == "1" ]]; then
|
||||
CMD+=(--show-distance-label)
|
||||
CMD+=(--distance-label-mode "${DISTANCE_LABEL_MODE}")
|
||||
|
||||
if [[ -n "${DISTANCE_LABEL_PANELS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
DISTANCE_LABEL_PANELS_ARR=(${DISTANCE_LABEL_PANELS})
|
||||
CMD+=(--distance-label-panels "${DISTANCE_LABEL_PANELS_ARR[@]}")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${MAX_IMAGES}" != "0" ]]; then
|
||||
CMD+=(--max-images "${MAX_IMAGES}")
|
||||
fi
|
||||
|
||||
if [[ -n "${EXTRA_ARGS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
EXTRA_ARR=(${EXTRA_ARGS})
|
||||
CMD+=("${EXTRA_ARR[@]}")
|
||||
fi
|
||||
|
||||
CMD+=("$@")
|
||||
|
||||
if [[ "${POSTPROCESS_ONLY}" == "1" ]]; then
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# POSTPROCESS_ONLY=1, skipping inference"
|
||||
echo "######################################################################"
|
||||
echo "Postprocess root: ${OUTPUT_DIR}"
|
||||
else
|
||||
"${CMD[@]}"
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_TRACKING}" == "1" ]]; then
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-inference tracking for exported video-root outputs"
|
||||
echo "######################################################################"
|
||||
echo "Tracking root: ${TRACK_RESULTS_ROOT}"
|
||||
|
||||
if [[ "${TRACK_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
RESULTS_ROOT="${TRACK_RESULTS_ROOT}" \
|
||||
TRACK_CLASSES="${TRACK_CLASSES}" \
|
||||
IOU_THRESH="${TRACK_IOU_THRESH}" \
|
||||
MAX_AGE="${TRACK_MAX_AGE}" \
|
||||
MIN_HITS="${TRACK_MIN_HITS}" \
|
||||
DIST_THRESH="${TRACK_DIST_THRESH}" \
|
||||
ENABLE_USE_3D="${TRACK_ENABLE_USE_3D}" \
|
||||
MAX_3D_DISTANCE="${TRACK_MAX_3D_DISTANCE}" \
|
||||
MAX_FRAMES="${TRACK_MAX_FRAMES}" \
|
||||
MODEL_VERSION="${TRACK_MODEL_VERSION}" \
|
||||
FILE_PATTERN="${TRACK_FILE_PATTERN}" \
|
||||
MERGE_OUTPUT_NAME="${TRACK_MERGE_OUTPUT_NAME}" \
|
||||
ENABLE_VRU_TRACKING="${ENABLE_VRU_TRACKING}" \
|
||||
bash "${TRACKING_WRAPPER}" "${TRACK_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Tracking failed, but inference outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
elif [[ "${ENABLE_CONVERT}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CONVERT}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-tracking protocol conversion for exported video-root outputs"
|
||||
echo "######################################################################"
|
||||
echo "Conversion target: ${CONVERT_RESULTS_ROOT}"
|
||||
echo "Conversion layout: ${CONVERT_OUTPUT_LAYOUT}"
|
||||
|
||||
if [[ "${CONVERT_OUTPUT_LAYOUT}" == "case_subdir" ]]; then
|
||||
echo "Conversion subdir: ${CONVERT_OUTPUT_DIR_NAME}"
|
||||
elif [[ -n "${CONVERT_OUTPUT_ROOT}" ]]; then
|
||||
echo "Conversion output root: ${CONVERT_OUTPUT_ROOT}"
|
||||
fi
|
||||
|
||||
if [[ "${CONVERT_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_OUTPUT_ROOT}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_OUTPUT_LAYOUT}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_MERGE_JSON_NAME}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"; then
|
||||
echo "[WARN] Protocol conversion failed, but tracking outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_CONVERT_VRU}" == "1" ]]; then
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Post-tracking protocol conversion for VRU tracking outputs"
|
||||
echo "######################################################################"
|
||||
echo "VRU conversion target: ${CONVERT_RESULTS_ROOT}"
|
||||
echo "VRU conversion layout: ${CONVERT_VRU_OUTPUT_LAYOUT}"
|
||||
if [[ "${CONVERT_VRU_OUTPUT_LAYOUT}" == "case_subdir" ]]; then
|
||||
echo "VRU conversion subdir: ${CONVERT_VRU_OUTPUT_DIR_NAME}"
|
||||
elif [[ -n "${CONVERT_VRU_OUTPUT_ROOT}" ]]; then
|
||||
echo "VRU conversion output root: ${CONVERT_VRU_OUTPUT_ROOT}"
|
||||
fi
|
||||
|
||||
if [[ -d "${CONVERT_RESULTS_ROOT}" ]] && [[ -n "$(find "${CONVERT_RESULTS_ROOT}" -type f -name "${CONVERT_VRU_MERGE_JSON_NAME}" -print -quit)" ]]; then
|
||||
if [[ "${CONVERT_STRICT}" == "1" ]]; then
|
||||
PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_VRU_OUTPUT_ROOT}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_VRU_OUTPUT_LAYOUT}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_VRU_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_VRU_MERGE_JSON_NAME}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"
|
||||
else
|
||||
if ! PYTHON_BIN="${PYTHON_BIN}" \
|
||||
OUTPUT_ROOT="${CONVERT_VRU_OUTPUT_ROOT}" \
|
||||
OUTPUT_LAYOUT="${CONVERT_VRU_OUTPUT_LAYOUT}" \
|
||||
OUTPUT_DIR_NAME="${CONVERT_VRU_OUTPUT_DIR_NAME}" \
|
||||
MERGE_JSON_NAME="${CONVERT_VRU_MERGE_JSON_NAME}" \
|
||||
CAM_ID="${CONVERT_CAM_ID}" \
|
||||
bash "${CONVERT_WRAPPER}" "${CONVERT_RESULTS_ROOT}"; then
|
||||
echo "[WARN] VRU protocol conversion failed, but tracking outputs were kept under ${OUTPUT_DIR}" >&2
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Info: no ${CONVERT_VRU_MERGE_JSON_NAME} files found under ${CONVERT_RESULTS_ROOT}, skipping VRU protocol conversion"
|
||||
fi
|
||||
fi
|
||||
24
tools/model_inference/scripts/run_two_roi_exported_onnx_postprocess_only.sh
Executable file
24
tools/model_inference/scripts/run_two_roi_exported_onnx_postprocess_only.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LAUNCHER="${SCRIPT_DIR}/run_two_roi_exported_onnx_infer_case.sh"
|
||||
|
||||
# 用途:在重跑 worker 全部完成后,统一执行 tracking 和 convert。
|
||||
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/KPI/OP_KPI_SCENE/model_20260427-raw_no_edge}"
|
||||
ENABLE_TRACKING="${ENABLE_TRACKING:-1}"
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT:-1}"
|
||||
|
||||
echo "Running postprocess only"
|
||||
echo "Launcher : ${LAUNCHER}"
|
||||
echo "Postprocess dir: ${OUTPUT_DIR}"
|
||||
echo "Tracking : ${ENABLE_TRACKING}"
|
||||
echo "Convert : ${ENABLE_CONVERT}"
|
||||
|
||||
env \
|
||||
POSTPROCESS_ONLY=1 \
|
||||
ENABLE_TRACKING="${ENABLE_TRACKING}" \
|
||||
ENABLE_CONVERT="${ENABLE_CONVERT}" \
|
||||
OUTPUT_DIR="${OUTPUT_DIR}" \
|
||||
bash "${LAUNCHER}"
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LAUNCHER="${SCRIPT_DIR}/run_two_roi_exported_onnx_infer_case.sh"
|
||||
|
||||
# 用途:重跑最后 4 个未处理的 case,且不保存 visualizations。
|
||||
# 前置条件:
|
||||
# 1. 已停止旧的推理进程
|
||||
# 2. 已按步骤 3 清理目标 case 的旧输出目录
|
||||
# 区间语义:CASE_INDEX_START/END 使用 0-based 且为 [start, end)
|
||||
# 当前默认区间对应 2026-04-28 的运行快照:
|
||||
# - GPU0: 第 70 到第 71 个 case -> [69, 71)
|
||||
# - GPU1: 第 72 到第 73 个 case -> [71, 73)
|
||||
|
||||
INPUT_DIR="${INPUT_DIR:-/data1/dongying/Mono3d/G1Q3/dataset_for_evaluation/OP_KPI_SCENE}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-/data1/dongying/Mono3d/G1Q3/model_inference/KPI/OP_KPI_SCENE/model_20260427-raw_no_edge}"
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL:-/deeplearning_team/ydong/dongying/projects/yolo26-3d/runs/export/train_mono3d_two_roi_20260427-raw_no_edge/merged_model.torchscript}"
|
||||
PARALLEL_LOG_DIR="${PARALLEL_LOG_DIR:-${OUTPUT_DIR%/}/parallel_logs}"
|
||||
|
||||
GPU0_ID="${GPU0_ID:-0}"
|
||||
GPU0_CASE_INDEX_START="${GPU0_CASE_INDEX_START:-69}"
|
||||
GPU0_CASE_INDEX_END="${GPU0_CASE_INDEX_END:-71}"
|
||||
GPU0_LOG="${GPU0_LOG:-${PARALLEL_LOG_DIR}/rerun_gpu${GPU0_ID}_${GPU0_CASE_INDEX_START}_${GPU0_CASE_INDEX_END}.log}"
|
||||
|
||||
GPU1_ID="${GPU1_ID:-1}"
|
||||
GPU1_CASE_INDEX_START="${GPU1_CASE_INDEX_START:-71}"
|
||||
GPU1_CASE_INDEX_END="${GPU1_CASE_INDEX_END:-73}"
|
||||
GPU1_LOG="${GPU1_LOG:-${PARALLEL_LOG_DIR}/rerun_gpu${GPU1_ID}_${GPU1_CASE_INDEX_START}_${GPU1_CASE_INDEX_END}.log}"
|
||||
|
||||
mkdir -p "${PARALLEL_LOG_DIR}"
|
||||
|
||||
echo "Starting rerun workers with SAVE_VISUALIZATION=0"
|
||||
echo "Launcher : ${LAUNCHER}"
|
||||
echo "Input dir : ${INPUT_DIR}"
|
||||
echo "Output dir : ${OUTPUT_DIR}"
|
||||
echo "Exported model : ${EXPORTED_MODEL}"
|
||||
echo "GPU${GPU0_ID} slice : [${GPU0_CASE_INDEX_START}, ${GPU0_CASE_INDEX_END}) -> ${GPU0_LOG}"
|
||||
echo "GPU${GPU1_ID} slice : [${GPU1_CASE_INDEX_START}, ${GPU1_CASE_INDEX_END}) -> ${GPU1_LOG}"
|
||||
|
||||
nohup env \
|
||||
SAVE_VISUALIZATION=0 \
|
||||
ENABLE_TRACKING=0 \
|
||||
ENABLE_CONVERT=0 \
|
||||
DEVICE="cuda:${GPU0_ID}" \
|
||||
ATTR_DEVICE="cuda:${GPU0_ID}" \
|
||||
INPUT_DIR="${INPUT_DIR}" \
|
||||
OUTPUT_DIR="${OUTPUT_DIR}" \
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL}" \
|
||||
CASE_INDEX_START="${GPU0_CASE_INDEX_START}" \
|
||||
CASE_INDEX_END="${GPU0_CASE_INDEX_END}" \
|
||||
bash "${LAUNCHER}" \
|
||||
>"${GPU0_LOG}" 2>&1 &
|
||||
gpu0_pid=$!
|
||||
|
||||
nohup env \
|
||||
SAVE_VISUALIZATION=0 \
|
||||
ENABLE_TRACKING=0 \
|
||||
ENABLE_CONVERT=0 \
|
||||
DEVICE="cuda:${GPU1_ID}" \
|
||||
ATTR_DEVICE="cuda:${GPU1_ID}" \
|
||||
INPUT_DIR="${INPUT_DIR}" \
|
||||
OUTPUT_DIR="${OUTPUT_DIR}" \
|
||||
EXPORTED_MODEL="${EXPORTED_MODEL}" \
|
||||
CASE_INDEX_START="${GPU1_CASE_INDEX_START}" \
|
||||
CASE_INDEX_END="${GPU1_CASE_INDEX_END}" \
|
||||
bash "${LAUNCHER}" \
|
||||
>"${GPU1_LOG}" 2>&1 &
|
||||
gpu1_pid=$!
|
||||
|
||||
echo "Started GPU${GPU0_ID} worker, PID=${gpu0_pid}"
|
||||
echo "Started GPU${GPU1_ID} worker, PID=${gpu1_pid}"
|
||||
echo "Use 'tail -f ${GPU0_LOG}' or 'tail -f ${GPU1_LOG}' to monitor progress."
|
||||
@@ -0,0 +1,346 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# 用法说明:
|
||||
# 适配 run_two_roi_exported_onnx_infer_video_root.sh 的输出目录,对每个 case 执行:
|
||||
# {case_dir}/merge.json -> {case_dir}/temporal_observation/stability_report.json
|
||||
#
|
||||
# 支持三种模式:
|
||||
# 1) 批量模式(默认):遍历 RESULTS_ROOT 下所有包含 merge.json 的 case
|
||||
# bash run_two_roi_exported_onnx_temporal_observe_video_root.sh
|
||||
# 2) 指定根目录模式:第一个参数传推理/跟踪输出根目录
|
||||
# bash run_two_roi_exported_onnx_temporal_observe_video_root.sh /path/to/inference_output_root
|
||||
# 3) 单 case 模式:第一个参数传 case 目录,或直接传 case_dir/merge.json
|
||||
# bash run_two_roi_exported_onnx_temporal_observe_video_root.sh /path/to/one_case --track-id 32
|
||||
# bash run_two_roi_exported_onnx_temporal_observe_video_root.sh /path/to/one_case/merge.json --track-id 32
|
||||
#
|
||||
# 默认读取 merge.json,因为 combined_tracking.json 会给不同 source 的 track_id 加偏移,
|
||||
# 不利于按单个目标 track_id 做精确筛选。
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MODEL_INFERENCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${MODEL_INFERENCE_DIR}/../.." && pwd)"
|
||||
export PYTHONPATH="${PROJECT_ROOT}:${PYTHONPATH:-}"
|
||||
|
||||
RESULTS_ROOT="${RESULTS_ROOT:-/data1/dongying/Mono3d/G1M3/test_data/cncap_20260414/20260416103945}"
|
||||
OUTPUT_ROOT="${OUTPUT_ROOT:-}"
|
||||
OUTPUT_DIR_NAME="${OUTPUT_DIR_NAME:-temporal_observation}"
|
||||
PYTHON_BIN="${PYTHON_BIN:-/deeplearning_team/ydong/dongying/miniconda/envs/dev/bin/python}"
|
||||
TEMPORAL_SCRIPT="${TEMPORAL_SCRIPT:-${PROJECT_ROOT}/tools/temporal_analysis/evaluate_temporal_stability.py}"
|
||||
TRACKING_JSON_NAME="${TRACKING_JSON_NAME:-merge.json}"
|
||||
TEMPORAL_MIN_LENGTH="${TEMPORAL_MIN_LENGTH:-3}"
|
||||
TEMPORAL_CLASS_ID="${TEMPORAL_CLASS_ID:-}"
|
||||
TEMPORAL_TRACK_IDS="${TEMPORAL_TRACK_IDS:-20}"
|
||||
TEMPORAL_FRAME_ID_START="${TEMPORAL_FRAME_ID_START:-325000}"
|
||||
TEMPORAL_FRAME_ID_END="${TEMPORAL_FRAME_ID_END:-325200}"
|
||||
TEMPORAL_PLOTS="${TEMPORAL_PLOTS:-0}"
|
||||
TEMPORAL_EXPORT_SERIES="${TEMPORAL_EXPORT_SERIES:-1}"
|
||||
TEMPORAL_FOCUS_TRACK_PLOTS="${TEMPORAL_FOCUS_TRACK_PLOTS:-1}"
|
||||
TEMPORAL_PREFER_EGO="${TEMPORAL_PREFER_EGO:-1}"
|
||||
TEMPORAL_X_AXIS="${TEMPORAL_X_AXIS:-frame_id}"
|
||||
TEMPORAL_HEADING_SOURCE="${TEMPORAL_HEADING_SOURCE:-camera_reg}"
|
||||
|
||||
TARGET_PATH="/data1/dongying/Mono3d/G1Q3/dataset_for_evaluation/CNCAP/CSTA_LN_outputs/model_20260416/CSTA-LN_AEB_10_20_20260414141804"
|
||||
CLI_TRACK_IDS=()
|
||||
CLI_CLASS_ID=""
|
||||
CLI_FRAME_ID_START=""
|
||||
CLI_FRAME_ID_END=""
|
||||
|
||||
while (($# > 0)); do
|
||||
case "$1" in
|
||||
--track-id)
|
||||
if (($# < 2)); then
|
||||
echo "Error: --track-id requires a value" >&2
|
||||
exit 1
|
||||
fi
|
||||
CLI_TRACK_IDS+=("$2")
|
||||
shift 2
|
||||
;;
|
||||
--track-id=*)
|
||||
CLI_TRACK_IDS+=("${1#*=}")
|
||||
shift
|
||||
;;
|
||||
--class-id)
|
||||
if (($# < 2)); then
|
||||
echo "Error: --class-id requires a value" >&2
|
||||
exit 1
|
||||
fi
|
||||
CLI_CLASS_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--class-id=*)
|
||||
CLI_CLASS_ID="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--frame-id-start)
|
||||
if (($# < 2)); then
|
||||
echo "Error: --frame-id-start requires a value" >&2
|
||||
exit 1
|
||||
fi
|
||||
CLI_FRAME_ID_START="$2"
|
||||
shift 2
|
||||
;;
|
||||
--frame-id-start=*)
|
||||
CLI_FRAME_ID_START="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--frame-id-end)
|
||||
if (($# < 2)); then
|
||||
echo "Error: --frame-id-end requires a value" >&2
|
||||
exit 1
|
||||
fi
|
||||
CLI_FRAME_ID_END="$2"
|
||||
shift 2
|
||||
;;
|
||||
--frame-id-end=*)
|
||||
CLI_FRAME_ID_END="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
echo "Error: unsupported option: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [[ -n "${TARGET_PATH}" ]]; then
|
||||
echo "Error: multiple target paths provided: ${TARGET_PATH} and $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
TARGET_PATH="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${TARGET_PATH}" ]]; then
|
||||
TARGET_PATH="${RESULTS_ROOT}"
|
||||
fi
|
||||
|
||||
if [[ ! -e "${TARGET_PATH}" ]]; then
|
||||
echo "Error: target path does not exist: ${TARGET_PATH}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
resolve_abs_path() {
|
||||
local target_path="$1"
|
||||
if [[ -d "${target_path}" ]]; then
|
||||
(
|
||||
cd "${target_path}"
|
||||
pwd -P
|
||||
)
|
||||
return 0
|
||||
fi
|
||||
|
||||
local parent_dir
|
||||
parent_dir=$(
|
||||
cd "$(dirname "${target_path}")"
|
||||
pwd -P
|
||||
)
|
||||
printf '%s/%s\n' "${parent_dir}" "$(basename "${target_path}")"
|
||||
}
|
||||
|
||||
RESULTS_ROOT_ABS="$(resolve_abs_path "${RESULTS_ROOT}")"
|
||||
|
||||
is_case_dir() {
|
||||
local dir_path="$1"
|
||||
[[ -d "${dir_path}" ]] && [[ -f "${dir_path}/${TRACKING_JSON_NAME}" ]]
|
||||
}
|
||||
|
||||
resolve_case_dir() {
|
||||
local target_path="$1"
|
||||
if is_case_dir "${target_path}"; then
|
||||
printf '%s\n' "${target_path}"
|
||||
return 0
|
||||
fi
|
||||
if [[ -f "${target_path}" ]] && [[ "$(basename "${target_path}")" == "${TRACKING_JSON_NAME}" ]]; then
|
||||
dirname "${target_path}"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
derive_output_dir() {
|
||||
local case_dir="$1"
|
||||
local case_abs
|
||||
local rel_case_dir
|
||||
|
||||
case_abs="$(resolve_abs_path "${case_dir}")"
|
||||
if [[ -n "${OUTPUT_ROOT}" ]]; then
|
||||
if [[ "${case_abs}" == "${RESULTS_ROOT_ABS}" ]]; then
|
||||
printf '%s\n' "${OUTPUT_ROOT}"
|
||||
return 0
|
||||
fi
|
||||
if [[ "${case_abs}" == "${RESULTS_ROOT_ABS}"/* ]]; then
|
||||
rel_case_dir="${case_abs#"${RESULTS_ROOT_ABS}/"}"
|
||||
printf '%s/%s\n' "${OUTPUT_ROOT%/}" "${rel_case_dir}"
|
||||
return 0
|
||||
fi
|
||||
printf '%s/%s\n' "${OUTPUT_ROOT%/}" "$(basename "${case_abs}")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '%s/%s\n' "${case_abs}" "${OUTPUT_DIR_NAME}"
|
||||
}
|
||||
|
||||
build_track_id_args() {
|
||||
local -n out_ref=$1
|
||||
out_ref=()
|
||||
|
||||
if [[ "${#CLI_TRACK_IDS[@]}" -gt 0 ]]; then
|
||||
for track_id in "${CLI_TRACK_IDS[@]}"; do
|
||||
out_ref+=(--track-ids "${track_id}")
|
||||
done
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -n "${TEMPORAL_TRACK_IDS}" ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
local track_id_arr=(${TEMPORAL_TRACK_IDS})
|
||||
for track_id in "${track_id_arr[@]}"; do
|
||||
out_ref+=(--track-ids "${track_id}")
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
run_single_case() {
|
||||
local case_dir="$1"
|
||||
local tracking_json="${case_dir}/${TRACKING_JSON_NAME}"
|
||||
local output_dir
|
||||
local cmd
|
||||
local track_id_args
|
||||
local class_id_value=""
|
||||
local frame_id_start_value=""
|
||||
local frame_id_end_value=""
|
||||
|
||||
if [[ ! -f "${tracking_json}" ]]; then
|
||||
echo "[ERROR] ${TRACKING_JSON_NAME} not found in case directory: ${case_dir}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
output_dir="$(derive_output_dir "${case_dir}")"
|
||||
build_track_id_args track_id_args
|
||||
|
||||
if [[ -n "${CLI_CLASS_ID}" ]]; then
|
||||
class_id_value="${CLI_CLASS_ID}"
|
||||
elif [[ -n "${TEMPORAL_CLASS_ID}" ]]; then
|
||||
class_id_value="${TEMPORAL_CLASS_ID}"
|
||||
fi
|
||||
|
||||
if [[ -n "${CLI_FRAME_ID_START}" ]]; then
|
||||
frame_id_start_value="${CLI_FRAME_ID_START}"
|
||||
elif [[ -n "${TEMPORAL_FRAME_ID_START}" ]]; then
|
||||
frame_id_start_value="${TEMPORAL_FRAME_ID_START}"
|
||||
fi
|
||||
|
||||
if [[ -n "${CLI_FRAME_ID_END}" ]]; then
|
||||
frame_id_end_value="${CLI_FRAME_ID_END}"
|
||||
elif [[ -n "${TEMPORAL_FRAME_ID_END}" ]]; then
|
||||
frame_id_end_value="${TEMPORAL_FRAME_ID_END}"
|
||||
fi
|
||||
|
||||
cmd=(
|
||||
"${PYTHON_BIN}" "${TEMPORAL_SCRIPT}"
|
||||
--input "${tracking_json}"
|
||||
--output "${output_dir}/stability_report.json"
|
||||
--min-length "${TEMPORAL_MIN_LENGTH}"
|
||||
--x-axis "${TEMPORAL_X_AXIS}"
|
||||
--heading-source "${TEMPORAL_HEADING_SOURCE}"
|
||||
)
|
||||
|
||||
if [[ -n "${class_id_value}" ]]; then
|
||||
cmd+=(--class-id "${class_id_value}")
|
||||
fi
|
||||
|
||||
if [[ -n "${frame_id_start_value}" ]]; then
|
||||
cmd+=(--frame-id-start "${frame_id_start_value}")
|
||||
fi
|
||||
|
||||
if [[ -n "${frame_id_end_value}" ]]; then
|
||||
cmd+=(--frame-id-end "${frame_id_end_value}")
|
||||
fi
|
||||
|
||||
if [[ "${#track_id_args[@]}" -gt 0 ]]; then
|
||||
cmd+=("${track_id_args[@]}")
|
||||
fi
|
||||
|
||||
if [[ "${TEMPORAL_PLOTS}" == "1" ]]; then
|
||||
cmd+=(--plots)
|
||||
fi
|
||||
|
||||
if [[ "${TEMPORAL_EXPORT_SERIES}" == "1" ]]; then
|
||||
cmd+=(--export-series)
|
||||
fi
|
||||
|
||||
if [[ "${TEMPORAL_FOCUS_TRACK_PLOTS}" == "1" ]]; then
|
||||
cmd+=(--focus-track-plots)
|
||||
fi
|
||||
|
||||
if [[ "${TEMPORAL_PREFER_EGO}" == "1" ]]; then
|
||||
cmd+=(--prefer-ego)
|
||||
else
|
||||
cmd+=(--no-prefer-ego)
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "######################################################################"
|
||||
echo "# Exported video-root temporal observation"
|
||||
echo "######################################################################"
|
||||
echo "Case : ${case_dir}"
|
||||
echo "Track : ${tracking_json}"
|
||||
echo "Output : ${output_dir}"
|
||||
if [[ -n "${class_id_value}" ]]; then
|
||||
echo "Class : ${class_id_value}"
|
||||
fi
|
||||
if [[ -n "${frame_id_start_value}" || -n "${frame_id_end_value}" ]]; then
|
||||
echo "Frame ID Range: [${frame_id_start_value:-"-inf"}, ${frame_id_end_value:-"+inf"}]"
|
||||
fi
|
||||
echo "Heading Source: ${TEMPORAL_HEADING_SOURCE}"
|
||||
if [[ "${#CLI_TRACK_IDS[@]}" -gt 0 ]]; then
|
||||
echo "Track IDs: ${CLI_TRACK_IDS[*]}"
|
||||
elif [[ -n "${TEMPORAL_TRACK_IDS}" ]]; then
|
||||
echo "Track IDs: ${TEMPORAL_TRACK_IDS}"
|
||||
fi
|
||||
|
||||
"${cmd[@]}"
|
||||
}
|
||||
|
||||
run_batch_root() {
|
||||
local batch_root="$1"
|
||||
local total_cases=0
|
||||
local success_cases=0
|
||||
local failed_cases=0
|
||||
|
||||
while IFS= read -r -d '' tracking_json; do
|
||||
local case_dir
|
||||
case_dir="$(dirname "${tracking_json}")"
|
||||
((total_cases += 1))
|
||||
|
||||
if run_single_case "${case_dir}"; then
|
||||
((success_cases += 1))
|
||||
else
|
||||
((failed_cases += 1))
|
||||
printf '[FAIL] case=%s\n' "${case_dir}" >&2
|
||||
fi
|
||||
done < <(
|
||||
find "${batch_root}" -type f -name "${TRACKING_JSON_NAME}" -print0 | sort -z
|
||||
)
|
||||
|
||||
if [[ "${total_cases}" -eq 0 ]]; then
|
||||
echo "[ERROR] No ${TRACKING_JSON_NAME} files were found under: ${batch_root}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
printf '[DONE] cases=%d success=%d failed=%d\n' \
|
||||
"${total_cases}" "${success_cases}" "${failed_cases}"
|
||||
|
||||
[[ "${failed_cases}" -eq 0 ]]
|
||||
}
|
||||
|
||||
if RESOLVED_CASE_DIR="$(resolve_case_dir "${TARGET_PATH}")"; then
|
||||
run_single_case "${RESOLVED_CASE_DIR}"
|
||||
elif [[ -d "${TARGET_PATH}" ]]; then
|
||||
run_batch_root "${TARGET_PATH}"
|
||||
else
|
||||
echo "Error: unsupported target path: ${TARGET_PATH}" >&2
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user