hotfix/camera not connected error

This commit is contained in:
ykcheungab
2026-09-02 21:37:40 +08:00
parent 32823a7666
commit 5be2d9759a
11 changed files with 427 additions and 677 deletions
+25 -26
View File
@@ -6,7 +6,7 @@ import numpy as np
from ..capture import (
CaptureConfig,
CaptureWorker,
CaptureSource,
ReconnectPolicy,
is_live_camera,
normalize_source,
@@ -35,23 +35,21 @@ def normalize_video_source(video):
def open_source(video, config, *, auto_reconnect: bool = False, verbose: bool = False):
"""Open a capture worker for finger pipelines (compat: returns worker.cap-like via ``.cap``).
"""Open a capture source for finger pipelines (compat: returns ``.cap``-like handle).
Historically returned a bare ``cv2.VideoCapture``. Callers that need the raw
OpenCV handle can use ``worker.source.cap``; prefer ``worker.read()``.
OpenCV handle can use ``source.cap``; prefer ``source.read()``.
"""
capture_config = CaptureConfig.from_camera_dict(
normalize_video_source(video),
config.get("camera", {}),
reconnect=ReconnectPolicy(enabled=auto_reconnect),
verbose=verbose,
start_worker=False,
background=False,
)
worker = open_capture(capture_config, start_worker=False)
# Preserve prior attribute access: treat returned object like VideoCapture for
# simple .read()/.release()/.isOpened() callers, while exposing capture worker.
cap = worker.source.cap
cap._orisys_worker = worker # type: ignore[attr-defined]
source = open_capture(capture_config, start_background=False)
cap = source.cap
cap._orisys_worker = source # type: ignore[attr-defined]
return cap
@@ -220,7 +218,7 @@ class FingerRuntime:
tactile: TactileProcessor,
frame_processor: FrameUnwarper,
capture,
capture_worker: CaptureWorker | None = None,
capture_source: CaptureSource | None = None,
):
self.geometry = geometry
self.domain = domain
@@ -228,7 +226,9 @@ class FingerRuntime:
self.sensor = tactile
self.frame_processor = frame_processor
self.capture = capture
self.capture_worker = capture_worker
self.capture_source = capture_source
# Deprecated alias.
self.capture_worker = capture_source
@classmethod
def open(
@@ -248,6 +248,7 @@ class FingerRuntime:
capture_mode: str = "latest",
) -> "FingerRuntime":
"""Open a live finger runtime from export bundle, config, and video source."""
del capture_mode # deprecated; latest-frame capture only
if camera_id is not None:
video = camera_id
video = normalize_video_source(video)
@@ -280,19 +281,16 @@ class FingerRuntime:
capture_config = CaptureConfig.from_camera_dict(
video,
geometry.config.get("camera", {}),
mode=capture_mode,
reconnect=ReconnectPolicy(enabled=auto_reconnect),
verbose=verbose,
start_worker=False,
background=False,
)
capture_worker = open_capture(capture_config, start_worker=False)
if not capture_worker.source.is_open():
capture_source = open_capture(capture_config, start_background=False)
if not capture_source.is_open():
raise RuntimeError("Cannot open camera/video source")
# Start latest-frame worker for live cameras so processing speed does not
# stall the device buffer.
if is_live_camera(video):
capture_worker.start()
capture = capture_worker.source.cap
capture_source.start_background()
capture = capture_source.cap
sensor = Sensor("external", config_name=config, verbose=verbose, mirror=mirror)
frame_processor = FrameUnwarper(
@@ -310,7 +308,7 @@ class FingerRuntime:
tactile=tactile,
frame_processor=frame_processor,
capture=capture,
capture_worker=capture_worker,
capture_source=capture_source,
)
@property
@@ -318,10 +316,10 @@ class FingerRuntime:
return self.frame_processor.valid_mask
def read_source(self):
if self.capture_worker is not None and self.capture_worker.running:
return self.capture_worker.read(copy=True, wait_s=1.0)
if self.capture_worker is not None:
return self.capture_worker.source.read_raw()
if self.capture_source is not None and self.capture_source.running:
return self.capture_source.read(copy=True, wait_s=1.0)
if self.capture_source is not None:
return self.capture_source.read_raw()
return self.capture.read()
def process_frame(self, frame, *, color=False):
@@ -355,8 +353,9 @@ class FingerRuntime:
return ok, unrolled
def close(self):
if self.capture_worker is not None:
self.capture_worker.close()
if self.capture_source is not None:
self.capture_source.close()
self.capture_source = None
self.capture_worker = None
self.capture = None
elif self.capture is not None: