seavision-python 0.1.2__py3-none-any.whl → 0.1.3__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.
seavision/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """SeaVision - Human-in-the-loop Computer Vision for Marine Environments."""
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.3"
@@ -1,8 +1,8 @@
1
1
  """Detection data structures and detector interface.
2
2
 
3
3
  Base classes (Detection, DetectorBase) are imported eagerly.
4
- Optional detector implementations (SAM3, YOLO) use lazy imports
5
- to avoid pulling in torch/ultralytics at package initialisation time.
4
+ Optional detector implementations (SAM3, YOLO, CFD) use lazy imports
5
+ to avoid pulling in torch/ultralytics/rfdetr at package initialisation time.
6
6
  This allows lightweight consumers (like the GUI) to import Detection
7
7
  without triggering heavy dependency loads.
8
8
  """
@@ -14,6 +14,7 @@ __all__ = ["Detection", "DetectorBase"]
14
14
  # Lazy-loaded flags — None means "not yet checked"
15
15
  _SAM3_AVAILABLE = None
16
16
  _YOLO_AVAILABLE = None
17
+ _CFD_AVAILABLE = None
17
18
 
18
19
  # Names that trigger lazy loading when accessed
19
20
  _SAM3_NAMES = frozenset({
@@ -25,23 +26,27 @@ _YOLO_NAMES = frozenset({
25
26
  "YOLODetector", "YOLODetectorConfig",
26
27
  "YOLO_AVAILABLE",
27
28
  })
29
+ _CFD_NAMES = frozenset({
30
+ "CFDDetector", "CFDDetectorConfig",
31
+ "CFD_AVAILABLE",
32
+ })
28
33
 
29
34
 
30
35
  def __getattr__(name):
31
36
  """Lazy import for optional detector implementations."""
32
- global _SAM3_AVAILABLE, _YOLO_AVAILABLE
37
+ global _SAM3_AVAILABLE, _YOLO_AVAILABLE, _CFD_AVAILABLE #pylint: disable=global-statement
33
38
 
34
39
  if name in _SAM3_NAMES:
35
40
  if _SAM3_AVAILABLE is None:
36
41
  try:
37
- from .sam3 import (
42
+ from .sam3 import ( # pylint: disable=import-outside-toplevel
38
43
  SAM3Detector,
39
44
  SAM3DetectorConfig,
40
45
  PromptType,
41
46
  HybridStrategy,
42
47
  PrompterConfig,
43
48
  PromptConfig,
44
- )
49
+ ) # pylint: disable=import-outside-toplevel
45
50
  _SAM3_AVAILABLE = True
46
51
  # Inject into module namespace so subsequent access is fast
47
52
  globals().update({
@@ -53,7 +58,7 @@ def __getattr__(name):
53
58
  "PromptConfig": PromptConfig,
54
59
  "SAM3_AVAILABLE": True,
55
60
  })
56
- except Exception:
61
+ except Exception: # pylint: disable=broad-exception-caught
57
62
  _SAM3_AVAILABLE = False
58
63
  globals()["SAM3_AVAILABLE"] = False
59
64
 
@@ -68,14 +73,14 @@ def __getattr__(name):
68
73
  if name in _YOLO_NAMES:
69
74
  if _YOLO_AVAILABLE is None:
70
75
  try:
71
- from .yolo import YOLODetector, YOLODetectorConfig
76
+ from .yolo import YOLODetector, YOLODetectorConfig # pylint: disable=import-outside-toplevel
72
77
  _YOLO_AVAILABLE = True
73
78
  globals().update({
74
79
  "YOLODetector": YOLODetector,
75
80
  "YOLODetectorConfig": YOLODetectorConfig,
76
81
  "YOLO_AVAILABLE": True,
77
82
  })
78
- except Exception:
83
+ except Exception: # pylint: disable=broad-exception-caught
79
84
  _YOLO_AVAILABLE = False
80
85
  globals()["YOLO_AVAILABLE"] = False
81
86
 
@@ -87,4 +92,26 @@ def __getattr__(name):
87
92
  )
88
93
  return globals()[name]
89
94
 
95
+ if name in _CFD_NAMES:
96
+ if _CFD_AVAILABLE is None:
97
+ try:
98
+ from .cfd import CFDDetector, CFDDetectorConfig # pylint: disable=import-outside-toplevel
99
+ _CFD_AVAILABLE = True
100
+ globals().update({
101
+ "CFDDetector": CFDDetector,
102
+ "CFDDetectorConfig": CFDDetectorConfig,
103
+ "CFD_AVAILABLE": True,
104
+ })
105
+ except Exception: # pylint: disable=broad-exception-caught
106
+ _CFD_AVAILABLE = False
107
+ globals()["CFD_AVAILABLE"] = False
108
+
109
+ if name == "CFD_AVAILABLE":
110
+ return _CFD_AVAILABLE
111
+ if not _CFD_AVAILABLE:
112
+ raise ImportError(
113
+ f"{name} is not available (CFD dependencies not installed)"
114
+ )
115
+ return globals()[name]
116
+
90
117
  raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,11 @@
1
+ """Community Fish Detector (CFD) detector for SeaVision.
2
+
3
+ Provides:
4
+ - CFDDetectorConfig: configuration for the CFD detector.
5
+ - CFDDetector: DetectorBase-compatible wrapper around the CFD RF-DETR models.
6
+ """
7
+
8
+ from .config import CFDDetectorConfig
9
+ from .detector import CFDDetector
10
+
11
+ __all__ = ["CFDDetector", "CFDDetectorConfig"]
@@ -0,0 +1,105 @@
1
+ """Configuration for the Community Fish Detector (CFD) detector.
2
+
3
+ CFD is the marine analogue of MegaDetector: a single-class ("fish") object
4
+ detector. The current, non-deprecated models are RF-DETR checkpoints published
5
+ by the CFD project; the older YOLOv12x checkpoint is deprecated upstream (and
6
+ AGPL-licensed) and is deliberately not supported here.
7
+
8
+ Weights are pinned to a specific GitHub release rather than resolved as
9
+ "latest", so a run is reproducible: a new upstream release cannot silently
10
+ change results. To move to a newer release, bump ``release_tag`` (and the
11
+ per-variant filenames in ``CFD_WEIGHT_FILES`` if they change).
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass
17
+ from typing import Dict, Optional
18
+
19
+ # --- Pinned release ---------------------------------------------------------
20
+ # Matches the URLs hardcoded in the CFD repo's own test script
21
+ # (test_community_fish_detector.py) for the 2026.07.06 release.
22
+ CFD_RELEASE_TAG = "2026.07.06-release"
23
+ CFD_RELEASE_BASE = (
24
+ "https://github.com/filippovarini/community-fish-detector/"
25
+ "releases/download/{tag}/"
26
+ )
27
+
28
+ # variant -> checkpoint filename within the release.
29
+ CFD_WEIGHT_FILES: Dict[str, str] = {
30
+ "nano": "cfd-rf-detr-nano-640-2026.02.02.cp-011.20260706-release.pth",
31
+ "small": "cfd-rf-detr-small-1024-2026.06.06.cp-016.20260706-release.pth",
32
+ "medium": "cfd-rf-detr-medium-1024-2026.03.24.cp-011.20260706-release.pth",
33
+ }
34
+
35
+ # Reported AP on the CFD validation split. Only useful for ranking the CFD
36
+ # variants against each other; the absolute values are not comparable to any
37
+ # other benchmark (see the CFD README). medium 0.609 > small 0.606 > nano 0.596
38
+ # is within noise on their split — do not over-read the medium/small gap.
39
+ CFD_VARIANT_AP: Dict[str, float] = {"nano": 0.596, "small": 0.606, "medium": 0.609}
40
+
41
+
42
+ @dataclass
43
+ class CFDDetectorConfig:
44
+ """Configuration for :class:`CFDDetector`.
45
+
46
+ Attributes:
47
+ variant: RF-DETR size, one of ``"nano"``, ``"small"``, ``"medium"``.
48
+ This is the accuracy/speed lever. ``nano`` runs at 640 px,
49
+ ``small``/``medium`` at 1024 px (resolved from the checkpoint).
50
+ device: Compute device string, e.g. ``"cuda:0"`` or ``"cpu"``.
51
+ threshold: Confidence floor applied by ``predict()``.
52
+ resolution: Optional inference resolution override (square). ``None``
53
+ uses the training resolution recorded in the checkpoint, which is
54
+ the correct default and needs no manual ``imgsz`` plumbing. If set,
55
+ it must be divisible by ``patch_size * num_windows`` (32 for these
56
+ RF-DETR variants) or ``predict()`` will raise. It is NOT RECCOMENDED
57
+ to override this unless you have a specific reason.
58
+ output_labels: If True, emit the model's class name as the detection
59
+ label (``"fish"``). CFD is single-class, so this is constant.
60
+ weights_path: Explicit local ``.pth`` path. If set and it exists, it is
61
+ used directly and no download occurs (overrides ``variant``).
62
+ weights_url: Explicit download URL. If set, overrides the URL resolved
63
+ from ``variant`` + ``release_tag``.
64
+ release_tag: GitHub release tag to pull weights from.
65
+ persist_weights: If True (default), cache the downloaded checkpoint to
66
+ ``cache_dir`` and skip the download on subsequent runs. If False,
67
+ download to a temporary file, load, then delete it — no persistent
68
+ disk footprint, at the cost of re-downloading every process start.
69
+ cache_dir: Directory for the cached checkpoint when
70
+ ``persist_weights`` is True. ``None`` uses
71
+ ``<tempdir>/community-fish-detector``.
72
+ optimize_for_inference: Call ``model.optimize_for_inference()`` after
73
+ load. Off by default, mirroring the CFD repo — its bfloat16 path is
74
+ reported to produce degenerate boxes.
75
+ """
76
+
77
+ variant: str = "medium"
78
+ device: str = "cuda:0"
79
+ threshold: float = 0.001
80
+ resolution: Optional[int] = None
81
+ output_labels: bool = True
82
+
83
+ # Weight source / caching
84
+ weights_path: Optional[str] = None
85
+ weights_url: Optional[str] = None
86
+ release_tag: str = CFD_RELEASE_TAG
87
+ persist_weights: bool = True
88
+ cache_dir: Optional[str] = None
89
+
90
+ # Runtime
91
+ optimize_for_inference: bool = False
92
+
93
+ def __post_init__(self) -> None:
94
+ if self.variant not in CFD_WEIGHT_FILES:
95
+ raise ValueError(
96
+ f"Unknown CFD variant {self.variant!r}. "
97
+ f"Valid variants: {sorted(CFD_WEIGHT_FILES)}."
98
+ )
99
+
100
+ def resolve_weights_url(self) -> str:
101
+ """Return the download URL for the configured variant/release."""
102
+ if self.weights_url:
103
+ return self.weights_url
104
+ base = CFD_RELEASE_BASE.format(tag=self.release_tag)
105
+ return base + CFD_WEIGHT_FILES[self.variant]
@@ -0,0 +1,268 @@
1
+ """Community Fish Detector (CFD) detector for SeaVision.
2
+
3
+ Wraps the CFD RF-DETR checkpoints (via the ``rfdetr`` package) to implement the
4
+ SeaVision :class:`DetectorBase` interface, so CFD can be dropped into the
5
+ standard pipeline.
6
+
7
+ Design notes
8
+ ------------
9
+ - **Single class.** CFD detects one class, "fish".
10
+ - **Proposal cap.** RF-DETR emits at most ``num_select`` proposals per image
11
+ (300 for these variants). Lowering ``threshold`` cannot exceed that cap, so
12
+ the recall curve is truncated at 300 predictions/frame.
13
+ - **Channel order.** SeaVision passes **BGR** frames (OpenCV convention);
14
+ ``rfdetr.predict()`` expects **RGB**. The conversion is handled here, once,
15
+ as a contiguous view flip — passing BGR straight through would silently
16
+ degrade detection. This is the main integration trap and is dealt with in
17
+ ``process_frame``.
18
+ - **Resolution.** ``rfdetr.from_checkpoint`` resolves the training resolution
19
+ from checkpoint metadata (1024 for small/medium, 640 for nano), so there is
20
+ no ``imgsz`` to set. An optional override is exposed via the config.
21
+ - **Lazy dependency.** ``rfdetr`` (and its heavy torch stack) is imported only
22
+ on first model load, not at module import, mirroring the other optional
23
+ detectors so lightweight consumers can import SeaVision without it.
24
+
25
+ Example:
26
+ from seavision.engine.detectors.cfd import CFDDetector, CFDDetectorConfig
27
+
28
+ config = CFDDetectorConfig(variant="medium", device="cuda:0")
29
+ with CFDDetector(config) as detector:
30
+ for frame, context in source.iter_frames():
31
+ for det in detector.process_frame(frame, context):
32
+ print(det.label, det.confidence, det.bbox)
33
+ """
34
+
35
+ from __future__ import annotations
36
+
37
+ import logging
38
+ import os
39
+ import tempfile
40
+ import urllib.request
41
+ from typing import Iterator, List, Optional, Tuple
42
+
43
+ import numpy as np
44
+
45
+ from ...source import FrameContext
46
+ from ..base import Detection, DetectorBase
47
+ from .config import CFDDetectorConfig
48
+
49
+ logger = logging.getLogger(__name__)
50
+
51
+
52
+ class CFDDetector(DetectorBase):
53
+ """RF-DETR-based Community Fish Detector, wrapped for SeaVision.
54
+
55
+ Stateless per frame: no temporal tracking or persistence filtering. The
56
+ model is loaded lazily on the first :meth:`process_frame` call and then
57
+ kept resident; inference does not touch disk after load.
58
+ """
59
+
60
+ def __init__(self, config: Optional[CFDDetectorConfig] = None):
61
+ self.config = config or CFDDetectorConfig()
62
+
63
+ # rfdetr model handle (lazy-loaded on first inference).
64
+ self._model = None
65
+ # Cached class-name lookup, resolved once from the model.
66
+ self._class_names: Optional[List[str]] = None
67
+
68
+ logger.info(
69
+ "CFDDetector initialised (variant=%s, device=%s)",
70
+ self.config.variant,
71
+ self.config.device,
72
+ )
73
+
74
+ # ------------------------------------------------------------------
75
+ # Weight resolution
76
+ # ------------------------------------------------------------------
77
+
78
+ def _resolve_weights(self) -> Tuple[str, bool]:
79
+ """Return ``(local_path, is_temporary)`` for the checkpoint.
80
+
81
+ Resolution order:
82
+ 1. An existing local ``weights_path`` — used directly, no download.
83
+ 2. Otherwise download the pinned release URL, either to the cache
84
+ (``persist_weights=True``) or to a temp file that the caller must
85
+ delete after loading (``persist_weights=False``).
86
+ """
87
+ # 1. Explicit local file.
88
+ if self.config.weights_path:
89
+ if os.path.isfile(self.config.weights_path):
90
+ logger.info("Using local CFD weights: %s", self.config.weights_path)
91
+ return self.config.weights_path, False
92
+ raise FileNotFoundError(
93
+ f"weights_path set but not found: {self.config.weights_path}"
94
+ )
95
+
96
+ url = self.config.resolve_weights_url()
97
+ basename = os.path.basename(url)
98
+
99
+ # 2a. Persistent cache: download once, reuse thereafter.
100
+ if self.config.persist_weights:
101
+ cache_dir = self.config.cache_dir or os.path.join(
102
+ tempfile.gettempdir(), "community-fish-detector"
103
+ )
104
+ os.makedirs(cache_dir, exist_ok=True)
105
+ dest = os.path.join(cache_dir, basename)
106
+ if os.path.isfile(dest):
107
+ logger.info("Using cached CFD weights: %s", dest)
108
+ return dest, False
109
+ logger.info("Downloading CFD weights\n from %s\n to %s", url, dest)
110
+ self._download(url, dest)
111
+ return dest, False
112
+
113
+ # 2b. Ephemeral: download to a temp file, to be deleted after load.
114
+ fd, tmp_path = tempfile.mkstemp(suffix=".pth", prefix="cfd-")
115
+ os.close(fd)
116
+ logger.info(
117
+ "Downloading CFD weights to ephemeral temp file %s (persist_weights=False)",
118
+ tmp_path,
119
+ )
120
+ self._download(url, tmp_path)
121
+ return tmp_path, True
122
+
123
+ @staticmethod
124
+ def _download(url: str, dest: str) -> None:
125
+ """Download ``url`` to ``dest``, cleaning up a partial file on failure."""
126
+ try:
127
+ urllib.request.urlretrieve(url, dest)
128
+ except Exception:
129
+ if os.path.isfile(dest):
130
+ try:
131
+ os.remove(dest)
132
+ except OSError:
133
+ pass
134
+ raise
135
+
136
+ # ------------------------------------------------------------------
137
+ # Model loading
138
+ # ------------------------------------------------------------------
139
+
140
+ def _ensure_model_loaded(self) -> None:
141
+ """Lazily import rfdetr, resolve weights, and load the model."""
142
+ if self._model is not None:
143
+ return
144
+
145
+ # Lazy import: keep the heavy torch/rfdetr stack out of import time.
146
+ try:
147
+ from rfdetr import from_checkpoint #type: ignore #pylint: disable=import-outside-toplevel
148
+ except ImportError as exc:
149
+ raise ImportError(
150
+ "The 'rfdetr' package is required for CFDDetector. "
151
+ "Install with: pip install rfdetr>=1.8.3"
152
+ ) from exc
153
+
154
+ weights_path, is_temp = self._resolve_weights()
155
+ try:
156
+ logger.info("Loading CFD RF-DETR checkpoint (device=%s)", self.config.device)
157
+ # from_checkpoint resolves the RF-DETR variant, resolution and
158
+ # (single) class count from checkpoint metadata. device is
159
+ # forwarded to the model constructor.
160
+ self._model = from_checkpoint(weights_path, device=self.config.device)
161
+ finally:
162
+ # Ephemeral weights: the checkpoint is now in memory; drop the file.
163
+ if is_temp and os.path.isfile(weights_path):
164
+ try:
165
+ os.remove(weights_path)
166
+ logger.info("Removed ephemeral CFD weights file %s", weights_path)
167
+ except OSError as exc:
168
+ logger.warning("Could not remove temp weights %s: %s", weights_path, exc)
169
+
170
+ if self.config.optimize_for_inference:
171
+ logger.info("Optimising CFD model for inference")
172
+ self._model.optimize_for_inference()
173
+
174
+ # Resolve and cache class names once (single class for CFD).
175
+ try:
176
+ names = self._model.class_names
177
+ self._class_names = list(names) if names else None
178
+ except Exception: # pylint: disable=broad-exception-caught
179
+ self._class_names = None
180
+
181
+ resolved_res = getattr(self._model, "resolution", None)
182
+ logger.info(
183
+ "CFD model loaded (resolution=%s, classes=%s)",
184
+ resolved_res,
185
+ self._class_names,
186
+ )
187
+
188
+ def _label_for(self, class_id: int) -> str:
189
+ """Map a class id to a label, falling back to 'fish' for CFD."""
190
+ if self._class_names and 0 <= class_id < len(self._class_names):
191
+ return str(self._class_names[class_id])
192
+ return "fish"
193
+
194
+ # ------------------------------------------------------------------
195
+ # DetectorBase interface
196
+ # ------------------------------------------------------------------
197
+
198
+ def process_frame(
199
+ self,
200
+ frame: np.ndarray,
201
+ context: FrameContext,
202
+ ) -> Iterator[Detection]:
203
+ """Run CFD on a single frame and yield detections.
204
+
205
+ Args:
206
+ frame: BGR image, shape (H, W, 3), uint8 (OpenCV convention).
207
+ context: Frame metadata.
208
+
209
+ Yields:
210
+ :class:`Detection` per predicted box, in original-frame pixel
211
+ coordinates. Confidence is the RF-DETR score; label is the model
212
+ class name ("fish") when ``output_labels`` is set.
213
+ """
214
+ self._ensure_model_loaded()
215
+
216
+ # BGR -> RGB. predict() requires RGB; ascontiguousarray gives torch a
217
+ # positive-strided buffer (a bare ::-1 view has negative strides and
218
+ # torch.from_numpy would reject it). include_source_image=False avoids
219
+ # an extra full-frame copy we don't need.
220
+ rgb = np.ascontiguousarray(frame[:, :, ::-1])
221
+
222
+ predict_kwargs = {
223
+ "threshold": self.config.threshold,
224
+ "include_source_image": False,
225
+ }
226
+ if self.config.resolution is not None:
227
+ predict_kwargs["shape"] = (self.config.resolution, self.config.resolution)
228
+
229
+ detections = self._model.predict(rgb, **predict_kwargs) #type: ignore
230
+ # A single-image input returns a single Detections; be defensive.
231
+ if isinstance(detections, list):
232
+ detections = detections[0] if detections else None
233
+ if detections is None or len(detections) == 0:
234
+ return
235
+
236
+ xyxy = detections.xyxy #type: ignore
237
+ conf = getattr(detections, "confidence", None)
238
+ class_id = getattr(detections, "class_id", None)
239
+
240
+ for i in range(len(detections)):
241
+ x1, y1, x2, y2 = (float(v) for v in xyxy[i])
242
+
243
+ confidence: Optional[float] = None
244
+ if conf is not None:
245
+ confidence = float(conf[i])
246
+
247
+ label: Optional[str] = None
248
+ if self.config.output_labels:
249
+ cid = int(class_id[i]) if class_id is not None else 0
250
+ label = self._label_for(cid)
251
+
252
+ yield Detection.from_bbox(
253
+ source_file=context.source_file,
254
+ timestamp=context.timestamp,
255
+ frame_number=context.frame_number,
256
+ x1=x1,
257
+ y1=y1,
258
+ x2=x2,
259
+ y2=y2,
260
+ confidence=confidence,
261
+ label=label,
262
+ track_id=None,
263
+ mask=None,
264
+ )
265
+
266
+ def reset(self) -> None:
267
+ """No per-video state to clear; the model stays loaded."""
268
+ pass #pylint: disable=unnecessary-pass
@@ -105,7 +105,7 @@ class YOLODetector(DetectorBase):
105
105
  if self.config.device:
106
106
  try:
107
107
  self._model.to(self.config.device)
108
- except Exception as exc:
108
+ except Exception as exc: # pylint: disable=broad-exception-caught
109
109
  logger.warning(
110
110
  "Failed to move YOLO model to device '%s': %s. "
111
111
  "Using default device instead.",
@@ -155,7 +155,7 @@ class YOLODetector(DetectorBase):
155
155
 
156
156
  # Run YOLO inference on the in-memory frame. All saving-related
157
157
  # options are explicitly disabled to avoid side effects.
158
- results_list = self._model.predict(
158
+ results_list = self._model.predict( #type: ignore
159
159
  frame,
160
160
  imgsz=self.config.imgsz,
161
161
  conf=self.config.conf_threshold,
@@ -183,7 +183,7 @@ class YOLODetector(DetectorBase):
183
183
  if boxes is None or len(boxes) == 0:
184
184
  return
185
185
 
186
- for i in range(len(boxes)):
186
+ for i in range(len(boxes)): # pylint: disable=consider-using-enumerate
187
187
  box = boxes[i]
188
188
 
189
189
  # xyxy format as numpy array
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seavision-python
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Human-in-the-loop Computer Vision for Marine Environments
5
5
  Author: Mario Lambrette
6
6
  License: Proprietary
@@ -35,17 +35,20 @@ Provides-Extra: sam3
35
35
  Requires-Dist: pillow>=10.0; extra == "sam3"
36
36
  Requires-Dist: torch>=2.0; extra == "sam3"
37
37
  Requires-Dist: torchvision>=0.20; extra == "sam3"
38
- Requires-Dist: transformers>=4.47; extra == "sam3"
38
+ Requires-Dist: transformers>=5.1; extra == "sam3"
39
39
  Requires-Dist: ultralytics>=8.3.237; extra == "sam3"
40
+ Provides-Extra: cfd
41
+ Requires-Dist: rfdetr>=1.8.3; extra == "cfd"
40
42
  Provides-Extra: all
41
43
  Requires-Dist: boto3>=1.26; extra == "all"
42
44
  Requires-Dist: onnxruntime>=1.16; extra == "all"
43
45
  Requires-Dist: pillow>=10.0; extra == "all"
44
46
  Requires-Dist: psutil>=5.9; extra == "all"
45
47
  Requires-Dist: PySide6<6.9,>=6.5; extra == "all"
48
+ Requires-Dist: rfdetr>=1.8.3; extra == "all"
46
49
  Requires-Dist: torch>=2.0; extra == "all"
47
50
  Requires-Dist: torchvision>=0.20; extra == "all"
48
- Requires-Dist: transformers>=4.47; extra == "all"
51
+ Requires-Dist: transformers>=5.1; extra == "all"
49
52
  Requires-Dist: ultralytics>=8.3.237; extra == "all"
50
53
  Provides-Extra: dev
51
54
  Requires-Dist: build>=1.2; extra == "dev"
@@ -1,4 +1,4 @@
1
- seavision/__init__.py,sha256=WapLhw_dT3dg5ktg83GDfv2f6zOnVDuhJPzdDU_7dbg,100
1
+ seavision/__init__.py,sha256=b0X-HcdKvw7V4sTeXBK_GZkqJH6Ztlqy8-jwNHlmag4,100
2
2
  seavision/defaults.py,sha256=xmRdk3cCvwiP03WmMrJi0nSB6x8o7s_wlxUXpTnmmS8,1193
3
3
  seavision/pipeline.py,sha256=kAlYeJe5BC2kjhU4gOBooUsDvVUuZP2M1j9lAMz3YD8,29959
4
4
  seavision/run_edge.py,sha256=Ly4HN3vGgh7i87Ue_RDvQJYQ9XYMv63qacs81liBJ6w,2767
@@ -13,8 +13,11 @@ seavision/edge/runtime.py,sha256=BgbQ38FmO-gFCFA0spdVdiOlphakC-omOYXvqVltAZo,146
13
13
  seavision/edge/writer.py,sha256=EvSzA2KUYYX6QeUJjL9I7KYOEiSgjfsL5djfFpJ_jDQ,5048
14
14
  seavision/engine/__init__.py,sha256=mrn9wT-nFOeSp1g8DWZjiY4UiYrV5aeRg7lRJnqb6mo,1145
15
15
  seavision/engine/postprocessor.py,sha256=IPDwNkoP4RGDwFl1hOua2r-c_aziPkz0UyH2Tr1AHNs,22483
16
- seavision/engine/detectors/__init__.py,sha256=Q7TIevKdHV_BaeDjPa7E47a7ynqckkkTwouAGtV46Jw,3095
16
+ seavision/engine/detectors/__init__.py,sha256=XMDrqrjRCRl2Igw3R3Briir5NzjpUXeBAGv0HoMNNK0,4320
17
17
  seavision/engine/detectors/base.py,sha256=E5AeXKnTvlnhPIDuZzgfYQBK6MzaS9h_5vycj-OPh5o,5429
18
+ seavision/engine/detectors/cfd/__init__.py,sha256=sTbHJ40L7kMh6tLQB0W8GyMn1B3NbCH8mCgSd6jRpuw,328
19
+ seavision/engine/detectors/cfd/config.py,sha256=oU59XpouK6NG6-JcYjuApSJ0NGeD6a3lyRPJn_aWb6g,4916
20
+ seavision/engine/detectors/cfd/detector.py,sha256=cRiPFNaxNDzMQdWFzHr3RofD5h8mz77Kfz13cMOTDt4,10766
18
21
  seavision/engine/detectors/motion/__init__.py,sha256=9-nrzV9rA_PPEbPGwz3W3ncjjGuBT6hEkkIQfwpKad4,368
19
22
  seavision/engine/detectors/motion/background.py,sha256=-lnXJ1bsM78lzLRVMOXVwq_sFkLK4Gdg4jkp68OY0ew,2731
20
23
  seavision/engine/detectors/motion/detector.py,sha256=v4QqrZxDRotQZqgCfgGO_M_hORjwwzsVs9vYUCt_66Y,7137
@@ -26,7 +29,7 @@ seavision/engine/detectors/sam3/detector.py,sha256=6rMv4xFuXh24FRbmmDs-66TOfz-Nk
26
29
  seavision/engine/detectors/sam3/native.py,sha256=CO4nsoz4S5pcCZZ5rjpjVrSpIT-KANpAGqlEJeNigHk,18373
27
30
  seavision/engine/detectors/yolo/__init__.py,sha256=t2zLKzFXcwocpHcqwbx6wzqDGAIa4jRfXtmM4aMwp0c,331
28
31
  seavision/engine/detectors/yolo/config.py,sha256=Nq2sxajr6QFsdqvY2LoOau_RIoAFEhfXKOWqR9mqbXU,1350
29
- seavision/engine/detectors/yolo/detector.py,sha256=xqr3_BhEq83mvkNLyUvSvhSHCITyF7hm6LcWvuEVcHk,7860
32
+ seavision/engine/detectors/yolo/detector.py,sha256=seABhXDYGJGNiwRReEZ8OlklpTuNp54aWKcP5ere4gk,7958
30
33
  seavision/engine/export/__init__.py,sha256=F44L687R-rHdT0b8qJTlO9vkMWlxZQRXngWLFR_s3Ns,670
31
34
  seavision/engine/export/config.py,sha256=50zrbkSM65NfM6KR12Vi_wGEb8ebeldbNk2NEoqqVOI,6460
32
35
  seavision/engine/export/exporter.py,sha256=9qzfgtXfehqsMCmv5muTHudPUJNBv6c7oKGvyioSyjU,9211
@@ -66,8 +69,8 @@ seavision/gui/validation/video_list.py,sha256=nSj2z7FMmObBLLtF2UVfw0B2n8pihBu4jB
66
69
  seavision/gui/validation/video_viewer.py,sha256=oN44xC43WX95SP8rVYHsD55-igAszoRsWocEVvPc4jQ,5245
67
70
  seavision/gui/validation/video_worker.py,sha256=0D91wycyr_jnmI0dRXjCaVO6oqlUb0iB60iiB0Hq0Q0,14580
68
71
  seavision/resources/default.yaml,sha256=SM8VU_gjS4gmFbn5QznHVOjeLnfLHK-TLiWRZySFQVE,4636
69
- seavision_python-0.1.2.dist-info/METADATA,sha256=lUz3Jg0-WAVM7tZJLtzT7lTOq1WSalQJuk7-mvq7hxc,11508
70
- seavision_python-0.1.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
71
- seavision_python-0.1.2.dist-info/entry_points.txt,sha256=1Kh1nUV78vq__NfspupsFAKpFbZF2_pxJ4xuZCCO6n8,183
72
- seavision_python-0.1.2.dist-info/top_level.txt,sha256=HpaaVurkxRkt1KuPw6Qow4sa1A5ijnH5bgpWeulDjic,10
73
- seavision_python-0.1.2.dist-info/RECORD,,
72
+ seavision_python-0.1.3.dist-info/METADATA,sha256=sCaI4k4ao0wmgjp5oTl632tvt7olXupfZvhg79CphDk,11616
73
+ seavision_python-0.1.3.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
74
+ seavision_python-0.1.3.dist-info/entry_points.txt,sha256=1Kh1nUV78vq__NfspupsFAKpFbZF2_pxJ4xuZCCO6n8,183
75
+ seavision_python-0.1.3.dist-info/top_level.txt,sha256=HpaaVurkxRkt1KuPw6Qow4sa1A5ijnH5bgpWeulDjic,10
76
+ seavision_python-0.1.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (82.0.1)
2
+ Generator: setuptools (83.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5