* Includes sound π
I have updated the script for this FFmpeg 'rainbow' effect I created in 2017¹ as there were numerous flaws, errors, and inadequacies in that earlier version. One major issue was the inability to colorkey with any colour other than black; this has been resolved.
This time, the effect is based on the 'extractplanes' filter and the alpha levels created after using a 'colorkey' filter. This produces a much more refined result; better colour shaping, and maintains most of the original foreground subject. This 'extractplanes' filter can even be removed from the filtergraph, to create an alternative, more subtle effect.
#!/usr/bin/env bash
# Generate rainbow-trail video effect with FFmpeg.
# Parameters:
# $1: Filename
# $2: Colorkey value [default: 0000FF]
# $3: Colorkey similarity value [default: 0.3]
# $4: Colorkey blend value [default: 0.1]
# $5: Number of colour iterations [default: 7]
# $6: Delay between colours [default: 0.1]
# $7: Alpha plane extraction [default: true]
# version: 2020.07.20_13.54.28
# - This version uses alpha plane extraction to significantly improve quality
# and allows for correct keying with colours other than black. Alpha plane
# extraction can be disabled for an alternative effect.
# - Created & tested with FFmpeg 4.3.1, GNU Bash 4.4.2, and Ubuntu MATE 18.04
# source: http://oioiiooixiii.blogspot.com
function rainbowFilter()
{
local iterations="${4:-7}" # Number of colour layers
local delay="${5:-0.1}" # Delay between appearance of each colour layer
local ptsDelay=0 # Tally for delay between colour layers
local key="0x${1:-0000FF}" # Colorkey colour
local colorSim="${2:-0.3}" # Colorkey similarity level
local colorBlend="${3:-0.1}" # Colorkey blending level
local filtergraph="" # Used to store for-loop generated filterchains
# Sets the state of the extractplanes filter
[[ "$6" == "false" ]] \
&& local extractFilter="null" || local extractFilter="extractplanes=a"
declare -a colours # Array of colours
colours+=("2:0:0:0:0:0:0:0:2:0:0:0") # Violet
colours+=(".5:0:0:0:0:0:0:0:2:0:0:0") # Indigo
colours+=("0:0:0:0:0:0:0:0:2:0:0:0") # Blue
colours+=("0:0:0:0:2:0:0:0:0:0:0:0") # Green
colours+=("2:0:0:0:2:0:0:0:0:0:0:0") # Yellow
colours+=("2:0:0:0:.5:0:0:0:0:0:0:0") # Orange
colours+=("2:0:0:0:0:0:0:0:0:0:0:0") # Red
# Build colour layers part of filtergraph
for (( i=0;i<${iterations};i++ ))
{
# 'bc' command used for floating point addition
ptsDelay="$(bc <<<"${ptsDelay}+${delay}")"
filtergraph="[original]split[original][top];
[top]colorkey=${key}:${colorSim}:${colorBlend},
${extractFilter},
colorchannelmixer=${colours[$((i%7))]},
setpts=PTS+$ptsDelay/TB,
chromakey=black:0.01:0.1[top];
[bottom][top]overlay[bottom];
${filtergraph}"
}
# Return full filtergraph, with necessary prefix and suffix filterchains
printf '%s%s%s' "colorkey=${key}:${colorSim}:${colorBlend},
split[original][bottom];
[bottom]colorchannelmixer=0:0:0:0:0:0:0:0:0:0:0:0[bottom];"\
"${filtergraph}"\
"[bottom][original]overlay"
}
# Alter/replace FFmpeg command to desired specification
ffmpeg -i "$1" -vf "$(rainbowFilter "${@:2}")" -crf 10 "${1}_rainbow.mkv"
download: ffmpeg-rainbow-2020.sh I have rewritten some parts of the script specifically to make things a bit clearer, which I hope is the case. In this vein, I have also included an alternative filtergraph, which lays out the basic process, without need for a for-loop.
violet="colorchannelmixer=2:0:0:0:0:0:0:0:2:0:0:0" indigo="colorchannelmixer=.5:0:0:0:0:0:0:0:2:0:0:0" blue="colorchannelmixer=0:0:0:0:0:0:0:0:2:0:0:0" green="colorchannelmixer=0:0:0:0:2:0:0:0:0:0:0:0" yellow="colorchannelmixer=2:0:0:0:2:0:0:0:0:0:0:0" orange="colorchannelmixer=2:0:0:0:.5:0:0:0:0:0:0:0" red="colorchannelmixer=2:0:0:0:0:0:0:0:0:0:0:0" ffmpeg -i video.mkv -vf " split [a][b]; [b]colorkey=0x0000FF:0.3:0.1, extractplanes=a,split=7[b1][b2][b3][b4][b5][b6][b7]; [b1]${red},setpts=PTS+0.7/TB[b1]; [b2]${orange},setpts=PTS+0.6/TB,chromakey=black:0.01:0.1[b2]; [b1][b2]overlay[b1]; [b3]${yellow},setpts=PTS+0.5/TB,chromakey=black:0.01:0.1[b3]; [b1][b3]overlay[b1]; [b4]${green},setpts=PTS+0.4/TB,chromakey=black:0.01:0.1[b4]; [b1][b4]overlay[b1]; [b5]${blue},setpts=PTS+0.3/TB,chromakey=black:0.01:0.1[b5]; [b1][b5]overlay[b1]; [b6]${indigo},setpts=PTS+0.2/TB,chromakey=black:0.01:0.1[b6]; [b1][b6]overlay[b1]; [b7]${violet},setpts=PTS+0.1/TB,chromakey=black:0.01:0.1[b7]; [b1][b7]overlay[b1]; [a]colorkey=0x0000FF:0.4:0.1[a]; [b1][a]overlay" \ output.mkv
As demonstrated in the example videos, the filtergraph produces an effect with a transparent background, which allows it to be used on top of other sources, or rendered in a video codec that allows transparency. The script arguments for each quadrant (top left; clockwise):
source video ffmpeg-rainbow-2020.sh video.mkv "" "" "" "14" ffmpeg-rainbow-2020.sh video.mkv ffmpeg-rainbow-2020.sh video.mkv "" "" "" "28" "0.07" "false"
[ 2020-09-01 | video removed ]
¹ original 2017 version: https://oioiiooixiii.blogspot.com/2017/09/ffmpeg-rainbow-trail-chromakey-effect.html
'extractplanes' documentation: https://ffmpeg.org/ffmpeg-filters.html#extractplanes
motivation: https://twitter.com/av_morgan/status/1283630773308809217
source video (Fanny - "Ain't that peculiar" (Beat-Club, 1972)): https://www.youtube.com/watch?v=imZUqkPlUaQ