question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Zoom-In Effect for moviepy

See original GitHub issue

I am trying to create a video from slides. Each slide has a zoom-in effect. All the code examples for creating the zoom-in effect gave poor results if the zoom speed is very slow. The side effect was a slight twitching.

Below I will provide examples that the documentation offers and the function that I offer.

The problem I faced too: https://github.com/Zulko/moviepy/issues/183

Example from documentation

https://zulko.github.io/moviepy/ref/videofx/moviepy.video.fx.all.resize.html

import moviepy.editor as mp

size = (1920, 1080)

img = 'https://www.colorado.edu/cumuseum/sites/default/files/styles/widescreen/public/slider/coachwhip2_1.jpg'

slide = mp.ImageClip(img).set_fps(25).set_duration(10).resize(size)

slide = slide.resize(lambda t: 1 + 0.04 * t)  # Zoom-in effect
slide = slide.set_position(('center', 'center'))
slide = mp.CompositeVideoClip([slide], size=size)

slide.write_videofile('zoom-test-1.mp4')

Result: https://youtu.be/qlU_4hVFm6I

My function

Slideshow example: https://gist.github.com/mowshon/2a0664fab0ae799734594a5e91e518d5

import moviepy.editor as mp
import math
from PIL import Image
import numpy


def zoom_in_effect(clip, zoom_ratio=0.04):
    def effect(get_frame, t):
        img = Image.fromarray(get_frame(t))
        base_size = img.size

        new_size = [
            math.ceil(img.size[0] * (1 + (zoom_ratio * t))),
            math.ceil(img.size[1] * (1 + (zoom_ratio * t)))
        ]

        # The new dimensions must be even.
        new_size[0] = new_size[0] + (new_size[0] % 2)
        new_size[1] = new_size[1] + (new_size[1] % 2)

        img = img.resize(new_size, Image.LANCZOS)

        x = math.ceil((new_size[0] - base_size[0]) / 2)
        y = math.ceil((new_size[1] - base_size[1]) / 2)

        img = img.crop([
            x, y, new_size[0] - x, new_size[1] - y
        ]).resize(base_size, Image.LANCZOS)

        result = numpy.array(img)
        img.close()

        return result

    return clip.fl(effect)


size = (1920, 1080)

img = 'https://www.colorado.edu/cumuseum/sites/default/files/styles/widescreen/public/slider/coachwhip2_1.jpg'

slide = mp.ImageClip(img).set_fps(25).set_duration(10).resize(size)
slide = zoom_in_effect(slide, 0.04)

slide.write_videofile('zoom-test-2.mp4')

Result: https://youtu.be/U-A54E00sC8

In my example, there is also a slight wobble, but not as obvious as in the first example. Below is a link to a video where you can compare both options.

Comparation video: https://www.youtube.com/watch?v=UPyYdrwWE14

  • Left side: My function
  • Right side: Example from docs

I would be glad to get advice on improving the code.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
jcbrockschmidtcommented, Jan 11, 2021

Looking at the various resizers in moviepy/video/fx/resize.py it looks like they are in fact casting the width and height to ints. I’m wondering if the aliasing algorithms can account for fractions of pixels. But that may be beyond the scope of what moviepys contract covers, as it’s using OpenCV, Pillow, and SciPy to resize.

Proposed solution

Always maintain the ratio of width-to-height by first calculating the new width, then calculating the height based on the width. So replace

        new_size = [
            math.ceil(img.size[0] * (1 + (zoom_ratio * t))),
            math.ceil(img.size[1] * (1 + (zoom_ratio * t)))
        ]

        # The new dimensions must be even.
        new_size[0] = new_size[0] + (new_size[0] % 2)
        new_size[1] = new_size[1] + (new_size[1] % 2)

with something like

w, h = img.size
new_w = w * (1 + (zoom_ratio * t))
new_h = new_w * (h / w)
# Determine the height based on the new width to maintain the aspect ratio.
new_size = (new_w, new_h)
0reactions
kalloszsoltycommented, Mar 30, 2022

At the end, I ended up generating separate videos of zooming with command line ffmpeg (credits to: https://superuser.com/a/1112680)

import subprocess

def run_ffmpeg_zoom(image_path, output_file, screensize, duration=5, fps=25, zoom_ratio=0.0015, zoom_smooth=5):
    ffmpeg_command = f"""./ffmpeg -framerate {fps} -loop 1 -i {image_path} -filter_complex "[0:v]scale={screensize[0] * zoom_smooth}x{screensize[1] * zoom_smooth},
    zoompan=z='min(zoom+{zoom_ratio},1.5)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d={duration * fps},trim=duration={duration}[v1];[ 
    v1]scale={screensize[0]}:{screensize[1]}[v]" -map "[v]" -y {output_file}"""
    process = subprocess.Popen(ffmpeg_command, shell=True, stdout=subprocess.PIPE)
    process.wait()

increase the zoom_smooth parameter for example to 10 to get a smoother zoom (it will also take you more time/resources)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Moviepy zooming effects need tweaking - Stack Overflow
I am using moviepy module. With the following code I can progressively zoom a clip, but having a hard time figuring out how...
Read more >
Clips transformations and effects — MoviePy 1.0.2 ...
video.fx and moviepy.audio.fx and are applied with the clip.fx method, for instance ...
Read more >
Zoom out effect? : r/moviepy - Reddit
I saw issue #183 about creating a zoom in effect and it works great. My question now is how would I do something...
Read more >
Developers - Zoom-In Effect for moviepy - - Bountysource
Zoom-In Effect for moviepy ... I am trying to create a video from slides. Each slide has a zoom-in effect. All the code...
Read more >
Moviepy Enlarging And Zooming In Video Outputs - ADocLib
In this tutorial, we will use MoviePy, a Python library, to edit and add effects to a given If you have to edit...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found