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.
This commit is contained in:
@@ -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,14 +2222,13 @@ 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
|
||||
@@ -2238,6 +2236,11 @@ class VideoEditor:
|
||||
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()
|
||||
self.display_needs_update = True
|
||||
|
Reference in New Issue
Block a user