Python 思い出の写真をコメントと共に動画にする「OpenCV」

 本記事では画像ファイルを繋げて動画にする雛形コードを載せました。下図は、ここ数年でワタクシが呑んで写真を撮った日本酒の一覧で61枚あります。写真の解像度はバラバラであっても、指定したサイズ(本コード中では1920×1080)に調整する仕様のため問題なく動画に出来ます。

f:id:HK29:20210626230850p:plain

下図は、日本酒の情報でexcelファイルにしたものです。動画にする際、上記画像の順番に合わせて、1行毎に情報を画像に付け加える仕様にしています。

f:id:HK29:20210626232948p:plain

作成した動画例は下記リンク先です。音声の付与は、Windows10の標準ソフト「フォト」を使用しています。

www.youtube.com

■本プログラム

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, glob, shutil
import pandas as pd
import cv2
from PIL import Image, ImageFont, ImageDraw
import numpy as np

def image_resize(image, height):
    # 高さに関して指定サイズと現物の比率を計算し、それをx, yに掛けることでアスペクト比を保つ
    scale = height / image.shape[0]
    return cv2.resize(image, dsize=None, fx=scale, fy=scale)

def image_add_message(img, message):
    font_path = 'C:\Windows\Fonts\meiryo.ttc'           # Windowsのフォントファイルへのパス
    font_size = 54                                      # フォントサイズ
    font = ImageFont.truetype(font_path, font_size)     # PILでフォントを定義
    img = Image.fromarray(img)                          # cv2(NumPy)型の画像をPIL型に変換
    draw = ImageDraw.Draw(img)                          # 描画用のDraw関数を用意
    
    # テキストを描画(位置、文章、フォント、文字色(BGR+α)を指定)
    draw.text((50, 50), message, font=font, fill=(255, 255, 255, 0))
    img = np.array(img)                                 # PIL型の画像をcv2(NumPy)型に変換
    return img                                          # 文字入りの画像をリターン

def jpg2mp4(folder, outfile, width, height, time):
    img_list = glob.glob(folder + '*.jpg') # ファイルをリストへ格納
    print(img_list)
    fps = len(img_list) / (time*60) # fpsを計算する。ファイル数/再生時間

    for i, e in enumerate(img_list):
        ### ファイル名を連番へリネームする
        e2 = str(i).zfill(4) + '.jpg'  # zfillの型は文字列
        #os.rename(e, e2)
        shutil.copy2(e, e2) # ファイルをカレントディレクトリへコピー
        img = cv2.imread(e2)

        ### ファイルサイズを指定サイズへ変更する
        dst = image_resize(img, height)
        print(f"{img.shape} -> {dst.shape}")
        dst_height, dst_width = dst.shape[:2]
        print("i -> " + str(i) + "/" + str(len(img_list)-1))
        print(str(dst_width) + " " + str(dst_height))
        
        ### 無地の画像ファイルをnumpyで作成する
        new_img = np.zeros((height, width, 3), np.uint8)
        #cv2.imwrite("blank.bmp", new_img);

        ### 無地の画像ファイルの上に、元ファイルを上書きする。
        ### →全てのファイルが同じ縦横比(アスペクト比)のファイルになる。
        if dst_width == width:
            print("set A")
            #new_img[上のy座標:下のy座標, 左のx座標:右のx座標]
            new_img[0:dst_height, 0:dst_width] = dst
        else:
            print("set B")
            offset = int((width - dst_width)/2)
            print("offset -> " + str(offset))
            new_img[0:height, offset:dst_width+offset] = dst
        ### 挿入するメッセージを加工する
        my_message_str = ''
        for j in range(len(my_message_list[i])):
            if j==0:
                my_message_str += '紹介No' + str(my_message_list[i][j]) + '\n\n'
            if j==1:
                my_message_str += my_message_list[i][j]
            if j==2:
                my_message_str += '(' + my_message_list[i][j] + ')' + '\n\n'
            if j==3:
                my_message_str += my_message_list[i][j] + '\n\n'
            if j==4:
                my_message_str += my_message_list[i][j] + ': '
            if j==5:
                my_message_str += my_message_list[i][j]
        # メッセージの挿入
        new_img = image_add_message(new_img, my_message_str)
        cv2.imwrite(e2 , new_img)
        
    cap = cv2.VideoCapture('%04d.jpg')
    #fourcc = cv2.VideoWriter_fourcc(*'X264')
    fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    writer = cv2.VideoWriter(outfile, fourcc, fps, (width, height))
    while True:
       ret, frame = cap.read()
       if not ret:
           break
       writer.write(frame)
    writer.release()
    cap.release()
    print("fps -> " + str(fps))

if __name__ == '__main__':
    ### 設定項目
    input_folder = r"./img/"
    out_file = 'output.mp4' #'output.avi'
    out_width = 1920
    out_height = 1080
    time = 6 #[min]
    
    df = pd.read_excel('210626_日本酒一覧.xlsx',
                   sheet_name = 'Sheet1',
                   #index_col = 0,
                   engine = "openpyxl")
    print(df)
    
    my_message_list = df.values.tolist()
    print(my_message_list)
    
    ### 関数呼び出し
    jpg2mp4(input_folder, out_file, out_width, out_height, time)

ちなみに、本記事で200記事目となりました。

以上

<広告>

<広告>