adaspun 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. adaspun-0.1.0/CHANGELOG.md +7 -0
  2. adaspun-0.1.0/CITATION.cff +10 -0
  3. adaspun-0.1.0/LICENSE +5 -0
  4. adaspun-0.1.0/MANIFEST.in +7 -0
  5. adaspun-0.1.0/PKG-INFO +47 -0
  6. adaspun-0.1.0/README.md +13 -0
  7. adaspun-0.1.0/configs/kaggle_stereo_v9.yaml +58 -0
  8. adaspun-0.1.0/configs/kaggle_stereo_v9_recall.yaml +58 -0
  9. adaspun-0.1.0/examples/configs/local_kaggle_stereo_v9.example.yaml +21 -0
  10. adaspun-0.1.0/pyproject.toml +48 -0
  11. adaspun-0.1.0/setup.cfg +4 -0
  12. adaspun-0.1.0/src/adaspun/__init__.py +3 -0
  13. adaspun-0.1.0/src/adaspun/audit/__init__.py +0 -0
  14. adaspun-0.1.0/src/adaspun/audit/hash_chain.py +27 -0
  15. adaspun-0.1.0/src/adaspun/cli/__init__.py +0 -0
  16. adaspun-0.1.0/src/adaspun/cli/audit_verify.py +15 -0
  17. adaspun-0.1.0/src/adaspun/cli/calibrate.py +15 -0
  18. adaspun-0.1.0/src/adaspun/cli/detect_depth_frame.py +127 -0
  19. adaspun-0.1.0/src/adaspun/cli/detect_frame.py +75 -0
  20. adaspun-0.1.0/src/adaspun/cli/make_stereo_video.py +60 -0
  21. adaspun-0.1.0/src/adaspun/cli/native_video.py +269 -0
  22. adaspun-0.1.0/src/adaspun/cli/qubo_smoke.py +205 -0
  23. adaspun-0.1.0/src/adaspun/cli/risk_smoke.py +174 -0
  24. adaspun-0.1.0/src/adaspun/cli/run_clip.py +15 -0
  25. adaspun-0.1.0/src/adaspun/cli/run_qubo.py +15 -0
  26. adaspun-0.1.0/src/adaspun/cli/run_video.py +101 -0
  27. adaspun-0.1.0/src/adaspun/cli/track_ttc_smoke.py +148 -0
  28. adaspun-0.1.0/src/adaspun/cli/v9_robust.py +159 -0
  29. adaspun-0.1.0/src/adaspun/config.py +20 -0
  30. adaspun-0.1.0/src/adaspun/conformal/__init__.py +0 -0
  31. adaspun-0.1.0/src/adaspun/depth/__init__.py +0 -0
  32. adaspun-0.1.0/src/adaspun/depth/object_depth.py +152 -0
  33. adaspun-0.1.0/src/adaspun/depth/sgbm.py +37 -0
  34. adaspun-0.1.0/src/adaspun/perception/__init__.py +0 -0
  35. adaspun-0.1.0/src/adaspun/perception/ensemble.py +143 -0
  36. adaspun-0.1.0/src/adaspun/qubo/__init__.py +0 -0
  37. adaspun-0.1.0/src/adaspun/qubo/shield.py +104 -0
  38. adaspun-0.1.0/src/adaspun/risk/__init__.py +0 -0
  39. adaspun-0.1.0/src/adaspun/risk/safety_states.py +108 -0
  40. adaspun-0.1.0/src/adaspun/risk/ttc.py +58 -0
  41. adaspun-0.1.0/src/adaspun/riskfield/__init__.py +0 -0
  42. adaspun-0.1.0/src/adaspun/robustness/__init__.py +0 -0
  43. adaspun-0.1.0/src/adaspun/tracking/__init__.py +0 -0
  44. adaspun-0.1.0/src/adaspun/tracking/track_manager.py +104 -0
  45. adaspun-0.1.0/src/adaspun/types.py +49 -0
  46. adaspun-0.1.0/src/adaspun/video/__init__.py +0 -0
  47. adaspun-0.1.0/src/adaspun/video/pipeline.py +15 -0
  48. adaspun-0.1.0/src/adaspun/visualization/__init__.py +0 -0
  49. adaspun-0.1.0/src/adaspun/visualization/depth_overlays.py +29 -0
  50. adaspun-0.1.0/src/adaspun/visualization/native_video_overlay.py +84 -0
  51. adaspun-0.1.0/src/adaspun/visualization/overlays.py +18 -0
  52. adaspun-0.1.0/src/adaspun/visualization/risk_overlays.py +30 -0
  53. adaspun-0.1.0/src/adaspun/visualization/track_overlays.py +28 -0
  54. adaspun-0.1.0/src/adaspun.egg-info/PKG-INFO +47 -0
  55. adaspun-0.1.0/src/adaspun.egg-info/SOURCES.txt +59 -0
  56. adaspun-0.1.0/src/adaspun.egg-info/dependency_links.txt +1 -0
  57. adaspun-0.1.0/src/adaspun.egg-info/entry_points.txt +14 -0
  58. adaspun-0.1.0/src/adaspun.egg-info/requires.txt +28 -0
  59. adaspun-0.1.0/src/adaspun.egg-info/top_level.txt +1 -0
  60. adaspun-0.1.0/tests/test_import.py +3 -0
  61. adaspun-0.1.0/tests/test_imports.py +9 -0
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Added ADASPUN local research package scaffold.
6
+ - Added native detector/depth/tracking/risk/QUBO modules.
7
+ - Added robust V9 source-of-truth CLI bridge: adaspun-v9-robust.
@@ -0,0 +1,10 @@
1
+ cff-version: 1.2.0
2
+ title: "ADASPUN: A Research Package for NeuroSentinel-4D++ ADAS Risk Perception"
3
+ message: "If you use this software, please cite it."
4
+ type: software
5
+ authors:
6
+ - family-names: "T"
7
+ given-names: "Puneeth"
8
+ version: "0.1.0"
9
+ date-released: "2026-06-16"
10
+ license: "TBD"
adaspun-0.1.0/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Research License Placeholder
2
+
3
+ Local research and academic experimentation only.
4
+ Replace before public release.
5
+ No warranty. Not certified for safety-critical deployment.
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CITATION.cff
4
+ include CHANGELOG.md
5
+ recursive-include configs *.yaml *.yml *.json
6
+ recursive-include examples *.yaml *.yml *.json *.md
7
+ recursive-include tests *.py
adaspun-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: adaspun
3
+ Version: 0.1.0
4
+ Summary: Camera-based ADAS perception-to-risk calibration toolkit for monocular and stereo pipelines.
5
+ Author: T, Puneeth
6
+ Keywords: ADAS,computer vision,stereo vision,conformal prediction,risk calibration,QUBO
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: numpy
11
+ Requires-Dist: pandas
12
+ Requires-Dist: opencv-python
13
+ Requires-Dist: pyyaml
14
+ Requires-Dist: tqdm
15
+ Requires-Dist: scipy
16
+ Requires-Dist: scikit-learn
17
+ Requires-Dist: matplotlib
18
+ Requires-Dist: pillow
19
+ Provides-Extra: yolo
20
+ Requires-Dist: ultralytics; extra == "yolo"
21
+ Requires-Dist: torch; extra == "yolo"
22
+ Provides-Extra: clip
23
+ Requires-Dist: open_clip_torch; extra == "clip"
24
+ Provides-Extra: quantum
25
+ Requires-Dist: qiskit; extra == "quantum"
26
+ Requires-Dist: qiskit-aer; extra == "quantum"
27
+ Provides-Extra: crypto
28
+ Requires-Dist: cryptography; extra == "crypto"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest; extra == "dev"
31
+ Requires-Dist: ruff; extra == "dev"
32
+ Requires-Dist: black; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # ADASPUN
36
+
37
+ ADASPUN is a local research package for the NeuroSentinel-4D++ ADAS pipeline.
38
+
39
+ Recommended paper/demo command:
40
+ adaspun-v9-robust --cuda --copy-output D:\Puneeth_Adas\outputs\adaspun_phase7a_v9_robust\adaspun_v9_robust.mp4
41
+
42
+ Development commands:
43
+ adaspun-native-video
44
+ adaspun-risk-smoke
45
+ adaspun-qubo-smoke
46
+
47
+ This package is currently for local research use. Public PyPI release requires removing hardcoded paths and finalizing licensing.
@@ -0,0 +1,13 @@
1
+ # ADASPUN
2
+
3
+ ADASPUN is a local research package for the NeuroSentinel-4D++ ADAS pipeline.
4
+
5
+ Recommended paper/demo command:
6
+ adaspun-v9-robust --cuda --copy-output D:\Puneeth_Adas\outputs\adaspun_phase7a_v9_robust\adaspun_v9_robust.mp4
7
+
8
+ Development commands:
9
+ adaspun-native-video
10
+ adaspun-risk-smoke
11
+ adaspun-qubo-smoke
12
+
13
+ This package is currently for local research use. Public PyPI release requires removing hardcoded paths and finalizing licensing.
@@ -0,0 +1,58 @@
1
+ mode: stereo
2
+
3
+ video:
4
+ left: "D:/Puneeth_Adas/videos/left.mp4"
5
+ right: "D:/Puneeth_Adas/videos/right.mp4"
6
+ output: "D:/Puneeth_Adas/output_adaspun_v9_package.mp4"
7
+ canvas_width: 1920
8
+ canvas_height: 720
9
+
10
+ detectors:
11
+ primary: "D:/Puneeth_Adas/runs/idd_finetune/yolov8m_idd_stage2_unfreeze/weights/best.pt"
12
+ ensemble:
13
+ - "D:/Puneeth_Adas/runs/idd_finetune/yolov8s_idd_stage2_Ddrive_continue/weights/best.pt"
14
+ - "D:/Puneeth_Adas/runs/idd_finetune/yolov8x_idd_stage1_freeze10_512_batch4/weights/best.pt"
15
+ confidence: 0.25
16
+ iou: 0.50
17
+ fusion: "nms"
18
+
19
+ depth:
20
+ mode: "stereo"
21
+ stereo_method: "sgbm"
22
+ fx: 721.5
23
+ baseline_m: 0.54
24
+ min_depth_m: 1.0
25
+ max_depth_m: 80.0
26
+ fallback: "mono_proxy"
27
+
28
+ risk:
29
+ crc_threshold_file: "D:/Puneeth_Adas/outputs/experiments/neurosentinel_crc_auto_balanced_labels/crc_human_threshold.json"
30
+ lambda_star: 0.61
31
+ epsilon: 0.05
32
+ alert_fraction: 0.60
33
+ conformal_q: 6.8465
34
+ ego_lane_x_min: 0.40
35
+ ego_lane_x_max: 0.60
36
+
37
+ qubo:
38
+ enabled: true
39
+ budget: 5
40
+ overlap_penalty: 0.30
41
+
42
+ riskfield:
43
+ enabled: true
44
+ type: "ddpm"
45
+ model_path: "D:/Puneeth_Adas/outputs/experiments/neurosentinel_diffusion_risk_field_model/diffusion_risk_field_ddpm.pt"
46
+ timesteps: 100
47
+ sample_steps: 20
48
+
49
+ ui:
50
+ style: "v9_clean"
51
+ show_distance_labels: true
52
+ show_bev: true
53
+ show_tpv: true
54
+ show_depth_panel: true
55
+
56
+ audit:
57
+ enabled: false
58
+ output_jsonl: "D:/Puneeth_Adas/outputs/audit/adaspun_hash_chain.jsonl"
@@ -0,0 +1,58 @@
1
+ mode: stereo
2
+
3
+ video:
4
+ left: "D:/Puneeth_Adas/videos/left.mp4"
5
+ right: "D:/Puneeth_Adas/videos/right.mp4"
6
+ output: "D:/Puneeth_Adas/output_adaspun_v9_package.mp4"
7
+ canvas_width: 1920
8
+ canvas_height: 720
9
+
10
+ detectors:
11
+ primary: "D:/Puneeth_Adas/runs/idd_finetune/yolov8m_idd_stage2_unfreeze/weights/best.pt"
12
+ ensemble:
13
+ - "D:/Puneeth_Adas/runs/idd_finetune/yolov8s_idd_stage2_Ddrive_continue/weights/best.pt"
14
+ - "D:/Puneeth_Adas/runs/idd_finetune/yolov8x_idd_stage1_freeze10_512_batch4/weights/best.pt"
15
+ confidence: 0.15
16
+ iou: 0.50
17
+ fusion: "nms"
18
+
19
+ depth:
20
+ mode: "stereo"
21
+ stereo_method: "sgbm"
22
+ fx: 721.5
23
+ baseline_m: 0.54
24
+ min_depth_m: 1.0
25
+ max_depth_m: 80.0
26
+ fallback: "mono_proxy"
27
+
28
+ risk:
29
+ crc_threshold_file: "D:/Puneeth_Adas/outputs/experiments/neurosentinel_crc_auto_balanced_labels/crc_human_threshold.json"
30
+ lambda_star: 0.61
31
+ epsilon: 0.05
32
+ alert_fraction: 0.60
33
+ conformal_q: 6.8465
34
+ ego_lane_x_min: 0.40
35
+ ego_lane_x_max: 0.60
36
+
37
+ qubo:
38
+ enabled: true
39
+ budget: 5
40
+ overlap_penalty: 0.30
41
+
42
+ riskfield:
43
+ enabled: true
44
+ type: "ddpm"
45
+ model_path: "D:/Puneeth_Adas/outputs/experiments/neurosentinel_diffusion_risk_field_model/diffusion_risk_field_ddpm.pt"
46
+ timesteps: 100
47
+ sample_steps: 20
48
+
49
+ ui:
50
+ style: "v9_clean"
51
+ show_distance_labels: true
52
+ show_bev: true
53
+ show_tpv: true
54
+ show_depth_panel: true
55
+
56
+ audit:
57
+ enabled: false
58
+ output_jsonl: "D:/Puneeth_Adas/outputs/audit/adaspun_hash_chain.jsonl"
@@ -0,0 +1,21 @@
1
+ mode: stereo
2
+ video:
3
+ left: D:/Puneeth_Adas/videos/left.mp4
4
+ right: D:/Puneeth_Adas/videos/right.mp4
5
+ perception:
6
+ backend: yolo
7
+ fusion: nms
8
+ confidence: 0.15
9
+ iou: 0.55
10
+ max_det: 300
11
+ depth:
12
+ fx: 721.5
13
+ baseline_m: 0.54
14
+ min_depth_m: 1.0
15
+ max_depth_m: 80.0
16
+ risk:
17
+ lambda_star: 0.61
18
+ ego_lane_x_min: 0.40
19
+ ego_lane_x_max: 0.60
20
+ qubo:
21
+ budget: 5
@@ -0,0 +1,48 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "adaspun"
7
+ version = "0.1.0"
8
+ description = "Camera-based ADAS perception-to-risk calibration toolkit for monocular and stereo pipelines."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ authors = [{ name = "T, Puneeth" }]
12
+ keywords = ["ADAS", "computer vision", "stereo vision", "conformal prediction", "risk calibration", "QUBO"]
13
+ dependencies = [
14
+ "numpy",
15
+ "pandas",
16
+ "opencv-python",
17
+ "pyyaml",
18
+ "tqdm",
19
+ "scipy",
20
+ "scikit-learn",
21
+ "matplotlib",
22
+ "pillow"
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ yolo = ["ultralytics", "torch"]
27
+ clip = ["open_clip_torch"]
28
+ quantum = ["qiskit", "qiskit-aer"]
29
+ crypto = ["cryptography"]
30
+ dev = ["pytest", "ruff", "black"]
31
+
32
+ [project.scripts]
33
+ adaspun-video = "adaspun.cli.run_video:main"
34
+ adaspun-make-stereo-video = "adaspun.cli.make_stereo_video:main"
35
+ adaspun-calibrate = "adaspun.cli.calibrate:main"
36
+ adaspun-qubo = "adaspun.cli.run_qubo:main"
37
+ adaspun-clip-anomaly = "adaspun.cli.run_clip:main"
38
+ adaspun-audit-verify = "adaspun.cli.audit_verify:main"
39
+ adaspun-detect-frame = "adaspun.cli.detect_frame:main"
40
+ adaspun-detect-depth-frame = "adaspun.cli.detect_depth_frame:main"
41
+ adaspun-track-ttc-smoke = "adaspun.cli.track_ttc_smoke:main"
42
+ adaspun-risk-smoke = "adaspun.cli.risk_smoke:main"
43
+ adaspun-qubo-smoke = "adaspun.cli.qubo_smoke:main"
44
+ adaspun-native-video = "adaspun.cli.native_video:main"
45
+ adaspun-v9-robust = "adaspun.cli.v9_robust:main"
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """ADASPUN: camera-based ADAS perception-to-risk calibration toolkit."""
2
+
3
+ __version__ = "0.1.0"
File without changes
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from pathlib import Path
6
+ from typing import Any, Dict
7
+
8
+
9
+ class HashChainAuditLogger:
10
+ """Tamper-evident JSONL hash-chain logger for frame-level ADAS decisions."""
11
+
12
+ def __init__(self, output_jsonl: str | Path):
13
+ self.output_jsonl = Path(output_jsonl)
14
+ self.output_jsonl.parent.mkdir(parents=True, exist_ok=True)
15
+ self.previous_hash = "GENESIS"
16
+
17
+ def append(self, record: Dict[str, Any]) -> str:
18
+ payload = dict(record)
19
+ payload["previous_hash"] = self.previous_hash
20
+ canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
21
+ current_hash = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
22
+ payload["current_hash"] = current_hash
23
+ with self.output_jsonl.open("a", encoding="utf-8") as f:
24
+ f.write(json.dumps(payload, sort_keys=True) + "
25
+ ")
26
+ self.previous_hash = current_hash
27
+ return current_hash
File without changes
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+ import argparse
3
+
4
+
5
+ def main() -> None:
6
+ ap = argparse.ArgumentParser(description="ADASPUN audit verification CLI scaffold.")
7
+ ap.add_argument("--config", required=False, help="Path to YAML config.")
8
+ ap.add_argument("--log", required=False, help="Path to audit log if applicable.")
9
+ args = ap.parse_args()
10
+ print("ADASPUN audit verification scaffold ready. Migrate project logic into this CLI.")
11
+ print(args)
12
+
13
+
14
+ if __name__ == "__main__":
15
+ main()
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+ import argparse
3
+
4
+
5
+ def main() -> None:
6
+ ap = argparse.ArgumentParser(description="ADASPUN C3RC calibration CLI scaffold.")
7
+ ap.add_argument("--config", required=False, help="Path to YAML config.")
8
+ ap.add_argument("--log", required=False, help="Path to audit log if applicable.")
9
+ args = ap.parse_args()
10
+ print("ADASPUN C3RC calibration scaffold ready. Migrate project logic into this CLI.")
11
+ print(args)
12
+
13
+
14
+ if __name__ == "__main__":
15
+ main()
@@ -0,0 +1,127 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from pathlib import Path
6
+
7
+ import cv2
8
+ import pandas as pd
9
+
10
+ from adaspun.config import load_config
11
+ from adaspun.perception.ensemble import DetectorEnsemble
12
+ from adaspun.depth.sgbm import SGBMDepthEstimator
13
+ from adaspun.depth.object_depth import extract_depths_for_detections
14
+ from adaspun.visualization.depth_overlays import depth_to_heatmap, draw_detections_with_depth
15
+
16
+
17
+ def _read_frame(video_path: str, frame_index: int):
18
+ cap = cv2.VideoCapture(str(video_path))
19
+ if not cap.isOpened():
20
+ raise RuntimeError(f"Could not open video: {video_path}")
21
+ cap.set(cv2.CAP_PROP_POS_FRAMES, int(frame_index))
22
+ ok, frame = cap.read()
23
+ cap.release()
24
+ if not ok:
25
+ raise RuntimeError(f"Could not read frame {frame_index} from {video_path}")
26
+ return frame
27
+
28
+
29
+ def main() -> None:
30
+ ap = argparse.ArgumentParser(description="ADASPUN Phase-2 native detector + stereo object-depth smoke test.")
31
+ ap.add_argument("--config", required=True, help="Path to ADASPUN YAML config.")
32
+ ap.add_argument("--frame-index", type=int, default=25)
33
+ ap.add_argument("--output-dir", default="D:/Puneeth_Adas/outputs/adaspun_phase2_depth_smoke")
34
+ args = ap.parse_args()
35
+
36
+ cfg = load_config(args.config)
37
+ mode = cfg.get("mode", "stereo")
38
+ if mode != "stereo":
39
+ raise ValueError("Phase-2 smoke test expects mode: stereo with video.left and video.right.")
40
+
41
+ out_dir = Path(args.output_dir)
42
+ out_dir.mkdir(parents=True, exist_ok=True)
43
+
44
+ video_cfg = cfg.get("video", {})
45
+ left_path = video_cfg.get("left")
46
+ right_path = video_cfg.get("right")
47
+ if not left_path or not right_path:
48
+ raise ValueError("Config must provide video.left and video.right for stereo depth smoke test.")
49
+
50
+ left = _read_frame(left_path, args.frame_index)
51
+ right = _read_frame(right_path, args.frame_index)
52
+ if right.shape[:2] != left.shape[:2]:
53
+ right = cv2.resize(right, (left.shape[1], left.shape[0]))
54
+
55
+ detector = DetectorEnsemble.from_config(cfg)
56
+ detections = detector.predict(left)
57
+
58
+ depth_cfg = cfg.get("depth", {})
59
+ estimator = SGBMDepthEstimator(
60
+ fx=float(depth_cfg.get("fx", 721.5)),
61
+ baseline_m=float(depth_cfg.get("baseline_m", 0.54)),
62
+ min_depth_m=float(depth_cfg.get("min_depth_m", 1.0)),
63
+ max_depth_m=float(depth_cfg.get("max_depth_m", 80.0)),
64
+ )
65
+ depth_map = estimator.compute(left, right)
66
+ depth_items = extract_depths_for_detections(
67
+ depth_map,
68
+ detections,
69
+ left.shape,
70
+ fallback=str(depth_cfg.get("fallback", "mono_proxy")),
71
+ min_depth_m=float(depth_cfg.get("min_depth_m", 1.0)),
72
+ max_depth_m=float(depth_cfg.get("max_depth_m", 80.0)),
73
+ )
74
+
75
+ annotated = draw_detections_with_depth(left, depth_items)
76
+ heat = depth_to_heatmap(depth_map, min_depth_m=float(depth_cfg.get("min_depth_m", 1.0)), max_depth_m=float(depth_cfg.get("max_depth_m", 80.0)))
77
+ blended = cv2.addWeighted(left, 0.55, heat, 0.45, 0)
78
+
79
+ out_annotated = out_dir / f"adaspun_depth_frame_{args.frame_index:06d}.jpg"
80
+ out_heat = out_dir / f"adaspun_depth_heatmap_{args.frame_index:06d}.jpg"
81
+ out_blend = out_dir / f"adaspun_depth_blend_{args.frame_index:06d}.jpg"
82
+ out_csv = out_dir / f"adaspun_depth_frame_{args.frame_index:06d}.csv"
83
+ out_json = out_dir / f"adaspun_depth_frame_{args.frame_index:06d}.json"
84
+
85
+ cv2.imwrite(str(out_annotated), annotated)
86
+ cv2.imwrite(str(out_heat), heat)
87
+ cv2.imwrite(str(out_blend), blended)
88
+
89
+ rows = []
90
+ for item in depth_items:
91
+ d = item.detection
92
+ rows.append({
93
+ "frame_index": args.frame_index,
94
+ "left_video": str(left_path),
95
+ "right_video": str(right_path),
96
+ "class_id": d.class_id,
97
+ "class_name": d.class_name,
98
+ "confidence": d.confidence,
99
+ "x1": d.bbox[0], "y1": d.bbox[1], "x2": d.bbox[2], "y2": d.bbox[3],
100
+ "source_model": d.source_model,
101
+ "distance_m": item.distance_m,
102
+ "depth_source": item.depth_source,
103
+ "stereo_valid": item.valid,
104
+ "valid_ratio": item.valid_ratio,
105
+ "depth_p25_m": item.depth_p25_m,
106
+ "depth_p50_m": item.depth_p50_m,
107
+ "depth_p75_m": item.depth_p75_m,
108
+ })
109
+ pd.DataFrame(rows).to_csv(out_csv, index=False)
110
+ out_json.write_text(json.dumps({"frame_index": args.frame_index, "objects": rows}, indent=2), encoding="utf-8")
111
+
112
+ stereo_valid_count = sum(1 for x in depth_items if x.depth_source == "stereo_sgbm")
113
+ fallback_count = sum(1 for x in depth_items if x.depth_source != "stereo_sgbm")
114
+
115
+ print("[ADASPUN] Phase-2 detector+depth smoke test complete")
116
+ print(f"[ADASPUN] Detections: {len(detections)}")
117
+ print(f"[ADASPUN] Stereo-valid object depths: {stereo_valid_count}")
118
+ print(f"[ADASPUN] Fallback object depths: {fallback_count}")
119
+ print(f"[ADASPUN] Annotated frame: {out_annotated}")
120
+ print(f"[ADASPUN] Depth heatmap: {out_heat}")
121
+ print(f"[ADASPUN] Depth blend: {out_blend}")
122
+ print(f"[ADASPUN] CSV: {out_csv}")
123
+ print(f"[ADASPUN] JSON: {out_json}")
124
+
125
+
126
+ if __name__ == "__main__":
127
+ main()
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from pathlib import Path
6
+
7
+ import cv2
8
+ import pandas as pd
9
+
10
+ from adaspun.config import load_config
11
+ from adaspun.perception.ensemble import DetectorEnsemble
12
+ from adaspun.visualization.overlays import draw_detections
13
+
14
+
15
+ def _open_frame_from_config(cfg: dict, frame_index: int):
16
+ mode = cfg.get("mode", "monocular")
17
+ video_cfg = cfg.get("video", {})
18
+ path = video_cfg.get("left") if mode == "stereo" else video_cfg.get("input")
19
+ if not path:
20
+ raise ValueError("Config must provide video.left for stereo or video.input for monocular.")
21
+ cap = cv2.VideoCapture(str(path))
22
+ if not cap.isOpened():
23
+ raise RuntimeError(f"Could not open video: {path}")
24
+ cap.set(cv2.CAP_PROP_POS_FRAMES, int(frame_index))
25
+ ok, frame = cap.read()
26
+ cap.release()
27
+ if not ok:
28
+ raise RuntimeError(f"Could not read frame {frame_index} from {path}")
29
+ return frame, Path(path)
30
+
31
+
32
+ def main() -> None:
33
+ ap = argparse.ArgumentParser(description="ADASPUN Phase-1 native detector ensemble one-frame smoke test.")
34
+ ap.add_argument("--config", required=True, help="Path to ADASPUN YAML config.")
35
+ ap.add_argument("--frame-index", type=int, default=25)
36
+ ap.add_argument("--output-dir", default="D:/Puneeth_Adas/outputs/adaspun_phase1_detector_smoke")
37
+ args = ap.parse_args()
38
+
39
+ cfg = load_config(args.config)
40
+ out_dir = Path(args.output_dir)
41
+ out_dir.mkdir(parents=True, exist_ok=True)
42
+
43
+ frame, video_path = _open_frame_from_config(cfg, args.frame_index)
44
+ detector = DetectorEnsemble.from_config(cfg)
45
+ detections = detector.predict(frame)
46
+
47
+ annotated = draw_detections(frame, detections)
48
+ out_img = out_dir / f"adaspun_detector_frame_{args.frame_index:06d}.jpg"
49
+ out_json = out_dir / f"adaspun_detector_frame_{args.frame_index:06d}.json"
50
+ out_csv = out_dir / f"adaspun_detector_frame_{args.frame_index:06d}.csv"
51
+
52
+ cv2.imwrite(str(out_img), annotated)
53
+ rows = []
54
+ for d in detections:
55
+ rows.append({
56
+ "frame_index": args.frame_index,
57
+ "video": str(video_path),
58
+ "class_id": d.class_id,
59
+ "class_name": d.class_name,
60
+ "confidence": d.confidence,
61
+ "x1": d.bbox[0], "y1": d.bbox[1], "x2": d.bbox[2], "y2": d.bbox[3],
62
+ "source_model": d.source_model,
63
+ })
64
+ pd.DataFrame(rows).to_csv(out_csv, index=False)
65
+ out_json.write_text(json.dumps({"frame_index": args.frame_index, "video": str(video_path), "detections": rows}, indent=2), encoding="utf-8")
66
+
67
+ print("[ADASPUN] Phase-1 detector smoke test complete")
68
+ print(f"[ADASPUN] Detections: {len(detections)}")
69
+ print(f"[ADASPUN] Annotated frame: {out_img}")
70
+ print(f"[ADASPUN] CSV: {out_csv}")
71
+ print(f"[ADASPUN] JSON: {out_json}")
72
+
73
+
74
+ if __name__ == "__main__":
75
+ main()
@@ -0,0 +1,60 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+ import re
6
+ import cv2
7
+
8
+ IMG_EXTS = {".png", ".jpg", ".jpeg", ".bmp", ".tif", ".tiff"}
9
+
10
+
11
+ def natural_key(p: Path):
12
+ return [int(t) if t.isdigit() else t.lower() for t in re.split(r"(\d+)", p.stem)]
13
+
14
+
15
+ def list_images(d: Path):
16
+ return sorted([p for p in d.iterdir() if p.is_file() and p.suffix.lower() in IMG_EXTS], key=natural_key)
17
+
18
+
19
+ def make_video(files, out_path: Path, fps: float):
20
+ first = cv2.imread(str(files[0]))
21
+ if first is None:
22
+ raise RuntimeError(f"Could not read {files[0]}")
23
+ h, w = first.shape[:2]
24
+ out_path.parent.mkdir(parents=True, exist_ok=True)
25
+ writer = cv2.VideoWriter(str(out_path), cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
26
+ for i, p in enumerate(files):
27
+ img = cv2.imread(str(p))
28
+ if img is None:
29
+ continue
30
+ if img.shape[:2] != (h, w):
31
+ img = cv2.resize(img, (w, h))
32
+ writer.write(img)
33
+ if (i + 1) % 100 == 0:
34
+ print(f"wrote {i+1}/{len(files)} to {out_path.name}")
35
+ writer.release()
36
+
37
+
38
+ def main() -> None:
39
+ ap = argparse.ArgumentParser(description="Create synchronized left/right videos from stereo image folders.")
40
+ ap.add_argument("--left-dir", required=True)
41
+ ap.add_argument("--right-dir", required=True)
42
+ ap.add_argument("--out-left", required=True)
43
+ ap.add_argument("--out-right", required=True)
44
+ ap.add_argument("--fps", type=float, default=10.0)
45
+ args = ap.parse_args()
46
+
47
+ lefts = list_images(Path(args.left_dir))
48
+ rights = list_images(Path(args.right_dir))
49
+ rb = {p.stem: p for p in rights}
50
+ pairs = [(l, rb[l.stem]) for l in lefts if l.stem in rb]
51
+ if not pairs:
52
+ n = min(len(lefts), len(rights))
53
+ pairs = list(zip(lefts[:n], rights[:n]))
54
+ print(f"paired frames: {len(pairs)}")
55
+ make_video([p[0] for p in pairs], Path(args.out_left), args.fps)
56
+ make_video([p[1] for p in pairs], Path(args.out_right), args.fps)
57
+
58
+
59
+ if __name__ == "__main__":
60
+ main()