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