better region matching
This commit is contained in:
parent
b8a51dc3cf
commit
26bfd663d5
1 changed files with 131 additions and 106 deletions
|
|
@ -6,23 +6,30 @@ No complex visual matching - just track displacement and append strips.
|
||||||
Continuous alignment correction for gear slippage compensation.
|
Continuous alignment correction for gear slippage compensation.
|
||||||
|
|
||||||
FIXES:
|
FIXES:
|
||||||
- Row-start alignment now checks BOTH bottom and side edges
|
- Row-start alignment now compares with TRANSITION STRIPS, not old row 1
|
||||||
- Larger overlap regions for better phase correlation
|
- Correct X position tracking after row transition
|
||||||
- Better strip capture with more overlap
|
- Fixed LEFT scan stop condition
|
||||||
|
|
||||||
DEBUG BORDER COLORS (for debugging row 2 placement):
|
DEBUG BORDER COLORS (for debugging row 2 placement):
|
||||||
=================================================
|
=================================================
|
||||||
In _detect_row_start_alignment():
|
In _detect_row_start_alignment():
|
||||||
- WHITE (thick): Outline of where OLD ROW 1 content is located in mosaic
|
- WHITE (thick): Outline of where TRANSITION STRIPS are in mosaic (X=x_offset, Y=0 to transition_height)
|
||||||
- BLUE line: Y=0 line (where NEW ROW should start)
|
- BLUE line: Y=transition_height (boundary between transition strips and old row 1)
|
||||||
- ORANGE line: Y=frame_height (bottom of new frame placement area)
|
- CYAN: Mosaic region used for Y alignment comparison (bottom of transition strips)
|
||||||
- CYAN: Mosaic region used for Y alignment comparison
|
|
||||||
- MAGENTA: Where the new frame is EXPECTED to be placed
|
- MAGENTA: Where the new frame is EXPECTED to be placed
|
||||||
- YELLOW: Mosaic region used for X alignment comparison
|
- YELLOW: Mosaic region used for X alignment comparison (edge of transition strips)
|
||||||
|
|
||||||
In _blend_horizontal_at_y (append_left):
|
In _blend_horizontal_at_y (append_left):
|
||||||
- RED (thick): Where strip WOULD have been placed (ORIGINAL position before alignment)
|
- RED (thick): Where strip WOULD have been placed (ORIGINAL position before alignment)
|
||||||
- GREEN: Where strip was ACTUALLY placed (ADJUSTED position after alignment)
|
- GREEN: Where strip was ACTUALLY placed (ADJUSTED position after alignment)
|
||||||
|
|
||||||
|
MOSAIC LAYOUT AFTER DOWN TRANSITION:
|
||||||
|
====================================
|
||||||
|
Y=0 to Y=transition_height: TRANSITION STRIPS (at X=x_offset to X=x_offset+fw)
|
||||||
|
Y=transition_height to Y=mh: OLD ROW 1 (shifted down, at X=0 to X=mw)
|
||||||
|
|
||||||
|
Where x_offset = mosaic_width - initial_frame_width
|
||||||
|
And transition_height = mosaic_height - initial_frame_height
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
|
|
@ -124,6 +131,11 @@ class StitchingScanner:
|
||||||
# This is critical for placing strips at the correct vertical position
|
# This is critical for placing strips at the correct vertical position
|
||||||
self._row_start_y: int = 0
|
self._row_start_y: int = 0
|
||||||
|
|
||||||
|
# Track the X position in the mosaic where the current row starts
|
||||||
|
# For row 1 (RIGHT scan): starts at X=0
|
||||||
|
# For row 2 (LEFT scan): starts at X = mosaic_width - frame_width (right edge)
|
||||||
|
self._row_start_x: int = 0
|
||||||
|
|
||||||
# Last strip's alignment for continuity
|
# Last strip's alignment for continuity
|
||||||
self._last_strip_alignment = AlignmentOffset()
|
self._last_strip_alignment = AlignmentOffset()
|
||||||
|
|
||||||
|
|
@ -200,10 +212,11 @@ class StitchingScanner:
|
||||||
Detect alignment at the START of a new row.
|
Detect alignment at the START of a new row.
|
||||||
|
|
||||||
After a DOWN transition with prepend, the mosaic layout is:
|
After a DOWN transition with prepend, the mosaic layout is:
|
||||||
- Y=0 to Y≈(transition_amount): NEW content from transition
|
- Y=0 to Y≈transition_height: TRANSITION STRIPS (placed at x_offset)
|
||||||
- Y≈(transition_amount) to Y=mosaic_height: OLD row 1 content (shifted down)
|
- Y≈transition_height to Y=mosaic_height: OLD row 1 content (shifted down)
|
||||||
|
|
||||||
The new frame should overlap visually with OLD row 1 content.
|
The current frame should overlap with the TRANSITION STRIPS, not old row 1.
|
||||||
|
The camera is at the X position where transition strips were placed.
|
||||||
"""
|
"""
|
||||||
offset = AlignmentOffset()
|
offset = AlignmentOffset()
|
||||||
|
|
||||||
|
|
@ -214,27 +227,30 @@ class StitchingScanner:
|
||||||
mh, mw = self.mosaic.shape[:2]
|
mh, mw = self.mosaic.shape[:2]
|
||||||
fh, fw = frame.shape[:2]
|
fh, fw = frame.shape[:2]
|
||||||
|
|
||||||
# After prepending during row transition:
|
# Calculate where transition strips are in the mosaic
|
||||||
# Old row 1 content was originally at Y=0 to Y=fh in the old mosaic
|
# x_offset is where the DOWN transition strips were placed horizontally
|
||||||
# Now it's shifted down by (mh - fh) pixels
|
x_offset = max(0, mw - self.state.mosaic_init_width)
|
||||||
# So old row 1 starts at approximately Y = mh - fh
|
|
||||||
old_row1_start = mh - fh
|
# Transition height is how much was added during DOWN transition
|
||||||
|
# transition_height = mh - original_height_before_transition
|
||||||
|
# But since row 1 was just fh tall, transition_height = mh - fh
|
||||||
|
transition_height = mh - fh
|
||||||
|
|
||||||
self.log(f" Row-start alignment: mosaic {mw}x{mh}, frame {fw}x{fh}")
|
self.log(f" Row-start alignment: mosaic {mw}x{mh}, frame {fw}x{fh}")
|
||||||
self.log(f" Old row 1 estimated start: Y={old_row1_start}")
|
self.log(f" Transition strips at: X={x_offset}, Y=0 to Y={transition_height}")
|
||||||
|
self.log(f" Old row 1 shifted to: Y={transition_height} to Y={mh}")
|
||||||
|
|
||||||
# ========== DEBUG: Draw WHITE border showing where OLD ROW 1 content is ==========
|
# ========== DEBUG: Draw borders showing layout ==========
|
||||||
if old_row1_start >= 0:
|
# WHITE border: Where TRANSITION STRIPS are (this is what we should compare with)
|
||||||
cv2.rectangle(self.mosaic,
|
cv2.rectangle(self.mosaic,
|
||||||
(0, old_row1_start),
|
(x_offset, 0),
|
||||||
(mw, min(old_row1_start + fh, mh)),
|
(min(x_offset + fw, mw), transition_height),
|
||||||
(255, 255, 255), 3) # WHITE - old row 1 location
|
(255, 255, 255), 3) # WHITE - transition strips location
|
||||||
self.log(f" DEBUG: WHITE border - OLD ROW 1 location Y={old_row1_start}:{min(old_row1_start + fh, mh)}")
|
self.log(f" DEBUG: WHITE border - TRANSITION STRIPS at X={x_offset}:{min(x_offset + fw, mw)}, Y=0:{transition_height}")
|
||||||
|
|
||||||
# ========== DEBUG: Draw BLUE line at Y=0 showing where NEW ROW starts ==========
|
# BLUE line at transition boundary (where transition ends and old row 1 begins)
|
||||||
cv2.line(self.mosaic, (0, 0), (mw, 0), (255, 0, 0), 3) # BLUE line at Y=0
|
cv2.line(self.mosaic, (0, transition_height), (mw, transition_height), (255, 0, 0), 3)
|
||||||
cv2.line(self.mosaic, (0, fh), (mw, fh), (255, 100, 0), 2) # ORANGE line at Y=fh (bottom of new frame area)
|
self.log(f" DEBUG: BLUE line at Y={transition_height} (transition/row1 boundary)")
|
||||||
self.log(f" DEBUG: BLUE line at Y=0 (new row start), ORANGE line at Y={fh} (new frame bottom)")
|
|
||||||
|
|
||||||
vertical_overlap = min(200, fh // 3)
|
vertical_overlap = min(200, fh // 3)
|
||||||
min_overlap = 50
|
min_overlap = 50
|
||||||
|
|
@ -242,79 +258,78 @@ class StitchingScanner:
|
||||||
# =============================================
|
# =============================================
|
||||||
# Step 1: Detect Y alignment
|
# Step 1: Detect Y alignment
|
||||||
# =============================================
|
# =============================================
|
||||||
# Compare frame's bottom with the TOP of old row 1 content
|
# Compare frame's TOP with the BOTTOM of transition strips
|
||||||
# Frame's bottom: frame[fh-overlap:fh]
|
# Frame's top portion overlaps with mosaic's transition bottom
|
||||||
# Old row 1's top: mosaic[old_row1_start:old_row1_start+overlap]
|
#
|
||||||
|
# Transition strips are at Y=0 to Y=transition_height
|
||||||
|
# So transition bottom is around Y=(transition_height - overlap) to Y=transition_height
|
||||||
|
|
||||||
if old_row1_start >= 0 and old_row1_start + vertical_overlap <= mh:
|
transition_compare_y_end = transition_height
|
||||||
expected_x = 0 if direction == ScanDirection.RIGHT else max(0, mw - fw)
|
transition_compare_y_start = max(0, transition_height - vertical_overlap)
|
||||||
x_end = min(expected_x + fw, mw)
|
|
||||||
|
# Frame's TOP should overlap with transition BOTTOM
|
||||||
|
frame_top = frame[:vertical_overlap, :]
|
||||||
|
|
||||||
|
# Get the X range - centered on where transition strips are
|
||||||
|
x_start = x_offset
|
||||||
|
x_end = min(x_offset + fw, mw)
|
||||||
|
compare_width = x_end - x_start
|
||||||
|
|
||||||
|
if transition_compare_y_start >= 0 and compare_width >= min_overlap:
|
||||||
|
# Mosaic region: bottom of transition strips
|
||||||
|
mosaic_transition_bottom = self.mosaic[transition_compare_y_start:transition_compare_y_end,
|
||||||
|
x_start:x_end]
|
||||||
|
|
||||||
# Frame's bottom portion (will overlap with old row 1's top)
|
# Frame region: top portion (what overlaps with transition)
|
||||||
frame_bottom = frame[fh - vertical_overlap:fh, :x_end - expected_x]
|
frame_compare = frame_top[:, :compare_width]
|
||||||
|
|
||||||
# Old row 1's top portion in the mosaic
|
|
||||||
mosaic_top_of_old = self.mosaic[old_row1_start:old_row1_start + vertical_overlap,
|
|
||||||
expected_x:x_end]
|
|
||||||
|
|
||||||
# ========== DEBUG: Save frame with comparison region marked ==========
|
# ========== DEBUG: Save frame with comparison region marked ==========
|
||||||
debug_frame = frame.copy()
|
debug_frame = frame.copy()
|
||||||
# CYAN border on frame showing the region being compared
|
cv2.rectangle(debug_frame, (0, 0), (compare_width, vertical_overlap),
|
||||||
cv2.rectangle(debug_frame,
|
(255, 255, 0), 2) # CYAN - frame's top region used for Y comparison
|
||||||
(0, fh - vertical_overlap),
|
self.log(f" DEBUG: Frame Y comparison region: X=0:{compare_width}, Y=0:{vertical_overlap}")
|
||||||
(x_end - expected_x, fh),
|
|
||||||
(255, 255, 0), 2) # CYAN - frame's bottom region used for Y comparison
|
|
||||||
self.log(f" DEBUG: Frame comparison region: Y={fh - vertical_overlap}:{fh}")
|
|
||||||
|
|
||||||
# Save debug frame
|
|
||||||
try:
|
try:
|
||||||
cv2.imwrite('/tmp/debug_frame_row2_start.png', debug_frame)
|
cv2.imwrite('/tmp/debug_frame_row2_start.png', debug_frame)
|
||||||
self.log(f" DEBUG: Saved frame to /tmp/debug_frame_row2_start.png")
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# ========== DEBUG: Draw borders on mosaic for comparison regions ==========
|
# ========== DEBUG: Draw CYAN border on mosaic for Y comparison region ==========
|
||||||
# CYAN border: Mosaic region used for Y alignment comparison
|
|
||||||
cv2.rectangle(self.mosaic,
|
cv2.rectangle(self.mosaic,
|
||||||
(expected_x, old_row1_start),
|
(x_start, transition_compare_y_start),
|
||||||
(x_end, old_row1_start + vertical_overlap),
|
(x_end, transition_compare_y_end),
|
||||||
(255, 255, 0), 2) # CYAN - mosaic comparison region for Y
|
(255, 255, 0), 2) # CYAN - mosaic comparison region for Y
|
||||||
self.log(f" DEBUG: CYAN border - mosaic Y comparison region X={expected_x}:{x_end}, Y={old_row1_start}:{old_row1_start + vertical_overlap}")
|
self.log(f" DEBUG: CYAN border - mosaic Y comparison region X={x_start}:{x_end}, Y={transition_compare_y_start}:{transition_compare_y_end}")
|
||||||
|
|
||||||
# MAGENTA border: Where frame WOULD be placed (Y=0 to fh)
|
# MAGENTA border: Where frame is EXPECTED to be placed (at transition position)
|
||||||
cv2.rectangle(self.mosaic,
|
cv2.rectangle(self.mosaic,
|
||||||
(expected_x, 0),
|
(x_start, 0),
|
||||||
(min(expected_x + fw, mw), fh),
|
(x_end, fh),
|
||||||
(255, 0, 255), 2) # MAGENTA - expected frame position
|
(255, 0, 255), 2) # MAGENTA - expected frame position
|
||||||
self.log(f" DEBUG: MAGENTA border - expected frame position X={expected_x}:{min(expected_x + fw, mw)}, Y=0:{fh}")
|
self.log(f" DEBUG: MAGENTA border - expected frame position X={x_start}:{x_end}, Y=0:{fh}")
|
||||||
|
|
||||||
min_w = min(frame_bottom.shape[1], mosaic_top_of_old.shape[1])
|
min_w = min(frame_compare.shape[1], mosaic_transition_bottom.shape[1])
|
||||||
min_h = min(frame_bottom.shape[0], mosaic_top_of_old.shape[0])
|
min_h = min(frame_compare.shape[0], mosaic_transition_bottom.shape[0])
|
||||||
|
|
||||||
if min_w >= min_overlap and min_h >= min_overlap:
|
if min_w >= min_overlap and min_h >= min_overlap:
|
||||||
frame_bottom = frame_bottom[:min_h, :min_w]
|
frame_compare = frame_compare[:min_h, :min_w]
|
||||||
mosaic_top_of_old = mosaic_top_of_old[:min_h, :min_w]
|
mosaic_transition_bottom = mosaic_transition_bottom[:min_h, :min_w]
|
||||||
|
|
||||||
# ========== DEBUG: Save the comparison regions as images ==========
|
# ========== DEBUG: Save the comparison regions as images ==========
|
||||||
try:
|
try:
|
||||||
cv2.imwrite('/tmp/debug_frame_bottom_region.png', frame_bottom)
|
cv2.imwrite('/tmp/debug_frame_top_region.png', frame_compare)
|
||||||
cv2.imwrite('/tmp/debug_mosaic_top_region.png', mosaic_top_of_old)
|
cv2.imwrite('/tmp/debug_mosaic_transition_region.png', mosaic_transition_bottom)
|
||||||
self.log(f" DEBUG: Saved comparison regions to /tmp/debug_*.png")
|
self.log(f" DEBUG: Saved comparison regions to /tmp/debug_*.png")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Detect displacement: how is frame_bottom shifted relative to mosaic_top_of_old?
|
# Detect displacement
|
||||||
dx_v, dy_v, conf_v = self._detect_displacement_with_confidence(
|
dx_v, dy_v, conf_v = self._detect_displacement_with_confidence(
|
||||||
mosaic_top_of_old, frame_bottom)
|
mosaic_transition_bottom, frame_compare)
|
||||||
|
|
||||||
self.log(f" Row-start Y alignment: dx={dx_v:.1f}, dy={dy_v:.1f}, conf={conf_v:.3f}")
|
self.log(f" Row-start Y alignment: dx={dx_v:.1f}, dy={dy_v:.1f}, conf={conf_v:.3f}")
|
||||||
self.log(f" Compared frame[{fh-vertical_overlap}:{fh}] with mosaic[{old_row1_start}:{old_row1_start+vertical_overlap}]")
|
self.log(f" Compared frame[0:{vertical_overlap}] with mosaic[{transition_compare_y_start}:{transition_compare_y_end}]")
|
||||||
|
|
||||||
if conf_v > 0.1:
|
if conf_v > 0.1:
|
||||||
# dy > 0 means frame_bottom is shifted DOWN relative to mosaic_top_of_old
|
|
||||||
# To correct in placement: move content UP
|
|
||||||
# blend formula: y_offset = row_start_y - alignment_y
|
|
||||||
# So positive alignment_y decreases y_offset, moving content UP
|
|
||||||
offset.y_offset = dy_v
|
offset.y_offset = dy_v
|
||||||
offset.confidence = conf_v
|
offset.confidence = conf_v
|
||||||
|
|
||||||
|
|
@ -324,22 +339,26 @@ class StitchingScanner:
|
||||||
horizontal_overlap = min(200, fw // 3)
|
horizontal_overlap = min(200, fw // 3)
|
||||||
|
|
||||||
if direction == ScanDirection.LEFT:
|
if direction == ScanDirection.LEFT:
|
||||||
# For LEFT scan: frame starts at right edge
|
# For LEFT scan: frame starts at the transition X position
|
||||||
# Compare frame's right edge with mosaic's right edge at OLD row 1 position
|
# Compare frame's RIGHT edge with mosaic's transition strip RIGHT edge
|
||||||
if old_row1_start >= 0 and mw >= horizontal_overlap:
|
|
||||||
y_start = old_row1_start
|
transition_x_end = min(x_offset + fw, mw)
|
||||||
y_end = min(old_row1_start + fh, mh)
|
transition_x_start = max(x_offset, transition_x_end - horizontal_overlap)
|
||||||
|
|
||||||
|
# Y range: within the transition strip area
|
||||||
|
y_start = 0
|
||||||
|
y_end = min(transition_height, fh)
|
||||||
|
|
||||||
|
if transition_x_end - transition_x_start >= min_overlap:
|
||||||
|
mosaic_edge = self.mosaic[y_start:y_end, transition_x_start:transition_x_end]
|
||||||
|
frame_edge = frame[:y_end, fw - (transition_x_end - transition_x_start):fw]
|
||||||
|
|
||||||
mosaic_edge = self.mosaic[y_start:y_end, mw - horizontal_overlap:mw]
|
# ========== DEBUG: Draw YELLOW border for X comparison region ==========
|
||||||
frame_edge = frame[:mosaic_edge.shape[0], fw - horizontal_overlap:fw]
|
|
||||||
|
|
||||||
# ========== DEBUG: Draw border for X comparison region ==========
|
|
||||||
# YELLOW border: Mosaic region used for X alignment comparison
|
|
||||||
cv2.rectangle(self.mosaic,
|
cv2.rectangle(self.mosaic,
|
||||||
(mw - horizontal_overlap, y_start),
|
(transition_x_start, y_start),
|
||||||
(mw, y_end),
|
(transition_x_end, y_end),
|
||||||
(0, 255, 255), 2) # YELLOW - mosaic comparison region for X
|
(0, 255, 255), 2) # YELLOW - mosaic comparison region for X
|
||||||
self.log(f" DEBUG: YELLOW border - mosaic X comparison region X={mw - horizontal_overlap}:{mw}, Y={y_start}:{y_end}")
|
self.log(f" DEBUG: YELLOW border - mosaic X comparison region X={transition_x_start}:{transition_x_end}, Y={y_start}:{y_end}")
|
||||||
|
|
||||||
min_h = min(mosaic_edge.shape[0], frame_edge.shape[0])
|
min_h = min(mosaic_edge.shape[0], frame_edge.shape[0])
|
||||||
min_w = min(mosaic_edge.shape[1], frame_edge.shape[1])
|
min_w = min(mosaic_edge.shape[1], frame_edge.shape[1])
|
||||||
|
|
@ -354,28 +373,26 @@ class StitchingScanner:
|
||||||
self.log(f" Row-start X alignment: dx={dx_h:.1f}, dy={dy_h:.1f}, conf={conf_h:.3f}")
|
self.log(f" Row-start X alignment: dx={dx_h:.1f}, dy={dy_h:.1f}, conf={conf_h:.3f}")
|
||||||
|
|
||||||
if conf_h > 0.1:
|
if conf_h > 0.1:
|
||||||
# dx > 0 means frame shifted RIGHT
|
|
||||||
# To correct: move LEFT (decrease x_offset)
|
|
||||||
# blend: x_offset = x_offset + alignment_x
|
|
||||||
# So negative alignment_x decreases x_offset
|
|
||||||
offset.x_offset = -dx_h
|
offset.x_offset = -dx_h
|
||||||
if conf_h > offset.confidence:
|
if conf_h > offset.confidence:
|
||||||
offset.confidence = conf_h
|
offset.confidence = conf_h
|
||||||
else:
|
else:
|
||||||
# For RIGHT scan at row start
|
# For RIGHT scan at row start (similar logic but for left edge)
|
||||||
if old_row1_start >= 0 and horizontal_overlap > 0:
|
transition_x_start = x_offset
|
||||||
y_start = old_row1_start
|
transition_x_end = min(x_offset + horizontal_overlap, mw)
|
||||||
y_end = min(old_row1_start + fh, mh)
|
|
||||||
|
y_start = 0
|
||||||
|
y_end = min(transition_height, fh)
|
||||||
|
|
||||||
|
if transition_x_end - transition_x_start >= min_overlap:
|
||||||
|
mosaic_edge = self.mosaic[y_start:y_end, transition_x_start:transition_x_end]
|
||||||
|
frame_edge = frame[:y_end, :transition_x_end - transition_x_start]
|
||||||
|
|
||||||
mosaic_edge = self.mosaic[y_start:y_end, :horizontal_overlap]
|
|
||||||
frame_edge = frame[:min(y_end - y_start, fh), :horizontal_overlap]
|
|
||||||
|
|
||||||
# ========== DEBUG: Draw border for X comparison region ==========
|
|
||||||
cv2.rectangle(self.mosaic,
|
cv2.rectangle(self.mosaic,
|
||||||
(0, y_start),
|
(transition_x_start, y_start),
|
||||||
(horizontal_overlap, y_end),
|
(transition_x_end, y_end),
|
||||||
(0, 255, 255), 2) # YELLOW - mosaic comparison region for X
|
(0, 255, 255), 2) # YELLOW
|
||||||
self.log(f" DEBUG: YELLOW border - mosaic X comparison region X=0:{horizontal_overlap}, Y={y_start}:{y_end}")
|
self.log(f" DEBUG: YELLOW border - mosaic X comparison region X={transition_x_start}:{transition_x_end}, Y={y_start}:{y_end}")
|
||||||
|
|
||||||
min_h = min(mosaic_edge.shape[0], frame_edge.shape[0])
|
min_h = min(mosaic_edge.shape[0], frame_edge.shape[0])
|
||||||
min_w = min(mosaic_edge.shape[1], frame_edge.shape[1])
|
min_w = min(mosaic_edge.shape[1], frame_edge.shape[1])
|
||||||
|
|
@ -1049,6 +1066,7 @@ class StitchingScanner:
|
||||||
|
|
||||||
self.log(f"=== Row {row + 1} ===")
|
self.log(f"=== Row {row + 1} ===")
|
||||||
self.log(f"Row start Y position: {self._row_start_y}")
|
self.log(f"Row start Y position: {self._row_start_y}")
|
||||||
|
self.log(f"Row start X position: {self.state.current_x}")
|
||||||
self.log(f"Cumulative alignment at row start: X={self._cumulative_align_x:.1f}, Y={self._cumulative_align_y:.1f}")
|
self.log(f"Cumulative alignment at row start: X={self._cumulative_align_x:.1f}, Y={self._cumulative_align_y:.1f}")
|
||||||
|
|
||||||
# Serpentine: even rows right, odd rows left
|
# Serpentine: even rows right, odd rows left
|
||||||
|
|
@ -1140,10 +1158,10 @@ class StitchingScanner:
|
||||||
stop_reason = 'max_dim'
|
stop_reason = 'max_dim'
|
||||||
break
|
break
|
||||||
|
|
||||||
if self.state.current_x >= 0 and direction == ScanDirection.LEFT:
|
# For LEFT scan: stop when we've reached the left edge (current_x <= 0)
|
||||||
self.log(f"Returned to start ({self.config.max_mosaic_width}px)")
|
if self.state.current_x <= 0 and direction == ScanDirection.LEFT:
|
||||||
self.log(f"Current X offset ({self.state.current_x}px) total_x ({total_x}px)")
|
self.log(f"Reached left edge (current_x={self.state.current_x:.1f})")
|
||||||
stop_reason = 'max_dim'
|
stop_reason = 'edge'
|
||||||
break
|
break
|
||||||
|
|
||||||
if abs(self.state.current_x) >= self.config.max_mosaic_width and direction == ScanDirection.RIGHT:
|
if abs(self.state.current_x) >= self.config.max_mosaic_width and direction == ScanDirection.RIGHT:
|
||||||
|
|
@ -1286,14 +1304,21 @@ class StitchingScanner:
|
||||||
# Calculate the Y position in the mosaic where the new row starts
|
# Calculate the Y position in the mosaic where the new row starts
|
||||||
# Since we use append_below=False during DOWN movement, new content
|
# Since we use append_below=False during DOWN movement, new content
|
||||||
# is PREPENDED to the TOP of the mosaic. So the new row starts at Y=0
|
# is PREPENDED to the TOP of the mosaic. So the new row starts at Y=0
|
||||||
# (or close to it, accounting for overlap)
|
|
||||||
overlap_pixels = int(h * self.config.row_overlap)
|
|
||||||
self._row_start_y = 0 # New row is at the TOP after prepending
|
self._row_start_y = 0 # New row is at the TOP after prepending
|
||||||
|
|
||||||
|
# Calculate the X position where transition strips were placed
|
||||||
|
# This is where the camera is now (ready to start row 2)
|
||||||
|
x_offset = max(0, self.state.mosaic_width - self.state.mosaic_init_width)
|
||||||
|
|
||||||
self.log(f"New row Y position: {self._row_start_y} (mosaic height: {self.state.mosaic_height})")
|
self.log(f"New row Y position: {self._row_start_y} (mosaic height: {self.state.mosaic_height})")
|
||||||
|
self.log(f"New row X position: {x_offset} (transition strip location)")
|
||||||
|
|
||||||
with self._state_lock:
|
with self._state_lock:
|
||||||
self.state.current_y = 0
|
self.state.current_y = 0
|
||||||
|
# Set current_x to the x_offset where transition strips are
|
||||||
|
# This is where row 2 will START (then scan LEFT from here)
|
||||||
|
self.state.current_x = x_offset
|
||||||
|
|
||||||
self.motion.send_command('s')
|
self.motion.send_command('s')
|
||||||
time.sleep(self.config.settle_time)
|
time.sleep(self.config.settle_time)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue