Video export
This commit is contained in:
parent
bb5a8ceb15
commit
2582da088b
20
config.toml
20
config.toml
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
gphoto2
|
||||
pillow
|
||||
python-ffmpeg
|
||||
Send2Trash
|
||||
opencv-python
|
||||
numpy
|
||||
tkinter
|
||||
|
|
Loading…
Reference in New Issue