# Rainbow Trails Video Effect

This is an effect to augment juggling videos: The goal of this effect is to add a rainbow trail to a video using a tracked set of points.

This is how the script works step-by-step:

Look at the relevant tracking points:

import numpy as np
import cv2
import pandas as pd
import numpy.polynomial.polynomial as poly
import math

cap = cv2.VideoCapture('/home/stephen/Desktop/ss5_id_412.MP4')
#Write Video Out
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('/home/stephen/Desktop/parabola.avi', fourcc, 120.0, (480,848))

# Define x and y as the first two columns of the spreadsheet
x = df['0']
y = df['1']
# Filter the data to smooth it out
from scipy.signal import savgol_filter
x = savgol_filter(x, 7, 3)
y = savgol_filter(y, 7, 3)

# Start at frame number 0
# Define trail length
trail = 30
# Colors of the rainbow
rainbow = [(0,0,255), (0,127,255), (0,255,0), (255,0,0), (95,43,46), (255,0,139)]

def distance(a,b): return(math.sqrt((a-b)**2+(a-b)**2))

# Read a few frames of the video
# Define distance to calculate parabola from (in frames)
interval = 6
for i in range(interval):

# https://stackoverflow.com/questions/57065080/draw-perpendicular-line-of-fixed-length-at-a-point-of-another-line
def perpendicular(slope, target, dist):
dy = math.sqrt(3**2/(slope**2+1))*dist
dx = -slope*dy
left = target - dx, target - dy
right = target + dx, target + dy
return left, right

# Create a list to store past points
history = []
completeHistory = []

### This is the first loop through the video
### In this loop the rainbow-trail data is collected
while True:
try: _ = img.shape
except: break

# Define a small distance
smallDistance = 0.2

# Find relevant data

# Graph x and y values
for point in zip(x_values, y_values):
point = tuple(np.array(point,int))
#cv2.circle(img, point, 1, (255,0,255), 2) Find a parabola that fits those points:

# Fit the parabola
coefs = poly.polyfit(x_values,y_values,2)
# Draw the parabola
xRange = np.arange(target-9,target+9,1)
yRange = poly.polyval(xRange, coefs)
rangePoints = zip(xRange, yRange)
for ppp in rangePoints:
center = tuple(np.array(ppp,int))
#cv2.circle(img, center, 1, 123, 2)
#print(yRange) Find the tangent of the parabola at the ball's position:

# https://stackoverflow.com/questions/57065080/draw-perpendicular-line-of-fixed-length-at-a-point-of-another-line
def perpendicular(slope, target, dist):
dy = math.sqrt(3**2/(slope**2+1))*dist
dx = -slope*dy
left = target - dx, target - dy
right = target + dx, target + dy
return left, right

# Calculate the points on either end of the tangent line
left = leftX, poly.polyval(leftX, coefs)
right = rightX, poly.polyval(rightX, coefs)
# Calculate the slope of the tangent line
slope = (left-right)/(left-right)
intercept = target - slope*target
# Draw line
leftPoint = target-10, (target-10)*slope + intercept
rightPoint = target+10, (target+10)*slope + intercept
leftPoint = tuple(np.array(leftPoint, int))
rightPoint= tuple(np.array(rightPoint, int))
cv2.line(img, leftPoint, rightPoint, (123,234,123), 3) Draw the trails:

# List to save data for this frame
frameHistory = []

# Find Perpendicular points
for i in range(len(rainbow)):
color = rainbow[i]
left, right = perpendicular(slope, target, i-3)
left, right = tuple(np.array(left, int)), tuple(np.array(right, int))
point = left
#cv2.circle(img, left, 1, color, 1)
frameHistory.append(point)
history.append(frameHistory)
completeHistory.append(frameHistory)

# Show the history too
a,b,c,d,e,f = zip(*history)
for pointList, color in zip([a,b,c,d,e,f], rainbow):
for i in range(len(pointList)-1):
pass
cv2.line(img, pointList[i], pointList[i+1], color, 2)

# Pop the oldest frame off the history if the history is longer than 0.25 seconds
if len(history)>15:
history.pop(0) Smooth the trails (this is the final output):

#Smooth the data
smoothed = []
a,b,c,d,e,f = zip(*completeHistory)
for i in a,b,c,d,e,f:
x, y = zip(*i)
x = savgol_filter(x, 27, 3)
y = savgol_filter(y, 21, 2)
smoothed.append(list(zip(x,y)))

cap = cv2.VideoCapture('/home/stephen/Desktop/ss5_id_412.MP4')
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('/home/stephen/Desktop/parabola.avi', fourcc, 120.0, (480,848))
### This is the second loop through the video
### In this loop the smoothed rinbow-trail points are diplayed
while True:
for color, line in zip(rainbow, smoothed):
for i in range(len(pointList)-1):
a,b = tuple(np.array(pointList[i], int)), tuple(np.array(pointList[i+1], int))
cv2.line(img, a,b, color, 2) This is SO COOL. Some minor improvements:

from scipy.signal import savgol_filter should be moved to the top of the file

You should be moving your global code into subroutines.

distance can be replaced with the built-in np.linalg.norm.

_,_ = cap.read() does not need any return assignments; just call cap.read().

    left = target - dx, target - dy
right = target + dx, target + dy


would benefit from unpacking:

x, y = target
left = x - dx, y - dy
right = x + dx, y + dy


By PEP8, frameHistory would be frame_history, and pointList to point_list.

You have a bunch of hard-coded paths - these should be parametrized, either to global constants, or a configuration file etc.