Merge branch 'stable'

This commit is contained in:
ykcheungab
2026-05-14 21:02:23 +08:00
82 changed files with 5812 additions and 5386 deletions
+51 -24
View File
@@ -19,7 +19,7 @@ from typing import Tuple
from .Stitcher import Stitcher
from .tracker import Tracker
from .HHD import nHHD
from .hhd import nHHD
from . import configs
from .get_depth import Contact3D
from .backend_availability import (check_cupy_available, check_opencl_available)
@@ -202,7 +202,7 @@ class Sensor:
Capture and preprocess a frame.
Returns:
np.ndarray: Processed grayscale image
np.ndarray | None: Processed image, or None on capture failure.
"""
# Simple direct read - buffer size of 1 should minimize frame accumulation
# Timing measurement helps identify if capture or processing is the bottleneck
@@ -265,39 +265,66 @@ class Sensor:
def detect_motion(self, threshold=6):
# detect motion by optical flow magnitude
mag = np.linalg.norm(self.flow, axis=1)
mag = np.linalg.norm(self.flow, axis=-1)
# print(f"mag: {mag.max()}, {mag.min()}, {mag.mean()}")
return mag.mean() > threshold
def compute_deformation(self, decompose=True, check_motion=False, threshold=6, tail_frames = 5):
def compute_deformation(self, decompose=True, check_motion=True, threshold=6, tail_frames=10):
"""
Compute optical flow and decompose into force components.
Returns:
np.ndarray: Optical flow field
Compute optical flow and optionally decompose it into force components.
Parameters
----------
decompose : bool
If True, run HHD decomposition (`compute_hhd`) after flow computation.
check_motion : bool
If True, gate decomposition with `detect_motion(threshold)`. When motion
falls below threshold, decomposition may still run for up to
`tail_frames` additional frames to avoid abrupt force drop-off.
threshold : float
Motion-detection threshold on mean flow magnitude.
tail_frames : int
Number of extra non-motion frames allowed to keep running HHD when
`check_motion=True`.
Returns
-------
bool | None
- `True` : motion is currently detected (`check_motion=True`)
- `False` : motion is currently not detected (`check_motion=True`)
- `None` : motion gating disabled (`check_motion=False`)
"""
if self.img is None:
raise Exception("Warning: Get image first")
self.compute_flow()
# self.compute_hhd()
if check_motion:
if self.detect_motion(threshold=threshold):
self.tail_frames_count = 0
self.compute_hhd()
return True
else:
if self.tail_frames_count <= tail_frames:
self.tail_frames_count +=1
self.compute_hhd()
return True
return False
else:
if not check_motion:
self.tail_frames_count = 0
if decompose:
self.compute_hhd()
return None
# return True
is_motion = self.detect_motion(threshold=threshold)
try:
tail_frames = max(0, int(tail_frames))
except (TypeError, ValueError):
tail_frames = 0
if is_motion:
self.tail_frames_count = 0
if decompose:
self.compute_hhd()
return True
# No motion this frame. Keep HHD alive briefly if requested, but do not
# report this as "motion detected".
if decompose and self.tail_frames_count < tail_frames:
self.tail_frames_count += 1
self.compute_hhd()
else:
self.tail_frames_count = tail_frames
return False
def compute_flow(self):
if self.img is None: