From e813be289075c1d81f7f5862a8db2f59af4baedc Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Fri, 26 Sep 2025 14:19:42 +0200 Subject: [PATCH] Improve feature tracking logic and debugging in VideoEditor This commit refines the feature tracking process by enhancing the get_tracking_position method to handle cases where frame features are missing. It also adds detailed debug messages throughout the VideoEditor class, particularly during frame seeking and feature interpolation, to provide better insights into the feature availability and interpolation process. These changes improve the robustness and user experience of the feature tracking functionality. --- croppa/main.py | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/croppa/main.py b/croppa/main.py index b25ccee..ebab0dd 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -202,15 +202,21 @@ class FeatureTracker: def get_tracking_position(self, frame_number: int) -> Optional[Tuple[float, float]]: """Get the average tracking position for a frame""" - if frame_number not in self.features or not self.features[frame_number]['positions']: + if frame_number not in self.features: + return None + + if not self.features[frame_number]['positions']: return None positions = self.features[frame_number]['positions'] + if not positions: return None + # Calculate average position avg_x = sum(pos[0] for pos in positions) / len(positions) avg_y = sum(pos[1] for pos in positions) / len(positions) + return (avg_x, avg_y) @@ -1334,9 +1340,20 @@ class VideoEditor: def seek_to_frame(self, frame_number: int): """Seek to specific frame""" + old_frame = self.current_frame self.current_frame = max(0, min(frame_number, self.total_frames - 1)) self.load_current_frame() + # Only log when we actually change frames + if old_frame != self.current_frame: + print(f"DEBUG: === LOADED NEW FRAME {self.current_frame} ===") + print(f"DEBUG: Features available for frames: {sorted(self.feature_tracker.features.keys())}") + if self.current_frame in self.feature_tracker.features: + feature_count = len(self.feature_tracker.features[self.current_frame]['positions']) + print(f"DEBUG: Frame {self.current_frame} has {feature_count} features") + else: + print(f"DEBUG: Frame {self.current_frame} has NO features") + # Auto-extract features if feature tracking is enabled and auto-tracking is on print(f"DEBUG: seek_to_frame {frame_number}: is_image_mode={self.is_image_mode}, tracking_enabled={self.feature_tracker.tracking_enabled}, auto_tracking={self.feature_tracker.auto_tracking}, display_frame={self.current_display_frame is not None}") @@ -1930,21 +1947,37 @@ class VideoEditor: def _interpolate_features_between_frames(self, start_frame, end_frame): """Interpolate features between two frames using linear interpolation""" try: + print(f"DEBUG: Starting interpolation between frame {start_frame} and {end_frame}") + if start_frame not in self.feature_tracker.features or end_frame not in self.feature_tracker.features: + print(f"DEBUG: Missing features on start_frame={start_frame} or end_frame={end_frame}") return start_features = self.feature_tracker.features[start_frame]['positions'] end_features = self.feature_tracker.features[end_frame]['positions'] + print(f"DEBUG: Start frame {start_frame} has {len(start_features)} features") + print(f"DEBUG: End frame {end_frame} has {len(end_features)} features") + if len(start_features) != len(end_features): - print(f"DEBUG: Feature count mismatch between frames {start_frame} and {end_frame}") - return + print(f"DEBUG: Feature count mismatch between frames {start_frame} and {end_frame} ({len(start_features)} vs {len(end_features)})") + print(f"DEBUG: Using minimum count for interpolation") + # Use the minimum count to avoid index errors + min_count = min(len(start_features), len(end_features)) + start_features = start_features[:min_count] + end_features = end_features[:min_count] # Interpolate for all frames between start and end + frames_to_interpolate = [] for frame_num in range(start_frame + 1, end_frame): if frame_num in self.feature_tracker.features: + print(f"DEBUG: Frame {frame_num} already has features, skipping") continue # Skip if already has features - + frames_to_interpolate.append(frame_num) + + print(f"DEBUG: Will interpolate {len(frames_to_interpolate)} frames: {frames_to_interpolate}") + + for frame_num in frames_to_interpolate: # Linear interpolation alpha = (frame_num - start_frame) / (end_frame - start_frame) interpolated_positions = [] @@ -1966,6 +1999,8 @@ class VideoEditor: } print(f"DEBUG: Interpolated {len(interpolated_positions)} features for frame {frame_num}") + + print(f"DEBUG: Finished interpolation between frame {start_frame} and {end_frame}") except Exception as e: print(f"Error interpolating features: {e}") @@ -1973,6 +2008,9 @@ class VideoEditor: def _fill_all_gaps_with_interpolation(self): """Fill all gaps between existing features with linear interpolation""" try: + print("=== FILLING ALL GAPS WITH INTERPOLATION ===") + print(f"DEBUG: Total features stored: {len(self.feature_tracker.features)}") + if not self.feature_tracker.features: print("DEBUG: No features to interpolate between") return @@ -1993,7 +2031,8 @@ class VideoEditor: print(f"DEBUG: Interpolating between frame {start_frame} and {end_frame}") self._interpolate_features_between_frames(start_frame, end_frame) - print("DEBUG: Finished filling all gaps with interpolation") + print(f"DEBUG: After interpolation, total features stored: {len(self.feature_tracker.features)}") + print("=== FINISHED FILLING ALL GAPS ===") except Exception as e: print(f"Error filling all gaps: {e}")