Compare commits

...

6 Commits

Author SHA1 Message Date
10284dad81 Implement template matching position retrieval in VideoEditor
This commit introduces a new method to get the template matching position and confidence for a specific frame. It optimizes the tracking process by utilizing cropped regions for faster template matching while maintaining functionality for full frame matching when no crop is set. Additionally, it updates the rendering logic to visualize the template matching point on the canvas, enhancing user feedback with confidence levels displayed. This update improves the overall accuracy and efficiency of the template matching feature.
2025-09-26 14:51:04 +02:00
a2dc4a2186 Refactor tracking position calculation in VideoEditor to compute the average of all available positions from manual, template, and feature tracking methods. This change simplifies the logic by aggregating positions instead of calculating weighted offsets, enhancing accuracy and clarity in tracking results. Debug messages have been updated to reflect the new averaging process. 2025-09-26 14:48:17 +02:00
5d76681ded Refactor tracking position calculation in VideoEditor to combine manual, template, and feature tracking methods. This update introduces a more robust approach to determine the final tracking position by calculating offsets from both template matching and feature tracking, weighted appropriately against a base position derived from manual tracking points. The logic ensures smoother transitions and improved accuracy in tracking results, with debug messages added for better insight into the combined tracking process. 2025-09-26 14:44:19 +02:00
f8acef2da4 Update VideoEditor to set current display frame during rendering for improved motion tracking
This commit adds functionality to store the current display frame and update the current frame index during the rendering process. This enhancement supports better motion tracking by ensuring the correct frame is referenced, contributing to more accurate processing of video frames.
2025-09-26 14:37:23 +02:00
65b80034cb Enhance template matching in VideoEditor by utilizing cropped regions for improved speed and accuracy. This update modifies the tracking logic to prioritize cropped areas for faster processing, while maintaining functionality for full frame matching when no crop is set. Debug messages have been refined to provide clearer insights into tracking results and confidence levels. 2025-09-26 14:35:51 +02:00
5400592afd Refactor template matching in VideoEditor to use raw frame coordinates for improved accuracy. This update simplifies the tracking logic by directly utilizing the raw display frame, eliminating unnecessary transformations. Additionally, it enhances the template setting process by ensuring the selected region is correctly mapped to raw frame coordinates, improving usability and feedback during template selection. Debug messages have been updated to reflect these changes. 2025-09-26 14:34:48 +02:00

View File

@@ -1637,13 +1637,17 @@ class VideoEditor:
def _get_interpolated_tracking_position(self, frame_number):
"""Linear interpolation in ROTATED frame coords. Returns (rx, ry) or None."""
# First try template matching if enabled (much better than optical flow)
# Get base position from manual tracking points
base_pos = self._get_manual_tracking_position(frame_number)
# Calculate offset from template matching if enabled
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
# 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:
# Track template in cropped frame (much faster!)
@@ -1652,12 +1656,12 @@ class VideoEditor:
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 rotated frame coordinates
# Map from cropped frame coordinates to raw frame coordinates
# Add crop offset back
rot_x = center_x + crop_x
rot_y = center_y + crop_y
raw_x = center_x + crop_x
raw_y = center_y + crop_y
return (rot_x, rot_y)
template_offset = (raw_x, raw_y)
else:
# No crop - use full frame
raw_frame = self.current_display_frame.copy()
@@ -1667,22 +1671,11 @@ class VideoEditor:
center_x, center_y, confidence = result
print(f"DEBUG: Template match found at ({center_x}, {center_y}) with confidence {confidence:.2f}")
# Map from raw frame coordinates to rotated frame coordinates
if self.rotation_angle == 90:
rot_x = self.frame_height - center_y
rot_y = center_x
elif self.rotation_angle == 180:
rot_x = self.frame_width - center_x
rot_y = self.frame_height - center_y
elif self.rotation_angle == 270:
rot_x = center_y
rot_y = self.frame_width - center_x
else:
rot_x, rot_y = center_x, center_y
return (rot_x, rot_y)
# Template matching returns coordinates in raw frame space
template_offset = (center_x, center_y)
# Fall back to feature tracking if enabled - but use smooth interpolation instead of averaging
# Calculate offset from feature tracking if enabled
feature_offset = None
if self.feature_tracker.tracking_enabled:
# Get the nearest frames with features for smooth interpolation
feature_frames = sorted(self.feature_tracker.features.keys())
@@ -1690,19 +1683,54 @@ class VideoEditor:
# Find the two nearest frames for interpolation
if frame_number <= feature_frames[0]:
# Before first feature frame - use first frame
return self._get_feature_center(feature_frames[0])
feature_offset = self._get_feature_center(feature_frames[0])
elif frame_number >= feature_frames[-1]:
# After last feature frame - use last frame
return self._get_feature_center(feature_frames[-1])
feature_offset = self._get_feature_center(feature_frames[-1])
else:
# Between two feature frames - interpolate smoothly
for i in range(len(feature_frames) - 1):
if feature_frames[i] <= frame_number <= feature_frames[i + 1]:
return self._interpolate_feature_positions(
feature_offset = self._interpolate_feature_positions(
feature_frames[i], feature_frames[i + 1], frame_number
)
break
# Fall back to manual tracking points
# Combine tracking methods: average of all available positions
positions = []
# Add manual tracking position
if base_pos:
positions.append(base_pos)
print(f"DEBUG: Manual tracking: ({base_pos[0]:.1f}, {base_pos[1]:.1f})")
# Add template matching position
if template_offset:
positions.append(template_offset)
print(f"DEBUG: Template matching: ({template_offset[0]:.1f}, {template_offset[1]:.1f})")
# Add feature tracking position
if feature_offset:
positions.append(feature_offset)
print(f"DEBUG: Feature tracking: ({feature_offset[0]:.1f}, {feature_offset[1]:.1f})")
# Calculate average of all available positions
if positions:
avg_x = sum(pos[0] for pos in positions) / len(positions)
avg_y = sum(pos[1] for pos in positions) / len(positions)
print(f"DEBUG: Average of {len(positions)} positions: ({avg_x:.1f}, {avg_y:.1f})")
return (avg_x, avg_y)
# Fall back to individual tracking methods if no base position
if template_offset:
return template_offset
elif feature_offset:
return feature_offset
else:
return None
def _get_manual_tracking_position(self, frame_number):
"""Get manual tracking position for a frame"""
if not self.tracking_points:
return None
frames = sorted(self.tracking_points.keys())
@@ -1732,6 +1760,38 @@ class VideoEditor:
return (x1 + t * (x2 - x1), y1 + t * (y2 - y1))
return None
def _get_template_matching_position(self, frame_number):
"""Get template matching position and confidence for a frame"""
if not self.template_matching_enabled or self.tracking_template is None:
return 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:
# Track template in cropped frame (much faster!)
result = self.track_template(cropped_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
raw_frame = self.current_display_frame.copy()
if raw_frame is not None:
result = self.track_template(raw_frame)
if result:
center_x, center_y, confidence = result
return (center_x, center_y, confidence)
return None
def _get_display_params(self):
"""Unified display transform parameters for current frame in rotated space."""
eff_x, eff_y, eff_w, eff_h = self._get_effective_crop_rect_for_frame(getattr(self, 'current_frame', 0))
@@ -2231,37 +2291,35 @@ class VideoEditor:
print(f"DEBUG: Setting template from region ({x}, {y}, {w}, {h})")
if self.current_display_frame is not None:
# Apply transformations to get the display frame
display_frame = self.apply_crop_zoom_and_rotation(self.current_display_frame)
if display_frame is not None:
# Map screen coordinates to display frame coordinates
frame_height, frame_width = display_frame.shape[:2]
available_height = self.window_height - (0 if self.is_image_mode else self.TIMELINE_HEIGHT)
start_y = (available_height - frame_height) // 2
start_x = (self.window_width - frame_width) // 2
# Map screen coordinates to rotated frame coordinates (raw frame)
# This is what we need for template matching during rendering
rot_x, rot_y = self._map_screen_to_rotated(x, y)
rot_x2, rot_y2 = self._map_screen_to_rotated(x + w, y + h)
# Calculate region in rotated frame coordinates
raw_x = min(rot_x, rot_x2)
raw_y = min(rot_y, rot_y2)
raw_w = abs(rot_x2 - rot_x)
raw_h = abs(rot_y2 - rot_y)
print(f"DEBUG: Mapped to raw frame coordinates ({raw_x}, {raw_y}, {raw_w}, {raw_h})")
# Ensure region is within raw frame bounds
if (raw_x >= 0 and raw_y >= 0 and
raw_x + raw_w <= self.frame_width and
raw_y + raw_h <= self.frame_height):
# Convert screen coordinates to display frame coordinates
display_x = x - start_x
display_y = y - start_y
display_w = w
display_h = h
# Ensure region is within frame bounds
if (display_x >= 0 and display_y >= 0 and
display_x + display_w <= frame_width and
display_y + display_h <= frame_height):
# Extract template from display frame
template = display_frame[display_y:display_y+display_h, display_x:display_x+display_w]
if template.size > 0:
self.tracking_template = template.copy()
self.template_region = (display_x, display_y, display_w, display_h)
self.show_feedback_message(f"Template set from region ({display_w}x{display_h})")
print(f"DEBUG: Template set with size {template.shape}")
else:
self.show_feedback_message("Template region too small")
# Extract template from raw frame
template = self.current_display_frame[raw_y:raw_y+raw_h, raw_x:raw_x+raw_w]
if template.size > 0:
self.tracking_template = template.copy()
self.template_region = (raw_x, raw_y, raw_w, raw_h)
self.show_feedback_message(f"Template set from region ({raw_w}x{raw_h})")
print(f"DEBUG: Template set with size {template.shape}")
else:
self.show_feedback_message("Template region outside frame bounds")
self.show_feedback_message("Template region too small")
else:
self.show_feedback_message("Template region outside frame bounds")
def apply_rotation(self, frame):
@@ -2931,6 +2989,23 @@ class VideoEditor:
cv2.circle(canvas, (sx, sy), 4, (0, 255, 0), -1) # Green circles for features
cv2.circle(canvas, (sx, sy), 4, (255, 255, 255), 1)
# Draw template matching point (blue circle with confidence)
if (not self.is_image_mode and
self.template_matching_enabled and
self.tracking_template is not None):
# Get template matching position for current frame
template_pos = self._get_template_matching_position(self.current_frame)
if template_pos:
tx, ty, confidence = template_pos
# Map to screen coordinates
sx, sy = self._map_rotated_to_screen(tx, ty)
# Draw blue circle for template matching
cv2.circle(canvas, (sx, sy), 8, (255, 0, 255), -1) # Magenta circle for template
cv2.circle(canvas, (sx, sy), 8, (255, 255, 255), 2)
# Draw confidence text
conf_text = f"{confidence:.2f}"
cv2.putText(canvas, conf_text, (sx + 10, sy - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
# Draw selection rectangles for feature extraction/deletion
if self.selective_feature_extraction_rect:
x, y, w, h = self.selective_feature_extraction_rect
@@ -3850,6 +3925,10 @@ class VideoEditor:
if not ret:
break
# Set current display frame for motion tracking during rendering
self.current_display_frame = frame.copy()
self.current_frame = start_frame + i
processed_frame = self._process_frame_for_render(frame, output_width, output_height, start_frame + i)
if processed_frame is not None:
if i == 0: