seavision-python 0.1.1__py3-none-any.whl

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 (73) hide show
  1. seavision/__init__.py +3 -0
  2. seavision/defaults.py +38 -0
  3. seavision/edge/__init__.py +38 -0
  4. seavision/edge/bundle.py +189 -0
  5. seavision/edge/capture.py +107 -0
  6. seavision/edge/config.py +219 -0
  7. seavision/edge/postprocess.py +185 -0
  8. seavision/edge/runtime.py +416 -0
  9. seavision/edge/writer.py +167 -0
  10. seavision/engine/__init__.py +52 -0
  11. seavision/engine/detectors/__init__.py +90 -0
  12. seavision/engine/detectors/base.py +179 -0
  13. seavision/engine/detectors/motion/__init__.py +14 -0
  14. seavision/engine/detectors/motion/background.py +92 -0
  15. seavision/engine/detectors/motion/detector.py +218 -0
  16. seavision/engine/detectors/motion/stabiliser.py +174 -0
  17. seavision/engine/detectors/motion/tracker.py +174 -0
  18. seavision/engine/detectors/sam3/__init__.py +23 -0
  19. seavision/engine/detectors/sam3/config.py +309 -0
  20. seavision/engine/detectors/sam3/detector.py +1316 -0
  21. seavision/engine/detectors/sam3/native.py +490 -0
  22. seavision/engine/detectors/yolo/__init__.py +12 -0
  23. seavision/engine/detectors/yolo/config.py +39 -0
  24. seavision/engine/detectors/yolo/detector.py +236 -0
  25. seavision/engine/export/__init__.py +24 -0
  26. seavision/engine/export/config.py +160 -0
  27. seavision/engine/export/exporter.py +286 -0
  28. seavision/engine/export/validation.py +314 -0
  29. seavision/engine/postprocessor.py +738 -0
  30. seavision/engine/source/__init__.py +16 -0
  31. seavision/engine/source/base.py +87 -0
  32. seavision/engine/source/discovery.py +154 -0
  33. seavision/engine/source/local.py +155 -0
  34. seavision/engine/source/s3.py +231 -0
  35. seavision/engine/visualiser/__init__.py +62 -0
  36. seavision/engine/visualiser/annotator.py +382 -0
  37. seavision/engine/visualiser/config.py +127 -0
  38. seavision/engine/visualiser/loader.py +558 -0
  39. seavision/engine/visualiser/visualiser.py +402 -0
  40. seavision/engine/visualiser/writer.py +245 -0
  41. seavision/gui/__init__.py +0 -0
  42. seavision/gui/app.py +30 -0
  43. seavision/gui/main_window.py +891 -0
  44. seavision/gui/shared/__init__.py +0 -0
  45. seavision/gui/shared/conversion.py +55 -0
  46. seavision/gui/shared/session_utils.py +37 -0
  47. seavision/gui/validation/__init__.py +0 -0
  48. seavision/gui/validation/button_styles.py +144 -0
  49. seavision/gui/validation/detection_detail.py +164 -0
  50. seavision/gui/validation/detection_rect_item.py +486 -0
  51. seavision/gui/validation/detection_table.py +563 -0
  52. seavision/gui/validation/interactive_frame_scene.py +340 -0
  53. seavision/gui/validation/interactive_frame_view.py +252 -0
  54. seavision/gui/validation/s3_browser.py +645 -0
  55. seavision/gui/validation/seekable_source.py +262 -0
  56. seavision/gui/validation/session.py +376 -0
  57. seavision/gui/validation/tab.py +2503 -0
  58. seavision/gui/validation/transport_bar.py +172 -0
  59. seavision/gui/validation/validation_model.py +482 -0
  60. seavision/gui/validation/video_cache.py +215 -0
  61. seavision/gui/validation/video_list.py +140 -0
  62. seavision/gui/validation/video_viewer.py +150 -0
  63. seavision/gui/validation/video_worker.py +422 -0
  64. seavision/pipeline.py +856 -0
  65. seavision/resources/default.yaml +139 -0
  66. seavision/run_edge.py +96 -0
  67. seavision/run_export.py +176 -0
  68. seavision/run_pipeline.py +388 -0
  69. seavision_python-0.1.1.dist-info/METADATA +286 -0
  70. seavision_python-0.1.1.dist-info/RECORD +73 -0
  71. seavision_python-0.1.1.dist-info/WHEEL +5 -0
  72. seavision_python-0.1.1.dist-info/entry_points.txt +5 -0
  73. seavision_python-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,139 @@
