0
0

JSONを用いた動画生成

Posted at

概要

AIのセグメンテーション結果の流し見など、色々な画像を動画に合わせて同時にみたいという時があります。
その時、いちいちコード上でレイアウトを変更して...とかやっているとミスが多いため、すべてをjson上でまとめてそこで管理すればいいのでは?と考えてコードを作成してみたので公開します。

コード内容

動作環境

  • opencv
  • PIL
  • python 3.10

ファイル構成

.
├── README.md
├── main.py      # まとめて動かすためのコード
├── outline.json # レイアウトを記載
├── pictures     # 複数の元画像を結合した画像を格納
├── src 
│   ├── movie_maker.py    # 動画作成
│   └── picture_maker.py  # 画像生成
├── venv
├── video.mp4
└── video_output

JSONによる画像の配置の設定

1フレームごとの画像を生成する際、複数の画像の配置やサイズ、背景画像の大きさを設定すれば良い。

outline.json
{
    "movie_property": {
      "framerate": 60
    },
    "picture_property":{
        "picture_number":2{
    "movie_property": {
      "framerate": 60
    },
    "picture_property":{
        "picture_number":2,
        "background": {
        "width": 300,
        "height": 300
        },
        "pictures": [{
        "source": "sample/img/sample1",
        "positionX": 0,
        "positionY": 0
        },
        {
        "source": "sample/img/sample2",
        "positionX": 150,
        "positionY": 0
        }]
    }
},
        "background": {
        "width": 300,
        "height": 300
        },
        "pictures": [{
        "source": "sample/img/sample1",
        "positionX": 0,
        "positionY": 0
        },
        {
        "source": "sample/img/sample2",
        "positionX": 150,
        "positionY": 0
        }]
    }
}

movie_propertyにはfpsなどの動画作成に必要なものを記載
picture_propertyには画像のソースや配置などを記載

picture_makerによるフレームごとの画像の生成

あとはPILを使ってファイルの検索を行い、JSONでの指示にしたがって並べる。
※画像ファイルには00000.pngなど、ゼロ詰めにしておかないと順番がおかしくなる。

picture_maker.py
from PIL import Image
from pathlib import Path
import os
def make_picture(outline: dict):
    #backgroundの作成
    background_width = outline["background"]["width"]
    background_height = outline["background"]["height"]
    # 背景画像の作成
    dst = Image.new(mode='RGB', size=(background_width, background_height))
    
    # 各フォルダに対してfileリストを作成
    image_pathlist = []
    for i in range(len(outline['pictures'])):
        path = Path(outline['pictures'][i]['source'])
        plist = path.glob('*.png')
        image_pathlist.append(sorted(list(plist)))

    print(image_pathlist)

    # 1個目のファイルリストの長さ分の画像を作る。
    for i in range(len(image_pathlist[0])):
        # 背景画像の生成list(plist)list(plist)
        dst = Image.new(mode='RGB', size=(background_width, background_height))
        
        # 画像の貼り付け
        for j in range(len(image_pathlist)):
            im = Image.open(image_pathlist[j][i])
            dst.paste(im,
                      (outline['pictures'][j]['positionX'], outline['pictures'][j]['positionY']))
        # 画像の保存
        if not(os.path.isdir('pictures')):
            os.mkdir('pictures')
        dst.save(f'pictures/{str(i).zfill(5)}.png')
from PIL import Image
from pathlib import Path
import os
def make_picture(outline: dict):
    #backgroundの作成
    background_width = outline["background"]["width"]
    background_height = outline["background"]["height"]
    # 背景画像の作成
    dst = Image.new(mode='RGB', size=(background_width, background_height))
    
    # 各フォルダに対してfileリストを作成
    image_pathlist = []
    for i in range(len(outline['pictures'])):
        path = Path(outline['pictures'][i]['source'])
        plist = path.glob('*.png')
        image_pathlist.append(sorted(list(plist)))

    print(image_pathlist)

    # 1個目のファイルリストの長さ分の画像を作る。
    for i in range(len(image_pathlist[0])):
        # 背景画像の生成list(plist)list(plist)
        dst = Image.new(mode='RGB', size=(background_width, background_height))
        
        # 画像の貼り付け
        for j in range(len(image_pathlist)):
            im = Image.open(image_pathlist[j][i])
            dst.paste(im,
                      (outline['pictures'][j]['positionX'], outline['pictures'][j]['positionY']))
        # 画像の保存
        if not(os.path.isdir('pictures')):
            os.mkdir('pictures')
        dst.save(f'pictures/{str(i).zfill(5)}.png')

movie_makerによる動画の生成

下記サイトを参考にしつつ作成
https://note.nkmk.me/python-opencv-video-to-still-image/

movie_maker.py
import cv2
import os

def make_movie(config):
    cap = cv2.VideoCapture(0)
    codec = cv2.VideoWriter_fourcc(*'mp4v')
    fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    out_file_name = 'output/video.mp4'
    video = cv2.VideoWriter(out_file_name,fourcc, 
                            config['movie_property']['framerate'],
                            (config['picture_property']['background']['width'],
                              config['picture_property']['background']['height'])
                            )
    image_list = sorted(os.listdir('pictures'))
    for frame in image_list:
        img = cv2.imread(os.path.join('pictures',frame))
        video.write(img)
    video.release()

今後の展開

  • エラー対応(画像のファイル数が違うなど)
  • 透過率への対応
  • その他必要に応じて作成を行うよて
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0