From b5a0811cbd7519dcb79c73fbdb53980f4c0a8003 Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Fri, 26 Sep 2025 19:35:13 +0200 Subject: [PATCH] Enhance template management in VideoEditor by including template images This commit updates the template management system in the VideoEditor to store template images alongside their start frames and regions. The changes include modifications to the loading and saving processes, ensuring that template images are recreated when needed. Additionally, the logic for adding and retrieving templates has been refined to accommodate the new structure, improving the overall efficiency and clarity of template handling during video editing sessions. --- croppa/main.py | 71 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/croppa/main.py b/croppa/main.py index 436ab17..b261f12 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -865,8 +865,8 @@ class VideoEditor: self.template_selection_start = None self.template_selection_rect = None - # Simple template system - list of (start_frame, region) tuples sorted by start_frame - self.templates = [] # [(start_frame, region), ...] sorted by start_frame + # Simple template system - list of (start_frame, region, template_image) tuples sorted by start_frame + self.templates = [] # [(start_frame, region, template_image), ...] sorted by start_frame # Template matching modes self.template_matching_full_frame = False # Toggle for full frame vs cropped template matching @@ -921,7 +921,7 @@ class VideoEditor: 'templates': [{ 'start_frame': start_frame, 'region': region - } for start_frame, region in self.templates] + } for start_frame, region, template_image in self.templates] } with open(state_file, 'w') as f: @@ -1017,10 +1017,16 @@ class VideoEditor: if 'templates' in state: self.templates = [] for template_data in state['templates']: - self.templates.append((template_data['start_frame'], template_data['region'])) + start_frame = template_data['start_frame'] + region = template_data['region'] + # We'll recreate the template image when needed + self.templates.append((start_frame, region, None)) # Sort by start_frame self.templates.sort(key=lambda x: x[0]) print(f"Loaded {len(self.templates)} templates") + + # Recreate template images by seeking to capture frames + self._recreate_template_images() # Validate cut markers against current video length if self.cut_start_frame is not None and self.cut_start_frame >= self.total_frames: @@ -2274,14 +2280,10 @@ class VideoEditor: if template_index is None: return None - start_frame, region = self.templates[template_index] - x, y, w, h = region + start_frame, region, template_image = self.templates[template_index] - # Extract template from current frame - if (y + h <= frame.shape[0] and x + w <= frame.shape[1]): - tracking_template = frame[y:y+h, x:x+w] - else: - return None + # Use the stored template image from when it was captured + tracking_template = template_image try: # Apply image preprocessing for better template matching @@ -2392,8 +2394,8 @@ class VideoEditor: if start_frame is None: start_frame = self.current_frame - # Add template to list - self.templates.append((start_frame, region)) + # Add template to list with the actual template image + self.templates.append((start_frame, region, template.copy())) # Sort by start_frame self.templates.sort(key=lambda x: x[0]) @@ -2410,7 +2412,7 @@ class VideoEditor: current_frame = self.current_frame template_to_remove = None - for i, (start_frame, region) in enumerate(self.templates): + for i, (start_frame, region, template_image) in enumerate(self.templates): if start_frame > current_frame: # Found template with start_frame > current_frame # Remove the previous one (if it exists) @@ -2432,7 +2434,7 @@ class VideoEditor: return None # Find template with start_frame > current_frame - for i, (start_frame, region) in enumerate(self.templates): + for i, (start_frame, region, template_image) in enumerate(self.templates): if start_frame > frame_number: # Found template with start_frame > current_frame # Use the previous one (if it exists) @@ -2449,6 +2451,35 @@ class VideoEditor: template_index = self.get_template_for_frame(frame_number) return template_index is not None + def _recreate_template_images(self): + """Recreate template images by seeking to their capture frames""" + if not self.templates: + return + + current_frame_backup = self.current_frame + + for i, (start_frame, region, template_image) in enumerate(self.templates): + if template_image is None: # Only recreate if missing + try: + # Seek to the capture frame + self.seek_to_frame(start_frame) + + # Extract template from current frame + x, y, w, h = region + if (y + h <= self.current_display_frame.shape[0] and + x + w <= self.current_display_frame.shape[1]): + template_image = self.current_display_frame[y:y+h, x:x+w].copy() + # Update the template in the list + self.templates[i] = (start_frame, region, template_image) + print(f"DEBUG: Recreated template {i} from frame {start_frame}") + else: + print(f"DEBUG: Failed to recreate template {i} - region outside frame bounds") + except Exception as e: + print(f"DEBUG: Failed to recreate template {i}: {e}") + + # Restore original frame + self.seek_to_frame(current_frame_backup) + def jump_to_previous_template(self): """Jump to the previous template marker (frame where template was created).""" @@ -2459,7 +2490,7 @@ class VideoEditor: print("DEBUG: No template markers; prev jump ignored") return current = self.current_frame - candidates = [start_frame for start_frame, region in self.templates if start_frame < current] + candidates = [start_frame for start_frame, region, template_image in self.templates if start_frame < current] if candidates: target = candidates[-1] print(f"DEBUG: Jump prev template from {current} -> {target}") @@ -2478,7 +2509,7 @@ class VideoEditor: print("DEBUG: No template markers; next jump ignored") return current = self.current_frame - for start_frame, region in self.templates: + for start_frame, region, template_image in self.templates: if start_frame > current: print(f"DEBUG: Jump next template from {current} -> {start_frame}") self.seek_to_frame(start_frame) @@ -2942,14 +2973,14 @@ class VideoEditor: ) # Draw template markers - for start_frame, region in self.templates: + for start_frame, region, template_image in self.templates: # Draw template start point start_progress = start_frame / max(1, self.total_frames - 1) start_x = bar_x_start + int(bar_width * start_progress) # Template color (green for active, red for inactive) template_index = self.get_template_for_frame(self.current_frame) - is_active = (template_index is not None and self.templates[template_index] == (start_frame, region)) + is_active = (template_index is not None and self.templates[template_index][0] == start_frame) template_color = (0, 255, 0) if is_active else (255, 0, 0) # Green if active, red if inactive # Draw template start marker @@ -3421,7 +3452,7 @@ class VideoEditor: screen_x, screen_y = x, y raw_x, raw_y = self._map_screen_to_rotated(screen_x, screen_y) - for i, (start_frame, region) in enumerate(self.templates): + for i, (start_frame, region, template_image) in enumerate(self.templates): tx, ty, tw, th = region center_x = tx + tw // 2 center_y = ty + th // 2