動画をマトリックス風に変換する
画像をマトリックス風に変換する について、「動画でやってみたら面白いのでは」とコメントいただいたので動画を映画「マトリックス」の仮想現実シーンのように変換するコードを作りました。動画から1コマずつ画像を取り込み、取り込んだ画像をエッジ検出、エッジ部分を反転した緑色のカタカナで置き換えます。作成した画像を再度動画に変換します。
関連記事
画像をマトリックス風に変換する
アスキーアートを自動生成する
環境
準備
画像ファイルは動画ACの「音楽を楽しむ男性」をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名’2065_640x360.mp4'で保存しました(動画のサイズは640x360)。このブログにはmp4ファイルが貼れないのでアニメーションgifファイルに変換したものを、また容量の制限があるため動画の前半を下に貼ります。
コード
pillowでカタカナの文字列を画像化し180°回転し反転したカタカナ画像を作成します。動画の取り込みはOpenCVのcv2.VideoCaptureを使い、取り込んだ画像をグレースケール変換しcv2.Cannyでエッジ検出、エッジ画像の画素値を調べエッジがあれば反転文字列のランダムな文字に置き換えます。作成した画像からcv2.VideoWriterでmp4動画を作成、またpillowでアニメーションgifファイルも作成しています。
画像データのフォーマットが異なるpillowとOpencvの間で画像のやり取りがあるので、都度形式を変換しています(PillowはRGB形式、OpencvはBGR形式のnp.ndarray)。
from PIL import Image, ImageDraw, ImageFont import numpy as np import cv2 import random # 反転カタカナ画像の作成 font_size = 8 # フォントサイズ text = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン1234567890#%&$' # 文字列 font = ImageFont.truetype('C:\Windows\Fonts\msgothic.ttc', font_size) # フォントの指定 im = Image.new('RGB', (int(len(text)/2*font_size), font_size), (0, 0, 0)) # 下地となるイメージオブジェクトの生成 draw = ImageDraw.Draw(im) # drawオブジェクトを生成 draw.text((0, 0), text, fill=(180, 255, 180), font=font) # 文字列を画像に描画 im_rotate = im.rotate(180) # 180°回転 # pillow形式の画像をopencv形式に変換 text_img = cv2.cvtColor(np.array(im_rotate, dtype=np.uint8), cv2.COLOR_RGB2BGR) # gifファイル作成用イメージリスト images =[] # 元の動画ファイルのキャプチャー cap = cv2.VideoCapture('2065_640x360.mp4') # 保存用動画ファイルのフォーマット設定 fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') out = cv2.VideoWriter('matrix.mp4', fourcc, 25.0, (640, 360)) # 動画を1コマずつ取り込んで処理 while(cap.isOpened()): ret, frame = cap.read() # キャプチャー画像の取り込み if ret==True: # キャプチャー画像がある場合 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 画像をグレースケール変換 edges = cv2.Canny(gray, 50, 150) # 画像のエッジ検出 # font_sizeの整数倍にエッジ画像をリサイズ height, width, _ = frame.shape resize_x = width//font_size*font_size resize_y = height//font_size*font_size resize = cv2.resize(edges, (resize_x, resize_y)) # リサイズしたエッジ画像と同じサイズの黒画像を生成 matrix = np.zeros((resize_y, resize_x, 3), np.uint8) # ブロックごとの画素最大値が1以上か判定 for y in range(0, resize_y, font_size): for x in range(0, resize_x, int(font_size/2)): if np.amax(resize[y:y+font_size, x:x+int(font_size/2)])>0: pos = int(random.random()*len(text))*int(font_size/2) matrix[y:y+font_size, x:x+int(font_size/2)] = text_img[0:font_size, pos:pos+int(font_size/2)] out.write(matrix) # mp4動画を保存 # opencvからpillow形式に変換しgifファイル作成用リストimagesに追加 matrix_pil = Image.fromarray(cv2.cvtColor(matrix, cv2.COLOR_BGR2RGB)) images.append(matrix_pil) else: # キャプチャー画像がない場合はループ終了 break cap.release() # 再生画像をクローズ out.release() # 出力動画ファイルをクローズ # gif動画保存 images[0].save('matrix.gif', save_all=True, append_images=images[1:], optimize=False, duration=30, loop=0)
実行結果
エッジが緑の反転カタカナで置換された動画が作成されました。
以下のサイトを参考にさせていただきました
Pythonの文法メモ > 【OpenCV】画像読み出しとサイズ・画素情報取得、切り抜き、貼り付け、チャネル操作
Pythonの文法メモ > 【OpenCV】画像サイズを変更するresize
Pythonの文法メモ > 【Numpy】インデックス・スライスによるndarray要素の取得