update using angle-based unwarp for display but projection for printing

This commit is contained in:
ykcheungab
2026-06-11 17:07:39 +08:00
parent 4cff6a1625
commit 667bdf1961
11 changed files with 856 additions and 225 deletions
+34 -7
View File
@@ -85,6 +85,8 @@ class Sensor:
if vid_src is None:
raise Exception("User must specify a video source.")
self._external_only = isinstance(vid_src, str) and vid_src.lower() == "external"
# Store settings
self.vid_src = vid_src
self.isstitch = isstitch
@@ -171,7 +173,7 @@ class Sensor:
self._is_live_camera = (
isinstance(self.vid_src, int)
or (isinstance(self.vid_src, str) and self.vid_src.startswith("/dev/video"))
)
) and not self._external_only
self._capture_thread = None
self._capture_running = False
self._latest_frame = None
@@ -179,8 +181,13 @@ class Sensor:
self._last_consumed_seq = -1
self._latest_frame_lock = threading.Lock()
# Setup video capture
self._open_video_source(override, box)
# Setup video capture unless this sensor is fed externally.
if self._external_only:
self.stitch_valid = False
if self.verbose:
print("Sensor initialized in external-frame mode.")
else:
self._open_video_source(override, box)
if self.verbose:
print(f" Video source: {vid_src}")
@@ -197,9 +204,19 @@ class Sensor:
# Public API - Core Methods (Most Frequently Used)
# =========================================================================
def get_img(self):
def get_img(self, frame=None, already_processed=False):
"""
Capture and preprocess a frame.
Parameters
----------
frame : np.ndarray | None
Optional externally supplied frame. When provided, the sensor skips
reading from its own video source and uses this frame instead.
already_processed : bool
If True, treat `frame` as the final BGR tactile image and skip the
configured frame processor. This is useful for pipelines that
generate a derived image, such as an unrolled tactile view.
Returns:
np.ndarray | None: Processed image, or None on capture failure.
@@ -207,7 +224,10 @@ class Sensor:
# Simple direct read - buffer size of 1 should minimize frame accumulation
# Timing measurement helps identify if capture or processing is the bottleneck
t_capture_start = time.perf_counter()
ret, frame = self._read_frame()
if frame is None:
ret, frame = self._read_frame()
else:
ret = frame is not None
t_capture_end = time.perf_counter()
self._last_capture_time = t_capture_end - t_capture_start
@@ -218,8 +238,15 @@ class Sensor:
# Start processing timing
t_processing_start = time.perf_counter()
self.frame = frame
img_bgr = self.frame_processor.process(frame)
self.frame = frame.copy() if isinstance(frame, np.ndarray) else frame
if already_processed:
img_bgr = frame
if img_bgr.ndim == 2:
img_bgr = cv2.cvtColor(img_bgr, cv2.COLOR_GRAY2BGR)
elif img_bgr.ndim == 3 and img_bgr.shape[2] == 1:
img_bgr = cv2.cvtColor(img_bgr[:, :, 0], cv2.COLOR_GRAY2BGR)
else:
img_bgr = self.frame_processor.process(frame)
t_after_extract = time.perf_counter()
t_after_stitch = time.perf_counter()