Video export

This commit is contained in:
ABelliqueux 2024-09-08 19:43:39 +02:00
parent bb5a8ceb15
commit 2582da088b
3 changed files with 55 additions and 42 deletions

View File

@ -1,30 +1,16 @@
[DEFAULT]
# gphoto2 = 0, picam = 1, webcam = 2
camera_type = 2
#camera_type = 2
file_extension = 'png'
trigger_mode = 'key'
projects_folder = 'testcv/'
onion_skin_onstartup = true
onionskin_alpha_default = 0.5
onionskin_fx = false
fullscreen_bool = true
screen_w = 1920
screen_h = 1080
framerate = 16
vflip = false
hflip = false
ffmpeg_path = '/usr/bin/ffmpeg'
export_options = 'scale=1920:-1,crop=1920:1080:0:102'
cache_images = false
[CAMERA]
# Nikon D40x
# Add meter mode to center, focus mode to fixed selection
# /main/capturesettings/autofocusarea to 0
# /main/capturesettings/focusmetermode to 1
capturemode = 3 # use IR remote
imagesize = 2 # use size S (1936x1296)
whitebalance = 1 # Natural light
capturetarget = 0 # Internal memory
nocfcardrelease = 0 # Allow capture without sd card
recordingmedia = 1 # Write to RAM
[CHECK]
acpower = 0 # we d'rather have this set to 0 which means we're running on AC

View File

@ -1,4 +1,3 @@
import collections
import cv2
import gettext
from itertools import count
@ -6,8 +5,10 @@ import os
from send2trash import send2trash
import signal
import sys
import subprocess
import time
import tomllib
# TODO : remove tkinter dep
import tkinter as tk
from tkinter import filedialog, messagebox
import numpy as np
@ -25,7 +26,7 @@ _ = gettext.translation('template', localedir='locales', languages=[LOCALE]).get
# defaults
project_settings_defaults = {
# gphoto2 = 0, picam = 1, webcam = 2
'camera_type': 0,
'camera_type': 2,
'file_extension':'JPG',
'trigger_mode': 'key',
'projects_folder': '',
@ -39,6 +40,7 @@ project_settings_defaults = {
'framerate' : 16,
'vflip' : False,
'hflip' : False,
'ffmpeg_path' : None,
'export_options' : 'scale=1920:-1,crop=1920:1080:0:102',
'cache_images' : False,
'liveview' : False,
@ -52,8 +54,6 @@ for location in config_locations:
if os.path.exists( os.path.expanduser(os.path.join(location, 'config.toml'))):
with open(os.path.expanduser(location + 'config.toml'), 'rb') as config_file:
project_settings = tomllib.load(config_file)
if 'CHECK' in project_settings:
camera_status = project_settings['CHECK']
if 'CAMERA' in project_settings:
camera_settings = project_settings['CAMERA']
if 'DEFAULT' in project_settings:
@ -130,26 +130,16 @@ def get_session_folder():
def get_frames_list(folder:str):
# Get JPG files list in current directory
# ~ existing_animation_files = []
# ~ if not len(img_list):
existing_animation_files = img_list
# ~ existing_animation_files =
file_list = os.listdir(folder)
for file in file_list:
if (file.startswith(project_letter) and file.endswith(project_settings['file_extension'])):
if file not in existing_animation_files:
existing_animation_files.append(file)
# ~ existing_animation_files[file] = None
if len(existing_animation_files) == 0:
# If no images were found, return fake name set to -001 to init file count to 000
return ["{}.{:04d}.{}".format(next_letter, -1, project_settings['file_extension'])]
# ~ return {"{}.{:04d}.{}".format(project_letter, -1, project_settings['file_extension']):None}
# ~ else:
# Remove fake file name as soon as we have real pics
# ~ if 'A.-001.JPG' in existing_animation_files:
# ~ existing_animation_files.pop('A.-001.JPG')
existing_animation_files.sort()
# ~ existing_animation_files = collections.OrderedDict(sorted(existing_animation_files.items()))
return existing_animation_files
@ -159,8 +149,6 @@ def get_last_frame(folder:str):
# Get last file
# Filename pattern is A.0001.JPG
return existing_animation_files[-1].split('.')
# ~ print(next(reversed(existing_animation_files.keys())))
# ~ return next(reversed(existing_animation_files.keys())).split('.')
def get_onionskin_frame(folder:str, index=None):
@ -322,6 +310,31 @@ def signal_handler(sig, frame):
ctrlc_pressed = True
def parse_export_options(options:str, vflip:bool=False, hflip:bool=False):
if vflip:
options += ',vflip'
if hflip:
options += ',hflip'
return options
def export_animation(input_filename, export_filename):
input_format, framerate = input_options
if project_settings['ffmpeg_path'] is None:
return False
ffmpeg_process = subprocess.Popen([
project_settings['ffmpeg_path'],
'-v','quiet',
'-y',
'-f', input_format,
'-r', framerate,
'-i', input_filename,
'-vf', output_options,
export_filename,
])
return ffmpeg_process
def main(args):
global onionskin, playback, loop_playback, playhead, index
@ -363,7 +376,7 @@ def main(args):
og_frame = overlay
# Resize preview
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
# ~ if overlay is not None:
# Apply onionskin
overlay = cv2.addWeighted(frame, 1.0, overlay, project_settings['onionskin_alpha_default'], 0)
# Flip preview (0 = vert; 1 = hor)
if project_settings['vflip'] or project_settings['hflip']:
@ -373,7 +386,7 @@ def main(args):
flip_dir = 0
elif project_settings['hflip']:
flip_dir = 1
frame = cv2.flip(overlay, flip_dir)
overlay = cv2.flip(overlay, flip_dir)
if not ret:
print(_("Failed to grab frame."))
break
@ -406,11 +419,10 @@ def main(args):
print("R: {}".format(index))
# Key e / keypad *
elif (k%256 == 101) or (k%256 == 42):
# TODO : Export
print("Export")
ffmpeg_process = export_animation(input_filename, export_filename)
# Key Return
elif (k%256 == 13):
# TODO : Playback
print("Playback")
playhead = index
loop_playback = True
@ -449,10 +461,17 @@ def main(args):
continue
else:
print(k) # else print its value
if 'ffmpeg_process' in locals():
if ffmpeg_process.poll() is None:
print("Ffmpeg is still running. Waiting for task to complete.")
try:
ffmpeg_process.wait(timeout=1)
except:
print("Terminating running process...")
ffmpeg_process.terminate()
cam.release()
cv2.destroyAllWindows()
ctrlc_pressed = False
projects_folder = project_settings['projects_folder']
img_list = []
@ -468,7 +487,17 @@ else:
project_letter = 'A'
img_list = get_frames_list(savepath)
index = len(img_list)-1
print(index)
print(project_letter)
# Export settings
input_filename = "{folder}{letter}{sep}{letter}.%04d.{ext}".format(folder=projects_folder, sep=os.sep, letter=project_letter, ext=project_settings['file_extension'])
print(input_filename)
input_options = ["image2", str(project_settings['framerate'])]
# ~ output_filename = "{folder}{sep}{filename}.mp4".format(folder=projects_folder, sep=os.sep, filename=savepath.split(os.sep)[-1])
output_filename = "{filename}.mp4".format(filename=project_letter)
output_options = parse_export_options(project_settings['export_options'], project_settings['vflip'], project_settings['hflip'] )
export_filename = os.path.join(savepath, output_filename)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)

View File

@ -1,6 +1,4 @@
gphoto2
pillow
python-ffmpeg
Send2Trash
opencv-python
numpy
tkinter