pythonでスターウォーズのOP風映像を作ってみる
なんとなく作りたくなったので。
こんなのが割と簡単に出来ます。
事前準備
必要なアプリとライブラリをインストールしてください。
ImageMagick
必要なアプリをインストール。
以下から環境に適したものをインストールしてください。
scikit-image
必要なライブラリインストール。
pip install scikit-image
MoviePy
必要なライブラリインストール。(*最新のverである「2.0.0dev2」を指定)
pip install moviepy==2.0.0dev2
そのままだとうまく動かなかったりするので、ImageMagickへのパスを見直してください。
修正ファイル
フォルダ C:\Users\ユーザー名\AppData\Local\Programs\Python\Python38\Lib\site-packages\moviepy
ファイル config_defaults.py
修正内容
IMAGEMAGICK_BINARY がある行をコメントして、インストールされた「magick.exe」を指定 。
# //IMAGEMAGICK_BINARY = os.getenv('IMAGEMAGICK_BINARY', 'auto-detect')
IMAGEMAGICK_BINARY = "C:\\Program Files\\ImageMagick-7.0.10-Q16\\magick.exe"
背景画像
背景画像を用意しておきましょう。
今回は以下から借用しました。
背景は全8種類✨
— スター・ウォーズ公式 (@starwarsjapan) April 17, 2020
あなたはどれにする❓👀 pic.twitter.com/7SKaBgCUcK
実装
PIC_PATH は事前に用意したバックグラウンド用の画像パスを指定。
import numpy as np
from skimage import transform as tf
from moviepy.editor import *
from moviepy.video.tools.drawing import color_gradient
# PIC PATH
PIC_PATH = 'back.jpg'
# # RESOLUTION
w = 720
h = w*9//16
moviesize = w,h
#INSERT THE RAW TEXT (here: "A New Hope")
txt = "\n".join([
"",
"とにかく観てほしい映画ベストテン",
"1. シューテムアップ",
"2. ポーラー 狙われた暗殺者",
"3. コンティニュー",
"4. ザ・レイド",
"5. 6アンダーグラウンド",
"6. グレイマン",
"7. ヒットマンズ・ボディガード",
"8. Mr.ノーバディ",
"9. メッセージマン",
"10. ブラックアウト 記憶の彼方に",
"",
"",
"",
"",
"",
"",
"",
])
# txt = "\n".join([
# "",
# "It is a period of civil war. Rebel",
# "spaceships, striking from a",
# "hidden base, have won their",
# "first victory against the evil",
# "Galactic Empire. During the battle,",
# "Rebel spies managed to steal secret",
# "plans to the Empire’s ultimate weapon,",
# "the DEATH STAR, an armored space station",
# "with enough power to destroy an entire planet."
# "",
# "",
# "",
# "",
# "",
# "",
# "",
# "",
# "",
# ])
# Add blanks before and after text
txt = 10*"\n" +txt + 10*"\n"
clip_txt = TextClip(txt,color='yellow', align='West',fontsize=25,
font="MS-Gothic-&-MS-UI-Gothic-&-MS-PGothic", method='label')
# SCROLL THE TEXT IMAGE BY CROPPING A MOVING AREA
txt_speed = 10
fl = lambda gf,t : gf(t)[int(txt_speed*t):int(txt_speed*t)+h,:]
moving_txt= clip_txt.fl(fl, apply_to=['mask'])
# ADD A VANISHING EFFECT ON THE TEXT WITH A GRADIENT MASK
grad = color_gradient(moving_txt.size,p1=(0,2*h/3),p2=(0,h/4),col1=0.0,col2=1.0)
gradmask = ImageClip(grad,ismask=True)
fl = lambda pic : np.minimum(pic,gradmask.img)
moving_txt.mask = moving_txt.mask.fl_image(fl)
# WARP THE TEXT INTO A TRAPEZOID (PERSPECTIVE EFFECT)
def trapzWarp(pic,cx,cy,ismask=False):
Y,X = pic.shape[:2]
src = np.array([[0,0],[X,0],[X,Y],[0,Y]])
dst = np.array([[cx*X,cy*Y],[(1-cx)*X,cy*Y],[X,Y],[0,Y]])
tform = tf.ProjectiveTransform()
tform.estimate(src,dst)
im = tf.warp(pic, tform.inverse, output_shape=(Y,X))
return im if ismask else (im*255).astype('uint8')
fl_im = lambda pic : trapzWarp(pic,0.2,0.3)
fl_mask = lambda pic : trapzWarp(pic,0.2,0.3, ismask=True)
warped_txt= moving_txt.fl_image(fl_im).set_position('center','bottom')
warped_txt.mask = warped_txt.mask.fl_image(fl_mask)
# BACKGROUND IMAGE, DARKENED HERE AT 60%
stars = ImageClip(PIC_PATH)
stars_darkened = stars.fl_image(lambda pic: (0.6*pic).astype('int16')).set_position('center','bottom')
# COMPOSE THE MOVIE
final = CompositeVideoClip([
stars_darkened,warped_txt],
size = moviesize)
# WRITE TO A FILE
# duration here set to 35 seconds, with 18 frames per second
final.set_duration(35).write_videofile("star_wars_crawl.webm", fps=18)
つまずいたこと
日本語を使いたいときは、フォント指定を以下のように見直す必要があった。
clip_txt = TextClip(txt,color='yellow', align='Center',fontsize=35,
font="MS-Gothic-&-MS-UI-Gothic-&-MS-PGothic", method='label')