Created
February 21, 2024 19:24
img2video_SideBySide
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#立体視のサイドバイサイド連番から動画作成 | |
# | |
#20240221 v1.0.0 png、1920x1200 サイドバイサイド。からシンプル動画変換と、SingleViewに変換。 | |
# v1.0.1 GUIレイアウト調整。動画上書き保存。 | |
# | |
# 想定命名規則 例1) rend/rend_r/s001/s001_v001_vr/s001_v001_vr_00001.png | |
# 想定命名規則 例2) rend/rend_r/s301/s301_v034_vr/s301_v034_vr_06482.png | |
# | |
import tkinter as tk | |
from tkinter import filedialog, ttk, messagebox | |
import subprocess | |
import os | |
import re | |
from glob import glob | |
def browse_folder(): | |
folder = filedialog.askdirectory() | |
if folder: # フォルダが選択された場合のみ処理を実行 | |
folder_path.set(folder) | |
auto_detect_filenames(folder) | |
detect_png_pattern(folder) | |
detect_smallest_number(folder) | |
# ユーザーが「キャンセル」を選択した場合は、何もしない(folder_pathを更新しない) | |
def auto_detect_filenames(folder): | |
if folder: | |
folder_name = os.path.basename(folder) | |
output1_name = f"{folder_name}.mp4" | |
output2_name = f"{folder_name.replace('vr', 'sv')}.mp4" | |
output1.set(os.path.join(output_folder.get(), output1_name)) | |
output2.set(os.path.join(output_folder.get(), output2_name)) | |
def detect_png_pattern(folder): | |
png_files = glob(os.path.join(folder, "*.png")) | |
if png_files: | |
sample_file = os.path.basename(png_files[0]) | |
match = re.match(r"(.+?)(\d+).png", sample_file) | |
if match: | |
prefix = match.group(1) | |
digits = len(match.group(2)) | |
pattern = f"{prefix}%0{digits}d.png" | |
png_pattern.set(pattern) | |
def detect_smallest_number(folder): | |
png_files = glob(os.path.join(folder, "*.png")) | |
numbers = [int(re.search(r"(\d+).png", os.path.basename(file)).group(1)) for file in png_files if re.search(r"(\d+).png", os.path.basename(file))] | |
if numbers: | |
smallest_number.set(min(numbers)) | |
else: | |
smallest_number.set(0) # ファイルが見つからない場合 | |
def convert_videos(): | |
folder = folder_path.get() | |
framerate = framerate_entry.get() | |
output1_path = output1.get() | |
output2_path = output2.get() | |
resolution_percentage = resolution_percentage_entry.get() | |
pattern = png_pattern.get() | |
start_number = smallest_number.get() | |
bitrate_value = bitrate_entry.get() + "M" # Mbpsを付加 | |
if generate_video1.get(): | |
# 元の解像度での動画生成コマンド | |
command1 = f'ffmpeg -y -framerate {framerate} -start_number {start_number} -i "{folder}/{pattern}" -b:v {bitrate_value} -c:v libx264 -profile:v main -pix_fmt yuv420p -movflags +faststart "{output1_path}"' | |
subprocess.run(command1, shell=True) | |
if generate_video2.get(): | |
# 解像度を計算 | |
resolution_percentage_float = float(resolution_percentage) / 100 | |
command2 = f'ffmpeg -y -framerate {framerate} -start_number {start_number} -i "{folder}/{pattern}" -vf "crop=iw/2:ih:iw/2:0,scale=iw*2*{resolution_percentage_float}:ih*{resolution_percentage_float},transpose=1" -b:v {bitrate_value} -c:v libx264 -profile:v main -pix_fmt yuv420p -movflags +faststart "{output2_path}"' | |
subprocess.run(command2, shell=True) | |
messagebox.showinfo("完了", "動画の変換が完了しました。") # 完了通知のポップアップ | |
app = tk.Tk() | |
app.title('img2video SideBySide (v1.0.1) [FFmpeg]') | |
# 変数の設定 | |
folder_path = tk.StringVar() | |
framerate_entry = tk.StringVar(value="30") | |
output_folder = tk.StringVar() | |
output1 = tk.StringVar() | |
output2 = tk.StringVar() | |
png_pattern = tk.StringVar() | |
smallest_number = tk.IntVar() | |
resolution_percentage_entry = tk.StringVar(value="50") | |
generate_video1 = tk.BooleanVar(value=True) | |
generate_video2 = tk.BooleanVar(value=True) | |
bitrate_entry = tk.StringVar(value="10") # ビットレートのデフォルト値 | |
# GUIの構築 | |
tk.Label(app, text="Output Folder:").pack(padx=5, anchor=tk.W) | |
tk.Entry(app, textvariable=output_folder).pack(fill='x', padx=5, expand=True) | |
tk.Button(app, text="Browse", command=lambda: output_folder.set(filedialog.askdirectory())).pack(padx=5, anchor=tk.W) | |
tk.Label(app, text="PNG Folder:").pack(padx=5, anchor=tk.W) | |
tk.Entry(app, textvariable=folder_path).pack(fill='x', padx=5, expand=True) | |
tk.Button(app, text="Browse", command=browse_folder).pack(padx=5, anchor=tk.W) | |
tk.Label(app, text="Frame Rate (fps):").pack(padx=5, anchor=tk.W) | |
tk.Entry(app, textvariable=framerate_entry).pack(padx=5, anchor=tk.W) | |
tk.Label(app, text="Bitrate (Mbps):").pack(padx=5, anchor=tk.W) | |
tk.Entry(app, textvariable=bitrate_entry).pack(padx=5, anchor=tk.W) | |
tk.Label(app, text="Output Video 1 Path:").pack(padx=5, anchor=tk.W) | |
tk.Entry(app, textvariable=output1).pack(fill='x', padx=5, expand=True) | |
tk.Label(app, text="Output Video 2 Path:").pack(padx=5, anchor=tk.W) | |
tk.Entry(app, textvariable=output2).pack(fill='x', padx=5, expand=True) | |
tk.Label(app, text="Resolution Percentage for Video 2 (%):").pack(padx=5, anchor=tk.W) | |
tk.Entry(app, textvariable=resolution_percentage_entry).pack(padx=5, anchor=tk.W) | |
ttk.Checkbutton(app, text="Generate Video 1", variable=generate_video1).pack(padx=5, anchor=tk.W) | |
ttk.Checkbutton(app, text="Generate Video 2", variable=generate_video2).pack(padx=5, anchor=tk.W) | |
tk.Button(app, text="Convert", command=convert_videos).pack() | |
app.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment