Pythonでいろいろやってみる

Pythonを使った画像処理や機械学習などの簡単なプログラムを載せています。

動画をマトリックス風に変換する

画像をマトリックス風に変換する について、「動画でやってみたら面白いのでは」とコメントいただいたので動画を映画「マトリックス」の仮想現実シーンのように変換するコードを作りました。動画から1コマずつ画像を取り込み、取り込んだ画像をエッジ検出、エッジ部分を反転した緑色のカタカナで置き換えます。作成した画像を再度動画に変換します。

関連記事

画像をマトリックス風に変換する
アスキーアートを自動生成する

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.8.8
  • Pillow 8.2.0
  • OpenCV 4.0.1
準備

画像ファイルは動画ACの「音楽を楽しむ男性」をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにファイル名’2065_640x360.mp4'で保存しました(動画のサイズは640x360)。このブログにはmp4ファイルが貼れないのでアニメーションgifファイルに変換したものを、また容量の制限があるため動画の前半を下に貼ります。

f:id:T_A_T:20211228145120g:plain
2065_640x360.mp4(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)  
実行結果

エッジが緑の反転カタカナで置換された動画が作成されました。
f:id:T_A_T:20211228145610g:plain

以下のサイトを参考にさせていただきました

Pythonの文法メモ > 【OpenCV】画像読み出しとサイズ・画素情報取得、切り抜き、貼り付け、チャネル操作
Pythonの文法メモ > 【OpenCV】画像サイズを変更するresize
Pythonの文法メモ > 【Numpy】インデックス・スライスによるndarray要素の取得

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村