Update .gitignore and enhance VideoEditor with improved crop handling and logging
This commit adds a new entry to the .gitignore file to exclude log files. In the VideoEditor class, it refines the crop position adjustment logic to calculate the center of the crop rectangle before applying offsets, ensuring more accurate positioning. Additionally, it enhances logging throughout the point transformation and tracking processes, providing better insights into the state of tracking points and their visibility relative to the crop area.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
__pycache__
|
||||
croppa/build/lib
|
||||
croppa/croppa.egg-info
|
||||
*.log
|
||||
|
132
croppa/main.py
132
croppa/main.py
@@ -1120,8 +1120,18 @@ class VideoEditor:
|
||||
|
||||
# Only apply offset if it's not zero
|
||||
if tracking_offset[0] != 0 or tracking_offset[1] != 0:
|
||||
x += int(tracking_offset[0])
|
||||
y += int(tracking_offset[1])
|
||||
# Calculate the center of the crop rect
|
||||
center_x = x + w // 2
|
||||
center_y = y + h // 2
|
||||
|
||||
# Apply offset to center
|
||||
new_center_x = center_x + int(tracking_offset[0])
|
||||
new_center_y = center_y + int(tracking_offset[1])
|
||||
|
||||
# Calculate new top-left corner
|
||||
x = new_center_x - w // 2
|
||||
y = new_center_y - h // 2
|
||||
|
||||
print(f"apply_crop_zoom_and_rotation: adjusted crop position to ({x}, {y})")
|
||||
|
||||
x, y, w, h = int(x), int(y), int(w), int(h)
|
||||
@@ -1192,7 +1202,6 @@ class VideoEditor:
|
||||
|
||||
x, y = float(point[0]), float(point[1])
|
||||
|
||||
# Log original point
|
||||
print(f"transform_point: original point ({x}, {y})")
|
||||
|
||||
# Step 1: Apply crop (adjust point relative to crop origin)
|
||||
@@ -1200,8 +1209,7 @@ class VideoEditor:
|
||||
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 - but don't filter out points
|
||||
# We'll still transform them and let the drawing code decide visibility
|
||||
# Check if point is inside the crop area
|
||||
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")
|
||||
|
||||
@@ -1214,10 +1222,11 @@ class VideoEditor:
|
||||
if self.rotation_angle != 0:
|
||||
# Get dimensions after crop
|
||||
if self.crop_rect:
|
||||
crop_w, crop_h = self.crop_rect[2], self.crop_rect[3]
|
||||
crop_w, crop_h = float(self.crop_rect[2]), float(self.crop_rect[3])
|
||||
else:
|
||||
if self.current_display_frame is not None:
|
||||
crop_h, crop_w = self.current_display_frame.shape[:2]
|
||||
crop_h, crop_w = float(crop_h), float(crop_w)
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -1306,15 +1315,9 @@ class VideoEditor:
|
||||
y += crop_y
|
||||
print(f"untransform_point: after reverse crop ({x}, {y}), crop_rect = {self.crop_rect}")
|
||||
|
||||
# Ensure coordinates are within the frame bounds
|
||||
if self.current_display_frame is not None:
|
||||
height, width = self.current_display_frame.shape[:2]
|
||||
orig_x, orig_y = x, y
|
||||
x = max(0, min(width - 1, x))
|
||||
y = max(0, min(height - 1, y))
|
||||
if orig_x != x or orig_y != y:
|
||||
print(f"untransform_point: clamped from ({orig_x}, {orig_y}) to ({x}, {y})")
|
||||
|
||||
# Don't clamp coordinates - allow points outside frame bounds
|
||||
# This is important for tracking points that may be outside the current crop
|
||||
|
||||
print(f"untransform_point: final result = ({x}, {y})")
|
||||
return (x, y)
|
||||
|
||||
@@ -1495,11 +1498,14 @@ class VideoEditor:
|
||||
tracking_points = self.motion_tracker.get_tracking_points_for_frame(self.current_frame)
|
||||
print(f"draw_tracking_points: found {len(tracking_points)} tracking points for frame {self.current_frame}")
|
||||
|
||||
# Get current frame dimensions for bounds checking
|
||||
frame_height, frame_width = self.current_display_frame.shape[:2]
|
||||
|
||||
for i, point in enumerate(tracking_points):
|
||||
print(f"draw_tracking_points: processing point {i}: {point}")
|
||||
|
||||
# Transform point from original frame coordinates to display coordinates
|
||||
display_point = self.transform_point(point)
|
||||
# Check if the point is within the frame bounds
|
||||
is_in_frame = (0 <= point[0] < frame_width and 0 <= point[1] < frame_height)
|
||||
|
||||
# Check if the point is within the crop area (if cropping is active)
|
||||
is_in_crop = True
|
||||
@@ -1507,8 +1513,11 @@ class VideoEditor:
|
||||
crop_x, crop_y, crop_w, crop_h = self.crop_rect
|
||||
is_in_crop = (crop_x <= point[0] < crop_x + crop_w and
|
||||
crop_y <= point[1] < crop_y + crop_h)
|
||||
|
||||
if display_point:
|
||||
|
||||
# Transform point from original frame coordinates to display coordinates
|
||||
display_point = self.transform_point(point)
|
||||
|
||||
if display_point is not None:
|
||||
print(f"draw_tracking_points: point {i} transformed to {display_point}")
|
||||
|
||||
# Scale and offset the point to match the canvas
|
||||
@@ -1517,19 +1526,25 @@ class VideoEditor:
|
||||
|
||||
print(f"draw_tracking_points: point {i} canvas position: ({x},{y})")
|
||||
|
||||
# Draw the point - use different colors based on whether it's in the crop area
|
||||
if is_in_crop:
|
||||
# Point is in crop area - draw normally
|
||||
# Draw white border
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius + 2, (255, 255, 255), 2)
|
||||
# Draw green circle
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius, (0, 255, 0), -1)
|
||||
# Check if the point is within the canvas bounds
|
||||
is_on_canvas = (0 <= x < self.window_width and 0 <= y < self.window_height)
|
||||
|
||||
if is_on_canvas:
|
||||
# Draw the point - use different colors based on whether it's in the crop area
|
||||
if is_in_crop:
|
||||
# Point is in crop area - draw normally
|
||||
# Draw white border
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius + 2, (255, 255, 255), 2)
|
||||
# Draw green circle
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius, (0, 255, 0), -1)
|
||||
else:
|
||||
# Point is outside crop area - draw with different color
|
||||
# Draw gray border
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius + 2, (128, 128, 128), 2)
|
||||
# Draw yellow circle
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius, (0, 255, 255), -1)
|
||||
else:
|
||||
# Point is outside crop area - draw with different color (semi-transparent)
|
||||
# Draw gray border
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius + 2, (128, 128, 128), 2)
|
||||
# Draw yellow circle
|
||||
cv2.circle(canvas, (x, y), self.tracking_point_radius, (0, 255, 255), -1)
|
||||
print(f"draw_tracking_points: point {i} is outside canvas bounds")
|
||||
else:
|
||||
print(f"draw_tracking_points: point {i} not visible in current view")
|
||||
|
||||
@@ -2112,6 +2127,8 @@ class VideoEditor:
|
||||
start_x = (self.window_width - final_display_width) // 2
|
||||
start_y = (available_height - final_display_height) // 2
|
||||
|
||||
print(f"mouse_callback: right-click at ({x}, {y}), display frame at ({start_x}, {start_y}), scale={scale}")
|
||||
|
||||
# Check if click is within the frame area
|
||||
if (start_x <= x < start_x + final_display_width and
|
||||
start_y <= y < start_y + final_display_height):
|
||||
@@ -2120,9 +2137,13 @@ class VideoEditor:
|
||||
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
|
||||
original_point = self.untransform_point((display_x, display_y))
|
||||
|
||||
print(f"mouse_callback: untransformed to original coords {original_point}")
|
||||
|
||||
if original_point:
|
||||
# Check if clicking on an existing tracking point to remove it
|
||||
removed = self.motion_tracker.remove_tracking_point(
|
||||
@@ -2132,13 +2153,16 @@ class VideoEditor:
|
||||
self.tracking_point_distance
|
||||
)
|
||||
|
||||
if not removed:
|
||||
if removed:
|
||||
print(f"mouse_callback: removed tracking point at {original_point}")
|
||||
else:
|
||||
# If no point was removed, add a new tracking point
|
||||
self.motion_tracker.add_tracking_point(
|
||||
self.current_frame,
|
||||
original_point[0],
|
||||
original_point[1]
|
||||
)
|
||||
print(f"mouse_callback: added tracking point at {original_point}")
|
||||
|
||||
# Save state when tracking points change
|
||||
self.save_state()
|
||||
@@ -3115,7 +3139,6 @@ class VideoEditor:
|
||||
if self.motion_tracker.tracking_enabled:
|
||||
self.motion_tracker.stop_tracking()
|
||||
print("Motion tracking disabled")
|
||||
print("Motion tracking disabled")
|
||||
else:
|
||||
# If we have tracking points, start tracking
|
||||
if self.motion_tracker.has_tracking_points():
|
||||
@@ -3123,33 +3146,28 @@ class VideoEditor:
|
||||
current_pos = self.motion_tracker.get_interpolated_position(self.current_frame)
|
||||
print(f"Toggle tracking: interpolated position = {current_pos}")
|
||||
|
||||
# Always use the current position as the base zoom center if available
|
||||
if current_pos:
|
||||
base_zoom_center = current_pos
|
||||
print(f"Toggle tracking: using interpolated position as base: {base_zoom_center}")
|
||||
# Use crop center if we have a crop rect
|
||||
if self.crop_rect:
|
||||
elif self.crop_rect:
|
||||
x, y, w, h = self.crop_rect
|
||||
crop_center = (x + w//2, y + h//2)
|
||||
print(f"Toggle tracking: crop_rect = {self.crop_rect}, crop_center = {crop_center}")
|
||||
|
||||
# If we have a current position from tracking points, use that as base
|
||||
if current_pos:
|
||||
# The base zoom center is the current position
|
||||
base_zoom_center = current_pos
|
||||
print(f"Toggle tracking: using interpolated position as base: {base_zoom_center}")
|
||||
else:
|
||||
# Use crop center as fallback
|
||||
base_zoom_center = crop_center
|
||||
print(f"Toggle tracking: using crop center as base: {base_zoom_center}")
|
||||
base_zoom_center = (x + w//2, y + h//2)
|
||||
print(f"Toggle tracking: using crop center as base: {base_zoom_center}")
|
||||
# No crop rect, use frame center
|
||||
elif self.current_display_frame is not None:
|
||||
h, w = self.current_display_frame.shape[:2]
|
||||
base_zoom_center = (w // 2, h // 2)
|
||||
print(f"Toggle tracking: using frame center as base: {base_zoom_center}")
|
||||
else:
|
||||
# No crop rect, use frame center
|
||||
if self.current_display_frame is not None:
|
||||
h, w = self.current_display_frame.shape[:2]
|
||||
base_zoom_center = (w // 2, h // 2)
|
||||
print(f"Toggle tracking: using frame center as base: {base_zoom_center}")
|
||||
else:
|
||||
base_zoom_center = None
|
||||
print("Toggle tracking: no base center available")
|
||||
base_zoom_center = None
|
||||
print("Toggle tracking: no base center available")
|
||||
|
||||
# Use current crop rect as base
|
||||
base_crop_rect = self.crop_rect
|
||||
|
||||
# Create a crop rect if one doesn't exist
|
||||
base_crop_rect = self.crop_rect
|
||||
if not base_crop_rect and current_pos and self.current_display_frame is not None:
|
||||
# Create a default crop rect centered on the current position
|
||||
h, w = self.current_display_frame.shape[:2]
|
||||
@@ -3157,6 +3175,8 @@ class VideoEditor:
|
||||
x = max(0, int(current_pos[0] - crop_size // 2))
|
||||
y = max(0, int(current_pos[1] - crop_size // 2))
|
||||
base_crop_rect = (x, y, crop_size, crop_size)
|
||||
# Update the actual crop rect
|
||||
self.crop_rect = base_crop_rect
|
||||
print(f"Toggle tracking: created default crop rect: {base_crop_rect}")
|
||||
|
||||
self.motion_tracker.start_tracking(
|
||||
@@ -3164,10 +3184,8 @@ class VideoEditor:
|
||||
base_zoom_center
|
||||
)
|
||||
print("Motion tracking enabled")
|
||||
print(f"Motion tracking enabled with base_crop_rect={base_crop_rect}, base_zoom_center={base_zoom_center}")
|
||||
else:
|
||||
print("No tracking points available. Add tracking points with right-click first.")
|
||||
print("Motion tracking not enabled - no tracking points available")
|
||||
self.save_state()
|
||||
else: # V - Clear all tracking points
|
||||
self.motion_tracker.clear_tracking_points()
|
||||
|
@@ -137,12 +137,16 @@ class MotionTracker:
|
||||
self.tracking_enabled = True
|
||||
self.base_crop_rect = base_crop_rect
|
||||
|
||||
print(f"start_tracking: base_crop_rect={base_crop_rect}, base_zoom_center={base_zoom_center}")
|
||||
|
||||
# If no base_zoom_center is provided, use the center of the crop rect
|
||||
if base_zoom_center is None and base_crop_rect is not None:
|
||||
x, y, w, h = base_crop_rect
|
||||
self.base_zoom_center = (x + w//2, y + h//2)
|
||||
print(f"start_tracking: using crop center as base_zoom_center: {self.base_zoom_center}")
|
||||
else:
|
||||
self.base_zoom_center = base_zoom_center
|
||||
print(f"start_tracking: using provided base_zoom_center: {self.base_zoom_center}")
|
||||
|
||||
def stop_tracking(self):
|
||||
"""Stop motion tracking"""
|
||||
|
Reference in New Issue
Block a user