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.
This commit is contained in:
@@ -1142,15 +1142,28 @@ class VideoEditor:
|
|||||||
|
|
||||||
# --- Motion tracking helpers ---
|
# --- Motion tracking helpers ---
|
||||||
def _get_effective_crop_rect_for_frame(self, frame_number):
|
def _get_effective_crop_rect_for_frame(self, frame_number):
|
||||||
"""Return crop_rect in ROTATED frame coordinates for this frame."""
|
"""Return EFFECTIVE crop_rect in ROTATED frame coords for this frame (applies tracking follow)."""
|
||||||
# When cropping after rotation, the crop_rect is directly in rotated frame coords
|
# Rotated base dims
|
||||||
# so no translation is needed for mapping overlays.
|
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:
|
if not self.crop_rect:
|
||||||
# Compute rotated dimensions of the full frame
|
return (0, 0, rot_w, rot_h)
|
||||||
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)
|
|
||||||
x, y, w, h = map(int, self.crop_rect)
|
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)
|
return (x, y, w, h)
|
||||||
|
|
||||||
def _get_interpolated_tracking_position(self, frame_number):
|
def _get_interpolated_tracking_position(self, frame_number):
|
||||||
@@ -1299,7 +1312,7 @@ class VideoEditor:
|
|||||||
|
|
||||||
def _map_rotated_to_screen(self, rx, ry):
|
def _map_rotated_to_screen(self, rx, ry):
|
||||||
"""Map a point in ROTATED frame coords to canvas screen coords (post-crop)."""
|
"""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))
|
cx, cy, cw, ch = self._get_effective_crop_rect_for_frame(getattr(self, 'current_frame', 0))
|
||||||
rx2 = rx - cx
|
rx2 = rx - cx
|
||||||
ry2 = ry - cy
|
ry2 = ry - cy
|
||||||
@@ -1365,7 +1378,7 @@ class VideoEditor:
|
|||||||
# Reverse zoom
|
# Reverse zoom
|
||||||
rx = zx / max(1e-6, self.zoom_factor)
|
rx = zx / max(1e-6, self.zoom_factor)
|
||||||
ry = zy / 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)
|
cx, cy, cw, ch = self._get_effective_crop_rect_for_frame(frame_number)
|
||||||
rx = rx + cx
|
rx = rx + cx
|
||||||
ry = ry + cy
|
ry = ry + cy
|
||||||
|
Reference in New Issue
Block a user