From 2246ef9f45e4012aa58dd2453aad4b4b28580eab Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Fri, 26 Sep 2025 14:56:06 +0200 Subject: [PATCH] Enable multi-scale template matching in VideoEditor with toggle functionality This commit introduces a toggle for multi-scale template matching, allowing users to switch between multi-scale and single-scale approaches for improved tracking accuracy. The default setting is now multi-scale, enhancing the template matching process by evaluating templates at various sizes. Additionally, debug messages and user feedback have been updated to reflect this new feature. --- croppa/main.py | 68 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/croppa/main.py b/croppa/main.py index f7c5e2b..3936dd6 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -881,7 +881,8 @@ class VideoEditor: self.template_matching_enabled = False self.tracking_template = None self.template_region = None - self.template_match_history = [] # Store recent match confidences for adaptive thresholding # (x, y, w, h) in rotated frame coordinates + self.template_match_history = [] # Store recent match confidences for adaptive thresholding + self.multi_scale_template_matching = True # Enable multi-scale by default # (x, y, w, h) in rotated frame coordinates self.template_selection_start = None self.template_selection_rect = None @@ -2229,33 +2230,48 @@ class VideoEditor: # Apply image preprocessing for better template matching gray_frame, gray_template = self._improve_template_matching(frame, self.tracking_template) - # Multi-scale template matching for better tracking - scales = [0.8, 0.9, 1.0, 1.1, 1.2] # Different scales to try - best_match = None - best_confidence = 0.0 - - for scale in scales: - # Resize template - template_h, template_w = gray_template.shape - new_w = int(template_w * scale) - new_h = int(template_h * scale) + # Multi-scale template matching for better tracking (if enabled) + if self.multi_scale_template_matching: + scales = [0.8, 0.9, 1.0, 1.1, 1.2] # Different scales to try + best_match = None + best_confidence = 0.0 - if new_w <= 0 or new_h <= 0 or new_w > gray_frame.shape[1] or new_h > gray_frame.shape[0]: - continue + for scale in scales: + # Resize template + template_h, template_w = gray_template.shape + new_w = int(template_w * scale) + new_h = int(template_h * scale) - scaled_template = cv2.resize(gray_template, (new_w, new_h)) - - # Perform template matching - result = cv2.matchTemplate(gray_frame, scaled_template, cv2.TM_CCOEFF_NORMED) + if new_w <= 0 or new_h <= 0 or new_w > gray_frame.shape[1] or new_h > gray_frame.shape[0]: + continue + + scaled_template = cv2.resize(gray_template, (new_w, new_h)) + + # Perform template matching + result = cv2.matchTemplate(gray_frame, scaled_template, cv2.TM_CCOEFF_NORMED) + _, max_val, _, max_loc = cv2.minMaxLoc(result) + + # Check if this is the best match so far + if max_val > best_confidence: + best_confidence = max_val + # Get center of template + center_x = max_loc[0] + new_w // 2 + center_y = max_loc[1] + new_h // 2 + best_match = (center_x, center_y, max_val) + else: + # Single-scale template matching (faster) + result = cv2.matchTemplate(gray_frame, gray_template, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc = cv2.minMaxLoc(result) - # Check if this is the best match so far - if max_val > best_confidence: - best_confidence = max_val - # Get center of template - center_x = max_loc[0] + new_w // 2 - center_y = max_loc[1] + new_h // 2 + if max_val > 0.6: # Higher threshold for single-scale + template_h, template_w = gray_template.shape + center_x = max_loc[0] + template_w // 2 + center_y = max_loc[1] + template_h // 2 best_match = (center_x, center_y, max_val) + best_confidence = max_val + else: + best_match = None + best_confidence = 0.0 # Adaptive thresholding based on recent match history if len(self.template_match_history) > 0: @@ -4127,6 +4143,7 @@ class VideoEditor: print(" H: Switch detector (SIFT/ORB)") print(" o: Toggle optical flow tracking") print(" m: Toggle template matching tracking") + print(" M: Toggle multi-scale template matching") print(" Shift+Right-click+drag: Extract features from selected region") print(" Ctrl+Right-click+drag: Delete features from selected region") print(" Ctrl+Left-click+drag: Set template region for tracking") @@ -4471,6 +4488,11 @@ class VideoEditor: print(f"DEBUG: Template matching toggled to {self.template_matching_enabled}") self.show_feedback_message(f"Template matching {'ON' if self.template_matching_enabled else 'OFF'}") self.save_state() + elif key == ord("M"): # Shift+M - Toggle multi-scale template matching + self.multi_scale_template_matching = not self.multi_scale_template_matching + print(f"DEBUG: Multi-scale template matching toggled to {self.multi_scale_template_matching}") + self.show_feedback_message(f"Multi-scale template matching {'ON' if self.multi_scale_template_matching else 'OFF'}") + self.save_state() elif key == ord("t"): # Marker looping only for videos if not self.is_image_mode: