FFmpeg: Improved 'Rainbow-Trail' effect

* 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}")"

   # Return full filtergraph, with necessary prefix and suffix filterchains
   printf '%s%s%s' "colorkey=${key}:${colorSim}:${colorBlend},

# 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.


ffmpeg -i video.mkv -vf "
   split [a][b];
   [b1][a]overlay" \

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