From 5d76681ded8af0919ca93a1e70c2e16a327c4c0f Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Fri, 26 Sep 2025 14:44:19 +0200 Subject: [PATCH] Refactor tracking position calculation in VideoEditor to combine manual, template, and feature tracking methods. This update introduces a more robust approach to determine the final tracking position by calculating offsets from both template matching and feature tracking, weighted appropriately against a base position derived from manual tracking points. The logic ensures smoother transitions and improved accuracy in tracking results, with debug messages added for better insight into the combined tracking process. --- croppa/main.py | 57 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/croppa/main.py b/croppa/main.py index b212098..eb9dcc3 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -1637,7 +1637,11 @@ class VideoEditor: def _get_interpolated_tracking_position(self, frame_number): """Linear interpolation in ROTATED frame coords. Returns (rx, ry) or None.""" - # First try template matching if enabled (much better than optical flow) + # Get base position from manual tracking points + base_pos = self._get_manual_tracking_position(frame_number) + + # Calculate offset from template matching if enabled + template_offset = None if self.template_matching_enabled and self.tracking_template is not None: if self.current_display_frame is not None: # Use only the cropped region for much faster template matching @@ -1657,7 +1661,7 @@ class VideoEditor: raw_x = center_x + crop_x raw_y = center_y + crop_y - return (raw_x, raw_y) + template_offset = (raw_x, raw_y) else: # No crop - use full frame raw_frame = self.current_display_frame.copy() @@ -1668,9 +1672,10 @@ class VideoEditor: print(f"DEBUG: Template match found at ({center_x}, {center_y}) with confidence {confidence:.2f}") # Template matching returns coordinates in raw frame space - return (center_x, center_y) + template_offset = (center_x, center_y) - # Fall back to feature tracking if enabled - but use smooth interpolation instead of averaging + # Calculate offset from feature tracking if enabled + feature_offset = None if self.feature_tracker.tracking_enabled: # Get the nearest frames with features for smooth interpolation feature_frames = sorted(self.feature_tracker.features.keys()) @@ -1678,19 +1683,55 @@ class VideoEditor: # Find the two nearest frames for interpolation if frame_number <= feature_frames[0]: # Before first feature frame - use first frame - return self._get_feature_center(feature_frames[0]) + feature_offset = self._get_feature_center(feature_frames[0]) elif frame_number >= feature_frames[-1]: # After last feature frame - use last frame - return self._get_feature_center(feature_frames[-1]) + feature_offset = self._get_feature_center(feature_frames[-1]) else: # Between two feature frames - interpolate smoothly for i in range(len(feature_frames) - 1): if feature_frames[i] <= frame_number <= feature_frames[i + 1]: - return self._interpolate_feature_positions( + feature_offset = self._interpolate_feature_positions( feature_frames[i], feature_frames[i + 1], frame_number ) + break - # Fall back to manual tracking points + # Combine tracking methods: base + offsets + if base_pos: + base_x, base_y = base_pos + offset_x, offset_y = 0, 0 + + # Add template matching offset + if template_offset: + template_x, template_y = template_offset + # Calculate offset from base position + offset_x += (template_x - base_x) * 0.5 # Weight template matching + offset_y += (template_y - base_y) * 0.5 + + # Add feature tracking offset + if feature_offset: + feature_x, feature_y = feature_offset + # Calculate offset from base position + offset_x += (feature_x - base_x) * 0.3 # Weight feature tracking + offset_y += (feature_y - base_y) * 0.3 + + # Apply combined offset + final_x = base_x + offset_x + final_y = base_y + offset_y + + print(f"DEBUG: Combined tracking - Base: ({base_x:.1f}, {base_y:.1f}) + Offset: ({offset_x:.1f}, {offset_y:.1f}) = Final: ({final_x:.1f}, {final_y:.1f})") + return (final_x, final_y) + + # Fall back to individual tracking methods if no base position + if template_offset: + return template_offset + elif feature_offset: + return feature_offset + else: + return None + + def _get_manual_tracking_position(self, frame_number): + """Get manual tracking position for a frame""" if not self.tracking_points: return None frames = sorted(self.tracking_points.keys())