generated from thinkode/modelRepository
84 lines
2.3 KiB
Python
84 lines
2.3 KiB
Python
|
|
from dataclasses import dataclass
|
||
|
|
|
||
|
|
from moviepy.Effect import Effect
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class AccelDecel(Effect):
|
||
|
|
"""Accelerates and decelerates a clip, useful for GIF making.
|
||
|
|
|
||
|
|
Parameters
|
||
|
|
----------
|
||
|
|
|
||
|
|
new_duration : float
|
||
|
|
Duration for the new transformed clip. If None, will be that of the
|
||
|
|
current clip.
|
||
|
|
|
||
|
|
abruptness : float
|
||
|
|
Slope shape in the acceleration-deceleration function. It will depend
|
||
|
|
on the value of the parameter:
|
||
|
|
|
||
|
|
* ``-1 < abruptness < 0``: speed up, down, up.
|
||
|
|
* ``abruptness == 0``: no effect.
|
||
|
|
* ``abruptness > 0``: speed down, up, down.
|
||
|
|
|
||
|
|
soonness : float
|
||
|
|
For positive abruptness, determines how soon the transformation occurs.
|
||
|
|
Should be a positive number.
|
||
|
|
|
||
|
|
Raises
|
||
|
|
------
|
||
|
|
|
||
|
|
ValueError
|
||
|
|
When ``sooness`` argument is lower than 0.
|
||
|
|
|
||
|
|
Examples
|
||
|
|
--------
|
||
|
|
|
||
|
|
The following graphs show functions generated by different combinations
|
||
|
|
of arguments, where the value of the slopes represents the speed of the
|
||
|
|
videos generated, being the linear function (in red) a combination that
|
||
|
|
does not produce any transformation.
|
||
|
|
|
||
|
|
.. image:: /_static/medias/accel_decel-fx-params.png
|
||
|
|
:alt: acced_decel FX parameters combinations
|
||
|
|
"""
|
||
|
|
|
||
|
|
new_duration: float = None
|
||
|
|
abruptness: float = 1.0
|
||
|
|
soonness: float = 1.0
|
||
|
|
|
||
|
|
def _f_accel_decel(
|
||
|
|
self, t, old_duration, new_duration, abruptness=1.0, soonness=1.0
|
||
|
|
):
|
||
|
|
a = 1.0 + abruptness
|
||
|
|
|
||
|
|
def _f(t):
|
||
|
|
def f1(t):
|
||
|
|
return (0.5) ** (1 - a) * (t**a)
|
||
|
|
|
||
|
|
def f2(t):
|
||
|
|
return 1 - f1(1 - t)
|
||
|
|
|
||
|
|
return (t < 0.5) * f1(t) + (t >= 0.5) * f2(t)
|
||
|
|
|
||
|
|
return old_duration * _f((t / new_duration) ** soonness)
|
||
|
|
|
||
|
|
def apply(self, clip):
|
||
|
|
"""Apply the effect to the clip."""
|
||
|
|
if self.new_duration is None:
|
||
|
|
self.new_duration = clip.duration
|
||
|
|
|
||
|
|
if self.soonness < 0:
|
||
|
|
raise ValueError("'sooness' should be a positive number")
|
||
|
|
|
||
|
|
return clip.time_transform(
|
||
|
|
lambda t: self._f_accel_decel(
|
||
|
|
t=t,
|
||
|
|
old_duration=clip.duration,
|
||
|
|
new_duration=self.new_duration,
|
||
|
|
abruptness=self.abruptness,
|
||
|
|
soonness=self.soonness,
|
||
|
|
)
|
||
|
|
).with_duration(self.new_duration)
|