Pythonでいろいろやってみる

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

複数の動画に字幕を付けて1つの動画にまとめる

 複数の動画を1つの動画にまとめます。また各動画の説明用字幕を付けます。画像処理ライブラリOpenCVの cv2.VideoCapture で各動画の先頭から3秒まで読みだし、画像処理ライブラリPillowのdraw.textで字幕を付けます。字幕が徐々に現れて徐々に消えるように見せるため、元の動画から読みだした画像とアルファ値を持たせた字幕用画像を、字幕用画像のアルファ値を変えながらPillowのImage.alpha_compositeで合成しています。

環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 6.4.6
  • Python 3.8.12
  • Pillow 9.0.0
  • OpenCV 4.5.5
準備

 Mixkitから3つの動画をダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリにフォルダ'movies'を作りその中にファイル名 ’01.mp4', ’02.mp4', ’03.mp4' で保存しました。
White sand beach and palm trees
Black scorpion walking closeup
Fly over a huge canyon covered in vegetation

コード

 はじめにmoviesフォルダに含まれるファイルをリストにし、動画をひとつづつ読みだします。cv2.VideoCaptureで動画を取り込み、cap.get(cv2.CAP_PROP_POS_MSEC)で現在の時間を調べ3000msまで取り込みます。字幕用画像のアルファ値を
 ~1000ms:0から徐々に増える
 1000~2000ms:一定の値(220)
 2000ms~:0まで徐々に減る
として字幕が表れて消える効果を表現しています。 
 動画読み出しと動画書き出しをOpenCVで行いますが、字幕の書き込みは日本語が描けるPillowで行うためOpenCV⇔Pillowで画像を受け渡す際には画像フォーマットの変換を行います。
 動画はmp4ファイルで書き出すとともに、このブログに貼るためにgifアニメーションも作成しています。      

import os
from PIL import Image, ImageDraw, ImageFont
import cv2
import numpy as np

# moviesフォルダ内のファイルをリストに
files = os.listdir('movies/') 

# gifファイル作成用イメージリスト
images =[]  

# 動画ファイル作成用イメージリスト
frames =[]  

# 字幕のリスト
subtitles =[
    '白い砂浜の南国のビーチ',
    '森を進む黒いサソリ',
    '森に囲まれたロッキー渓谷'
            ]
# 字幕のアルファ値(不透明度)の最大値
amax = 220

# 保存用動画ファイルのフォーマット設定
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') 
out = cv2.VideoWriter('subtitles.mp4', fourcc, 25.0, (384, 216)) 

# 動画ファイルをひとつずつ読みだして処理
for i in range(3):
    movie = files[i]
    subtitle = subtitles[i]
    
    # 動画ファイルのキャプチャー
    cap = cv2.VideoCapture('movies/'+movie)
    
    while(cap.isOpened()): 
        # キャプチャー画像の取り込み
        ret, frame = cap.read() 
        
        # 現在時間を取得
        time = cap.get(cv2.CAP_PROP_POS_MSEC)

        # キャプチャー画像があって3000msec以内の場合
        if ret==True and time<3000: 

            # 384x216にリサイズ
            resize = cv2.resize(frame, (384, 216))
            
            # 画像をcv2形式からPillow形式に変換しアルファチャンネルを追加
            im = Image.fromarray(cv2.cvtColor(resize, cv2.COLOR_BGR2RGB))
            im.putalpha(255)
            
            # 字幕のアルファ値設定
            if time < 1000:
                alpha = int(amax*time/1000)

            elif time > 2000:
                alpha = int(amax*(3000-time)/1000)
                
            else:    
                alpha = amax

            # 字幕用画像に字幕を縁取り文字で描画        
            im2 = Image.new('RGBA', (384, 216), (0, 0, 0, 0))
            draw = ImageDraw.Draw(im2)
            font = ImageFont.truetype('C:\Windows\Fonts\BIZ-UDGothicB.ttc', 24)
            draw.text((40, 180), subtitle, fill=(255, 255, 255, alpha), font=font, 
                      stroke_width=1, stroke_fill=(150, 150, 150, alpha))
                        
            # 動画のフレームと字幕用画像の合成
            comp = Image.alpha_composite(im, im2)
            
            # gifファイル作成用イメージリストにフレームを追加
            images.append(comp)
            
            # Pillow形式からcv2形式に変換
            img = cv2.cvtColor(np.array(comp), cv2.COLOR_RGB2BGR)
            
            # VideoWriterにフレームを追加
            out.write(img)
            
        else: # キャプチャー画像がない場合はループ終了 
            break
    
    # 再生画像をクローズ
    cap.release() 

# 出力動画ファイルをクローズ
out.release() 

# gif動画保存
images[0].save('subtitles.gif', save_all=True, append_images=images[1:], 
               optimize=True, duration=40, loop=0)       
実行結果

 3つの動画が字幕を付けて1つの動画にまとめられました。
f:id:T_A_T:20220206173827g:plain

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

Pythonの文法メモ > 【OpenCV】動画ファイルの読み出しとプロパティ取得、キャプチャー画像の保存
Pythonの文法メモ > 【Pillow】アルファチャンネル付き図形と画像の合成

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

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