script to use ffmpeg to animate images with the "Ken Burns Effect"

interpretive language scripts


Moderator: Forum moderators

Post Reply
HerrBert
Posts: 370
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 21 times
Been thanked: 136 times

script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by HerrBert »

What it's about:

Especially after christmas i was 'spammed' with a lot of photos by some family members, asking if i could make a video-slide-show of them. Of course, i can. Problem is that nowadays most people take photos with a mobile phone in portrait mode...

Add black borders to fill vertical hd to horizontal hd :/ The result is more than dissapointing.

I recall on my imac there was a screensaver zooming and panning a picture. Did some search on the internet and found it is called the Ken-Burns-Effect. Further searching led to some few results for using ffmpeg on linux to achieve this animation effect.
Threw together a script to get what i wanted.

Not at least because of the few search results i thought about posting a script to give some more advanced options to use the zoompan filter of ffmpeg (not only in Puppy Linux...).

Code: Select all

#!/bin/bash

# Abhängigkeiten: bc, ffprobe, ffmpeg, urxvt, mtpaint (optional)

GEOMETRY=1280x720
TIME=5
FPS=30
INTRO=1
STILL=1
ACC="time"

[ -e "$1" ] && INFILE="$1" && shift # dnd

# rudimental:
chkarg() { [ "$(tr -d [:digit:]$3 <<< "$2")" = "" ] || { echo "invalid argument to option: $1 $2"; DRYRUN="error"; }; }

while [ "$1" ]; do
	case $1 in
		--debug) set -x; HOLD="-hold";;
		-i) [ "$2" ] && shift && INFILE="$1";;
		-o) [ "$2" ] && shift && OUTFILE="$1";;
		-fps) chkarg "$1" "$2" "" && shift && FPS=$1;;
		-d) chkarg "$1" "$2" "" && shift && TIME=$1;;
		-u) chkarg "$1" "$2" "" && shift && UPSCALE="$1";;
		-p) chkarg "$1" "$2" "" && shift && INTRO=$1;;
		-w) chkarg "$1" "$2" "" && shift && STILL=$1;;
		-f) chkarg "$1" "$2" "" && shift && F_IN="$1";;
		-b) chkarg "$1" "$2" "" && shift && F_OUT="$1";;
		-x|-x1) chkarg "$1" "$2" "-" && shift && X1="$1";;
		-x2) chkarg "$1" "$2" "-" && shift && X2="$1";;
		-y|-y1) chkarg "$1" "$2" "" && shift && Y1=$1;;
		-y2) chkarg "$1" "$2" "" && shift && Y2=$1;;
		-z|-z1) chkarg "$1" "$2" "." && shift && Z1=$1;;
		-z2) chkarg "$1" "$2" "." && shift && Z2=$1;;
		-g) chkarg "$1" "$2" "x" && shift && GEOMETRY=$1;;
		-s) chkarg "$1" "$2" "xy" && shift && SYNC=$1;;
		-a) ACC="zoom";;
		-e) OVR="-y";;
		-v) VERBOSE=true;;
		-m) DRYRUN="true";VERBOSE=true;PREVIEW=true;;
		-n) DRYRUN="true";VERBOSE=true;;
		-h|--help) echo "usage: ${0##*/} -i FILE OPTIONS

Options:
	-i	input file
	-o	output file name (can be full path and|or file name)
	-a	force acceleration method zoom
	-b I	blank time (fade out)
	-d I	duration - total length of output video
	-e	overwrite existing file
	-f I	fade in time
	-fps I	frames per second (default: 30)
	-g WxH	geometry of output video (default: 1280x720)
	-h	show this help
	-m	preview zoom areas in mtpaint
	-n	dryrun - show some info and exit
	-p I	pause time after zoompan
	-s [xy]	sync pan and zoom speed for x and/or y
	-u I	upscale (default: width+4000)
	-v	verbose output
	-w I	wait time before zoompan
	-x I	horizontal start position (default: 0)
	-x2 I	horizontal stop position (default: 0)
	-y I	vertical start position (default: 0)
	-y2 I	vertical stop position (default: bottom of image)
	-z D	start zoom factor (default: fit to image width)
	-z2 D	stop zoom factor (default: fit to image width)
"; exit;;
	esac
	shift
done

[ -z "$INFILE" ] && exit
[ -d "$OUTFILE" ] && OUTNAME="${INFILE##*/}" && OUTFILE="$OUTFILE/${OUTNAME%.*}_zoompan.mp4"

