vidstab.sh

blog post: http://oioiiooixiii.blogspot.com/2016/09/ffmpeg-video-stabilisation-using.html
download: https://drive.google.com/open?id=0BwPs5IZNFfT1WXh5SFNBMlJTUWc

#!/bin/bash
#set -e -x

################################################################################
#
# Script for setting all vibstab options in FFmpeg, using Zenity interface.
#
# Takes filename as argument - asks for filename otherwise.
# If a filter value is not given by user, then the default value is used.
#
# Ver. 1.0 - 17th June 2016
# Source: http://oioiiooixiii.blogspot.com
#
################################################################################

### VARIABLES ##################################################################

[ ! -z "$1" ] && inFile="$1" || inFile="$(zenity --file-selection)" # Input file
[ "$?" != "0" ] && exit 1 # Catch cancle button

outFile="${inFile%.*}_VIDSTAB.mkv" # Output file

### FUNCTIONS ##################################################################

function displayInterface()
{
   zenity \
      --title="Define vid.stab values" \
      --forms --text="VIDSTABDETECT" \
         --add-entry="[  ] Default: transforms.trf ..... RESULT" \
         --add-entry="[1~10] Default: 5 .............. SHAKINESS" \
         --add-entry="[1~15] Default: 15 ............. ACCURACY" \
         --add-entry="[  ] Default: 6 ........................ STEPSIZE" \
         --add-entry="[0~1] Default: 0.3 ....... MINCONTRAST" \
         --add-entry="[n] Default: 0 .......................... TRIPOD" \
         --add-entry="[0~2] Default: 0 ........................ SHOW" \
         --add-list="--- VIDSTABTRANSFORM ---" \
         --add-entry="[  ] Default: transforms.trf ....... INPUT" \
         --add-entry="[n] Default: 10 ............... SMOOTHING" \
         --add-entry="[gauss/avg] Default: avg ... OPTALGO" \
         --add-entry="[  ] Default: -1 ..................... MAXSHIFT" \
         --add-entry="[-1~360] Default: -1 ......... MAXANGLE" \
         --add-entry="[black/keep] Default: keep ...... CROP" \
         --add-entry="[0/1] Default: 0 ....................... INVERT" \
         --add-entry="[0/1] Default: 0 ................... RELATIVE" \
         --add-entry="[  ] Default: 0 ............................ ZOOM" \
         --add-entry="[0/1/2] Default: 1 .............. OPTZOOM" \
         --add-entry="[0~5] Default: 0.25 ........ ZOOMSPEED" \
         --add-entry="[no/...] Default: bilinear .... INTERPOL" \
         --add-entry="[0/1] Default: 0 ....................... TRIPOD" \
         --add-entry="[0/1] Default: 0 ....................... DEBUG"
}

function buildDetectFilter() # takes full values string; outputs ffmpeg filter
{
   # Convert input string to array
   IFS='|' read -ra valuesArray <<< "$1"
   
   # Array used to hold constructed FFmpeg 'vidstabdetect' filter elements
   detectArray=()

   # RESULT
   resultVal="${valuesArray[0]:-transforms.trf}"
   # Set the path to the file used to write the transforms information. 
   # Default value is transforms.trf.
   detectArray+=(result=$resultVal)

   # SHAKINESS
   shakinessVal="${valuesArray[1]:-5}"
   # Set how shaky the video is and how quick the camera is. It accepts an 
   # integer in the range 1-10, a value of 1 means little shakiness, a  
   # value of 10 means strong shakiness. Default value is 5.
   detectArray+=(shakiness=$shakinessVal)

   # ACCURACY
   accuracyVal="${valuesArray[2]:-15}"
   # Set the accuracy of the detection process. It must be a value in the range 
   # 1-15. A value of 1 means low accuracy, a value of 15 means high accuracy. 
   # Default value is 15.
   detectArray+=(accuracy=$accuracyVal)

   # STEPSIZE
   stepsizeVal="${valuesArray[3]:-6}"
   # Set stepsize of the search process. The region around minimum is scanned 
   # with 1 pixel resolution. Default value is 6.
   detectArray+=(stepsize=$stepsizeVal)

   # MINCONTRAST
   mincontrastVal="${valuesArray[4]:-0.3}"
   # Set minimum contrast. Below this value a local measurement field is 
   # discarded. Must be a floating point value in the range 0-1. Default
   # value is 0.3.
   detectArray+=(mincontrast=$mincontrastVal)

   # TRIPOD
   tripodDVal="${valuesArray[5]:-0}"
   # Set reference frame number for tripod mode.
   # If enabled, the motion of the frames is compared to a reference frame in
   # the filtered stream, identified by the specified number. The idea is to
   # compensate all movements in a more-or-less static scene and keep the 
   # camera view absolutely still. If set to 0, it is disabled. The frames 
   # are counted starting from 1.
   detectArray+=(tripod=$tripodDVal)

   # SHOW
   showVal="${valuesArray[6]:-0}"
   # Show fields and transforms in the resulting frames. It accepts an integer 
   # in the range 0-2. Default value is 0, which disables any visualization. 
   detectArray+=(show=$showVal)
   
   # Create VidStabDetect filter
   printf "vidstabdetect=$(tr ' ' ':'  <<< ${detectArray[@]})"
}

