Reputation: 43
I'm using ffmpeg to zoom an image to a specific point (x, y).
I want the point to be the final position of the zoom. The command I use now is:
ffmpeg -y -i zoomInimg.jpg -vf "scale=6198:2350:-1,zoompan=z='min(max(zoom,pzoom)+0.06,10)':d=2400:x=4000 :y=1000 :s=6198x2350" -t 5 zoomIn.mp4
I want to have a video of zooming an image to the point (x=4000, y=1000).
Upvotes: 2
Views: 3086
Reputation: 17181
I made some small improvements in the answer of Eugene Khyst (with the help of ChatGPT 4).
The following script let you choose the output name and randomize a coordinate x,y. The size of input now is irrelevant too.
#!/bin/bash
# Based on: https://stackoverflow.com/a/72329573/450148
# Example: <cmd> image.JPG output.mp4 3 6
# max zoom (times). Default 2.5.
# duration (seconds). Default 5.
INPUT="$1"
OUTPUT="$2"
MAX_ZOOM="${3:-2.5}"
DURATION_SECONDS="${4:-5}"
FPS="30"
DURATION=$(bc <<< "${DURATION_SECONDS}*${FPS}")
ZOOM_SPEED=$(bc <<< "scale=6;(${MAX_ZOOM}-1)/${DURATION}")
SIZE=$(ffprobe -v error -select_streams v -show_entries stream=width,height -of csv=p=0:s=x "$INPUT")
OW=$(echo $SIZE | cut -d'x' -f1)
OH=$(echo $SIZE | cut -d'x' -f2)
# Randomly select X and Y coordinates
XP=$(shuf -i 0-$OW -n 1)
YP=$(shuf -i 0-$OH -n 1)
# Use the original image size
W=$OW
H=$OH
# Ensure width and height are divisible by 2
W=$((W % 2 == 0 ? W : W - 1))
H=$((H % 2 == 0 ? H : H - 1))
ffmpeg -y -loop 1 -i "$INPUT" -vf "scale=iw*6:ih*6,zoompan=z='zoom+${ZOOM_SPEED}':x='$XP':y='$YP':d=$DURATION:s='${W}x${H}'" -c:v libx264 -pix_fmt yuv420p -t $DURATION_SECONDS -shortest "$OUTPUT"
Upvotes: 0
Reputation: 10315
The ffmpeg
command to use zoom in to a custom point of an image:
ffmpeg -i "$INPUT" \
-vf "zoompan=z='min(zoom+${ZOOM_SPEED},${MAX_ZOOM})':x='iw/2-iw*(1/2-${XP}/100)*on/${DURATION}-iw/zoom/2':y='ih/2-ih*(1/2-${YP}/100)*on/${DURATION}-ih/zoom/2':d=${DURATION}:fps=${FPS}:s=${W}x${H}" \
-c:v libx264 "$OUTPUT" -y
ffprobe
can be used to get the original image dimension.
I created a convenient script image_to_video_zoom.sh
to create a video of zooming to a custom point of an image and controlling a zoom level and duration of the video:
#!/bin/bash
INPUT="$1"
OUTPUT="${INPUT%%.*}_zoom.MP4"
MAX_ZOOM="${2:-2.5}"
DURATION_SECONDS="${3:-5}"
FPS="30"
DURATION=$(bc <<< "${DURATION_SECONDS}*${FPS}")
ZOOM_SPEED=$(bc <<< "scale=4;(${MAX_ZOOM}-1)/${DURATION}")
SIZE=$(ffprobe -v error -select_streams v -show_entries stream=width,height -of csv=p=0:s=x "$INPUT")
OW=$(echo $SIZE | cut -d'x' -f1)
OH=$(echo $SIZE | cut -d'x' -f2)
if (( $(bc -l <<< "scale=4;${OW}/${OH} >= 16/9") ))
then
R=$(bc <<< "scale=4;${OH}/1080")
W=$(bc <<< "${OW}/${R}")
H=$(bc <<< "${OH}/${R}")
else
R=$(bc <<< "scale=4;${OW}/1920")
W=$(bc <<< "${OW}/${R}")
H=$(bc <<< "${OH}/${R}")
if (( $(bc <<< "${H}%2") ))
then
H=$(bc <<< "${H}-1")
fi
fi
if [[ -z "$4" || -z "$5" ]]
then
XP="50"
YP="50"
else
XP=$(bc <<< "100*${4}/${OW}")
YP=$(bc <<< "100*${5}/${OH}")
fi
ffmpeg -i "$INPUT" \
-vf "zoompan=z='min(zoom+${ZOOM_SPEED},${MAX_ZOOM})':x='iw/2-iw*(1/2-${XP}/100)*on/${DURATION}-iw/zoom/2':y='ih/2-ih*(1/2-${YP}/100)*on/${DURATION}-ih/zoom/2':d=${DURATION}:fps=${FPS}:s=${W}x${H}" \
-c:v libx264 "$OUTPUT" -y
Example:
./image_to_video_zoom.sh image.JPG 3 6 1200 1800
3
- max zoom (times). Default 2.5.6
- duration (seconds). Default 5.1200
- X coordinate (pixels) to zoom in.1800
- Y coordinate (pixels) to zoom in.The result:
The script allows controlling the zoom level, duration of the video and point to zoom in. If a point to zoom in is not specified, the script will create a video of zooming to the center of the image.
The resulting video is proportionally scaled to have height 1080 or width 1920 depending on the aspect ratio (16:9).
Video with width 1920 and height greater than 1080 can be cropped to 1920x1080 using crop filter:
ffmpeg -i "$INPUT" -filter:v "crop=1920:1080" "$OUTPUT"
Upvotes: 5