debug images

This commit is contained in:
2ManyProjects 2026-01-11 17:55:55 -06:00
parent 88ffea8807
commit b8a51dc3cf

View file

@ -9,6 +9,20 @@ FIXES:
- Row-start alignment now checks BOTH bottom and side edges
- Larger overlap regions for better phase correlation
- Better strip capture with more overlap
DEBUG BORDER COLORS (for debugging row 2 placement):
=================================================
In _detect_row_start_alignment():
- WHITE (thick): Outline of where OLD ROW 1 content is located in mosaic
- BLUE line: Y=0 line (where NEW ROW should start)
- ORANGE line: Y=frame_height (bottom of new frame placement area)
- CYAN: Mosaic region used for Y alignment comparison
- MAGENTA: Where the new frame is EXPECTED to be placed
- YELLOW: Mosaic region used for X alignment comparison
In _blend_horizontal_at_y (append_left):
- RED (thick): Where strip WOULD have been placed (ORIGINAL position before alignment)
- GREEN: Where strip was ACTUALLY placed (ADJUSTED position after alignment)
"""
import cv2
@ -209,6 +223,19 @@ class StitchingScanner:
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}")
# ========== DEBUG: Draw WHITE border showing where OLD ROW 1 content is ==========
if old_row1_start >= 0:
cv2.rectangle(self.mosaic,
(0, old_row1_start),
(mw, min(old_row1_start + fh, mh)),
(255, 255, 255), 3) # WHITE - old row 1 location
self.log(f" DEBUG: WHITE border - OLD ROW 1 location Y={old_row1_start}:{min(old_row1_start + fh, mh)}")
# ========== DEBUG: Draw BLUE line at Y=0 showing where NEW ROW starts ==========
cv2.line(self.mosaic, (0, 0), (mw, 0), (255, 0, 0), 3) # BLUE line at Y=0
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=0 (new row start), ORANGE line at Y={fh} (new frame bottom)")
vertical_overlap = min(200, fh // 3)
min_overlap = 50
@ -230,6 +257,37 @@ class StitchingScanner:
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_frame = frame.copy()
# CYAN border on frame showing the region being compared
cv2.rectangle(debug_frame,
(0, fh - 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:
cv2.imwrite('/tmp/debug_frame_row2_start.png', debug_frame)
self.log(f" DEBUG: Saved frame to /tmp/debug_frame_row2_start.png")
except:
pass
# ========== DEBUG: Draw borders on mosaic for comparison regions ==========
# CYAN border: Mosaic region used for Y alignment comparison
cv2.rectangle(self.mosaic,
(expected_x, old_row1_start),
(x_end, old_row1_start + vertical_overlap),
(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}")
# MAGENTA border: Where frame WOULD be placed (Y=0 to fh)
cv2.rectangle(self.mosaic,
(expected_x, 0),
(min(expected_x + fw, mw), fh),
(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}")
min_w = min(frame_bottom.shape[1], mosaic_top_of_old.shape[1])
min_h = min(frame_bottom.shape[0], mosaic_top_of_old.shape[0])
@ -237,6 +295,14 @@ class StitchingScanner:
frame_bottom = frame_bottom[:min_h, :min_w]
mosaic_top_of_old = mosaic_top_of_old[:min_h, :min_w]
# ========== DEBUG: Save the comparison regions as images ==========
try:
cv2.imwrite('/tmp/debug_frame_bottom_region.png', frame_bottom)
cv2.imwrite('/tmp/debug_mosaic_top_region.png', mosaic_top_of_old)
self.log(f" DEBUG: Saved comparison regions to /tmp/debug_*.png")
except:
pass
# Detect displacement: how is frame_bottom shifted relative to mosaic_top_of_old?
dx_v, dy_v, conf_v = self._detect_displacement_with_confidence(
mosaic_top_of_old, frame_bottom)
@ -267,6 +333,14 @@ class StitchingScanner:
mosaic_edge = self.mosaic[y_start:y_end, mw - horizontal_overlap:mw]
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,
(mw - horizontal_overlap, y_start),
(mw, y_end),
(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}")
min_h = min(mosaic_edge.shape[0], frame_edge.shape[0])
min_w = min(mosaic_edge.shape[1], frame_edge.shape[1])
@ -296,6 +370,13 @@ class StitchingScanner:
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,
(0, y_start),
(horizontal_overlap, y_end),
(0, 255, 255), 2) # YELLOW - mosaic comparison region for X
self.log(f" DEBUG: YELLOW border - mosaic X comparison region X=0:{horizontal_overlap}, Y={y_start}:{y_end}")
min_h = min(mosaic_edge.shape[0], frame_edge.shape[0])
min_w = min(mosaic_edge.shape[1], frame_edge.shape[1])
@ -428,11 +509,9 @@ class StitchingScanner:
# Detect displacement with confidence
dx, dy, confidence = self._detect_displacement_with_confidence(mosaic_region, frame_region)
self.log(f"Displacement dx ({dx} dy {dy}) con {confidence})")
# Sanity check - reject large displacements
max_adjust = 400 # Max pixels to adjust
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
@ -440,7 +519,7 @@ class StitchingScanner:
offset.x_offset = dx
offset.y_offset = dy
offset.confidence = confidence
offset.valid = True #confidence > 0.1 # Require minimum 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}")
@ -542,6 +621,10 @@ class StitchingScanner:
if x_offset is None:
x_offset = 0
# Store ORIGINAL position before alignment (for debug)
original_x_offset = x_offset
original_y_offset = y_offset
# Apply alignment offsets (continuous correction)
x_offset = x_offset + int(round(alignment_x))
y_offset_before = y_offset
@ -550,7 +633,7 @@ class StitchingScanner:
self.log(f" Y offset computation: {y_offset_before} - {int(round(alignment_y))} = {y_offset}")
# Clamp x_offset to valid range
x_offset = 0 - min(x_offset, w_base)
x_offset = max(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
@ -580,6 +663,8 @@ class StitchingScanner:
self.log(f" cumulative: X={self._cumulative_align_x:.1f}, Y={self._cumulative_align_y:.1f}")
self.log(f" row_start_y: {self._row_start_y}")
self.log(f" Strip crop: rows [{strip_y_start}:{strip_y_end}] -> height {h_cropped}")
self.log(f" ORIGINAL position: X={original_x_offset}, Y={original_y_offset}")
self.log(f" ADJUSTED position: X={x_offset}, Y={y_offset}")
# Result is same size as base (no expansion when going left)
result = base.copy()
@ -592,6 +677,17 @@ class StitchingScanner:
self.log(f" Placing strip at X={strip_x_start}:{strip_x_end}, Y={y_offset}:{y_offset + h_cropped}")
self.log(f" Strip cols to copy: {strip_cols_to_copy}")
# ========== DEBUG: Draw borders BEFORE placing strip ==========
# RED border: Where strip WOULD have been placed (original position)
orig_x_end = min(original_x_offset + w_strip, w_base)
orig_y_end = min(original_y_offset + h_strip, h_base)
if original_x_offset >= 0 and original_y_offset >= 0:
cv2.rectangle(result,
(original_x_offset, max(0, original_y_offset)),
(orig_x_end, orig_y_end),
(0, 0, 255), 3) # RED - original position
self.log(f" DEBUG: RED border at original position X={original_x_offset}:{orig_x_end}, Y={original_y_offset}:{orig_y_end}")
# Step 1: Copy strip content (non-blend portion) at correct position
# For LEFT scanning, blend is on the RIGHT side of the strip
non_blend_end = strip_cols_to_copy - blend_w
@ -612,6 +708,14 @@ class StitchingScanner:
result[y_offset:y_offset + h_cropped, blend_x_start:blend_x_end] = blended
self.log(f" Step 2: Blend zone at X={blend_x_start}:{blend_x_end}")
# ========== DEBUG: Draw border AFTER placing strip ==========
# GREEN border: Where strip was ACTUALLY placed (adjusted position)
cv2.rectangle(result,
(strip_x_start, y_offset),
(strip_x_end, y_offset + h_cropped),
(0, 255, 0), 2) # GREEN - actual position
self.log(f" DEBUG: GREEN border at actual position X={strip_x_start}:{strip_x_end}, Y={y_offset}:{y_offset + h_cropped}")
self.log(f" Final: Strip placed at X={strip_x_start}, Y={y_offset}, mosaic size unchanged: {w_base}x{h_base}")
return result