Remove tk dep, use date for session option
This commit is contained in:
parent
2582da088b
commit
0e49b446c6
Binary file not shown.
|
@ -1,5 +1,6 @@
|
|||
[DEFAULT]
|
||||
#camera_type = 2
|
||||
use_date_for_folder = false
|
||||
file_extension = 'png'
|
||||
projects_folder = 'testcv/'
|
||||
onion_skin_onstartup = true
|
||||
|
|
151
frame_opencv.py
151
frame_opencv.py
|
@ -2,6 +2,8 @@ import cv2
|
|||
import gettext
|
||||
from itertools import count
|
||||
import os
|
||||
# Needed for utf-8 text
|
||||
from PIL import ImageFont, ImageDraw, Image
|
||||
from send2trash import send2trash
|
||||
import signal
|
||||
import sys
|
||||
|
@ -9,14 +11,14 @@ import subprocess
|
|||
import time
|
||||
import tomllib
|
||||
# TODO : remove tkinter dep
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog, messagebox
|
||||
# ~ import tkinter as tk
|
||||
# ~ from tkinter import messagebox
|
||||
import numpy as np
|
||||
|
||||
|
||||
running_from_folder = os.path.realpath(__file__)
|
||||
alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
||||
next_letter = 'A'
|
||||
|
||||
|
||||
# l10n
|
||||
LOCALE = os.getenv('LANG', 'en_EN')
|
||||
|
@ -30,7 +32,7 @@ project_settings_defaults = {
|
|||
'file_extension':'JPG',
|
||||
'trigger_mode': 'key',
|
||||
'projects_folder': '',
|
||||
# ~ 'project_letter': 'A'
|
||||
'use_date_for_folder': False,
|
||||
'onion_skin_onstartup' : False,
|
||||
'onionskin_alpha_default' : 0.4,
|
||||
'onionskin_fx' : False,
|
||||
|
@ -61,20 +63,85 @@ for location in config_locations:
|
|||
config_found_msg = _("Found configuration file in {}").format(os.path.expanduser(location))
|
||||
print(config_found_msg)
|
||||
|
||||
# Create blank image with 0s
|
||||
blank_image = np.zeros((project_settings['screen_h'], project_settings['screen_w'],3), np.uint8)
|
||||
# Set all pixels to light grey
|
||||
blank_image[:,0:] = 200
|
||||
font = cv2.FONT_HERSHEY_SIMPLEX
|
||||
cv2.putText(blank_image,_("Pas d'image"),(int(project_settings['screen_w']/3),int(project_settings['screen_h']/2)), font, 4, (100, 100, 100), 8, cv2.LINE_AA)
|
||||
def generate_text_image(text:str, screen_w, screen_h, bullets=False):
|
||||
text_image = Image.new('RGB',
|
||||
(screen_w, screen_h),
|
||||
(0,0,0)
|
||||
)
|
||||
# ~ text_image = np.zeros((screen_h,screen_w,3),np.uint8)
|
||||
# ~ text_image_pil = Image.fromarray(text_image)
|
||||
text_image_draw = ImageDraw.Draw(text_image)
|
||||
if text is not None:
|
||||
font = ImageFont.truetype("Tuffy_Bold.ttf", (screen_w/32))
|
||||
font_len = font.getlength(text.split('\n')[0])
|
||||
text_image_draw.multiline_text((screen_w/2 - font_len/2, screen_h/2 ),
|
||||
text,
|
||||
fill=(255, 255, 255),
|
||||
font=font,
|
||||
align='center',
|
||||
spacing=20
|
||||
)
|
||||
if bullets:
|
||||
dot_radius = screen_w/24
|
||||
x_unit = (screen_w/32)
|
||||
y_unit = (screen_h/32)
|
||||
green_dot = (x_unit*14, y_unit*24)
|
||||
red_dot = (green_dot[0]+x_unit*4, green_dot[1])
|
||||
# Green dot
|
||||
text_image_draw.circle(green_dot,
|
||||
dot_radius,
|
||||
fill=(0,255,0),
|
||||
outline=None,
|
||||
width=1
|
||||
)
|
||||
text_image_draw.text(green_dot,
|
||||
_("Yes"),
|
||||
fill=(0, 0, 0),
|
||||
font=font,
|
||||
anchor="mm",
|
||||
spacing=20
|
||||
)
|
||||
# Red dot
|
||||
text_image_draw.circle(red_dot,
|
||||
dot_radius,
|
||||
fill=(0,0,255),
|
||||
outline=None,
|
||||
width=1
|
||||
)
|
||||
text_image_draw.text(red_dot,
|
||||
_("No"),
|
||||
fill=(0, 0, 0),
|
||||
font=font,
|
||||
anchor="mm",
|
||||
spacing=20
|
||||
)
|
||||
text_image = np.array(text_image)
|
||||
return text_image
|
||||
|
||||
def find_letter_after(letter:str):
|
||||
if letter in alphabet and alphabet.index(letter) < len(alphabet) - 1:
|
||||
return alphabet[alphabet.index(letter) + 1]
|
||||
|
||||
def askyesno(text:str):
|
||||
blank = generate_text_image(text, project_settings['screen_w'], project_settings['screen_h'], bullets=True)
|
||||
cv2.imshow("StopiCV", blank)
|
||||
# Wait for input to continue
|
||||
answer = cv2.waitKey(0)
|
||||
# Space pressed == yes
|
||||
if answer%256 == 32 or answer%256 == 48 :
|
||||
return True
|
||||
# Any other key == no
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def find_letter_after(letter:str, date=False):
|
||||
if letter in alphabet and alphabet.index(letter) < len(alphabet) - 1 and not date:
|
||||
letter = alphabet[alphabet.index(letter) + 1]
|
||||
else:
|
||||
# Create folder with date
|
||||
year,mon,day,hour,minute,sec,wd,yd,dst = time.localtime()
|
||||
letter = '{}-{}-{}_{}-{}-{}'.format(year,mon,day,hour,minute,sec)
|
||||
return letter
|
||||
|
||||
|
||||
def get_projects_folder():
|
||||
if len(projects_folder):
|
||||
project_folder = projects_folder
|
||||
|
@ -99,28 +166,34 @@ def get_projects_folder():
|
|||
|
||||
|
||||
def get_session_folder():
|
||||
global next_letter
|
||||
project_folder = get_projects_folder()
|
||||
if project_folder:
|
||||
sessions_list = []
|
||||
dir_list = os.listdir(project_folder)
|
||||
# Filter folders with name only one char long
|
||||
for dir in dir_list:
|
||||
if len(dir) == 1 and dir in alphabet:
|
||||
sessions_list.append(dir)
|
||||
for folder in dir_list:
|
||||
if len(folder) == 1 and folder in alphabet:
|
||||
sessions_list.append(folder)
|
||||
# If folders exist, find last folder in alphabetical order
|
||||
if len(sessions_list):
|
||||
sessions_list.sort()
|
||||
last_letter = sessions_list[-1]
|
||||
# By default, find next letter for a new session
|
||||
next_letter = find_letter_after(last_letter)
|
||||
next_letter = find_letter_after(last_letter, project_settings['use_date_for_folder'])
|
||||
if next_letter is False:
|
||||
return False
|
||||
# A previous session folder was found; ask the user if they wish to resume session
|
||||
resume_session = tk.messagebox.askyesno(_("Resume session?"), _("A previous session was found in {}, resume shooting ?").format(os.path.join(project_folder, last_letter)))
|
||||
if resume_session:
|
||||
next_letter = last_letter
|
||||
if not project_settings['use_date_for_folder']:
|
||||
resume_session = askyesno(_("A previous session was found in {},\n resume shooting ?").format(os.path.join(project_folder, last_letter)))
|
||||
# ~ resume_session = tk.messagebox.askyesno(_("Resume session?"), _("A previous session was found in {}, resume shooting ?").format(os.path.join(project_folder, last_letter)))
|
||||
if resume_session:
|
||||
next_letter = last_letter
|
||||
else:
|
||||
next_letter = 'A'
|
||||
if not project_settings['use_date_for_folder']:
|
||||
next_letter = 'A'
|
||||
else:
|
||||
next_letter = find_letter_after('A', project_settings['use_date_for_folder'])
|
||||
if os.path.exists(os.path.join(project_folder, next_letter)) is False:
|
||||
os.mkdir(os.path.join(project_folder, next_letter))
|
||||
print(_("Using {} as session folder.").format(os.path.join(project_folder, next_letter)))
|
||||
|
@ -346,10 +419,10 @@ def main(args):
|
|||
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
|
||||
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
|
||||
|
||||
cv2.namedWindow("StopiCV", cv2.WINDOW_GUI_NORMAL)
|
||||
cv2.setWindowProperty("StopiCV", cv2.WND_PROP_OPENGL, cv2.WINDOW_OPENGL)
|
||||
cv2.setWindowProperty("StopiCV", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
|
||||
cv2.setWindowProperty("StopiCV", cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_KEEPRATIO)
|
||||
# ~ cv2.namedWindow("StopiCV", cv2.WINDOW_GUI_NORMAL)
|
||||
# ~ cv2.setWindowProperty("StopiCV", cv2.WND_PROP_OPENGL, cv2.WINDOW_OPENGL)
|
||||
# ~ cv2.setWindowProperty("StopiCV", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
|
||||
# ~ cv2.setWindowProperty("StopiCV", cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_KEEPRATIO)
|
||||
|
||||
frame = get_onionskin_frame(savepath, index)
|
||||
while True:
|
||||
|
@ -403,20 +476,16 @@ def main(args):
|
|||
# Key left
|
||||
elif (k%256 == 81) or (k%256 == 52):
|
||||
# Displau previous frame
|
||||
print("Left")
|
||||
if len(img_list):
|
||||
if playback:
|
||||
playback = False
|
||||
index, frame = previous_frame(index)
|
||||
print("L: {}".format(index))
|
||||
elif (k%256 == 83) or (k%256 == 54):
|
||||
# Displau next frame
|
||||
print("Right")
|
||||
if len(img_list):
|
||||
if playback:
|
||||
playback = False
|
||||
index, frame = next_frame(index)
|
||||
print("R: {}".format(index))
|
||||
# Key e / keypad *
|
||||
elif (k%256 == 101) or (k%256 == 42):
|
||||
print("Export")
|
||||
|
@ -444,8 +513,8 @@ def main(args):
|
|||
print(_("Window was closed, exiting..."))
|
||||
break
|
||||
# Take pic
|
||||
# SPACE or numpad 0 pressed
|
||||
elif (k%256 == 32) or (k%256 == 48):
|
||||
# SPACE pressed
|
||||
img_name = return_next_frame_number(get_last_frame(savepath))
|
||||
img_path = os.path.join(savepath, img_name)
|
||||
cv2.imwrite(img_path, og_frame)
|
||||
|
@ -455,31 +524,43 @@ def main(args):
|
|||
else:
|
||||
index += 1
|
||||
frame = get_onionskin_frame(savepath, index)
|
||||
# TODO : go back to last frame ?
|
||||
# REMOVE : Debug print keycode
|
||||
elif k==-1: # normally -1 returned,so don't print it
|
||||
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.")
|
||||
if ffmpeg_process.poll() is None:
|
||||
print(_("Ffmpeg is still running.\n Waiting for task to complete."))
|
||||
msg = generate_text_image(_("Ffmpeg is still running.\n Waiting for task to complete."),
|
||||
project_settings['screen_w'], project_settings['screen_h']
|
||||
)
|
||||
cv2.imshow("StopiCV", msg)
|
||||
# Force window refresh
|
||||
cv2.pollKey()
|
||||
try:
|
||||
ffmpeg_process.wait(timeout=1)
|
||||
ffmpeg_process.wait(timeout=20)
|
||||
except:
|
||||
print("Terminating running process...")
|
||||
print(_("Terminating running process..."))
|
||||
ffmpeg_process.terminate()
|
||||
cam.release()
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
cv2.namedWindow("StopiCV", cv2.WINDOW_GUI_NORMAL)
|
||||
cv2.setWindowProperty("StopiCV", cv2.WND_PROP_OPENGL, cv2.WINDOW_OPENGL)
|
||||
cv2.setWindowProperty("StopiCV", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
|
||||
cv2.setWindowProperty("StopiCV", cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_KEEPRATIO)
|
||||
|
||||
ctrlc_pressed = False
|
||||
projects_folder = project_settings['projects_folder']
|
||||
next_letter = 'Z'
|
||||
img_list = []
|
||||
savepath = get_session_folder()
|
||||
onionskin = project_settings['onion_skin_onstartup']
|
||||
playback = False
|
||||
playhead = 0
|
||||
loop_playback = True
|
||||
blank_image = generate_text_image(_("No images yet! Start shooting..."), project_settings['screen_w'], project_settings['screen_h'])
|
||||
|
||||
if len(savepath):
|
||||
project_letter = savepath.split(os.sep)[-1]
|
||||
|
|
Binary file not shown.
|
@ -6,14 +6,20 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2024-02-18 11:30+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"PO-Revision-Date: 2024-09-09 12:28+0200\n"
|
||||
"Last-Translator: arthus <arthus@ateliers>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
msgid "Yes"
|
||||
msgstr "Oui"
|
||||
|
||||
msgid "No"
|
||||
msgstr "Non"
|
||||
|
||||
#: ../main_c.py:96
|
||||
msgid "No configuration file found, using defaults."
|
||||
msgstr "Aucun fichier de configuration trouvé, utilisation des valeurs par défaut."
|
||||
|
@ -37,8 +43,8 @@ msgid ""
|
|||
msgstr "\nCaméra introuvable ou occupée."
|
||||
|
||||
#: ../main_c.py:256
|
||||
msgid "A previous session was found in {}, resume shooting ?"
|
||||
msgstr "Une session précédente à été trouvée dans {}, reprendre la session ?"
|
||||
msgid "A previous session was found in {},\n resume shooting ?"
|
||||
msgstr "Une session précédente à été trouvée dans {},\n reprendre la session ?"
|
||||
|
||||
#: ../main_c.py:256
|
||||
msgid "Resume session?"
|
||||
|
@ -86,3 +92,9 @@ msgstr "Exportation dans {}"
|
|||
|
||||
msgid "Mp4 files"
|
||||
msgstr "Fichier Mp4"
|
||||
|
||||
msgid "Ffmpeg is still running.\n Waiting for task to complete."
|
||||
msgstr "Ffmpeg est toujours en cours d'éxécution.\n Attente de la fin du processus.'"
|
||||
|
||||
msgid "Terminating running process..."
|
||||
msgstr "Terminaison des processus en cours..."
|
||||
|
|
|
@ -6,8 +6,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2024-02-19 18:47+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"PO-Revision-Date: 2024-09-09 12:28+0200\n"
|
||||
"Last-Translator: arthus <arthus@ateliers>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@ -15,6 +15,12 @@ msgstr ""
|
|||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: ../main_c.py:96
|
||||
msgid "No configuration file found, using defaults."
|
||||
msgstr ""
|
||||
|
@ -38,7 +44,7 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: ../main_c.py:281
|
||||
msgid "A previous session was found in {}, resume shooting ?"
|
||||
msgid "A previous session was found in {},\n resume shooting ?"
|
||||
msgstr ""
|
||||
|
||||
#: ../main_c.py:281
|
||||
|
@ -85,3 +91,8 @@ msgstr ""
|
|||
msgid "Exporting to {}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ffmpeg is still running.\n Waiting for task to complete."
|
||||
msgstr ""
|
||||
|
||||
msgid "Terminating running process..."
|
||||
msgstr ""
|
Loading…
Reference in New Issue