continuous drift detection
This commit is contained in:
parent
5177eea77e
commit
d7bd2fe6cd
1 changed files with 98 additions and 92 deletions
|
|
@ -191,97 +191,96 @@ class StitchingScanner:
|
|||
"""
|
||||
offset = AlignmentOffset()
|
||||
|
||||
with self._mosaic_lock:
|
||||
if self.mosaic is None:
|
||||
return offset
|
||||
|
||||
mh, mw = self.mosaic.shape[:2]
|
||||
fh, fw = frame.shape[:2]
|
||||
|
||||
# Clamp expected positions
|
||||
expected_y = max(0, min(expected_y, mh - fh))
|
||||
expected_x = max(0, min(expected_x, mw - fw))
|
||||
|
||||
if direction == ScanDirection.RIGHT:
|
||||
# We're appending to the right
|
||||
# Compare left portion of frame with right edge of mosaic
|
||||
overlap_width = min(fw // 2, mw - expected_x, 200) # Use up to 200px overlap
|
||||
|
||||
if overlap_width < 30:
|
||||
return offset
|
||||
|
||||
# Extract regions
|
||||
mosaic_region = self.mosaic[expected_y:expected_y + fh, mw - overlap_width:mw]
|
||||
frame_region = frame[:, :overlap_width]
|
||||
|
||||
elif direction == ScanDirection.LEFT:
|
||||
# We're placing within existing mosaic, moving left
|
||||
# Compare right portion of frame with mosaic at expected position
|
||||
overlap_width = min(fw // 2, mw - expected_x, 200)
|
||||
|
||||
if overlap_width < 30:
|
||||
return offset
|
||||
|
||||
# The frame's right edge should align with mosaic at expected_x + fw
|
||||
mosaic_x_end = min(expected_x + fw, mw)
|
||||
mosaic_x_start = max(mosaic_x_end - overlap_width, 0)
|
||||
actual_overlap = mosaic_x_end - mosaic_x_start
|
||||
|
||||
if actual_overlap < 30:
|
||||
return offset
|
||||
|
||||
mosaic_region = self.mosaic[expected_y:expected_y + fh, mosaic_x_start:mosaic_x_end]
|
||||
frame_region = frame[:, fw - actual_overlap:]
|
||||
|
||||
elif direction == ScanDirection.DOWN:
|
||||
# We're appending below
|
||||
# Compare top portion of frame with bottom edge of mosaic
|
||||
overlap_height = min(fh // 2, mh - expected_y, 200)
|
||||
|
||||
if overlap_height < 30:
|
||||
return offset
|
||||
|
||||
mosaic_region = self.mosaic[mh - overlap_height:mh, expected_x:expected_x + fw]
|
||||
frame_region = frame[:overlap_height, :]
|
||||
|
||||
else: # UP
|
||||
# Compare bottom portion of frame with top edge of mosaic
|
||||
overlap_height = min(fh // 2, expected_y, 200)
|
||||
|
||||
if overlap_height < 30:
|
||||
return offset
|
||||
|
||||
mosaic_region = self.mosaic[:overlap_height, expected_x:expected_x + fw]
|
||||
frame_region = frame[fh - overlap_height:, :]
|
||||
|
||||
# Ensure regions have the same size
|
||||
min_h = min(mosaic_region.shape[0], frame_region.shape[0])
|
||||
min_w = min(mosaic_region.shape[1], frame_region.shape[1])
|
||||
|
||||
if min_h < 30 or min_w < 30:
|
||||
self.log(f"Strip alignment: overlap too small ({min_w}x{min_h})")
|
||||
return offset
|
||||
|
||||
mosaic_region = mosaic_region[:min_h, :min_w]
|
||||
frame_region = frame_region[:min_h, :min_w]
|
||||
|
||||
# Detect displacement with confidence
|
||||
dx, dy, confidence = self._detect_displacement_with_confidence(mosaic_region, frame_region)
|
||||
|
||||
# Sanity check - reject large displacements
|
||||
max_adjust = 50 # Max pixels to adjust
|
||||
if abs(dx) > max_adjust or abs(dy) > max_adjust:
|
||||
self.log(f"Strip alignment: displacement too large ({dx:.1f}, {dy:.1f}), ignoring")
|
||||
return offset
|
||||
|
||||
offset.x_offset = dx
|
||||
offset.y_offset = dy
|
||||
offset.confidence = confidence
|
||||
offset.valid = confidence > 0.1 # Require minimum confidence
|
||||
|
||||
if offset.valid:
|
||||
self.log(f" Strip alignment: X={dx:.1f}, Y={dy:.1f}, conf={confidence:.3f}")
|
||||
if self.mosaic is None:
|
||||
return offset
|
||||
|
||||
mh, mw = self.mosaic.shape[:2]
|
||||
fh, fw = frame.shape[:2]
|
||||
|
||||
# Clamp expected positions
|
||||
expected_y = max(0, min(expected_y, mh - fh))
|
||||
expected_x = max(0, min(expected_x, mw - fw))
|
||||
|
||||
if direction == ScanDirection.RIGHT:
|
||||
# We're appending to the right
|
||||
# Compare left portion of frame with right edge of mosaic
|
||||
overlap_width = min(fw // 2, mw - expected_x, 200) # Use up to 200px overlap
|
||||
|
||||
if overlap_width < 30:
|
||||
return offset
|
||||
|
||||
# Extract regions
|
||||
mosaic_region = self.mosaic[expected_y:expected_y + fh, mw - overlap_width:mw]
|
||||
frame_region = frame[:, :overlap_width]
|
||||
|
||||
elif direction == ScanDirection.LEFT:
|
||||
# We're placing within existing mosaic, moving left
|
||||
# Compare right portion of frame with mosaic at expected position
|
||||
overlap_width = min(fw // 2, mw - expected_x, 200)
|
||||
|
||||
if overlap_width < 30:
|
||||
return offset
|
||||
|
||||
# The frame's right edge should align with mosaic at expected_x + fw
|
||||
mosaic_x_end = min(expected_x + fw, mw)
|
||||
mosaic_x_start = max(mosaic_x_end - overlap_width, 0)
|
||||
actual_overlap = mosaic_x_end - mosaic_x_start
|
||||
|
||||
if actual_overlap < 30:
|
||||
return offset
|
||||
|
||||
mosaic_region = self.mosaic[expected_y:expected_y + fh, mosaic_x_start:mosaic_x_end]
|
||||
frame_region = frame[:, fw - actual_overlap:]
|
||||
|
||||
elif direction == ScanDirection.DOWN:
|
||||
# We're appending below
|
||||
# Compare top portion of frame with bottom edge of mosaic
|
||||
overlap_height = min(fh // 2, mh - expected_y, 200)
|
||||
|
||||
if overlap_height < 30:
|
||||
return offset
|
||||
|
||||
mosaic_region = self.mosaic[mh - overlap_height:mh, expected_x:expected_x + fw]
|
||||
frame_region = frame[:overlap_height, :]
|
||||
|
||||
else: # UP
|
||||
# Compare bottom portion of frame with top edge of mosaic
|
||||
overlap_height = min(fh // 2, expected_y, 200)
|
||||
|
||||
if overlap_height < 30:
|
||||
return offset
|
||||
|
||||
mosaic_region = self.mosaic[:overlap_height, expected_x:expected_x + fw]
|
||||
frame_region = frame[fh - overlap_height:, :]
|
||||
|
||||
# Ensure regions have the same size
|
||||
min_h = min(mosaic_region.shape[0], frame_region.shape[0])
|
||||
min_w = min(mosaic_region.shape[1], frame_region.shape[1])
|
||||
|
||||
if min_h < 30 or min_w < 30:
|
||||
self.log(f"Strip alignment: overlap too small ({min_w}x{min_h})")
|
||||
return offset
|
||||
|
||||
mosaic_region = mosaic_region[:min_h, :min_w]
|
||||
frame_region = frame_region[:min_h, :min_w]
|
||||
|
||||
# Detect displacement with confidence
|
||||
dx, dy, confidence = self._detect_displacement_with_confidence(mosaic_region, frame_region)
|
||||
|
||||
# Sanity check - reject large displacements
|
||||
max_adjust = 50 # Max pixels to adjust
|
||||
if abs(dx) > max_adjust or abs(dy) > max_adjust:
|
||||
self.log(f"Strip alignment: displacement too large ({dx:.1f}, {dy:.1f}), ignoring")
|
||||
return offset
|
||||
|
||||
offset.x_offset = dx
|
||||
offset.y_offset = dy
|
||||
offset.confidence = confidence
|
||||
offset.valid = confidence > 0.1 # Require minimum confidence
|
||||
|
||||
if offset.valid:
|
||||
self.log(f" Strip alignment: X={dx:.1f}, Y={dy:.1f}, conf={confidence:.3f}")
|
||||
|
||||
return offset
|
||||
|
||||
# =========================================================================
|
||||
|
|
@ -381,7 +380,8 @@ class StitchingScanner:
|
|||
y_offset = y_offset - int(round(alignment_y))
|
||||
|
||||
# Clamp x_offset to valid range
|
||||
x_offset = max(0, min(x_offset, w_base - blend_w))
|
||||
# x_offset = max(0, min(x_offset, w_base - blend_w))
|
||||
x_offset = 0 - min(x_offset, w_base)
|
||||
|
||||
# Handle strip cropping if y_offset is negative (strip protrudes above frame)
|
||||
strip_y_start = 0 # How much to crop from top of strip
|
||||
|
|
@ -837,7 +837,7 @@ class StitchingScanner:
|
|||
no_movement_count = 0
|
||||
max_no_movement = 50
|
||||
stop_reason = 'stopped'
|
||||
|
||||
self.log(f"Scanning 2..")
|
||||
while self.running and not self.paused:
|
||||
if time.time() - start_time > self.config.max_scan_time:
|
||||
self.log("Scan timeout")
|
||||
|
|
@ -871,6 +871,7 @@ class StitchingScanner:
|
|||
curr_frame = self._capture_frame()
|
||||
dx, dy = self._detect_displacement_robust(self._prev_frame, curr_frame)
|
||||
|
||||
self.log(f"Scanning dx{dx} dy{dy}..")
|
||||
self._displacement_since_append_x += dx
|
||||
self._displacement_since_append_y += dy
|
||||
total_x += dx
|
||||
|
|
@ -885,6 +886,8 @@ class StitchingScanner:
|
|||
|
||||
# Edge detection
|
||||
movement = abs(dx) if direction in [ScanDirection.RIGHT, ScanDirection.LEFT] else abs(dy)
|
||||
|
||||
self.log(f"Scanning movement{movement}..")
|
||||
if movement < 1.0:
|
||||
no_movement_count += 1
|
||||
if no_movement_count >= max_no_movement:
|
||||
|
|
@ -896,7 +899,10 @@ class StitchingScanner:
|
|||
|
||||
# Append when threshold reached (with continuous alignment)
|
||||
disp = abs(self._displacement_since_append_x) if direction in [ScanDirection.RIGHT, ScanDirection.LEFT] else abs(self._displacement_since_append_y)
|
||||
|
||||
self.log(f"Scanning disp{disp}..")
|
||||
if disp >= threshold_pixels:
|
||||
self.log(f"Scanning threshold_pixels..")
|
||||
self._append_strip(curr_frame, direction)
|
||||
self.log(f"Appended {disp:.1f}px, mosaic: {self.state.mosaic_width}x{self.state.mosaic_height}, align: ({self._cumulative_align_x:.1f}, {self._cumulative_align_y:.1f})")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue