本記事では、下記リンク先のような動画を作成します。
www.youtube.com
iPhoneで録画した動画をPythonで編集して作成する。
具体的には、次の1~8のような処理をする。
特に、黒■が本記事の新規項目である。一方、白□は以前の記事に記載したものではあるものの、本記事で出来ること一覧として載せる。
実際に真似する場合には、本記事の最後に記載したプログラム中のそれ前後を参考下さい。
□1. 時刻指定による動画の区間抽出
→メソッドがある。
video = mp.VideoFileClip(input_file).subclip(start, end)
■2. 動画の一部分モザイク処理
→動画からフレーム(画像)毎に処理する。
cut_area = img[y:y+h, x:x+w]
small = cv2.resize(cut_area, dsize=None, fx=scale, fy=scale, interpolation=cv2.INTER_NEAREST)
zoom = cv2.resize(small, dsize=(w, h), interpolation=cv2.INTER_NEAREST)
img[y:y+h, x:x+w] = zoom
□3. 動画のアスペクト比を保ったまま、解像度を変更
→縦を軸に縮尺して、その変化率を横に適応することで縦横比を保つ
frame = cv2.resize(frame, dsize=None, fx=scale, fy=scale)
■4. 無地の画像の作成
→numpyで作成する。背景色の指定はRGBをBGRに変換して与える
new_frame = np.zeros((out_height, out_width, 3), np.uint8)
if True:
rgb_color = (255, 250, 205)
bgr_color = tuple(reversed(rgb_color))
new_frame[:] = bgr_color
□5. 無地の画像を下地に画像の合成
→合成する画像の配置位置の指定は、左上の座標と幅と高さで指定
new_frame[0:out_height, offset:(frame_width+offset)] = frame
■6. 日本語の挿入
→フォント色の指定方法も記載。指定はRGBの順ではなく、BGRの順で指定
font_color = (255, 0, 0)
draw.text((250, 200), message, font_color, font)
□7. 動画から音声のみを抽出mp3
→メソッドがある
clip_in = mp.VideoFileClip(input_video1).subclip()
clip_in.audio.write_audiofile(out_audio)
■8. ビープ音を鳴らす。これにより、プログラム終了を音で知らせる
→from winsound import Beep する。
mysound = [523, 587, 659, 698, 784, 880, 932]
for e in mysound:
Beep(e, 1000)
▼本プログラム
特記事項:モザイクや画像合成の処理において、思った通りにならない、もしくはエラーになる場合は、凡そ、場所指定に問題がある場合が多いと思われます。
import cv2
from PIL import Image, ImageFont, ImageDraw
import numpy as np
import moviepy.editor as mp
from winsound import Beep
def simplification(input_file, out_file, cut_time, fps):
start, end = cut_time
video = mp.VideoFileClip(input_file).subclip(start, end)
video.write_videofile(out_file, fps=fps)
def image_add_message(img, message):
font_path = 'C:\Windows\Fonts\meiryo.ttc'
font_size = 58
font = ImageFont.truetype(font_path, font_size)
img = Image.fromarray(img)
draw = ImageDraw.Draw(img)
font_color = (255, 0, 0)
draw.text((250, 200), message, font_color, font)
return np.array(img)
def edit_mp4(input_file, out_file, out_size, fps):
print("start edit_mp4")
out_width, out_height = out_size
video = cv2.VideoCapture(input_file)
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
size = (width, height)
num_of_frame = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(video.get(cv2.CAP_PROP_FPS))
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
writer = cv2.VideoWriter(out_file, fourcc, fps, out_size)
scale = out_height / height
flag = num_of_frame // len(global_list)
j=0
k=0
for i in range(num_of_frame):
if i % 50 == 0:
print(str(i) + "/" + str(num_of_frame))
ret, frame = video.read()
new_frame = np.zeros((out_height, out_width, 3), np.uint8)
if True:
rgb_color = (255, 250, 205)
bgr_color = tuple(reversed(rgb_color))
new_frame[:] = bgr_color
if out_width == width:
new_frame[0:out_height, 0:out_width] = frame
else:
frame = cv2.resize(frame, dsize=None, fx=scale, fy=scale)
frame_height, frame_width = frame.shape[:2]
offset = int((out_width - frame_width)*2/3)
new_frame[0:out_height, offset:(frame_width+offset)] = frame
'''
print("i -> " + str(i) + "/" + str(num_of_frame))
print("k/len(global_list) -> " + str(k) + "/" + str(len(global_list)))
print(global_list[k])
'''
new_frame = image_add_message(new_frame, global_list[k])
writer.write(new_frame)
j += 1
if flag < j:
j = 0
k += 1
writer.release()
video.release()
print(str(size) + " -> " + str(out_width) + "," + str(out_height))
print("num_of_frame -> " + str(num_of_frame))
print("fps -> " + str(fps))
def extract_audio(input_video1, input_video2, out_file, out_audio):
print("start extract_audio")
clip_in = mp.VideoFileClip(input_video1).subclip()
clip_in.audio.write_audiofile(out_audio)
clip_out = mp.VideoFileClip(input_video2).subclip()
clip_out.write_videofile(out_file, audio=out_audio)
def mosaic_movie(input_file, out_file, fps, x, y, w, h, scale=0.1):
print("start mosaic_movie")
video = cv2.VideoCapture(input_file)
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
size = (width, height)
num_of_frame = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(video.get(cv2.CAP_PROP_FPS))
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
writer = cv2.VideoWriter(out_file, fourcc, fps, (width, height))
for i in range(num_of_frame):
ret, frame = video.read()
buf = mosaic_area(frame, 70, 850, 360, 50, scale=0.1)
dst = mosaic_area(buf, 600, 850, 180, 50, scale=0.1)
writer.write(dst)
if i % 50 == 0:
print(str(i) + "/" + str(num_of_frame))
writer.release()
video.release()
print("num_of_frame -> " + str(num_of_frame))
print("fps -> " + str(fps))
def mosaic_area(img, x, y, w, h, scale=0.1):
height, width = img.shape[:2]
cut_area = img[y:y+h, x:x+w]
small = cv2.resize(cut_area, dsize=None, fx=scale, fy=scale, interpolation=cv2.INTER_NEAREST)
zoom = cv2.resize(small, dsize=(w, h), interpolation=cv2.INTER_NEAREST)
img[y:y+h, x:x+w] = zoom
return img
def alerm():
mysound = [523, 587, 659, 698, 784, 880, 932]
for e in mysound:
Beep(e, 1000)
global_list = ['星のドラゴンクエスト\n 略して、星ドラ',
'配信開始は2015年。\nその頃から\nプレイしている',
'スマホはiPhoneXRで\n操作はヌルサク動く',
'ネット通信で\n4人で協力プレイ可能',
'知らない3名の名前は\nモザイク掛けてますf^^;',
'キャラは職業によって、\n攻撃力や体力、守備力\nなどが異なる',
'武器、防具は、\nガチャで入手する',
'無論、\nワタクシことぽっくんは\n無課金である',
'いつの間にか4年。。\n無料ガチャ、\n相当引いた。。',
'そのため、\n無課金でもそこそこ強い。',
'最近は、武器の\nハイパーインフレ状態。\n次から次へと\n強いのが出てくる(笑)',
'このゲームの面白さは、\n武器、防具集めである',
'それは、昔、\n皆ビックリマンシールを\n集めてたように。。',
'そして、今や\n私もあなたも\n星ドラおっさん♪おばはん',
'昔のキャラも出てくる\nドラクエ2の勇者やら=3',
'ところで、\nこの動画編集には、\nPythonを使用した',
'スマホの画面サイズから、\nYouTube用の\nアスペクト比へ変更',
'モザイクを入れたり、\n背景色変えたり、\n文章をこうして入れた',
'結局、\n星ドラとPythonは\n面白い!ってこと!?',
'See you',
]
if __name__ == '__main__':
input_video = "CHEN7662.mp4"
cut_time = (3, 263)
out_video1 = 'zzz_out1_simple.mp4'
out_audio = 'zzz_audio.mp3'
out_video2_wo = 'zzz_out2_mosaic_wo_audio.mp4'
out_video2_w = 'zzz_out2_mosaic_w_audio.mp4'
out_video3_wo = 'zzz_out3_wo_audio.mp4'
out_video3_w = 'zzz_out3_w_audio.mp4'
out_size = (1920, 1080)
fps = 30
simplification(input_video, out_video1, cut_time, fps)
input_video = out_video1
mosaic_movie(input_video, out_video2_wo, fps, x=800, y=400, w=400, h=300, scale=0.1)
input_video2 = out_video2_wo
extract_audio(input_video, input_video2, out_video2_w, out_audio)
input_video = out_video2_w
edit_mp4(input_video, out_video3_wo, out_size, fps)
input_video2 = out_video3_wo
extract_audio(input_video, input_video2, out_video3_w, out_audio)
alerm()
'''
img = cv2.imread('mosaic0.jpg')
img2 = mosaic_area(img, 70, 850, 400, 50, scale=0.1)
img3 = mosaic_area(img2, 600, 850, 200, 50, scale=0.1)
cv2.imwrite('mosaic_000.jpg', img3)
'''
print("finished")
以上
<広告>
リンク