Refactor template management in VideoEditor to streamline template handling

This commit removes unused attributes and logic related to template matching, enhancing the clarity and efficiency of the template management system. The changes include the removal of the template matching enabled flag and associated state management, focusing on the current template ID and its associated data. Debug messages have been updated to reflect these changes, ensuring better tracking and feedback during video editing sessions.
This commit is contained in:
2025-09-26 18:42:35 +02:00
parent 9df6d73db8
commit e1d94f2b24

View File

@@ -860,9 +860,6 @@ class VideoEditor:
self.previous_frame_for_flow = None self.previous_frame_for_flow = None
# Template matching tracking # Template matching tracking
self.template_matching_enabled = False
self.tracking_template = None
self.template_region = None
self.template_match_history = [] # Store recent match confidences for adaptive thresholding self.template_match_history = [] # Store recent match confidences for adaptive thresholding
# (x, y, w, h) in rotated frame coordinates # (x, y, w, h) in rotated frame coordinates
self.template_selection_start = None self.template_selection_start = None
@@ -922,8 +919,6 @@ class VideoEditor:
'tracking_enabled': self.tracking_enabled, 'tracking_enabled': self.tracking_enabled,
'tracking_points': {str(k): v for k, v in self.tracking_points.items()}, 'tracking_points': {str(k): v for k, v in self.tracking_points.items()},
'feature_tracker': self.feature_tracker.get_state_dict(), 'feature_tracker': self.feature_tracker.get_state_dict(),
'template_matching_enabled': self.template_matching_enabled,
'template_region': self.template_region,
'template_matching_full_frame': self.template_matching_full_frame, 'template_matching_full_frame': self.template_matching_full_frame,
'templates': {str(k): { 'templates': {str(k): {
'template': None, # Don't save template images (too large) 'template': None, # Don't save template images (too large)
@@ -1021,12 +1016,6 @@ class VideoEditor:
print(f"Loaded feature tracker state") print(f"Loaded feature tracker state")
# Load template matching state # Load template matching state
if 'template_matching_enabled' in state:
self.template_matching_enabled = state['template_matching_enabled']
if 'template_region' in state and state['template_region'] is not None:
self.template_region = state['template_region']
# Recreate template from region when needed
self.tracking_template = None
if 'template_matching_full_frame' in state: if 'template_matching_full_frame' in state:
self.template_matching_full_frame = state['template_matching_full_frame'] self.template_matching_full_frame = state['template_matching_full_frame']
@@ -1666,7 +1655,7 @@ class VideoEditor:
# Calculate offset from template matching if enabled # Calculate offset from template matching if enabled
template_offset = None template_offset = None
if self.template_matching_enabled and self.tracking_template is not None: if self.templates and self.current_template_id is not None:
if self.current_display_frame is not None: if self.current_display_frame is not None:
if self.template_matching_full_frame: if self.template_matching_full_frame:
# Full frame mode - use the entire original frame # Full frame mode - use the entire original frame
@@ -1836,7 +1825,7 @@ class VideoEditor:
def _get_template_matching_position(self, frame_number): def _get_template_matching_position(self, frame_number):
"""Get template matching position and confidence for a frame""" """Get template matching position and confidence for a frame"""
if not self.template_matching_enabled or self.tracking_template is None: if not self.templates or self.current_template_id is None:
return None return None
if self.current_display_frame is not None: if self.current_display_frame is not None:
@@ -1948,8 +1937,6 @@ class VideoEditor:
def _map_screen_to_rotated(self, sx, sy): def _map_screen_to_rotated(self, sx, sy):
"""Map a point on canvas screen coords back to ROTATED frame coords (pre-crop).""" """Map a point on canvas screen coords back to ROTATED frame coords (pre-crop)."""
frame_number = getattr(self, 'current_frame', 0)
angle = self.rotation_angle
# Use unified display params # Use unified display params
params = self._get_display_params() params = self._get_display_params()
# Back to processed (zoomed+cropped) space # Back to processed (zoomed+cropped) space
@@ -2293,12 +2280,18 @@ class VideoEditor:
def track_template(self, frame): def track_template(self, frame):
"""Track the template in the current frame""" """Track the template in the current frame"""
if self.tracking_template is None: if self.current_template_id is None or self.current_template_id not in self.templates:
return None
template_data = self.templates[self.current_template_id]
tracking_template = template_data['template']
if tracking_template is None:
return None return None
try: try:
# Apply image preprocessing for better template matching # Apply image preprocessing for better template matching
gray_frame, gray_template = self._improve_template_matching(frame, self.tracking_template) gray_frame, gray_template = self._improve_template_matching(frame, tracking_template)
# Single-scale template matching (faster) # Single-scale template matching (faster)
result = cv2.matchTemplate(gray_frame, gray_template, cv2.TM_CCOEFF_NORMED) result = cv2.matchTemplate(gray_frame, gray_template, cv2.TM_CCOEFF_NORMED)
@@ -2391,7 +2384,7 @@ class VideoEditor:
# Extract template from raw frame # Extract template from raw frame
template = self.current_display_frame[raw_y:raw_y+raw_h, raw_x:raw_x+raw_w] template = self.current_display_frame[raw_y:raw_y+raw_h, raw_x:raw_x+raw_w]
if template.size > 0: if template.size > 0:
# Add template to collection instead of setting single template # Add template to collection
template_id = self.add_template(template, (raw_x, raw_y, raw_w, raw_h)) template_id = self.add_template(template, (raw_x, raw_y, raw_w, raw_h))
self.show_feedback_message(f"Template {template_id} set from region ({raw_w}x{raw_h})") self.show_feedback_message(f"Template {template_id} set from region ({raw_w}x{raw_h})")
print(f"DEBUG: Template {template_id} set with size {template.shape}") print(f"DEBUG: Template {template_id} set with size {template.shape}")
@@ -2410,16 +2403,19 @@ class VideoEditor:
if end_frame is None: if end_frame is None:
end_frame = self.total_frames - 1 end_frame = self.total_frames - 1
# End any templates that start after the current frame # Only end the current template if it exists and starts at or before the current frame
if self.current_template_id is not None and self.current_template_id in self.templates:
current_template = self.templates[self.current_template_id]
if current_template['start_frame'] <= self.current_frame:
# End the current template at the previous frame
self.templates[self.current_template_id]['end_frame'] = self.current_frame - 1
print(f"DEBUG: Ended current template {self.current_template_id} at frame {self.current_frame - 1}")
# Remove any templates that start after the current frame (they shouldn't exist yet)
for template_id, template_data in list(self.templates.items()): for template_id, template_data in list(self.templates.items()):
if template_data['start_frame'] > self.current_frame: if template_data['start_frame'] > self.current_frame:
# This template starts after the current frame, so remove it
del self.templates[template_id] del self.templates[template_id]
print(f"DEBUG: Removed future template {template_id} that started at frame {template_data['start_frame']}") print(f"DEBUG: Removed future template {template_id} that started at frame {template_data['start_frame']}")
elif template_data['start_frame'] == self.current_frame:
# This template starts at the same frame, end it at the previous frame
self.templates[template_id]['end_frame'] = self.current_frame - 1
print(f"DEBUG: Ended template {template_id} at frame {self.current_frame - 1}")
self.templates[template_id] = { self.templates[template_id] = {
'template': template.copy(), 'template': template.copy(),
@@ -2428,11 +2424,8 @@ class VideoEditor:
'end_frame': end_frame 'end_frame': end_frame
} }
# Set as current template and enable template matching # Set as current template
self.current_template_id = template_id self.current_template_id = template_id
self.tracking_template = template.copy()
self.template_region = region
self.template_matching_enabled = True # Enable template matching when template is created
self.show_feedback_message(f"Template {template_id} added (frames {start_frame}-{end_frame})") self.show_feedback_message(f"Template {template_id} added (frames {start_frame}-{end_frame})")
return template_id return template_id
@@ -2446,11 +2439,8 @@ class VideoEditor:
if self.current_template_id == template_id: if self.current_template_id == template_id:
self._select_best_template_for_frame(self.current_frame) self._select_best_template_for_frame(self.current_frame)
# If no templates left, disable template matching # If no templates left, clear current template
if not self.templates: if not self.templates:
self.template_matching_enabled = False
self.tracking_template = None
self.template_region = None
self.current_template_id = None self.current_template_id = None
self.show_feedback_message(f"Template {template_id} removed") self.show_feedback_message(f"Template {template_id} removed")
@@ -2491,13 +2481,10 @@ class VideoEditor:
else: else:
return False return False
self.tracking_template = template_data['template'].copy() # Template is already stored in the templates dict
self.template_region = template_data['region']
return True return True
else: else:
self.current_template_id = None self.current_template_id = None
self.tracking_template = None
self.template_region = None
return False return False
def _recreate_template_from_template_data(self, template_id, frame): def _recreate_template_from_template_data(self, template_id, frame):
@@ -3168,7 +3155,7 @@ class VideoEditor:
if self.optical_flow_enabled: if self.optical_flow_enabled:
feature_text += " (OPTICAL FLOW)" feature_text += " (OPTICAL FLOW)"
template_text = "" template_text = ""
if self.template_matching_enabled: if self.templates:
mode = "Full Frame" if self.template_matching_full_frame else "Cropped" mode = "Full Frame" if self.template_matching_full_frame else "Cropped"
template_text = f" | Template: {mode}" template_text = f" | Template: {mode}"
autorepeat_text = ( autorepeat_text = (
@@ -3284,8 +3271,8 @@ class VideoEditor:
# Draw template matching point (blue circle with confidence) # Draw template matching point (blue circle with confidence)
if (not self.is_image_mode and if (not self.is_image_mode and
self.template_matching_enabled and self.templates and
self.tracking_template is not None): self.current_template_id is not None):
# Get template matching position for current frame # Get template matching position for current frame
template_pos = self._get_template_matching_position(self.current_frame) template_pos = self._get_template_matching_position(self.current_frame)
if template_pos: if template_pos:
@@ -3911,13 +3898,10 @@ class VideoEditor:
def _render_video_worker(self, output_path: str): def _render_video_worker(self, output_path: str):
"""Worker method that runs in the render thread""" """Worker method that runs in the render thread"""
render_cap = None
try: try:
if not output_path.endswith(".mp4"): if not output_path.endswith(".mp4"):
output_path += ".mp4" output_path += ".mp4"
start_time = time.time()
# Send progress update to main thread # Send progress update to main thread
self.render_progress_queue.put(("init", "Initializing render...", 0.0, 0.0)) self.render_progress_queue.put(("init", "Initializing render...", 0.0, 0.0))
@@ -4728,10 +4712,15 @@ class VideoEditor:
self.show_feedback_message(f"Optical flow {'ON' if self.optical_flow_enabled else 'OFF'}") self.show_feedback_message(f"Optical flow {'ON' if self.optical_flow_enabled else 'OFF'}")
self.save_state() self.save_state()
elif key == ord("m"): elif key == ord("m"):
# Toggle template matching tracking # Clear all templates
self.template_matching_enabled = not self.template_matching_enabled if self.templates:
print(f"DEBUG: Template matching toggled to {self.template_matching_enabled}") self.templates.clear()
self.show_feedback_message(f"Template matching {'ON' if self.template_matching_enabled else 'OFF'}") self.current_template_id = None
print("DEBUG: All templates cleared")
self.show_feedback_message("All templates cleared")
else:
print("DEBUG: No templates to clear")
self.show_feedback_message("No templates to clear")
self.save_state() self.save_state()
elif key == ord("M"): # Shift+M - Toggle multi-scale template matching elif key == ord("M"): # Shift+M - Toggle multi-scale template matching
self.template_matching_full_frame = not self.template_matching_full_frame self.template_matching_full_frame = not self.template_matching_full_frame