function buildTransformFilter() # takes full values string; outputs filter
{
   # Convert input string into array
   IFS='|' read -ra valuesArray <<< "$1"
   
   # Array used to hold constructed FFmpeg 'vidstabtransform' filter elements
   transformArray=()

   # INPUT
   inputVal="${valuesArray[8]:-transforms.trf}"
   # Set path to the file used to read the transforms. 
   # Default value is transforms.trf
   transformArray+=(input=$inputVal)

   # SMOOTHING
   smoothingVal="${valuesArray[9]:-10}"
   # Set the number of frames (value*2 + 1) used for lowpass filtering the 
   # camera movements. Default value is 10. For example a number of 10 means
   # that 21 frames are used (10 in the past and 10 in the future) to smoothen
   # the motion in the video. A larger value leads to a smoother video, but 
   # limits the acceleration of the camera (pan/tilt movements). 0 is a special
   # case where a static camera is simulated.
   transformArray+=(smoothing=$smoothingVal)

   # OPTALGO
   optalgoVal="${valuesArray[10]:-gauss}"
   # Set the camera path optimization algorithm. Accepted values are:
   # ‘gauss’ gaussian kernel low-pass filter on camera motion (default) 
   # ‘avg’ averaging on transformations
   transformArray+=(optalgo=$optalgoVal)

   # MAXSHIFT
   maxshiftVal="${valuesArray[11]:--1}"
   # Set maximal number of pixels to translate frames. 
   # Default value is -1, meaning no limit.
   transformArray+=(maxshift=$maxshiftVal)

   # MAXANGLE
   maxangleVal="${valuesArray[12]:--1}"
   # Set maximal angle in radians (degree*PI/180) to rotate frames. 
   # Default value is -1, meaning no limit.
   transformArray+=(maxangle=$maxangleVal)

   # CROP
   cropVal="${valuesArray[13]:-keep}"
   # Specify how to deal with borders that may be visible due to movement 
   # compensation. Available values are:
   # ‘keep’ keep image information from previous frame (default) 
   # ‘black’ fill the border black"
   transformArray+=(crop=$cropVal)

   # INVERT
   invertVal="${valuesArray[14]:-0}"
   # Invert transforms if set to 1. Default value is 0.
   transformArray+=(invert=$invertVal)
    
   # RELATIVE
   relativeVal="${valuesArray[15]:-0}"
   # Consider transforms as relative to previous frame if set to 1, 
   # absolute if set to 0. Default value is 0.
   transformArray+=(relative=$relativeVal)

   # ZOOM
   zoomVal="${valuesArray[16]:-0}"
   # Set percentage to zoom. A positive value will result in a zoom-in effect, 
   # a negative value in a zoom-out effect. Default value is 0 (no zoom).
   transformArray+=(zoom=$zoomVal)

   # OPTZOOM
   optzoomVal="${valuesArray[17]:-1}"
   # Set optimal zooming to avoid borders. Accepted values are:
   # ‘0’ disabled 
   # ‘1’ optimal static zoom value is determined (only very strong movements
   #     will lead to visible borders) (default) 
   # ‘2’ optimal adaptive zoom value is determined (no borders will be visible) 
   #     see zoomspeed 
   # Note that the value given at zoom is added to the one calculated here.
   transformArray+=(optzoom=$optzoomVal)

   # ZOOMSPEED
   zoomspeedVal="${valuesArray[18]:-0.25}"
   # Set percent to zoom maximally each frame (enabled when optzoom is set to
   # 2). Range is from 0 to 5, default value is 0.25.
   transformArray+=(zoomspeed=$zoomspeedVal)

   # INTERPOL
   interpolVal="${valuesArray[19]:-bilinear}"
   # Specify type of interpolation. Available values are:
   # ‘no’ no interpolation 
   # ‘linear’ linear only horizontal 
   # ‘bilinear’ linear in both directions (default) 
   # ‘bicubic’ cubic in both directions (slow) 
   transformArray+=(interpol=$interpolVal)

   # TRIPOD
   tripodTVal="${valuesArray[20]:-0}"
   # Enable virtual tripod mode if set to 1, which is equivalent to 
   # relative=0:smoothing=0. Default value is 0. 
   # Use also tripod option of vidstabdetect.
   transformArray+=(tripod=$tripodTVal)
    
   # DEBUG
   debugVal="${valuesArray[21]:-0}"
   # Increase log verbosity if set to 1. Also the detected global motions are 
   # written to the temporary file global_motions.trf. Default value is 0. 
   transformArray+=(debug=$debugVal)

   # Create VidStabTransform filter
   printf "vidstabtransform=$(tr ' ' ':'  <<< ${transformArray[@]})"
}

function displayFilters() # takes strings as input
{
   zenity \
      --width="600" \
      --info \
      --text="$1 \n $2"
}

function logFiltersUsed() # $1 - filename $2/$3 - FFmpeg filters $4 - array vals
{
   printf "**** $(date) ****\n" >> "$1_filters.log"
   printf "ARRAY VALUES: $4\n" >> "$1_filters.log"
   printf "$2\n$3\n\n" >> "$1_filters.log"
}

### BEGIN ######################################################################

# Get filter values from user
values="$(displayInterface)"
[ "$?" != "0" ] && exit 1 # Catch cancle button

# Create VidStabDetect filter
detectFilter="$(buildDetectFilter $values)"
# Create VidStabTransform filter
transformFilter="$(buildTransformFilter $values)"

# Display full filter strings instead of executing FFmpeg
#displayFilters "$detectFilter" "$transformFilter"
logFiltersUsed "$inFile" "$detectFilter" "$transformFilter" "$values"

# First-pass
ffmpeg -i "$inFile" -vf "$detectFilter" -f null -
# Second-pass
ffmpeg -i "$inFile" -vf "$transformFilter" "$outFile" -y

exit 0

### NOTES ######################################################################

# See more: https://ffmpeg.org/ffmpeg-filters.html#vidstabtransform-1