pythonで動画データの編集は可能なのでしょうか?
このような疑問にお答えします。
openCVを使えば実現できます。
openCVは、コンピュータで動画像を処理するための機能を提供するライブラリです。pythonでも使用することができ、opencv-pythonとして提供されています。
今回は、opencv-pythonを用いて動画編集をしてみたいと思います。
opencv-pythonを用いた動画編集手順
opencv-pythonのインストールは下記のコマンドで行うことができます。
1 |
pip install opencv-python |
pythonプロンプトを起動し、以下のプログラムを実行して、importエラーが発生しなければインストール成功です。
1 |
import cv2 |
入力となる動画データは、以下のwebページの画像素材を使用して作成しました。
フリー素材ぱくたそ
opencv-pythonでの画像データは、ndarrayとして扱われます。
そのため、動画からキャプチャした画像を保存したり何らかの処理を実施する場合には、このndarray形式にして処理することになります。
opencvでのread()が実行されると動画フレームをndarrayとして取得し、現在位置から1フレーム進めます。read()が呼ばれるたびに1フレームずつ読み込むことができます。
メソッドの返り値は、フレーム画像の読み込み可否を表すbool値とフレーム画像を表すndarrayを返します。
1 |
res, frame = cap_file.read() |
動画をすべて再生する場合は、上記の読み込み可否情報を用いて判定すれば実現できます。
動画にテロップを追加する方法は、以下の手順になります。
フォント設定を行います。
フォントデータは、「NotoSansCJKjp-Regular.otf」を使用しました。フォントデータは、お好みのものを使用してください。
本記事では、pythonの実行ディレクトリにフォントデータを置きました。
テロップをキャプチャ画像に追加するためにPILライブラリを使用します。PILライブラリを使用するにあたり、キャプチャ画像が扱えるように変換します。
テキスト本文と位置を指定し、キャプチャ画像にテキストを反映します。opencvライブラリでキャプチャ画像を処理するために、再度ndarray形式に変換します。
1 2 3 4 5 6 7 8 9 |
font_path = 'NotoSansCJKjp-Regular.otf' font_size = 24 font = ImageFont.truetype(font_path, font_size) frame = Image.fromarray(frame) draw = ImageDraw.Draw(frame) tw, th = draw.textsize("画像処理", font) draw.text((100, 50), "画像処理", font=font, fill=(0, 0, 0, 0)) frame = np.array(frame) |
動画からキャプチャした画像を編集し、その画像データを用いて新たな動画として保存する方法は以下になります。
1 2 3 4 5 |
w = int(cap_file.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap_file.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = int(cap_file.get(cv2.CAP_PROP_FPS)) fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') video = cv2.VideoWriter('output.mp4', fourcc, fps, (w, h)) |
ndarray形式のデータを随時保存することで、動画を作成します。
1 |
video.write(frame) |
動画編集の例として、今回は元動画に対して輪郭抽出した動画を新たに作成します。
1 2 3 4 5 6 7 8 |
imgray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(imgray, 100, 255, 0) thresh = cv2.bitwise_not(thresh) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) frame = cv2.drawContours(frame, contours, -1, (0, 255, 0), 3) |
輪郭抽出を行った画像は、ndarray形式のデータとなります。
ソースコードの全体を以下に示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# coding: utf-8 import numpy as np import cv2 import matplotlib.pyplot as plt from PIL import Image, ImageFont, ImageDraw movie_name = input("movie name ->") cap_file = cv2.VideoCapture(movie_name) print(type(cap_file)) if cap_file.isOpened(): print('frame width:', cap_file.get(cv2.CAP_PROP_FRAME_WIDTH)) print('frame height:', cap_file.get(cv2.CAP_PROP_FRAME_HEIGHT)) print('FPS:', cap_file.get(cv2.CAP_PROP_FPS)) print('frame count:', cap_file.get(cv2.CAP_PROP_FRAME_COUNT)) print('video play time:', int(cap_file.get(cv2.CAP_PROP_FRAME_COUNT)/cap_file.get(cv2.CAP_PROP_FPS))) selected_process = input("select process 0:one shot, 1:all start ->") if selected_process == '0': res, frame = cap_file.read() print(type(frame)) print(frame.shape) cv2.imshow('frame', frame) cv2.waitKey(0) cv2.destroyAllWindows() cv2.imwrite('output_image.jpg', frame) elif selected_process == '1': w = int(cap_file.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap_file.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = int(cap_file.get(cv2.CAP_PROP_FPS)) fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') video = cv2.VideoWriter('output.mp4', fourcc, fps, (w, h)) delay = 1 while True: res, frame = cap_file.read() if res: imgray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(imgray, 100, 255, 0) thresh = cv2.bitwise_not(thresh) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) frame = cv2.drawContours(frame, contours, -1, (0, 255, 0), 3) font_path = 'NotoSansCJKjp-Regular.otf' font_size = 24 font = ImageFont.truetype(font_path, font_size) frame = Image.fromarray(frame) draw = ImageDraw.Draw(frame) tw, th = draw.textsize("画像処理", font) draw.text((100, 50), "画像処理", font=font, fill=(0, 0, 0, 0)) frame = np.array(frame) cv2.imshow('frame', frame) video.write(frame) if cv2.waitKey(delay) & 0xFF == ord('q'): break else: # cap_file.set(cv2.CAP_PROP_POS_FRAMES, 0) break cv2.waitKey(0) cv2.destroyAllWindows() video.release() else: pass cap_file.release() else: pass |
出力結果としては、以下のようになりました。
元動画
出力動画
どうでしょうか?
このように、pythonでもopenCVを使用することができ、簡単に動画に対する応用的な処理ができます。
また、動画編集ソフトも作成できるような気もしますね。
これを機会にpythonによるopenCVを試してみてはいかがでしょうか。