From d0d2f66b11f18019b6c0be9c5c73e8c73eaeef7e Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Wed, 17 Sep 2025 01:48:49 +0200 Subject: [PATCH] Enhance effective crop rectangle calculation in VideoEditor for motion tracking This commit updates the _get_effective_crop_rect_for_frame method to improve the calculation of the crop rectangle in rotated frame coordinates, incorporating tracking follow functionality. It ensures that the crop rectangle is accurately centered on the interpolated tracking position when motion tracking is enabled. Additionally, comments have been clarified to reflect the use of the effective crop, enhancing code readability and maintainability. --- croppa/main.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/croppa/main.py b/croppa/main.py index 066700d..3f6fb00 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -1142,15 +1142,28 @@ class VideoEditor: # --- Motion tracking helpers --- def _get_effective_crop_rect_for_frame(self, frame_number): - """Return crop_rect in ROTATED frame coordinates for this frame.""" - # When cropping after rotation, the crop_rect is directly in rotated frame coords - # so no translation is needed for mapping overlays. + """Return EFFECTIVE crop_rect in ROTATED frame coords for this frame (applies tracking follow).""" + # Rotated base dims + if self.rotation_angle in (90, 270): + rot_w, rot_h = self.frame_height, self.frame_width + else: + rot_w, rot_h = self.frame_width, self.frame_height + # Default full-frame if not self.crop_rect: - # Compute rotated dimensions of the full frame - if self.rotation_angle in (90, 270): - return (0, 0, self.frame_height, self.frame_width) - return (0, 0, self.frame_width, self.frame_height) + return (0, 0, rot_w, rot_h) x, y, w, h = map(int, self.crop_rect) + # Tracking follow: center crop on interpolated rotated position + if self.tracking_enabled: + pos = self._get_interpolated_tracking_position(frame_number) + if pos: + cx, cy = pos + x = int(round(cx - w / 2)) + y = int(round(cy - h / 2)) + # Clamp in rotated space + x = max(0, min(x, rot_w - 1)) + y = max(0, min(y, rot_h - 1)) + w = min(w, rot_w - x) + h = min(h, rot_h - y) return (x, y, w, h) def _get_interpolated_tracking_position(self, frame_number): @@ -1299,7 +1312,7 @@ class VideoEditor: def _map_rotated_to_screen(self, rx, ry): """Map a point in ROTATED frame coords to canvas screen coords (post-crop).""" - # Subtract crop offset in rotated space + # Subtract crop offset in rotated space (use current EFFECTIVE crop) cx, cy, cw, ch = self._get_effective_crop_rect_for_frame(getattr(self, 'current_frame', 0)) rx2 = rx - cx ry2 = ry - cy @@ -1365,7 +1378,7 @@ class VideoEditor: # Reverse zoom rx = zx / max(1e-6, self.zoom_factor) ry = zy / max(1e-6, self.zoom_factor) - # Unapply current crop to get PRE-crop rotated coords + # Unapply current EFFECTIVE crop to get PRE-crop rotated coords cx, cy, cw, ch = self._get_effective_crop_rect_for_frame(frame_number) rx = rx + cx ry = ry + cy