Compare commits

...

4 Commits

Author SHA1 Message Date
ABelliqueux 0d8434136a Add anti-flicker control 2025-01-12 10:29:04 +01:00
ABelliqueux 6219e18b96 Add focus control for picamera modules 2025-01-11 14:54:17 +01:00
ABelliqueux 913a4b7eb6 Switch to JPG format 2025-01-04 11:51:16 +01:00
ABelliqueux 0bf7fb9d98 Add pi camera v3 support 2024-12-15 12:28:40 +01:00
4 changed files with 204 additions and 68 deletions

View File

@ -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

View File

@ -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,6 +72,7 @@ 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)
if project_settings['cam_is_showmewebcam']:
camera_current_settings = { 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']),
@ -72,6 +80,14 @@ camera_current_settings = {
'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)

View File

@ -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`
``

View File

@ -1,5 +1,5 @@
Send2Trash Send2Trash
opencv-python
numpy numpy
pyserial pyserial
pillow pillow
opencv-python