From 1accbe27b6e8c9e94e7c0d9ca93d34f70de86983 Mon Sep 17 00:00:00 2001 From: 2ManyProjects Date: Thu, 8 Jan 2026 21:51:44 -0600 Subject: [PATCH] vfertical at x style rewrite --- src/stitching_scanner.py | 62 +++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/stitching_scanner.py b/src/stitching_scanner.py index ba1d623..ab38e38 100644 --- a/src/stitching_scanner.py +++ b/src/stitching_scanner.py @@ -199,53 +199,57 @@ class StitchingScanner: return result def _blend_vertical_at_x(self, base: np.ndarray, strip: np.ndarray, - blend_height: int, append_below: bool, - x_offset: int = 0) -> np.ndarray: - mh, mw = base.shape[:2] - sh, sw = strip.shape[:2] + blend_height: int, append_below: bool, + x_offset: int = 0) -> np.ndarray: + h_base, w_base = base.shape[:2] + h_strip, w_strip = strip.shape[:2] # Clamp x_offset to valid range - x_offset = max(0, min(x_offset, mw - 1)) - - # Calculate how much of strip fits in mosaic - available_width = mw - x_offset - strip_width = min(sw, available_width) + x_offset = max(0, min(x_offset, w_base - 1)) # Create full-width strip with strip placed at x_offset - full_strip = np.zeros((sh, mw, 3), dtype=np.uint8) - full_strip[:, x_offset:x_offset + strip_width] = strip[:, :strip_width] + full_strip = np.zeros((h_strip, w_base, 3), dtype=np.uint8) + available_width = w_base - x_offset + copy_width = min(w_strip, available_width) + full_strip[:, x_offset:x_offset + copy_width] = strip[:, :copy_width] - # Now blend using existing logic - blend_h = min(blend_height, sh, mh) - - if blend_h <= 0: + # Early exit: no blending possible + if blend_height <= 0 or blend_height >= h_strip: if append_below: return np.vstack([base, full_strip]) return np.vstack([full_strip, base]) + # Height mismatch shouldn't happen with full_strip, but safety check + if w_strip > w_base: + self.log(f"Warning: strip wider than base ({w_strip} > {w_base})") + + blend_h = min(blend_height, h_strip, h_base) + if append_below: + result_height = h_base + h_strip - blend_h + result = np.zeros((result_height, w_base, 3), dtype=np.uint8) + result[:h_base, :] = base + alpha = np.linspace(1, 0, blend_h, dtype=np.float32)[:, np.newaxis, np.newaxis] - base_overlap = base[-blend_h:].astype(np.float32) - strip_overlap = full_strip[:blend_h].astype(np.float32) + base_overlap = base[-blend_h:, :].astype(np.float32) + strip_overlap = full_strip[:blend_h, :].astype(np.float32) blended = (base_overlap * alpha + strip_overlap * (1 - alpha)).astype(np.uint8) - result_h = mh + sh - blend_h - result = np.zeros((result_h, mw, 3), dtype=np.uint8) - result[:mh - blend_h] = base[:-blend_h] - result[mh - blend_h:mh] = blended - result[mh:] = full_strip[blend_h:] + result[h_base - blend_h:h_base, :] = blended + result[h_base:, :] = full_strip[blend_h:, :] return result else: + result_height = h_base + h_strip - blend_h + result = np.zeros((result_height, w_base, 3), dtype=np.uint8) + result[:h_strip, :] = full_strip + alpha = np.linspace(0, 1, blend_h, dtype=np.float32)[:, np.newaxis, np.newaxis] - strip_overlap = full_strip[-blend_h:].astype(np.float32) - base_overlap = base[:blend_h].astype(np.float32) + strip_overlap = full_strip[-blend_h:, :].astype(np.float32) + base_overlap = base[:blend_h, :].astype(np.float32) blended = (strip_overlap * (1 - alpha) + base_overlap * alpha).astype(np.uint8) - result_h = mh + sh - blend_h - result = np.zeros((result_h, mw, 3), dtype=np.uint8) - result[:sh - blend_h] = full_strip[:-blend_h] - result[sh - blend_h:sh] = blended - result[sh:] = base[blend_h:] + result[h_strip - blend_h:h_strip, :] = blended + result[h_strip:, :] = base[blend_h:, :] return result def _blend_vertical(self, base: np.ndarray, strip: np.ndarray, blend_height: int, append_below: bool) -> np.ndarray: