Enhance VideoEditor with motion path visualization for tracking points
This commit updates the VideoEditor class to visualize the motion path between previous and next tracking points using yellow arrows. The rendering of tracking points has been modified, with previous points displayed as red circles and next points as magenta circles, both with white borders for better visibility. The specification has been updated to reflect these changes in the display of tracking points and their motion direction.
This commit is contained in:
@@ -2090,29 +2090,63 @@ class VideoEditor:
|
||||
cv2.circle(canvas, (sx, sy), 6, (255, 0, 0), -1)
|
||||
cv2.circle(canvas, (sx, sy), 6, (255, 255, 255), 1)
|
||||
|
||||
# Draw previous and next tracking points with 50% alpha
|
||||
# Draw previous and next tracking points with motion path visualization
|
||||
if not self.is_image_mode and self.tracking_points:
|
||||
# Previous tracking point (red) - from the most recent frame with tracking points before current
|
||||
prev_result = self._get_previous_tracking_point()
|
||||
next_result = self._get_next_tracking_point()
|
||||
|
||||
# Draw motion path if we have both previous and next points
|
||||
if prev_result and next_result:
|
||||
prev_frame, prev_pts = prev_result
|
||||
next_frame, next_pts = next_result
|
||||
|
||||
# Draw lines between corresponding tracking points
|
||||
for i, (prev_rx, prev_ry) in enumerate(prev_pts):
|
||||
if i < len(next_pts):
|
||||
next_rx, next_ry = next_pts[i]
|
||||
prev_sx, prev_sy = self._map_rotated_to_screen(prev_rx, prev_ry)
|
||||
next_sx, next_sy = self._map_rotated_to_screen(next_rx, next_ry)
|
||||
|
||||
# Draw motion path line with arrow (thin and transparent)
|
||||
overlay = canvas.copy()
|
||||
cv2.line(overlay, (prev_sx, prev_sy), (next_sx, next_sy), (255, 255, 0), 1) # Thin yellow line
|
||||
|
||||
# Draw arrow head pointing from previous to next
|
||||
angle = np.arctan2(next_sy - prev_sy, next_sx - prev_sx)
|
||||
arrow_length = 12
|
||||
arrow_angle = np.pi / 6 # 30 degrees
|
||||
|
||||
# Calculate arrow head points
|
||||
arrow_x1 = int(next_sx - arrow_length * np.cos(angle - arrow_angle))
|
||||
arrow_y1 = int(next_sy - arrow_length * np.sin(angle - arrow_angle))
|
||||
arrow_x2 = int(next_sx - arrow_length * np.cos(angle + arrow_angle))
|
||||
arrow_y2 = int(next_sy - arrow_length * np.sin(angle + arrow_angle))
|
||||
|
||||
cv2.line(overlay, (next_sx, next_sy), (arrow_x1, arrow_y1), (255, 255, 0), 1)
|
||||
cv2.line(overlay, (next_sx, next_sy), (arrow_x2, arrow_y2), (255, 255, 0), 1)
|
||||
cv2.addWeighted(overlay, 0.3, canvas, 0.7, 0, canvas) # Very transparent
|
||||
|
||||
# Previous tracking point (red) - from the most recent frame with tracking points before current
|
||||
if prev_result:
|
||||
prev_frame, prev_pts = prev_result
|
||||
for (rx, ry) in prev_pts:
|
||||
sx, sy = self._map_rotated_to_screen(rx, ry)
|
||||
# Create overlay for alpha blending
|
||||
# Create overlay for alpha blending (more transparent)
|
||||
overlay = canvas.copy()
|
||||
cv2.circle(overlay, (sx, sy), 4, (0, 0, 255), -1) # Red circle
|
||||
cv2.addWeighted(overlay, 0.5, canvas, 0.5, 0, canvas)
|
||||
cv2.circle(overlay, (sx, sy), 5, (0, 0, 255), -1) # Red circle
|
||||
cv2.circle(overlay, (sx, sy), 5, (255, 255, 255), 1) # White border
|
||||
cv2.addWeighted(overlay, 0.4, canvas, 0.6, 0, canvas) # More transparent
|
||||
|
||||
# Next tracking point (green) - from the next frame with tracking points after current
|
||||
next_result = self._get_next_tracking_point()
|
||||
# Next tracking point (magenta/purple) - from the next frame with tracking points after current
|
||||
if next_result:
|
||||
next_frame, next_pts = next_result
|
||||
for (rx, ry) in next_pts:
|
||||
sx, sy = self._map_rotated_to_screen(rx, ry)
|
||||
# Create overlay for alpha blending
|
||||
# Create overlay for alpha blending (more transparent)
|
||||
overlay = canvas.copy()
|
||||
cv2.circle(overlay, (sx, sy), 4, (0, 255, 0), -1) # Green circle
|
||||
cv2.addWeighted(overlay, 0.5, canvas, 0.5, 0, canvas)
|
||||
cv2.circle(overlay, (sx, sy), 5, (255, 0, 255), -1) # Magenta circle
|
||||
cv2.circle(overlay, (sx, sy), 5, (255, 255, 255), 1) # White border
|
||||
cv2.addWeighted(overlay, 0.4, canvas, 0.6, 0, canvas) # More transparent
|
||||
if self.tracking_enabled and not self.is_image_mode:
|
||||
interp = self._get_interpolated_tracking_position(self.current_frame)
|
||||
if interp:
|
||||
|
@@ -63,7 +63,7 @@ Be careful to save and load settings when navigating this way
|
||||
- **Blue cross**: Shows computed tracking position
|
||||
- **Automatic interpolation**: Tracks between keyframes
|
||||
- **Crop follows**: Crop area centers on tracked object
|
||||
- **Display** Points are rendered as blue dots per frame, in addition the previous tracking point (red) and next tracking point (green) are shown regardless of which frame they're on
|
||||
- **Display** Points are rendered as blue dots per frame, in addition the previous tracking point (red) and next tracking point (magenta) are shown with yellow arrows indicating motion direction
|
||||
|
||||
#### Motion Tracking Navigation
|
||||
- **,**: Jump to previous tracking marker (previous frame that has one or more tracking points). Wrap-around supported.
|
||||
|
Reference in New Issue
Block a user