Picamera2 support

This commit is contained in:
ABelliqueux 2024-02-26 18:32:18 +01:00
parent bf156cb6e2
commit b6cf074362
2 changed files with 65 additions and 29 deletions

View File

@ -1,4 +1,5 @@
[DEFAULT] [DEFAULT]
camera_type = 0
file_extension = 'JPG' file_extension = 'JPG'
trigger_mode = 'key' trigger_mode = 'key'
projects_folder = '' projects_folder = ''

View File

@ -30,7 +30,7 @@ from io import BytesIO
from itertools import count from itertools import count
import locale import locale
import os import os
from PIL import Image, ImageTk, ImageFilter, ImageDraw, ImageFont from PIL import Image, ImageTk, ImageFilter, ImageDraw, ImageOps, ImageFont
import sys import sys
import threading import threading
import time import time
@ -73,6 +73,8 @@ _ = gettext.translation('template', localedir='locales', languages=[LOCALE]).get
# Config # Config
# defaults # defaults
project_settings_defaults = { project_settings_defaults = {
# DSLR = 0, picam = 1, webcam = 2
'camera_type': 0,
'file_extension':'JPG', 'file_extension':'JPG',
'trigger_mode': 'key', 'trigger_mode': 'key',
'projects_folder': '', 'projects_folder': '',
@ -103,7 +105,7 @@ for location in config_locations:
with open(os.path.expanduser(location + 'config.toml'), 'rb') as config_file: with open(os.path.expanduser(location + 'config.toml'), 'rb') as config_file:
project_settings = tomllib.load(config_file) project_settings = tomllib.load(config_file)
if 'CHECK' in project_settings: if 'CHECK' in project_settings:
camera_settings = project_settings['CHECK'] camera_status = project_settings['CHECK']
if 'CAMERA' in project_settings: if 'CAMERA' in project_settings:
camera_settings = project_settings['CAMERA'] camera_settings = project_settings['CAMERA']
if 'DEFAULT' in project_settings: if 'DEFAULT' in project_settings:
@ -115,6 +117,8 @@ class KISStopmo(tk.Tk):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
self.check_config() self.check_config()
if project_settings['camera_type']:
from picamera2 import Picamera2
# Default config # Default config
# Set script settings according to config file # Set script settings according to config file
self.onion_skin = project_settings['onion_skin_onstartup'] self.onion_skin = project_settings['onion_skin_onstartup']
@ -157,16 +161,36 @@ class KISStopmo(tk.Tk):
self.img_index = self.check_range(len(self.img_list)-1, False) self.img_index = self.check_range(len(self.img_list)-1, False)
self.splash_text = _("No images yet! Start shooting...") self.splash_text = _("No images yet! Start shooting...")
# Camera setup # Camera setup
self.camera = gp.check_result(gp.gp_camera_new()) if project_settings['camera_type'] != 0:
try: try:
gp.check_result(gp.gp_camera_init(self.camera)) self.camera = Picamera2()
# get configuration tree self.picam_conf_full = self.camera.create_still_configuration(main={"size":(1920,1080)}, lores={"size":(800,600)})
self.current_camera_config = gp.check_result(gp.gp_camera_get_config(self.camera)) self.camera.configure(self.picam_conf_full)
self.apply_camera_settings(self.camera, self.current_camera_config) # Autofocus, get lens position and switch to manual mode
if self.check_status(self.camera, self.current_camera_config) is False: # Set Af mode to Manual (1). Default is Continuous (2), Auto is 1
print(_("Warning: Some settings are not set to the recommended value!")) # TODO: lock exposure, wb
except: self.camera.set_controls({'AfMode':1})
self.splash_text += _("\nCamera not found or busy.") self.camera.start(show_preview=False)
self.camera.autofocus_cycle()
self.camera_lenspos = self.camera.capture_metadata()['LensPosition']
self.camera.set_controls({'AfMode':0, 'AwbEnable': False, 'AeEnable': False})
self.camera.stop()
except:
self.camera = False
self.splash_text += _("\nCamera not found or busy.")
else:
self.camera = gp.check_result(gp.gp_camera_new())
try:
gp.check_result(gp.gp_camera_init(self.camera))
# get configuration tree
self.current_camera_config = gp.check_result(gp.gp_camera_get_config(self.camera))
self.apply_camera_settings(self.camera, self.current_camera_config)
if self.check_status(self.camera, self.current_camera_config) is False:
print(_("Warning: Some settings are not set to the recommended value!"))
except:
self.camera = False
self.splash_text += _("\nCamera not found or busy.")
self.timeout = 3000 # milliseconds self.timeout = 3000 # milliseconds
@ -200,8 +224,8 @@ class KISStopmo(tk.Tk):
if project_settings['trigger_mode'] != 'event': if project_settings['trigger_mode'] != 'event':
root.bind("<j>", self.capture_image) root.bind("<j>", self.capture_image)
def check_config(self): def check_config(self):
global project_settings global project_settings
for setting in project_settings_defaults: for setting in project_settings_defaults:
@ -414,7 +438,8 @@ class KISStopmo(tk.Tk):
# ~ image = Image.open(filepath) # ~ image = Image.open(filepath)
# ~ print( filetuple[0] + "is not in cache") # ~ print( filetuple[0] + "is not in cache")
image = Image.open(os.path.join(self.savepath, filetuple[0])) image = Image.open(os.path.join(self.savepath, filetuple[0]))
image = image.resize((w, h)) # ~ image = image.resize((w, h),reducing_gap=1.5)
image = ImageOps.fit(image, (w, h))
if vflip: if vflip:
image = image.transpose(Image.Transpose.FLIP_TOP_BOTTOM) image = image.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
if hflip: if hflip:
@ -465,6 +490,7 @@ class KISStopmo(tk.Tk):
def update_image(self, event=None, index=None): def update_image(self, event=None, index=None):
# TODO : check event mode stille works
if event is not None: if event is not None:
self.img_index = self.check_range(self.img_index+1) self.img_index = self.check_range(self.img_index+1)
if index is None: if index is None:
@ -639,20 +665,25 @@ class KISStopmo(tk.Tk):
next_filename = self.return_next_frame_number(self.get_last_frame(self.savepath)) next_filename = self.return_next_frame_number(self.get_last_frame(self.savepath))
# build full path to file # build full path to file
target_path = os.path.join(self.savepath, next_filename) target_path = os.path.join(self.savepath, next_filename)
# ~ print(target_path) if project_settings['camera_type']:
# Get file from camera self.camera.start(show_preview=False)
if event_data is None: self.camera.set_controls({"LensPosition": self.camera_lenspos})
# ~ print("j pressed") self.camera.capture_file(target_path, 'main', format='jpeg')
new_frame_path = self.camera.capture(gp.GP_CAPTURE_IMAGE) self.camera.stop()
# ~ self.camera.trigger_capture()
new_frame = self.camera.file_get(
new_frame_path.folder, new_frame_path.name, gp.GP_FILE_TYPE_NORMAL)
print(_("Saving {}{}").format(new_frame_path.folder, new_frame_path.name))
else: else:
print(_("Getting file {}").format(event_data.name)) # Get file from DSLR camera
new_frame = self.camera.file_get( if event_data is None:
event_data.folder, event_data.name, gp.GP_FILE_TYPE_NORMAL) # ~ print("j pressed")
new_frame.save(target_path) new_frame_path = self.camera.capture(gp.GP_CAPTURE_IMAGE)
# ~ self.camera.trigger_capture()
new_frame = self.camera.file_get(
new_frame_path.folder, new_frame_path.name, gp.GP_FILE_TYPE_NORMAL)
print(_("Saving {}{}").format(new_frame_path.folder, new_frame_path.name))
else:
print(_("Getting file {}").format(event_data.name))
new_frame = self.camera.file_get(
event_data.folder, event_data.name, gp.GP_FILE_TYPE_NORMAL)
new_frame.save(target_path)
# ~ next_filename = prefix+next(filename)+ext # ~ next_filename = prefix+next(filename)+ext
# ~ print(self.img_list) # ~ print(self.img_list)
if '{letter}.-001.JPG'.format(letter=self.project_letter) in self.img_list: if '{letter}.-001.JPG'.format(letter=self.project_letter) in self.img_list:
@ -698,7 +729,11 @@ class KISStopmo(tk.Tk):
# check with self.export_task.done() == True ? https://stackoverflow.com/questions/69350645/proper-way-to-retrieve-the-result-of-tasks-in-asyncio # check with self.export_task.done() == True ? https://stackoverflow.com/questions/69350645/proper-way-to-retrieve-the-result-of-tasks-in-asyncio
def end_bg_loop(KISStopmo): def end_bg_loop(KISStopmo):
KISStopmo.camera.exit() if KISStopmo.camera is not False:
if project_settings['camera_type']:
KISStopmo.camera.stop()
else:
KISStopmo.camera.exit()
KISStopmo.end_thread = True KISStopmo.end_thread = True
root = tk.Tk() root = tk.Tk()