74 lines
2.1 KiB
Python
74 lines
2.1 KiB
Python
import numpy as np
|
|
|
|
from moviepy.decorators import apply_to_mask
|
|
|
|
try:
|
|
from PIL import Image
|
|
PIL_FOUND = True
|
|
def pil_rotater(pic, angle, resample, expand):
|
|
return np.array( Image.fromarray(pic).rotate(angle, expand=expand,
|
|
resample=resample))
|
|
except ImportError:
|
|
PIL_FOUND = False
|
|
|
|
def rotate(clip, angle, unit='deg', resample="bicubic", expand=True):
|
|
"""
|
|
Change unit to 'rad' to define angles as radians.
|
|
If the angle is not one of 90, 180, -90, -180 (degrees) there will be
|
|
black borders. You can make them transparent with
|
|
|
|
>>> newclip = clip.add_mask().rotate(72)
|
|
|
|
Parameters
|
|
===========
|
|
|
|
clip
|
|
A video clip
|
|
|
|
angle
|
|
Either a value or a function angle(t) representing the angle of rotation
|
|
|
|
unit
|
|
Unit of parameter `angle` (either `deg` for degrees or `rad` for radians)
|
|
|
|
resample
|
|
One of "nearest", "bilinear", or "bicubic".
|
|
|
|
expand
|
|
Only applIf False, the clip will maintain the same True, the clip will be resized so that the whole
|
|
"""
|
|
|
|
resample = {"bilinear": Image.BILINEAR,
|
|
"nearest": Image.NEAREST,
|
|
"bicubic": Image.BICUBIC}[resample]
|
|
|
|
if not hasattr(angle, '__call__'):
|
|
# if angle is a constant, convert to a constant function
|
|
a = +angle
|
|
angle = lambda t: a
|
|
|
|
transpo = [1,0] if clip.ismask else [1,0,2]
|
|
|
|
def fl(gf, t):
|
|
|
|
a = angle(t)
|
|
im = gf(t)
|
|
|
|
if unit == 'rad':
|
|
a = 360.0*a/(2*np.pi)
|
|
|
|
if (a==90) and expand:
|
|
return np.transpose(im, axes=transpo)[::-1]
|
|
elif (a==-90) and expand:
|
|
return np.transpose(im, axes=transpo)[:,::-1]
|
|
elif (a in [180, -180]) and expand:
|
|
return im[::-1,::-1]
|
|
elif not PIL_FOUND:
|
|
raise ValueError('Without "Pillow" installed, only angles 90, -90,'
|
|
'180 are supported, please install "Pillow" with'
|
|
"pip install pillow")
|
|
else:
|
|
return pil_rotater(im, a, resample=resample, expand=expand)
|
|
|
|
return clip.fl(fl, apply_to=["mask"])
|