Compare commits
4 Commits
master
...
picamera_s
Author | SHA1 | Date |
---|---|---|
ABelliqueux | 0d8434136a | |
ABelliqueux | 6219e18b96 | |
ABelliqueux | 913a4b7eb6 | |
ABelliqueux | 0bf7fb9d98 |
20
config.toml
20
config.toml
|
@ -1,21 +1,23 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
cam_is_showmewebcam = true
|
cam_is_picam = true
|
||||||
|
cam_is_showmewebcam = false
|
||||||
use_date_for_folder = false
|
use_date_for_folder = false
|
||||||
file_extension = 'png'
|
file_extension = 'jpg'
|
||||||
|
jpg_quality = 88
|
||||||
projects_folder = ''
|
projects_folder = ''
|
||||||
onion_skin_onstartup = true
|
onion_skin_onstartup = true
|
||||||
onionskin_alpha_default = 0.5
|
onionskin_alpha_default = 0.5
|
||||||
fullscreen_bool = true
|
fullscreen_bool = true
|
||||||
screen_w = 1920
|
screen_w = 1440
|
||||||
screen_h = 1080
|
screen_h = 900
|
||||||
framerate = 16
|
framerate = 16
|
||||||
ffmpeg_path = '/usr/bin/ffmpeg'
|
ffmpeg_path = '/usr/bin/ffmpeg'
|
||||||
export_options = 'scale=1920:-1,crop=1920:1080'
|
export_options = 'scale=1920:-1,crop=1920:1080'
|
||||||
[CAMERA]
|
[CAMERA]
|
||||||
cam_w = 1600
|
cam_w = 1920
|
||||||
cam_h = 900
|
cam_h = 1080
|
||||||
vflip = 1
|
vflip = 0
|
||||||
hflip = 1
|
hflip = 0
|
||||||
auto_exposure = 1
|
auto_exposure = 1
|
||||||
white_balance_auto_preset = 2
|
white_balance_auto_preset = 1
|
||||||
video_bitrate=25000000
|
video_bitrate=25000000
|
||||||
|
|
202
frame_opencv.py
202
frame_opencv.py
|
@ -1,3 +1,4 @@
|
||||||
|
#!/bin/env python
|
||||||
import cv2
|
import cv2
|
||||||
import gettext
|
import gettext
|
||||||
from itertools import count
|
from itertools import count
|
||||||
|
@ -14,6 +15,10 @@ import tomllib
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import serialutils
|
import serialutils
|
||||||
|
|
||||||
|
# Run from SSH
|
||||||
|
if not os.getenv('DISPLAY'):
|
||||||
|
os.putenv('DISPLAY', ':0')
|
||||||
|
|
||||||
running_from_folder = os.path.realpath(__file__)
|
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']
|
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']
|
||||||
|
|
||||||
|
@ -25,9 +30,11 @@ _ = gettext.translation('template', localedir='locales', languages=[LOCALE]).get
|
||||||
# Config
|
# Config
|
||||||
# defaults
|
# defaults
|
||||||
project_settings_defaults = {
|
project_settings_defaults = {
|
||||||
|
'cam_is_picam': True,
|
||||||
'cam_is_showmewebcam': False,
|
'cam_is_showmewebcam': False,
|
||||||
'use_date_for_folder': False,
|
'use_date_for_folder': False,
|
||||||
'file_extension':'png',
|
'file_extension':'png',
|
||||||
|
'jpg_quality':90,
|
||||||
'projects_folder': '',
|
'projects_folder': '',
|
||||||
'onion_skin_onstartup' : False,
|
'onion_skin_onstartup' : False,
|
||||||
'onionskin_alpha_default' : 0.4,
|
'onionskin_alpha_default' : 0.4,
|
||||||
|
@ -65,13 +72,22 @@ for location in config_locations:
|
||||||
config_found_msg = _("Found configuration file in {}").format(os.path.expanduser(location))
|
config_found_msg = _("Found configuration file in {}").format(os.path.expanduser(location))
|
||||||
print(config_found_msg)
|
print(config_found_msg)
|
||||||
|
|
||||||
camera_current_settings = {
|
if project_settings['cam_is_showmewebcam']:
|
||||||
|
camera_current_settings = {
|
||||||
'auto_exposure': dict(min=0, max=1, default=camera_settings['auto_exposure'], value=camera_settings['auto_exposure']),
|
'auto_exposure': dict(min=0, max=1, default=camera_settings['auto_exposure'], value=camera_settings['auto_exposure']),
|
||||||
'white_balance_auto_preset': dict(min=0, max=9, default=camera_settings['white_balance_auto_preset'], value=camera_settings['white_balance_auto_preset']),
|
'white_balance_auto_preset': dict(min=0, max=9, default=camera_settings['white_balance_auto_preset'], value=camera_settings['white_balance_auto_preset']),
|
||||||
'horizontal_flip': dict(min=0, max=1, default=camera_settings['hflip'], value=camera_settings['hflip']),
|
'horizontal_flip': dict(min=0, max=1, default=camera_settings['hflip'], value=camera_settings['hflip']),
|
||||||
'vertical_flip': dict(min=0, max=1, default=camera_settings['vflip'], value=camera_settings['vflip']),
|
'vertical_flip': dict(min=0, max=1, default=camera_settings['vflip'], value=camera_settings['vflip']),
|
||||||
'video_bitrate': dict(min=25000000, max=25000000, default=camera_settings['video_bitrate'], value=camera_settings['video_bitrate']),
|
'video_bitrate': dict(min=25000000, max=25000000, default=camera_settings['video_bitrate'], value=camera_settings['video_bitrate']),
|
||||||
}
|
}
|
||||||
|
else: # cam is picam
|
||||||
|
camera_current_settings = {
|
||||||
|
'auto_exposure': dict(min=0, max=4, default=camera_settings['auto_exposure'], value=camera_settings['auto_exposure']),
|
||||||
|
'white_balance_auto_preset': dict(min=0, max=7, default=camera_settings['white_balance_auto_preset'], value=camera_settings['white_balance_auto_preset']),
|
||||||
|
'horizontal_flip': dict(min=0, max=1, default=camera_settings['hflip'], value=camera_settings['hflip']),
|
||||||
|
'vertical_flip': dict(min=0, max=1, default=camera_settings['vflip'], value=camera_settings['vflip']),
|
||||||
|
'anti_flicker': dict(min=0, max=2, default=1, value=1),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def apply_cam_setting(cam_settings:dict, to_set:list=None):
|
def apply_cam_setting(cam_settings:dict, to_set:list=None):
|
||||||
|
@ -113,7 +129,7 @@ def generate_text_image(text:str, screen_w, screen_h, bullets=False):
|
||||||
)
|
)
|
||||||
text_image_draw = ImageDraw.Draw(text_image)
|
text_image_draw = ImageDraw.Draw(text_image)
|
||||||
if text is not None:
|
if text is not None:
|
||||||
font = ImageFont.truetype("Tuffy_Bold.ttf", (screen_w/32))
|
font = ImageFont.truetype("Tuffy_Bold.ttf", int(screen_w/32))
|
||||||
lines = text.split('\n')
|
lines = text.split('\n')
|
||||||
longest_line = lines[0]
|
longest_line = lines[0]
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
@ -435,12 +451,45 @@ def main(args):
|
||||||
|
|
||||||
global onionskin, liveview_only, playback, loop_playback, playhead, index, img_list, first_playback, camera_current_settings
|
global onionskin, liveview_only, playback, loop_playback, playhead, index, img_list, first_playback, camera_current_settings
|
||||||
|
|
||||||
|
if not project_settings['cam_is_picam']:
|
||||||
if not testDevice(0):
|
if not testDevice(0):
|
||||||
print(_("No camera device found. Exiting..."))
|
print(_("No camera device found. Exiting..."))
|
||||||
return 1
|
return 1
|
||||||
cam = cv2.VideoCapture(0)
|
cam = cv2.VideoCapture(0)
|
||||||
cam.set(cv2.CAP_PROP_FRAME_WIDTH, camera_settings['cam_w'])
|
cam.set(cv2.CAP_PROP_FRAME_WIDTH, camera_settings['cam_w'])
|
||||||
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, camera_settings['cam_h'])
|
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, camera_settings['cam_h'])
|
||||||
|
else:
|
||||||
|
# Pi Cam V3 setup
|
||||||
|
from picamera2 import Picamera2
|
||||||
|
from libcamera import Transform
|
||||||
|
cam = Picamera2()
|
||||||
|
picam_config = cam.create_video_configuration(main={"format": 'RGB888',"size": (camera_settings['cam_w'], camera_settings['cam_h'])})
|
||||||
|
# ~ picam_config["transform"] = Transform(hflip=camera_settings['hflip'], vflip=camera_settings['vflip'])
|
||||||
|
picam_config["transform"] = Transform(vflip=camera_current_settings['vertical_flip']['value'],hflip=camera_current_settings['horizontal_flip']['value'])
|
||||||
|
|
||||||
|
cam.configure(picam_config)
|
||||||
|
# Autofocus, get lens position and switch to manual mode
|
||||||
|
# Set Af mode to Auto then Manual (0). Default is Continuous (2), Auto is 1
|
||||||
|
cam.set_controls({'AfMode':1})
|
||||||
|
cam.start()
|
||||||
|
cam.autofocus_cycle()
|
||||||
|
cam_lenspos = cam.capture_metadata()['LensPosition']
|
||||||
|
# Set focus, wb, exp to manual
|
||||||
|
cam.set_controls({'AfMode': 0,
|
||||||
|
'AwbEnable': 1,
|
||||||
|
'AwbMode': camera_current_settings['white_balance_auto_preset']['default'],
|
||||||
|
'AeEnable': 1,
|
||||||
|
'AeExposureMode': camera_current_settings['auto_exposure']['default'],
|
||||||
|
# Enable flicker avoidance due to mains
|
||||||
|
'AeFlickerMode': 1,
|
||||||
|
# Mains 50hz = 10000, 60hz = 8333
|
||||||
|
# ~ 'AeFlickerPeriod': 8333,
|
||||||
|
'AeFlickerPeriod': 10000,
|
||||||
|
# Format is (min, max, default) in ms
|
||||||
|
# here: (60fps, 12fps, None)
|
||||||
|
# ~ 'FrameDurationLimits':(16666,83333,None)
|
||||||
|
})
|
||||||
|
# ~ cam.stop()
|
||||||
|
|
||||||
frame = get_onionskin_frame(savepath, index)
|
frame = get_onionskin_frame(savepath, index)
|
||||||
|
|
||||||
|
@ -480,10 +529,13 @@ def main(args):
|
||||||
|
|
||||||
if liveview_only:
|
if liveview_only:
|
||||||
# ~ onionskin = False
|
# ~ onionskin = False
|
||||||
|
if not project_settings['cam_is_picam']:
|
||||||
ret, overlay = cam.read()
|
ret, overlay = cam.read()
|
||||||
if not ret:
|
if not ret:
|
||||||
print(_("Failed to grab frame."))
|
print(_("Failed to grab frame."))
|
||||||
break
|
break
|
||||||
|
else:
|
||||||
|
overlay = cam.capture_array("main")
|
||||||
# Resize preview
|
# Resize preview
|
||||||
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
|
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
|
||||||
cv2.imshow("StopiCV", overlay)
|
cv2.imshow("StopiCV", overlay)
|
||||||
|
@ -491,7 +543,13 @@ def main(args):
|
||||||
# ~ onionskin = True
|
# ~ onionskin = True
|
||||||
|
|
||||||
if onionskin:
|
if onionskin:
|
||||||
|
if not project_settings['cam_is_picam']:
|
||||||
ret, overlay = cam.read()
|
ret, overlay = cam.read()
|
||||||
|
if not ret:
|
||||||
|
print(_("Failed to grab frame."))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
overlay = cam.capture_array("main")
|
||||||
og_frame = overlay.copy()
|
og_frame = overlay.copy()
|
||||||
# Resize preview
|
# Resize preview
|
||||||
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
|
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
|
||||||
|
@ -499,81 +557,153 @@ def main(args):
|
||||||
alpha = project_settings['onionskin_alpha_default']
|
alpha = project_settings['onionskin_alpha_default']
|
||||||
beta = (1.0 - alpha)
|
beta = (1.0 - alpha)
|
||||||
overlay = cv2.addWeighted(frame, alpha, overlay, beta, 0)
|
overlay = cv2.addWeighted(frame, alpha, overlay, beta, 0)
|
||||||
|
|
||||||
if not ret:
|
|
||||||
print(_("Failed to grab frame."))
|
|
||||||
break
|
|
||||||
cv2.imshow("StopiCV", overlay)
|
cv2.imshow("StopiCV", overlay)
|
||||||
|
|
||||||
if not playback and not onionskin and not liveview_only:
|
if not playback and not onionskin and not liveview_only:
|
||||||
cv2.imshow("StopiCV", frame)
|
cv2.imshow("StopiCV", frame)
|
||||||
|
|
||||||
k = cv2.waitKey(1)
|
k = cv2.waitKey(1)
|
||||||
# TODO : Show liveview only
|
# Key l / kp 5
|
||||||
# Key l / 5
|
if (k%256 == 108) or (k%256 == 53) or (k%256 == 181):
|
||||||
if (k%256 == 108) or (k%256 == 53):
|
print(_("Liveview only"))
|
||||||
# Toggle liveview
|
# Toggle liveview
|
||||||
liveview_only = not liveview_only
|
liveview_only = not liveview_only
|
||||||
onionskin = not onionskin
|
onionskin = not onionskin
|
||||||
# Key o / 9
|
# Key o / kp slash
|
||||||
if (k%256 == 111) or (k%256 == 47):
|
elif (k%256 == 111) or (k%256 == 47) or (k%256 == 175):
|
||||||
|
print(_("Onionskin toggle"))
|
||||||
# Toggle onionskin
|
# Toggle onionskin
|
||||||
onionskin = not onionskin
|
onionskin = not onionskin
|
||||||
liveview_only = False
|
liveview_only = False
|
||||||
# Key w / 7 - cycle wb
|
# Key w / 7 - cycle wb
|
||||||
if (k%256 == 119) or (k%256 == 55):
|
elif (k%256 == 119) or (k%256 == 55) or (k%256 == 183):
|
||||||
|
print(_("White balance mode"))
|
||||||
camera_current_settings = apply_cam_setting(camera_current_settings, ['white_balance_auto_preset'])
|
camera_current_settings = apply_cam_setting(camera_current_settings, ['white_balance_auto_preset'])
|
||||||
|
if project_settings['cam_is_picam']:
|
||||||
|
cam.set_controls({'AwbMode': camera_current_settings['white_balance_auto_preset']['value']})
|
||||||
# Key x / 1 - cycle exposure
|
# Key x / 1 - cycle exposure
|
||||||
if (k%256 == 120) or (k%256 == 49):
|
elif (k%256 == 120) or (k%256 == 49) or (k%256 == 177):
|
||||||
|
print(_("Exp. mode"))
|
||||||
camera_current_settings = apply_cam_setting(camera_current_settings, ['auto_exposure'])
|
camera_current_settings = apply_cam_setting(camera_current_settings, ['auto_exposure'])
|
||||||
|
if project_settings['cam_is_picam']:
|
||||||
|
print(camera_current_settings['auto_exposure']['value'])
|
||||||
|
if camera_current_settings['auto_exposure']['value'] == 4:
|
||||||
|
cam.set_controls({'AeEnable': 1})
|
||||||
|
else:
|
||||||
|
cam.set_controls({'AeEnable': 0})
|
||||||
|
cam.set_controls({"AeExposureMode": camera_current_settings['auto_exposure']['value']})
|
||||||
# Key f / 3 - flip image
|
# Key f / 3 - flip image
|
||||||
if (k%256 == 102) or (k%256 == 51):
|
elif (k%256 == 102) or (k%256 == 51) or (k%256 == 179):
|
||||||
|
print(_("Flip image"))
|
||||||
camera_current_settings = apply_cam_setting(camera_current_settings, ['vertical_flip','horizontal_flip'])
|
camera_current_settings = apply_cam_setting(camera_current_settings, ['vertical_flip','horizontal_flip'])
|
||||||
# Key up
|
if project_settings['cam_is_picam']:
|
||||||
elif (k%256 == 82) or (k%256 == 56):
|
cam.stop()
|
||||||
|
picam_config["transform"] = Transform(vflip=camera_current_settings['vertical_flip']['value'],hflip=camera_current_settings['horizontal_flip']['value'])
|
||||||
|
cam.configure(picam_config)
|
||||||
|
cam.start()
|
||||||
|
# Key up, kp 8
|
||||||
|
elif (k%256 == 82) or (k%256 == 56) or (k%256 == 184):
|
||||||
|
print(_("Last frame"))
|
||||||
if len(img_list):
|
if len(img_list):
|
||||||
if playback:
|
if playback:
|
||||||
playback = False
|
playback = False
|
||||||
index, frame = last_frame(index)
|
index, frame = last_frame(index)
|
||||||
# Key down
|
# Key down , kp 2
|
||||||
elif (k%256 == 84) or (k%256 == 50):
|
elif (k%256 == 84) or (k%256 == 50) or (k%256 == 178):
|
||||||
|
print(_("First frame"))
|
||||||
if len(img_list):
|
if len(img_list):
|
||||||
if playback:
|
if playback:
|
||||||
playback = False
|
playback = False
|
||||||
index, frame = first_frame(index)
|
index, frame = first_frame(index)
|
||||||
# Key left
|
# Key left, kp 4
|
||||||
elif (k%256 == 81) or (k%256 == 52):
|
elif (k%256 == 81) or (k%256 == 52) or (k%256 == 180):
|
||||||
|
print(_("Prev. frame"))
|
||||||
# Displau previous frame
|
# Displau previous frame
|
||||||
if len(img_list):
|
if len(img_list):
|
||||||
if playback:
|
if playback:
|
||||||
playback = False
|
playback = False
|
||||||
index, frame = previous_frame(index)
|
index, frame = previous_frame(index)
|
||||||
# Key right
|
# Key right, kp 6
|
||||||
elif (k%256 == 83) or (k%256 == 54):
|
elif (k%256 == 83) or (k%256 == 54) or (k%256 == 182):
|
||||||
|
print(_("Next frame"))
|
||||||
# Displau next frame
|
# Displau next frame
|
||||||
if len(img_list):
|
if len(img_list):
|
||||||
if playback:
|
if playback:
|
||||||
playback = False
|
playback = False
|
||||||
index, frame = next_frame(index)
|
index, frame = next_frame(index)
|
||||||
# Key r / keypad 9 - reset wb,exp
|
# Key r / keypad 9 - reset wb,exp
|
||||||
elif (k%256 == 114) or (k%256 == 57):
|
elif (k%256 == 114) or (k%256 == 57) or (k%256 == 185) :
|
||||||
print(_("Reset camera settings"))
|
print(_("Reset camera settings"))
|
||||||
camera_current_settings = apply_cam_setting(camera_current_settings)
|
camera_current_settings = apply_cam_setting(camera_current_settings)
|
||||||
|
if project_settings['cam_is_picam']:
|
||||||
|
if camera_current_settings['auto_exposure']['default'] == 4:
|
||||||
|
cam.set_controls({'AeEnable': 0})
|
||||||
|
else:
|
||||||
|
cam.set_controls({'AeEnable': 1})
|
||||||
|
cam.set_controls({"AeExposureMode": camera_current_settings['auto_exposure']['default']})
|
||||||
|
cam.set_controls({'AwbMode': camera_current_settings['white_balance_auto_preset']['default']})
|
||||||
|
cam.stop()
|
||||||
|
picam_config["transform"] = Transform(vflip=camera_current_settings['vertical_flip']['default'],hflip=camera_current_settings['horizontal_flip']['default'])
|
||||||
|
cam.configure(picam_config)
|
||||||
|
cam.start()
|
||||||
|
|
||||||
# Key e / keypad *
|
# Key e / keypad *
|
||||||
elif (k%256 == 101) or (k%256 == 42):
|
elif (k%256 == 101) or (k%256 == 42) or (k%256 == 170) :
|
||||||
print(_("Export"))
|
print(_("Export"))
|
||||||
ffmpeg_process = export_animation(input_filename, export_filename)
|
ffmpeg_process = export_animation(input_filename, export_filename)
|
||||||
# Key Return
|
# Key Return, kp return
|
||||||
elif (k%256 == 13):
|
elif (k%256 == 13) or (k%256 == 141) :
|
||||||
print(_("Playback"))
|
print(_("Playback"))
|
||||||
playhead = index
|
playhead = index
|
||||||
loop_playback = True
|
loop_playback = True
|
||||||
playback = not playback
|
playback = not playback
|
||||||
# Key remove frame - backspace, del, numpad_minus
|
# Key remove frame - backspace, del, numpad_minus
|
||||||
elif (k%256 == 8) or (k%256 == 45) or (k == 255):
|
elif (k%256 == 8) or (k%256 == 45) or (k == 255) or (k%256 == 173) :
|
||||||
# Remove frame
|
# Remove frame
|
||||||
print(_("Remove frame"))
|
print(_("Remove frame"))
|
||||||
img_list, index, frame = remove_frame(img_list, index)
|
img_list, index, frame = remove_frame(img_list, index)
|
||||||
|
# TODO: replace keys with rotary encoder
|
||||||
|
# Focus +/- with a,z
|
||||||
|
elif (k%256 == 97) and project_settings['cam_is_picam']:
|
||||||
|
cam_lenspos += 0.2
|
||||||
|
# Set AfMode to Manual
|
||||||
|
cam.set_controls({'AfMode': 0, 'LensPosition': cam_lenspos})
|
||||||
|
print(_("+Lens pos: {}".format(cam_lenspos)))
|
||||||
|
elif (k%256 == 122) and project_settings['cam_is_picam']:
|
||||||
|
cam_lenspos -= 0.2
|
||||||
|
# Set AfMode to Manual
|
||||||
|
cam.set_controls({'AfMode': 0, 'LensPosition': cam_lenspos})
|
||||||
|
print(_("-Lens pos: {}".format(cam_lenspos)))
|
||||||
|
# Set anti-flicker mode with q
|
||||||
|
elif (k%256 == 113) and project_settings['cam_is_picam']:
|
||||||
|
# Set AfMode to Manual
|
||||||
|
camera_current_settings = apply_cam_setting(camera_current_settings, ['anti_flicker'])
|
||||||
|
if camera_current_settings['anti_flicker']['value'] == 0:
|
||||||
|
cam.set_controls({'AeFlickerMode': 0})
|
||||||
|
elif camera_current_settings['anti_flicker']['value'] == 1:
|
||||||
|
cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':8333})
|
||||||
|
else:
|
||||||
|
cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':10000})
|
||||||
|
print(camera_current_settings['anti_flicker']['value'])
|
||||||
|
# ~ elif (k%256 == 115) and project_settings['cam_is_picam']:
|
||||||
|
# ~ # Set AfMode to Manual
|
||||||
|
# ~ cam.set_controls({'AeFlickerMode': 0, 'AeFlickerPeriod': 8333})
|
||||||
|
# Take pic
|
||||||
|
# SPACE or numpad 0 pressed
|
||||||
|
elif (k%256 == 32) or (k%256 == 48) or (k%256 == 176):
|
||||||
|
print(_("Capture frame"))
|
||||||
|
img_name = return_next_frame_number(get_last_frame(savepath))
|
||||||
|
img_path = os.path.join(savepath, img_name)
|
||||||
|
if project_settings['file_extension'] == 'jpg':
|
||||||
|
cv2.imwrite(img_path, og_frame, [int(cv2.IMWRITE_JPEG_QUALITY), project_settings['jpg_quality']])
|
||||||
|
else:
|
||||||
|
cv2.imwrite(img_path, og_frame)
|
||||||
|
print(_("File {} written.").format(img_path))
|
||||||
|
if len(img_list) and (img_list[index] == '{letter}.-001.{ext}'.format(letter=project_letter, ext=project_settings['file_extension'])):
|
||||||
|
img_list[index] = img_name
|
||||||
|
else:
|
||||||
|
index += 1
|
||||||
|
frame = get_onionskin_frame(savepath, index)
|
||||||
# Quit app
|
# Quit app
|
||||||
elif k%256 == 27:
|
elif k%256 == 27:
|
||||||
# ESC pressed
|
# ESC pressed
|
||||||
|
@ -582,21 +712,10 @@ def main(args):
|
||||||
elif ctrlc_pressed:
|
elif ctrlc_pressed:
|
||||||
print(_("Ctrl-C hit, exiting..."))
|
print(_("Ctrl-C hit, exiting..."))
|
||||||
break
|
break
|
||||||
elif cv2.getWindowProperty("StopiCV", cv2.WND_PROP_VISIBLE) < 1:
|
elif cv2.getWindowProperty("StopiCV", cv2.WND_PROP_AUTOSIZE) == -1:
|
||||||
print(_("Window was closed, exiting..."))
|
print(_("Window was closed, exiting..."))
|
||||||
|
# ~ pass
|
||||||
break
|
break
|
||||||
# Take pic
|
|
||||||
# SPACE or numpad 0 pressed
|
|
||||||
elif (k%256 == 32) or (k%256 == 48):
|
|
||||||
img_name = return_next_frame_number(get_last_frame(savepath))
|
|
||||||
img_path = os.path.join(savepath, img_name)
|
|
||||||
cv2.imwrite(img_path, og_frame)
|
|
||||||
print(_("File {} written.").format(img_path))
|
|
||||||
if len(img_list) and (img_list[index] == '{letter}.-001.{ext}'.format(letter=project_letter, ext=project_settings['file_extension'])):
|
|
||||||
img_list[index] = img_name
|
|
||||||
else:
|
|
||||||
index += 1
|
|
||||||
frame = get_onionskin_frame(savepath, index)
|
|
||||||
# REMOVE : Debug print keycode
|
# REMOVE : Debug print keycode
|
||||||
elif k==-1: # normally -1 returned,so don't print it
|
elif k==-1: # normally -1 returned,so don't print it
|
||||||
continue
|
continue
|
||||||
|
@ -619,7 +738,10 @@ def main(args):
|
||||||
except:
|
except:
|
||||||
print(_("Terminating running process..."))
|
print(_("Terminating running process..."))
|
||||||
ffmpeg_process.terminate()
|
ffmpeg_process.terminate()
|
||||||
|
if not project_settings["cam_is_picam"]:
|
||||||
cam.release()
|
cam.release()
|
||||||
|
else:
|
||||||
|
cam.close()
|
||||||
cv2.destroyAllWindows()
|
cv2.destroyAllWindows()
|
||||||
|
|
||||||
cv2.namedWindow("StopiCV", cv2.WINDOW_GUI_NORMAL)
|
cv2.namedWindow("StopiCV", cv2.WINDOW_GUI_NORMAL)
|
||||||
|
|
20
readme.md
20
readme.md
|
@ -1,10 +1,15 @@
|
||||||
# Stopi2
|
# Stopi2
|
||||||
|
|
||||||
|
## Branche libcamera
|
||||||
|
|
||||||
|
**Ceci est la branche qui restaure la possibilité d'utiliser des périphériques compatibles rpi-libcamera (Modules Raspicam v1,v2 et v3).**
|
||||||
|
**En utilisant la [branche correspondante pour la télécommande picote](/arthus/picote/src/branch/picamera), vous pouvez régler la mise au point du module caméra avec un [codeur rotatif](https://fr.wikipedia.org/wiki/Codeur_rotatif).**
|
||||||
|
|
||||||
<a style="max-height: 300px;display: inline-block;" href="./stopi2/raw/branch/master/stopi_station.jpg"><img src="./stopi_station.jpg"/><a/>
|
<a style="max-height: 300px;display: inline-block;" href="./stopi2/raw/branch/master/stopi_station.jpg"><img src="./stopi_station.jpg"/><a/>
|
||||||
|
|
||||||
Seconde version du script python [stopi](https://git.arthus.net/arthus/stopi) destiné à être utilisé avec une télécommande [picote](/arthus/picote).
|
Seconde version du script python [stopi](https://git.arthus.net/arthus/stopi) destiné à être utilisé avec une télécommande [picote](/arthus/picote/src/branch/picamera).
|
||||||
|
|
||||||
Cette version utilise opencv et ne fonctionne pour le moment qu'avec une webcam.
|
Cette version utilise opencv et libcamera.Elle fonctionne avec une webcam ou un module vidéo Picamera (v1,v2 ou v3).
|
||||||
Encore une fois, l'objectif est de créer un logiciel simple et minimaliste dans son interface, dont les caractéristiques sont les suivantes :
|
Encore une fois, l'objectif est de créer un logiciel simple et minimaliste dans son interface, dont les caractéristiques sont les suivantes :
|
||||||
|
|
||||||
* Affichage des images en plein écran sans interface : toutes les fonctions utilisent quelques touches du clavier.
|
* Affichage des images en plein écran sans interface : toutes les fonctions utilisent quelques touches du clavier.
|
||||||
|
@ -17,7 +22,7 @@ Encore une fois, l'objectif est de créer un logiciel simple et minimaliste dans
|
||||||
|
|
||||||
## Banc de test
|
## Banc de test
|
||||||
|
|
||||||
Ce script a été testé avec une webcam compatible V4L2, et plus précisement une ["showmewebcam"](https://github.com/showmewebcam/showmewebcam) à base de rpi 0 et d'un module caméra v2 (8Mp), et un ordinateur classique sous [Debian](https://debian.org).
|
Ce script a été testé avec une webcam compatible V4L2, une ["showmewebcam"](https://github.com/showmewebcam/showmewebcam) à base de rpi 0 et d'un module caméra v2 (8Mp), et un ordinateur classique sous [Debian](https://debian.org) et un [RPI 4B](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) munis d'un module [Picamera V3](https://www.raspberrypi.com/products/camera-module-3/).
|
||||||
Les contributions et rapports de bugs sont les bienvenus !
|
Les contributions et rapports de bugs sont les bienvenus !
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
@ -28,7 +33,7 @@ Dans un terminal :
|
||||||
1. Installer les dépendances suivantes :
|
1. Installer les dépendances suivantes :
|
||||||
```
|
```
|
||||||
# Avec une distribution basée sur Debian (Ubuntu, Mint...)
|
# Avec une distribution basée sur Debian (Ubuntu, Mint...)
|
||||||
sudo apt install --no-install-recommends --no-install-suggests git ffmpeg python3-tk python3-pip python3-venv libtiff5-dev libtopenjp2 libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev libharfbuzz-dev libfribidi-dev libxcb1-dev python3-tk python3-dev
|
sudo apt install --no-install-recommends --no-install-suggests git ffmpeg python3-tk python3-pip python3-venv libtiff5-dev libtopenjp2 libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev libharfbuzz-dev libfribidi-dev libxcb1-dev python3-tk python3-dev libopenblas-dev libatlas-base-dev libhdf5-dev libhdf5-serial-dev libatlas-base-dev libjasper-dev libqtgui4 libqt4-test
|
||||||
```
|
```
|
||||||
- (Optionnel) Pour installer un environnement graphique minimal sur une [installation console](https://debian-facile.org/doc:install:installation-minimale) : `sudo apt install --no-install-recommends --no-install-suggests openbox xserver-xorg xinit pcmanfm gmrun lxterminal hsetroot unclutter plymouth plymouth-themes`
|
- (Optionnel) Pour installer un environnement graphique minimal sur une [installation console](https://debian-facile.org/doc:install:installation-minimale) : `sudo apt install --no-install-recommends --no-install-suggests openbox xserver-xorg xinit pcmanfm gmrun lxterminal hsetroot unclutter plymouth plymouth-themes`
|
||||||
2. Cloner le dépôt dans le dossier de votre choix : `git clone https://git.arthus.net/arthus/stopi2.git`
|
2. Cloner le dépôt dans le dossier de votre choix : `git clone https://git.arthus.net/arthus/stopi2.git`
|
||||||
|
@ -128,3 +133,10 @@ en :
|
||||||
Puis configurer plymouth : `sudo plymouth-set-default-theme`
|
Puis configurer plymouth : `sudo plymouth-set-default-theme`
|
||||||
|
|
||||||
Appliquer les modifs avec `sudo update-grub`.
|
Appliquer les modifs avec `sudo update-grub`.
|
||||||
|
|
||||||
|
## Raspberry Pi OS
|
||||||
|
|
||||||
|
Avec Raspberry Pi OS, il suffit d'ajouter les options suivantes dans '/boot/firmware/cmdline.txt':
|
||||||
|
`loglevel=3 vt.global_cursor_default=0 logo.nologo consoleblank=3 quiet`
|
||||||
|
|
||||||
|
``
|
|
@ -1,5 +1,5 @@
|
||||||
Send2Trash
|
Send2Trash
|
||||||
opencv-python
|
|
||||||
numpy
|
numpy
|
||||||
pyserial
|
pyserial
|
||||||
pillow
|
pillow
|
||||||
|
opencv-python
|
||||||
|
|
Loading…
Reference in New Issue