FFmpeg: Improved 'Rainbow-Trail' effect


Video Player is loading.
Current Time 0:00
Duration 0:00
Loaded: 0%
Stream Type LIVE
Remaining Time 0:00
 
1x
    • Chapters
    • descriptions off, selected
    • captions off, selected

      * 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