1
+ # =============================================================================
2
+ # Buoy Detection Pipeline - Default Configuration
3
+ # =============================================================================
4
+ #
5
+ # This file contains all configurable options for the detection pipeline.
6
+ # Copy this file and modify as needed for different experiments.
7
+ #
8
+ # Usage:
9
+ # seavision --config config/default.yaml --input ./footage/
10
+ # seavision --config config/default.yaml --min-area 200 # CLI overrides
11
+ #
12
+ # =============================================================================
13
+
14
+ # -----------------------------------------------------------------------------
15
+ # Input Options
16
+ # -----------------------------------------------------------------------------
17
+
18
+ input:
19
+ # Path to video file or directory (can be overridden via CLI --input)
20
+ # path: "./footage/"
21
+
22
+ # Glob pattern for matching videos in a directory
23
+ pattern: "*.ts"
24
+
25
+ # Source type: "local" or "s3"
26
+ source_type: "local"
27
+
28
+ # S3-specific options (only used when source_type is "s3")
29
+ s3:
30
+ bucket: ""
31
+ prefix: ""
32
+ profile_name: "" # AWS SSO profile name (e.g., "m3b-detector")
33
+
34
+ # Process every Nth frame (1 = all frames, 5 = every 5th frame)
35
+ frame_skip: 1
36
+
37
+ # -----------------------------------------------------------------------------
38
+ # Output Options
39
+ # -----------------------------------------------------------------------------
40
+
41
+ output:
42
+ # Directory where detection CSV files will be saved
43
+ directory: "./output"
44
+
45
+ # Output mode: "per_video" or "single"
46
+ # per_video: Create one CSV per video (e.g., video1_detections.csv)
47
+ # single: All detections in one CSV file
48
+ mode: "per_video"
49
+
50
+ # Filename for single_file mode (ignored in per_video mode)
51
+ single_file_name: "detections.csv"
52
+
53
+ # Whether to overwrite existing output files
54
+ # Set to true to replace existing files, false to raise an error
55
+ overwrite: false
56
+
57
+ # -----------------------------------------------------------------------------
58
+ # Pipeline Options
59
+ # -----------------------------------------------------------------------------
60
+
61
+ # Resume mode: skip videos that already have output CSV files
62
+ # Useful for continuing interrupted processing runs
63
+ resume: false
64
+
65
+ # -----------------------------------------------------------------------------
66
+ # Detector Configuration
67
+ # -----------------------------------------------------------------------------
68
+
69
+ detector:
70
+ # Detector type (currently only "motion" is implemented)
71
+ type: "motion"
72
+
73
+ # Detector-specific configuration
74
+ config:
75
+ # --- Motion Detection Options ---
76
+
77
+ # Enable/disable frame stabilisation (compensates for buoy sway)
78
+ stabilisation_enabled: true
79
+
80
+ # Minimum contour area in pixels (smaller = more sensitive, more noise)
81
+ min_area: 500
82
+
83
+ # Maximum contour area in pixels (larger areas are likely not fish)
84
+ max_area: 5000
85
+
86
+ # Morphological operation kernel size (for noise cleanup)
87
+ morph_kernel_size: 5
88
+
89
+ # Number of morphological operation iterations
90
+ morph_iterations: 2
91
+
92
+ # --- Persistence Tracking Options ---
93
+
94
+ # Enable persistence filtering (require objects to persist across frames)
95
+ persistence_enabled: true
96
+
97
+ # Minimum frames an object must persist before being reported
98
+ min_persistence: 3
99
+
100
+ # Maximum frames an object can be missing before track is dropped
101
+ max_frames_missing: 5
102
+
103
+ # IoU threshold for matching detections between frames
104
+ iou_threshold: 0.3
105
+
106
+ # --- Stabiliser Options ---
107
+ stabiliser:
108
+ # Feature detector type: "ORB" or "AKAZE"
109
+ feature_detector: "ORB"
110
+
111
+ # Maximum number of features to detect per frame
112
+ max_features: 500
113
+
114
+ # Lowe's ratio test threshold for feature matching (0.0 - 1.0)
115
+ # Lower = stricter matching, fewer but better matches
116
+ match_ratio: 0.75
117
+
118
+ # Minimum number of feature matches required for homography
119
+ min_matches: 10
120
+
121
+ # RANSAC reprojection threshold for outlier rejection
122
+ ransac_threshold: 5.0
123
+
124
+ # --- Background Model Options ---
125
+ background:
126
+ # Number of frames used to build the background model
127
+ # Higher = more stable but slower to adapt
128
+ history: 600
129
+
130
+ # Variance threshold for foreground classification
131
+ # Lower = more sensitive to changes
132
+ var_threshold: 16.0
133
+
134
+ # Whether to detect and mark shadows
135
+ detect_shadows: true
136
+
137
+ # Learning rate for background model adaptation
138
+ # -1 = automatic, or 0.0-1.0 where higher = faster adaptation
139
+ learning_rate: -1.0
seavision/run_edge.py ADDED
@@ -0,0 +1,96 @@
1
+ """
2
+ CLI entry point for the SeaVision edge runtime.
3
+
4
+ Usage:
5
+ seavision-edge # Use artifact in current directory
6
+ seavision-edge --artifact-dir ./artifact
7
+ seavision-edge --source 0 # Camera 0
8
+ seavision-edge --source video.mp4 # Video file
9
+ """
10
+
11
+ import argparse
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
16
+ def _load_runtime_class():
17
+ """Import the runtime only when startup validation has passed."""
18
+ from seavision.edge import EdgeRuntime
19
+
20
+ return EdgeRuntime
21
+
22
+
23
+ def _resolve_artifact_dir(path: str, manifest_filename: str) -> str:
24
+ """Resolve artifact directory, auto-selecting a nested artifact folder."""
25
+ artifact_dir = Path(path)
26
+ if not artifact_dir.exists() or not artifact_dir.is_dir():
27
+ return path
28
+
29
+ if (artifact_dir / manifest_filename).exists():
30
+ return str(artifact_dir)
31
+
32
+ nested_artifact_dir = artifact_dir / "artifact"
33
+ if (nested_artifact_dir / manifest_filename).exists():
34
+ return str(nested_artifact_dir)
35
+
36
+ return str(artifact_dir)
37
+
38
+
39
+ def main() -> int:
40
+ """Main entry point."""
41
+ parser = argparse.ArgumentParser(
42
+ prog="seavision-edge",
43
+ description="SeaVision edge inference runtime",
44
+ )
45
+ parser.add_argument(
46
+ "--artifact-dir", default=".",
47
+ help="Path to the exported model artifact directory (default: current directory)",
48
+ )
49
+ parser.add_argument(
50
+ "--source", default=None,
51
+ help="Override video source (camera index or file path)",
52
+ )
53
+ parser.add_argument(
54
+ "--conf", type=float, default=None,
55
+ help="Override confidence threshold",
56
+ )
57
+ parser.add_argument(
58
+ "--frame-skip", type=int, default=None,
59
+ help="Override frame skip",
60
+ )
61
+
62
+ args = parser.parse_args()
63
+
64
+ from seavision.edge import EdgeConfig
65
+ from seavision.edge.config import ARTIFACT_MANIFEST_FILENAME
66
+
67
+ resolved_artifact_dir = _resolve_artifact_dir(
68
+ args.artifact_dir, ARTIFACT_MANIFEST_FILENAME
69
+ )
70
+
71
+ try:
72
+ config = EdgeConfig.from_artifact_dir(resolved_artifact_dir)
73
+ except FileNotFoundError:
74
+ print(
75
+ "ERROR: Artifact directory is incomplete or missing required files: "
76
+ f"{args.artifact_dir}"
77
+ )
78
+ print("Run seavision-export first to create an edge artifact directory.")
79
+ return 1
80
+
81
+ # Apply CLI overrides
82
+ if args.source is not None:
83
+ config.source = args.source
84
+ if args.conf is not None:
85
+ config.conf_threshold = args.conf
86
+ if args.frame_skip is not None:
87
+ config.frame_skip = args.frame_skip
88
+
89
+ EdgeRuntime = _load_runtime_class()
90
+ runtime = EdgeRuntime(config)
91
+ runtime.run()
92
+ return 0
93
+
94
+
95
+ if __name__ == "__main__":
96
+ sys.exit(main())
@@ -0,0 +1,176 @@
1
+ """
2
+ CLI entry point for model export and edge artifact creation.
3
+
4
+ Usage:
5
+ seavision-export --weights models/fish.pt --output ./deployment
6
+ seavision-export --weights models/fish.pt --imgsz 320 --target onnx
7
+ """
8
+
9
+ import argparse
10
+ import logging
11
+ import sys
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def parse_args():
17
+ """Parse command-line arguments."""
18
+ parser = argparse.ArgumentParser(
19
+ prog="seavision-export",
20
+ description="Export a trained YOLO model for edge deployment",
21
+ )
22
+
23
+ parser.add_argument(
24
+ "--weights", required=True,
25
+ help="Path to the trained .pt weights file",
26
+ )
27
+ parser.add_argument(
28
+ "--output", default="./export",
29
+ help="Output directory for exported model and edge artifact (default: ./export)",
30
+ )
31
+ parser.add_argument(
32
+ "--target", default="onnx",
33
+ choices=["onnx", "tflite", "ncnn", "torchscript"],
34
+ help="Export target format (default: onnx)",
35
+ )
36
+ parser.add_argument(
37
+ "--imgsz", type=int, default=640,
38
+ help="Input image size (default: 640)",
39
+ )
40
+ parser.add_argument(
41
+ "--half", action="store_true",
42
+ help="Use float16 quantisation",
43
+ )
44
+ parser.add_argument(
45
+ "--int8", action="store_true",
46
+ help="Use int8 quantisation",
47
+ )
48
+ parser.add_argument(
49
+ "--no-validate", action="store_true",
50
+ help="Skip export validation",
51
+ )
52
+ parser.add_argument(
53
+ "--device", default="cpu",
54
+ help="Device for export (default: cpu)",
55
+ )
56
+ parser.add_argument(
57
+ "--conf", type=float, default=0.25,
58
+ help="Default confidence threshold for edge config (default: 0.25)",
59
+ )
60
+ parser.add_argument(
61
+ "--frame-skip", type=int, default=1,
62
+ help="Default frame skip for edge config (default: 1)",
63
+ )
64
+ parser.add_argument(
65
+ "-v", "--verbose", action="store_true",
66
+ help="Enable debug logging",
67
+ )
68
+
69
+ return parser.parse_args()
70
+
71
+
72
+ def main() -> int:
73
+ """Main entry point."""
74
+ args = parse_args()
75
+
76
+ logging.basicConfig(
77
+ level=logging.DEBUG if args.verbose else logging.INFO,
78
+ format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
79
+ )
80
+
81
+ from seavision.engine.export import (
82
+ ExportConfig,
83
+ ExportTarget,
84
+ ModelExporter,
85
+ )
86
+
87
+ # Map string target to enum
88
+ target_map = {
89
+ "onnx": ExportTarget.ONNX,
90
+ "tflite": ExportTarget.TFLITE,
91
+ "ncnn": ExportTarget.NCNN,
92
+ "torchscript": ExportTarget.TORCHSCRIPT,
93
+ }
94
+
95
+ config = ExportConfig(
96
+ weights_path=args.weights,
97
+ output_dir=args.output,
98
+ target=target_map[args.target],
99
+ imgsz=args.imgsz,
100
+ half=args.half,
101
+ int8=args.int8,
102
+ validate=not args.no_validate,
103
+ device=args.device,
104
+ )
105
+
106
+ # --- Export ---
107
+ print(f"Exporting {args.weights} to {args.target.upper()}...")
108
+ exporter = ModelExporter(config)
109
+ result = exporter.export()
110
+
111
+ if not result.success:
112
+ print(f"\nERROR: Export failed: {result.error}")
113
+ return 1
114
+
115
+ print(f"\nExport successful:")
116
+ print(f" Model: {result.exported_path}")
117
+ print(f" Size: {result.model_size_mb:.1f} MB")
118
+ print(f" Classes: {result.num_classes}")
119
+ if result.class_names:
120
+ names = ", ".join(
121
+ f"{k}={v}" for k, v in sorted(result.class_names.items())[:10]
122
+ )
123
+ if len(result.class_names) > 10:
124
+ names += f", ... ({len(result.class_names)} total)"
125
+ print(f" Labels: {names}")
126
+
127
+ if result.validation:
128
+ status = "PASSED" if result.validation.passed else "FAILED"
129
+ print(f" Validation: {status}")
130
+ print(f" {result.validation.details}")
131
+
132
+ from pathlib import Path
133
+ from seavision.edge.bundle import ArtifactBuilder
134
+ from seavision.edge.config import EdgeConfig
135
+
136
+ exported_path = Path(result.exported_path)
137
+ if exported_path.is_dir():
138
+ metadata_path = exported_path / "export_metadata.json"
139
+ else:
140
+ metadata_path = exported_path.with_suffix(".json")
141
+
142
+ if not metadata_path.exists():
143
+ print(f"\nWARNING: Metadata file not found at {metadata_path}")
144
+ print("Skipping artifact creation.")
145
+ return 0
146
+
147
+ edge_config = EdgeConfig(
148
+ conf_threshold=args.conf,
149
+ frame_skip=args.frame_skip,
150
+ )
151
+
152
+ artifact_dir = Path(args.output) / "artifact"
153
+ print(f"\nCreating edge artifact: {artifact_dir}")
154
+
155
+ builder = ArtifactBuilder(
156
+ exported_model_path=result.exported_path,
157
+ export_metadata_path=str(metadata_path),
158
+ output_dir=str(artifact_dir),
159
+ edge_config=edge_config,
160
+ )
161
+ artifact_path = builder.build()
162
+
163
+ print(f"\nArtifact created: {artifact_path}")
164
+ print("\nDeployment instructions:")
165
+ print(f" 1. Copy the '{artifact_dir.name}' directory to your Pi:")
166
+ print(f" scp -r {artifact_dir} pi@<pi-ip>:~/")
167
+ print(" 2. Install or update the SeaVision wheel on the Pi:")
168
+ print(" python3 -m pip install '<seavision-wheel>[edge]'")
169
+ print(" 3. Run the detector:")
170
+ print(f" seavision-edge --artifact-dir ~/{artifact_dir.name}")
171
+
172
+ return 0
173
+
174
+
175
+ if __name__ == "__main__":
176
+ sys.exit(main())