diff --git a/src/stitching_scanner.py b/src/stitching_scanner.py index e37f2fc..8161327 100644 --- a/src/stitching_scanner.py +++ b/src/stitching_scanner.py @@ -162,17 +162,17 @@ class StitchingScanner: def _blend_horizontal_at_y(self, base: np.ndarray, strip: np.ndarray, blend_width: int, append_right: bool, y_offset: int = 0) -> np.ndarray: - """Blend strip horizontally at a specific Y position in the mosaic.""" h_base, w_base = base.shape[:2] h_strip, w_strip = strip.shape[:2] - # Clamp y_offset to valid range + # Clamp y_offset y_offset = max(0, min(y_offset, h_base - h_strip)) - # Early exit: no blending possible - if blend_width <= 0 or blend_width >= w_strip: + blend_w = min(blend_width, w_strip, w_base) + + # Early exit: no blending + if blend_w <= 0 or blend_w >= w_strip: if append_right: - # Create result with expanded width result_width = w_base + w_strip result = np.zeros((h_base, result_width, 3), dtype=np.uint8) result[:, :w_base] = base @@ -181,45 +181,50 @@ class StitchingScanner: else: result_width = w_base + w_strip result = np.zeros((h_base, result_width, 3), dtype=np.uint8) - result[y_offset:y_offset + h_strip, :w_strip] = strip result[:, w_strip:] = base + result[y_offset:y_offset + h_strip, :w_strip] = strip return result - blend_w = min(blend_width, w_strip, w_base) - if append_right: result_width = w_base + w_strip - blend_w result = np.zeros((h_base, result_width, 3), dtype=np.uint8) + + # Step 1: Copy entire base result[:, :w_base] = base - # Extract overlaps at the correct Y position + # Step 2: Copy non-overlap portion of strip at correct Y + result[y_offset:y_offset + h_strip, w_base:] = strip[:, blend_w:] + + # Step 3: Create blend alpha = np.linspace(1, 0, blend_w, dtype=np.float32)[np.newaxis, :, np.newaxis] base_overlap = base[y_offset:y_offset + h_strip, -blend_w:].astype(np.float32) strip_overlap = strip[:, :blend_w].astype(np.float32) blended = (base_overlap * alpha + strip_overlap * (1 - alpha)).astype(np.uint8) - # Place blended region and remainder at correct Y + # Step 4: Place blend (overwrites part of base at correct Y) result[y_offset:y_offset + h_strip, w_base - blend_w:w_base] = blended - result[y_offset:y_offset + h_strip, w_base:] = strip[:, blend_w:] + return result - + else: # append_left result_width = w_base + w_strip - blend_w result = np.zeros((h_base, result_width, 3), dtype=np.uint8) - # Place strip at correct Y position - result[y_offset:y_offset + h_strip, :w_strip] = strip + # Step 1: Copy ENTIRE base shifted right + result[:, w_strip - blend_w:] = base - # Copy base (shifted right) - result[:, w_strip:] = base[:, blend_w:] + # Step 2: Copy non-overlap portion of strip at correct Y + result[y_offset:y_offset + h_strip, :w_strip - blend_w] = strip[:, :w_strip - blend_w] - # Extract overlaps at correct Y position + # Step 3: Create blend alpha = np.linspace(0, 1, blend_w, dtype=np.float32)[np.newaxis, :, np.newaxis] strip_overlap = strip[:, -blend_w:].astype(np.float32) base_overlap = base[y_offset:y_offset + h_strip, :blend_w].astype(np.float32) blended = (strip_overlap * (1 - alpha) + base_overlap * alpha).astype(np.uint8) + # Step 4: Place blend at correct Y result[y_offset:y_offset + h_strip, w_strip - blend_w:w_strip] = blended + return result def _blend_horizontal(self, base: np.ndarray, strip: np.ndarray,