Search code examples
ffmpegvideo-processing

ffmpeg: zoom image to positions X Y (zoompan)


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


Solution

  • 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
    
    1. 3 - max zoom (times). Default 2.5.
    2. 6 - duration (seconds). Default 5.
    3. 1200 - X coordinate (pixels) to zoom in.
    4. 1800 - Y coordinate (pixels) to zoom in.

    The result:

    ffmpeg video of zooming in to a custom point

    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"