SIZE="$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0:s=x "$INFILE")"
INWIDTH=${SIZE%%x*}
INHEIGHT=${SIZE##*x}

# upscaling
(( INWIDTH > INHEIGHT )) && {
	(( INHEIGHT < 4000 || UPSCALE )) && SCALE="scale=-2:${UPSCALE:-ih+400$((INHEIGHT % 2))}," || :
} || {
	(( INWIDTH < 4000 || UPSCALE )) && SCALE="scale=${UPSCALE:-iw+400$((INWIDTH % 2))}:-2,"
}

# padding
OUTHEIGHT=${GEOMETRY##*x}
OUTWIDTH=${GEOMETRY%%x*}
OUTASPECT="$(bc <<< "scale=4;$OUTWIDTH / $OUTHEIGHT")"
(( $(bc <<< "scale=4;$INWIDTH / $INHEIGHT > $OUTASPECT") )) && {
	echo "vertical padding not available..."
	exit
}
PAD="pad=ih*${OUTWIDTH}/${OUTHEIGHT}:ih:(ow-iw)/2:(oh-ih)/2,"
PADWIDTH="$((INHEIGHT * OUTWIDTH / OUTHEIGHT))"

OUTWIDTH=$(( OUTWIDTH - (OUTWIDTH % 2) ))
OUTHEIGHT=$(( OUTHEIGHT - (OUTHEIGHT % 2) ))

# ffmpeg zoompan filter
# zoom
[ -z "$Z1" ] && Z1=$(bc <<< "scale=6;$PADWIDTH / $INWIDTH")
[ -z "$Z2" ] && Z2=$(bc <<< "scale=6;$PADWIDTH / $INWIDTH")

DURATION=$((TIME * FPS))
PAUSE=$((INTRO * FPS))
WAIT=$((STILL * FPS))
NET=$((DURATION - PAUSE - WAIT))

(( $(bc <<< "scale=4;$Z1 > $Z2") )) && { # zoom out
	STEP=$(bc <<< "scale=6;($Z1 - $Z2) / $NET")
	[ "$ACC" = "time" ] && {
		DIRECTION="if(lte(on,$WAIT),$Z1,max(zoom-$STEP,$Z2))"
	} || {
		DIRECTION="if(lte(on,$WAIT),$Z1,zoom-$STEP*max((2-(on-$WAIT)/($NET+1)*2),0))" # S-Kurve linksrechtsmitte
	}
} || { # zoom in
	STEP=$(bc <<< "scale=6;(($Z2-1) - ($Z1-1)) / $NET")
	[ "$ACC" = "time" ] && {
		DIRECTION="if(lte(on,$WAIT),$Z1,min(zoom+$STEP,$Z2))"
	} || {
		DIRECTION="if(lte(on,$WAIT),$Z1,min(zoom+$STEP*(on-$WAIT)/$NET*2,$Z2))" # S-Kurve linksrechtsmitte
	}
}

# pan
# engine
[ "$Z1" = "$Z2" -o "$ACC" = "time" ] && {
	ENGINE="if(lte(on,$WAIT),0,min((on-$WAIT)/$NET,1))"
} || {
	ENGINE="(zoom-$Z1)/($Z2-$Z1)"
}

[[ $SYNC = *x* ]] && SX="*$Z2/zoom"

OFFSET=$(( (PADWIDTH - INWIDTH) / 2 ))
XDIFF=$(bc <<< "scale=6;(($OFFSET + ${X2:-0}) - ($OFFSET + ${X1:-0})) / $PADWIDTH")
PAN_X="iw*$(bc <<< "scale=6;($OFFSET + ${X1:-0}) / $PADWIDTH")+iw*$XDIFF*$ENGINE$SX"

[[ $SYNC = *y* ]] && SY="*$Z2/zoom"
[ -z "$Y2" ] && Y2=$(bc <<< "$INHEIGHT - $INHEIGHT / $Z2")

YDIFF=$(bc <<< "scale=6;($Y2 - ${Y1:-0}) / $INHEIGHT")
PAN_Y="ih*$(bc <<< "scale=6;${Y1:-0} / $INHEIGHT")+ih*$YDIFF*$ENGINE$SY"

# fade
[ "$F_IN" ] && FADE_IN=",fade=t=in:st=0:d=$F_IN"
[ "$F_OUT" ] && FADE_OUT=",fade=t=out:st=$((TIME - F_OUT)):d=$F_OUT"

# info
[ "$VERBOSE" ] && {
	PX1=$(( $OFFSET + ${X1:-0} ))
	PX2=$(( $OFFSET + ${X2:-0} ))
	PZ1="$(bc <<< "$PADWIDTH / $Z1"):$(bc <<< "$PADWIDTH * $OUTHEIGHT / $OUTWIDTH / $Z1")"
	PZ2="$(bc <<< "$PADWIDTH / $Z2"):$(bc <<< "$PADWIDTH * $OUTHEIGHT / $OUTWIDTH / $Z2")"
	echo "Input image geometry: $SIZE"
	echo "Output video geometry: ${OUTWIDTH}x${OUTHEIGHT}"
	echo "Pad window width: $PADWIDTH"
	echo "Left padding is $OFFSET"
	echo "Zoom is $Z1 to $Z2"
	echo "Zoom window geometry: $PZ1:$PX1:${Y1:-0} to $PZ2:$PX2:$Y2"
	echo "Acceleration method is $ACC"
}

[ "$PREVIEW" ] && {
	[ -z "$(which mtpaint)" ] && echo "mtpaint not found. Exiting..." && exit
	PREVIEW="/tmp/ffzoompan_tmp/${INFILE##*/}"
	[ ! -d "${PREVIEW%/*}" ] && mkdir -p "${PREVIEW%/*}"
	mtpaint --cmd -f/open="$INFILE" -s/all -e/copy -f/new w=$PADWIDTH h=$INHEIGHT =24 -e/centre -e/Brush Size=3 -e/col A=2 -s/all \($PX1,${Y1:-0},${PZ1%:*},${PZ1##*:}\) -s/"Outline Selection" -e/col A=1 -s/all \($PX2,$Y2,${PZ2%:*},${PZ2##*:}\) -s/"Outline Selection" -f/as="${PREVIEW%.*}_preview.jpg" f=jpeg 1>/dev/null
	echo
	echo "NOTICE:"
	echo "When using coordinates from preview image keep in mind that x is absolute to the original image and you have to substract padding... "
	echo "e.g. -x \$((coord - $OFFSET))"
	echo
	mtpaint "${PREVIEW%.*}_preview.jpg" & exit
}

[ "$DRYRUN" ] && echo "Exiting now (dryrun)" && exit

# run in separate window
urxvt $HOLD -e ffmpeg $OVR -i "$INFILE" -vf "${SCALE}${PAD}zoompan=z='${DIRECTION}':d='${DURATION}':x='${PAN_X}':y='${PAN_Y}':s=${OUTWIDTH}x${OUTHEIGHT}:fps=${FPS}${FADE_IN}${FADE_OUT}" -pix_fmt yuv420p -c:v libx264 -crf 24 -preset veryfast "${OUTFILE:-${INFILE%.*}_zoompan.mp4}"

Notice the amount of options. Try out what works for you...

Have fun and stay curious ;)

User avatar
Flash
Moderator
Posts: 1023
Joined: Tue Dec 03, 2019 3:13 pm
Location: Arizona, U.S.
Has thanked: 58 times
Been thanked: 138 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by Flash »

Here's an excellent YouTube video describing the 'Ken Burns Effect' and how to make it happen. It's basically just zooming and panning within the still frame.

Chaos coordinator :?
HerrBert
Posts: 370
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 21 times
Been thanked: 136 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by HerrBert »

Flash wrote: Sat Mar 30, 2024 10:08 pm

Here's an excellent YouTube video describing the 'Ken Burns Effect' and how to make it happen. It's basically just zooming and panning within the still frame.
...

One of my favourites... But how do you do it in Puppyland?

[edit]removed repeated url to youtube video[/edit]

User avatar
rockedge
Site Admin
Posts: 7021
Joined: Mon Dec 02, 2019 1:38 am
Location: Connecticut,U.S.A.
Has thanked: 3147 times
Been thanked: 2933 times
Contact:

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by rockedge »

part of the Ken Burns Effect is cutting out foreground objects and pasting them back in the original position on a new layer. Possibly several objects on individual layers or alpha channels. Then panning the background separated from the stationary foreground object. You see the full effect used in Ken Burns' documentaries.

User avatar
greengeek
Posts: 1549
Joined: Thu Jul 16, 2020 11:06 pm
Has thanked: 651 times
Been thanked: 228 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by greengeek »

HerrBert wrote: Sat Mar 30, 2024 9:39 pm

Did some search on the internet and found it is called the Ken-Burns-Effect. Further searching led to some few results for using ffmpeg on linux to achieve this animation effect.
Threw together a script to get what i wanted.
......
Notice the amount of options. Try out what works for you...

Have fun and stay curious ;)

Does it have any form of gui or is it cli only?
Do i need to specify a single image file or does it look for a directory of images?

Very interesting concept. Hoping to get it working in Fossa 9.5

HerrBert
Posts: 370
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 21 times
Been thanked: 136 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by HerrBert »

@greengeek
The script in the first post has no gui.
I've written a very basic yad gui for personal use. Works with a modified version of the main script.
[edit]
If you start with a new file, all entries are empty.
To get basic values click mtPaint. This creates a preview of zoom areas and auto fills the most important entries.
[/edit]

yad_gui_ffzoompan.jpg
yad_gui_ffzoompan.jpg (30.73 KiB) Viewed 1881 times

I'll attache both in a tared folder. Use at own risk.
Make sure to decompress the archive to a location that does not contain a directory named zoompan!

zoompan-0.2.tar.gz
(4.75 KiB) Downloaded 9 times

And yes, a single image has to be specified.

Last edited by HerrBert on Mon Feb 24, 2025 12:47 pm, edited 3 times in total.
User avatar
greengeek
Posts: 1549
Joined: Thu Jul 16, 2020 11:06 pm
Has thanked: 651 times
Been thanked: 228 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by greengeek »

Wow! That's amazing!!
I could not get it to work initially - but then I copied your sample settings from the gui image in your post - and the result was fantastic.
Well done! Awesome stuff. :thumbup: :thumbup: :thumbup: :!: :!:

I just grabbed a still pic from a dashcam shot for testing.
(This zoompan effect will be great for family photos!)

Remove false .gz suffix

pic01_zoompan.mp4.gz
Remove false .gz suffix
(226.75 KiB) Downloaded 44 times
HerrBert
Posts: 370
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 21 times
Been thanked: 136 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by HerrBert »

@greengeek
Forgot to mention how to use the gui. Sorry.
If you start with a new file, all entries are empty.
To get basic values click mtPaint. This creates a preview of zoom areas and auto fills the most important entries.
(also added instruction to my previous post)

ozsouth
Posts: 1713
Joined: Sun Jul 12, 2020 2:38 am
Location: S.E. Australia
Has thanked: 260 times
Been thanked: 780 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by ozsouth »

Just got sent this by MyHeritage - seems similar:

We invite you to try LiveMemory™, our incredible new AI feature that enables you to relive your favorite memories by turning any photo into a short video clip! The video reimagines the scene as if you were watching it live, and is perfect for sharing with family and friends. LiveMemory™ is available on the MyHeritage mobile app for iOS and Android.

User avatar
greengeek
Posts: 1549
Joined: Thu Jul 16, 2020 11:06 pm
Has thanked: 651 times
Been thanked: 228 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by greengeek »

@HerrBert I have been having a lot of fun with this little utility!
We had our 6 year old grandson over for the weekend and he loves playing with his Lego. He came up with a "tunnel boring machine" complete with a working set of gears so he could turn the boring head by hand.
So I decided to see if I could bring some Ken Burns life into the photo and I love how it looks.
Thanks so much for this!
(Remove .gz suffix to view mp4 video)

TunnelBoringMachine_zoompan.mp4.gz
Remove false .gz suffix
(418.09 KiB) Downloaded 21 times
User avatar
rockedge
Site Admin
Posts: 7021
Joined: Mon Dec 02, 2019 1:38 am
Location: Connecticut,U.S.A.
Has thanked: 3147 times
Been thanked: 2933 times
Contact:

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by rockedge »

Excellent little video. Machine does look like it can drill a tunnel or perhaps mine for Gold!!

HerrBert
Posts: 370
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 21 times
Been thanked: 136 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by HerrBert »

Updated the tar file in previous post viewtopic.php?p=138528#p138528

Just some minor changes and fixes.
Added a help button for options.
Now ROX Application. Drag 'n drop an image onto it to start with the gui.

Still made for personal use... Use at own risk.

User avatar
greengeek
Posts: 1549
Joined: Thu Jul 16, 2020 11:06 pm
Has thanked: 651 times
Been thanked: 228 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by greengeek »

HerrBert wrote: Sun Feb 23, 2025 3:53 pm

Updated the tar file in previous post viewtopic.php?p=138528#p138528

Just some minor changes and fixes.
Added a help button for options.
Now ROX Application. Drag 'n drop an image onto it to start with the gui.

Still made for personal use... Use at own risk.

I think the AppRun symlink is incorrectly formed. Won't run for me.

HerrBert
Posts: 370
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 21 times
Been thanked: 136 times

Re: script to use ffmpeg to animate images with the "Ken Burns Effect"

Post by HerrBert »

greengeek wrote: Sun Feb 23, 2025 7:42 pm

I think the AppRun symlink is incorrectly formed. Won't run for me.

You're right. Made an absolute symbolic link instead of relative. My mistake. :oops:
Updated tar file in viewtopic.php?p=138528#p138528

Post Reply

Return to “Scripts”