From 33a553c092d0c756b38c79d362190964ce096c3a Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Tue, 16 Sep 2025 20:58:54 +0200 Subject: [PATCH] Refine VideoEditor point transformation methods with enhanced consistency and logging This commit improves the point transformation and untransformation methods in the VideoEditor class by ensuring they match the applied transformations precisely. It adds checks for null points and current display frames, enhancing robustness. Additionally, detailed logging has been introduced to track coordinate adjustments during cropping and transformations, aiding in debugging and ensuring consistent behavior across the coordinate mapping process. --- croppa/main.py | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/croppa/main.py b/croppa/main.py index 7429e6b..0c40d63 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -1206,30 +1206,25 @@ class VideoEditor: 2. Rotation 3. Zoom - The key insight is that we need to handle coordinates in the same way - the frame is processed in apply_crop_zoom_and_rotation. + IMPORTANT: This function must exactly match the transformations applied in + apply_crop_zoom_and_rotation to ensure consistent coordinate mapping. """ - if point is None: + if point is None or self.current_display_frame is None: return None # Get original coordinates and convert to float for precise calculations orig_x, orig_y = float(point[0]), float(point[1]) print(f"transform_point: original point ({orig_x}, {orig_y})") - # Get frame dimensions - if self.current_display_frame is None: - return None - + # Get original frame dimensions frame_height, frame_width = self.current_display_frame.shape[:2] - # STEP 1: Apply crop - # If we're cropped, check if the point is within the crop area + # STEP 1: Apply crop - adjust coordinates relative to crop origin x, y = orig_x, orig_y if self.crop_rect: crop_x, crop_y, crop_w, crop_h = self.crop_rect - print(f"transform_point: crop_rect = {self.crop_rect}") - # Check if point is inside the crop area + # Check if point is inside the crop area (for debugging only) is_inside = (crop_x <= x < crop_x + crop_w and crop_y <= y < crop_y + crop_h) print(f"transform_point: point ({x}, {y}) is {'inside' if is_inside else 'outside'} crop area") @@ -1237,13 +1232,11 @@ class VideoEditor: x -= crop_x y -= crop_y - # If point is outside crop area, it will have negative coordinates or coordinates > crop dimensions - # We'll still transform it for consistent behavior - print(f"transform_point: after crop adjustment ({x}, {y})") - # Update dimensions for rotation calculations frame_width, frame_height = crop_w, crop_h + print(f"transform_point: after crop adjustment ({x}, {y})") + # STEP 2: Apply rotation if self.rotation_angle != 0: print(f"transform_point: rotation_angle = {self.rotation_angle}, dimensions = ({frame_width}, {frame_height})") @@ -1283,8 +1276,8 @@ class VideoEditor: 2. Reverse rotation 3. Reverse crop - The key insight is that we need to handle coordinates in the exact reverse - order as they are processed in apply_crop_zoom_and_rotation. + IMPORTANT: This function must exactly reverse the transformations applied in + transform_point to ensure consistent coordinate mapping. """ if point is None or self.current_display_frame is None: return None @@ -1293,10 +1286,10 @@ class VideoEditor: display_x, display_y = float(point[0]), float(point[1]) print(f"untransform_point: original display point ({display_x}, {display_y})") - # Get frame dimensions + # Get original frame dimensions orig_frame_height, orig_frame_width = self.current_display_frame.shape[:2] - # Get dimensions of the frame after crop (if any) + # Get dimensions for rotation calculations if self.crop_rect: frame_width, frame_height = float(self.crop_rect[2]), float(self.crop_rect[3]) else: @@ -1338,7 +1331,7 @@ class VideoEditor: y += crop_y print(f"untransform_point: after reverse crop ({x}, {y}), crop_rect = {self.crop_rect}") - # Ensure the point is within the original frame bounds + # Clamp coordinates to frame bounds to ensure they're valid x = max(0, min(x, orig_frame_width - 1)) y = max(0, min(y, orig_frame_height - 1)) @@ -2192,17 +2185,23 @@ class VideoEditor: start_y <= y < start_y + final_display_height): # Convert screen coordinates to display frame coordinates + # This is critical - we need to account for the canvas offset and scale display_x = (x - start_x) / scale display_y = (y - start_y) / scale print(f"mouse_callback: converted to display coords ({display_x}, {display_y})") # Now convert display coordinates to original frame coordinates + # This is where the magic happens - we need to reverse all transformations original_point = self.untransform_point((display_x, display_y)) print(f"mouse_callback: untransformed to original coords {original_point}") if original_point: + # Store the original frame dimensions for reference + frame_height, frame_width = self.current_display_frame.shape[:2] + print(f"mouse_callback: frame dimensions: {frame_width}x{frame_height}") + # Check if clicking on an existing tracking point to remove it removed = self.motion_tracker.remove_tracking_point( self.current_frame, @@ -2223,20 +2222,24 @@ class VideoEditor: print(f"mouse_callback: added tracking point at {original_point}") # Perform a round-trip verification to ensure our coordinate system is consistent - # This will help debug any issues with the transformation verification_point = self.transform_point(original_point) if verification_point: print(f"mouse_callback: verification - point transforms back to {verification_point}") # Calculate expected canvas position for verification - expected_x = int(offset_x + verification_point[0] * scale) - expected_y = int(offset_y + verification_point[1] * scale) + expected_x = int(start_x + verification_point[0] * scale) + expected_y = int(start_y + verification_point[1] * scale) print(f"mouse_callback: verification - expected canvas position: ({expected_x}, {expected_y}), actual: ({x}, {y})") # Calculate the error between click and expected position error_x = abs(expected_x - x) error_y = abs(expected_y - y) print(f"mouse_callback: verification - position error: ({error_x}, {error_y}) pixels") + + # If error is significant, print a warning + if error_x > 2 or error_y > 2: + print(f"WARNING: Significant coordinate transformation error detected!") + print(f"This may indicate a problem with the transform/untransform functions.") # Save state when tracking points change self.save_state()