Refactor template matching logic in VideoEditor to support full frame and cropped modes

This commit introduces a toggle for template matching modes in the VideoEditor, allowing users to choose between full frame and cropped region matching. The logic has been updated to handle both modes effectively, improving flexibility and performance during template tracking. Additionally, the multi-scale template matching feature has been removed, streamlining the template matching process. Debug messages and feedback have been enhanced to reflect the current mode, ensuring better user experience during video editing sessions.
This commit is contained in:
2025-09-26 18:20:12 +02:00
parent 151744d144
commit 44ed4220b9

View File

@@ -882,7 +882,7 @@ class VideoEditor:
self.tracking_template = None
self.template_region = None
self.template_match_history = [] # Store recent match confidences for adaptive thresholding
self.multi_scale_template_matching = False # Disable multi-scale by default # (x, y, w, h) in rotated frame coordinates
# (x, y, w, h) in rotated frame coordinates
self.template_selection_start = None
self.template_selection_rect = None
@@ -890,6 +890,9 @@ class VideoEditor:
self.templates = {} # {template_id: {'template': image, 'region': (x,y,w,h), 'start_frame': int, 'end_frame': int}}
self.current_template_id = None
self.template_id_counter = 0
# Template matching modes
self.template_matching_full_frame = False # Toggle for full frame vs cropped template matching
# Project view mode
self.project_view_mode = False
@@ -939,7 +942,7 @@ class VideoEditor:
'feature_tracker': self.feature_tracker.get_state_dict(),
'template_matching_enabled': self.template_matching_enabled,
'template_region': self.template_region,
'multi_scale_template_matching': self.multi_scale_template_matching,
'template_matching_full_frame': self.template_matching_full_frame,
'templates': {str(k): {
'template': None, # Don't save template images (too large)
'region': v['region'],
@@ -1042,8 +1045,8 @@ class VideoEditor:
self.template_region = state['template_region']
# Recreate template from region when needed
self.tracking_template = None
if 'multi_scale_template_matching' in state:
self.multi_scale_template_matching = state['multi_scale_template_matching'] # Will be recreated on first use
if 'template_matching_full_frame' in state:
self.template_matching_full_frame = state['template_matching_full_frame']
# Load multiple templates state
if 'templates' in state:
@@ -1683,34 +1686,42 @@ class VideoEditor:
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
if self.crop_rect:
crop_x, crop_y, crop_w, crop_h = self.crop_rect
# Extract only the cropped region from raw frame
cropped_frame = self.current_display_frame[crop_y:crop_y+crop_h, crop_x:crop_x+crop_w]
if cropped_frame is not None and cropped_frame.size > 0:
# Apply motion tracking offset to the cropped frame
offset_frame = self._apply_motion_tracking_offset(cropped_frame, base_pos)
if self.template_matching_full_frame:
# Full frame mode - use the entire original frame
result = self.track_template(self.current_display_frame)
if result:
center_x, center_y, confidence = result
print(f"DEBUG: Template match found at ({center_x}, {center_y}) with confidence {confidence:.2f}")
template_offset = (center_x, center_y)
else:
# Cropped mode - use only the cropped region for faster template matching
if self.crop_rect:
crop_x, crop_y, crop_w, crop_h = self.crop_rect
# Extract only the cropped region from raw frame
cropped_frame = self.current_display_frame[crop_y:crop_y+crop_h, crop_x:crop_x+crop_w]
if cropped_frame is not None and cropped_frame.size > 0:
# Apply motion tracking offset to the cropped frame
offset_frame = self._apply_motion_tracking_offset(cropped_frame, base_pos)
if offset_frame is not None:
# Track template in cropped and offset frame (much faster!)
result = self.track_template(offset_frame)
if result:
center_x, center_y, confidence = result
print(f"DEBUG: Template match found at ({center_x}, {center_y}) with confidence {confidence:.2f}")
# Map from cropped frame coordinates to raw frame coordinates
# Add crop offset back
raw_x = center_x + crop_x
raw_y = center_y + crop_y
template_offset = (raw_x, raw_y)
else:
# No crop - use full frame with offset
offset_frame = self._apply_motion_tracking_offset(self.current_display_frame, base_pos)
if offset_frame is not None:
# Track template in cropped and offset frame (much faster!)
result = self.track_template(offset_frame)
if result:
center_x, center_y, confidence = result
print(f"DEBUG: Template match found at ({center_x}, {center_y}) with confidence {confidence:.2f}")
# Map from cropped frame coordinates to raw frame coordinates
# Add crop offset back
raw_x = center_x + crop_x
raw_y = center_y + crop_y
template_offset = (raw_x, raw_y)
else:
# No crop - use full frame with offset
offset_frame = self._apply_motion_tracking_offset(self.current_display_frame, base_pos)
if offset_frame is not None:
result = self.track_template(offset_frame)
if result:
center_x, center_y, confidence = result
template_offset = (center_x, center_y)
template_offset = (center_x, center_y)
# Calculate offset from feature tracking if enabled
feature_offset = None
@@ -1850,32 +1861,39 @@ class VideoEditor:
# Get base position for motion tracking offset
base_pos = self._get_manual_tracking_position(frame_number)
# Use only the cropped region for much faster template matching
if self.crop_rect:
crop_x, crop_y, crop_w, crop_h = self.crop_rect
# Extract only the cropped region from raw frame
cropped_frame = self.current_display_frame[crop_y:crop_y+crop_h, crop_x:crop_x+crop_w]
if cropped_frame is not None and cropped_frame.size > 0:
# Apply motion tracking offset to the cropped frame
offset_frame = self._apply_motion_tracking_offset(cropped_frame, base_pos)
if self.template_matching_full_frame:
# Full frame mode - use the entire original frame
result = self.track_template(self.current_display_frame)
if result:
center_x, center_y, confidence = result
return (center_x, center_y, confidence)
else:
# Cropped mode - use only the cropped region for faster template matching
if self.crop_rect:
crop_x, crop_y, crop_w, crop_h = self.crop_rect
# Extract only the cropped region from raw frame
cropped_frame = self.current_display_frame[crop_y:crop_y+crop_h, crop_x:crop_x+crop_w]
if cropped_frame is not None and cropped_frame.size > 0:
# Apply motion tracking offset to the cropped frame
offset_frame = self._apply_motion_tracking_offset(cropped_frame, base_pos)
if offset_frame is not None:
# Track template in cropped and offset frame (much faster!)
result = self.track_template(offset_frame)
if result:
center_x, center_y, confidence = result
# Map from cropped frame coordinates to raw frame coordinates
# Add crop offset back
raw_x = center_x + crop_x
raw_y = center_y + crop_y
return (raw_x, raw_y, confidence)
else:
# No crop - use full frame with offset
offset_frame = self._apply_motion_tracking_offset(self.current_display_frame, base_pos)
if offset_frame is not None:
# Track template in cropped and offset frame (much faster!)
result = self.track_template(offset_frame)
if result:
center_x, center_y, confidence = result
# Map from cropped frame coordinates to raw frame coordinates
# Add crop offset back
raw_x = center_x + crop_x
raw_y = center_y + crop_y
return (raw_x, raw_y, confidence)
else:
# No crop - use full frame with offset
offset_frame = self._apply_motion_tracking_offset(self.current_display_frame, base_pos)
if offset_frame is not None:
result = self.track_template(offset_frame)
if result:
center_x, center_y, confidence = result
return (center_x, center_y, confidence)
return (center_x, center_y, confidence)
return None
@@ -2312,7 +2330,7 @@ class VideoEditor:
gray_frame, gray_template = self._improve_template_matching(frame, self.tracking_template)
# Multi-scale template matching for better tracking (if enabled)
if self.multi_scale_template_matching:
if False: # Multi-scale template matching removed
scales = [0.8, 0.9, 1.0, 1.1, 1.2] # Different scales to try
best_match = None
best_confidence = 0.0
@@ -3231,10 +3249,11 @@ class VideoEditor:
feature_text = f" | Features: {feature_count} pts"
if self.optical_flow_enabled:
feature_text += " (OPTICAL FLOW)"
template_text = (
f" | Template: {self.template_matching_enabled}" if self.template_matching_enabled else ""
)
if self.template_matching_enabled and self.multi_scale_template_matching:
template_text = ""
if self.template_matching_enabled:
mode = "Full Frame" if self.template_matching_full_frame else "Cropped"
template_text = f" | Template: {mode}"
if False: # Multi-scale template matching removed
template_text += " (MULTI-SCALE)"
autorepeat_text = (
f" | Loop: ON" if self.looping_between_markers else ""
@@ -4799,9 +4818,9 @@ class VideoEditor:
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.template_matching_full_frame = not self.template_matching_full_frame
print(f"DEBUG: Template matching full frame toggled to {self.template_matching_full_frame}")
self.show_feedback_message(f"Template matching: {'Full Frame' if self.template_matching_full_frame else 'Cropped'}")
self.save_state()
elif key == ord(";"): # Semicolon - Jump to previous template marker
self.jump_to_previous_template()