DSLR, webcam ok.

This commit is contained in:
ABelliqueux 2025-02-12 17:06:39 +01:00
parent ab586d29ca
commit d254b6307b
3 changed files with 160 additions and 94 deletions

View File

@ -1,6 +1,6 @@
[DEFAULT] [DEFAULT]
# Camera type - can be : showmewebcam, picam, webcam, dslr # Camera type - can be : showmewebcam, picam, webcam, dslr
cam_type = 'dslr' cam_type = 'webcam'
use_date_for_folder = false use_date_for_folder = false
file_extension = 'jpg' file_extension = 'jpg'
jpg_quality = 88 jpg_quality = 88
@ -15,8 +15,8 @@ ffmpeg_path = '/usr/bin/ffmpeg'
v4l2-ctl_path = '/usr/bin/v4l2-ctl' v4l2-ctl_path = '/usr/bin/v4l2-ctl'
export_options = 'scale=1920:-1,crop=1920:1080' export_options = 'scale=1920:-1,crop=1920:1080'
[CAMERA] [CAMERA]
cam_w = 1920 cam_w = 1280
cam_h = 1080 cam_h = 960
vflip = 0 vflip = 0
hflip = 0 hflip = 0
auto_exposure = 1 auto_exposure = 1

View File

@ -28,6 +28,7 @@ camera_settings = 0
camera_status = [] camera_status = []
# l10n # l10n
# TODO: Update fr translation
LOCALE = os.getenv('LANG', 'en_EN') LOCALE = os.getenv('LANG', 'en_EN')
_ = gettext.translation('template', localedir='locales', languages=[LOCALE]).gettext _ = gettext.translation('template', localedir='locales', languages=[LOCALE]).gettext
@ -79,15 +80,27 @@ print(config_found_msg)
class webcam(): class webcam():
def __init__(self): def __init__(self):
self.camera_current_settings = { self.camera_current_settings = {
'auto_exposure': dict(min=0, max=1, default=camera_settings['auto_exposure'], value=camera_settings['auto_exposure']), 'auto_exposure': dict(min=1, max=3, step=2, 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_temperature': dict(min=0, max=10000, step=1000, default=4000, value=8000),
'horizontal_flip': dict(min=0, max=1, default=camera_settings['hflip'], value=camera_settings['hflip']), 'white_balance_automatic' : dict(min=0, max=1, step=1, default=0, value=0), # Auto wb
'vertical_flip': dict(min=0, max=1, default=camera_settings['vflip'], value=camera_settings['vflip']), 'power_line_frequency': dict(min=0, max=2, step=1, default=2, value=2), # power_line_frequency
'video_bitrate': dict(min=25000000, max=25000000, default=camera_settings['video_bitrate'], value=camera_settings['video_bitrate']),
} }
self.cam_settings_map = {
'white_balance_auto_preset': 'white_balance_temperature',
'white_balance_automatic': 'white_balance_automatic',
'auto_exposure':'auto_exposure',
'anti_flicker' : 'power_line_frequency',
'lenspos' : 'sharpness',
}
self.has_liveview = True self.has_liveview = True
# UI frame
self.frame = None self.frame = None
# Onionskin_frame
self.o_frame = None
# Overlay frame
self.overlay = None self.overlay = None
# Original frame for saving
self.og_frame = None
self.onionskin = project_settings['onion_skin_onstartup'] self.onionskin = project_settings['onion_skin_onstartup']
self.onionskin_was_on = self.onionskin self.onionskin_was_on = self.onionskin
self.liveview_only = False self.liveview_only = False
@ -110,27 +123,28 @@ class webcam():
return False return False
self.cap.release() self.cap.release()
return True return True
def capture_preview(self): def capture_preview(self):
ret, overlay = self.cam.read() ret, overlay = self.cam.read()
if not ret: if not ret:
print(_("Failed to grab frame.")) print(_("Failed to grab frame."))
return False return False
# Resize preview # Resize preview to fit screen
frame = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h'])) overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
if self.liveview_only: if self.liveview_only:
# Don't mix it # Don't mix it
self.frame = frame self.frame = overlay
# ~ return frame return True
if self.onionskin: if self.onionskin:
# Keep original pic in memory # Keep original pic in memory
self.og_frame = overlay.copy() self.og_frame = overlay.copy()
# calculate and apply alpha # calculate and apply alpha
alpha = project_settings['onionskin_alpha_default'] alpha = project_settings['onionskin_alpha_default']
beta = (1.0 - alpha) beta = (1.0 - alpha)
frame = cv2.addWeighted(frame, alpha, overlay, beta, 0) self.frame = cv2.addWeighted(self.o_frame, alpha, overlay, beta, 0)
# ~ self.frame = frame return True
# ~ return frame self.frame = self.o_frame
return True
def capture_frame(self, img_path): def capture_frame(self, img_path):
if project_settings['file_extension'] == 'jpg': if project_settings['file_extension'] == 'jpg':
@ -139,48 +153,62 @@ class webcam():
capture_ok = cv2.imwrite(img_path, self.og_frame) capture_ok = cv2.imwrite(img_path, self.og_frame)
return capture_ok return capture_ok
def increment_setting(self, setting:str): def increment_setting(self, setting:str, value:int=-1):
if self.camera_current_settings[setting]['value']+1 in range(self.camera_current_settings[setting]['min'],self.camera_current_settings[setting]['max']+1): # If value has default -1 value, increment setting
self.camera_current_settings[setting]['value'] += 1 if value == -1:
if setting in self.camera_current_settings:
if self.camera_current_settings[setting]['value'] + self.camera_current_settings[setting]['step'] in range(self.camera_current_settings[setting]['min'],self.camera_current_settings[setting]['max']+1):
self.camera_current_settings[setting]['value'] += self.camera_current_settings[setting]['step']
else:
self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['min']
# Apply special cases
else: else:
self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['min'] pass
def build_v4l2_cmd(self, to_set:list=None): def build_v4l2_cmd(self, to_set:list=None):
self.cmd = '{v4l2-ctl_path} -d /dev/video0'.format(project_settings['v4l2-ctl_path']) cmd = '{} -d /dev/video0'.format(project_settings['v4l2-ctl_path'])
self.args = [] args = []
value = -1
for setting in self.camera_current_settings: for setting in self.camera_current_settings:
if to_set is None: if to_set is None:
# Apply defaults # Apply defaults
self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['default'] self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['default']
self.cmd += ' -c {}={}' cmd += ' -c {}={}'
self.args.append(setting) args.append(setting)
self.args.append(self.camera_current_settings[setting]['value']) args.append(self.camera_current_settings[setting]['value'])
else: else:
# Increment settings in to_set # Increment settings in to_set
for setting in to_set: for setting in to_set:
if type(setting) is tuple:
value = setting[1]
setting = setting[0]
if setting in self.cam_settings_map:
setting = self.cam_settings_map[setting]
if setting in self.camera_current_settings: if setting in self.camera_current_settings:
self.increment_setting(setting) self.increment_setting(setting, value)
self.cmd += ' -c {}={}' cmd += ' -c {}={}'
self.args.append(setting) args.append(setting)
self.args.append(self.camera_current_settings[setting]['value']) args.append(self.camera_current_settings[setting]['value'])
else: else:
print(_("Unknown setting!")) print(_("Unknown setting!"))
break break
return self.cmd, self.args return cmd.format(*args)
def run_v4l2_ctl(self): def run_v4l2_ctl(self, cmd):
if project_settings['v4l2-ctl_path'] is None: if project_settings['v4l2-ctl_path'] is None:
return False return False
v4l2_ctl_process = subprocess.Popen(self.cmd.split(' ')) print(cmd)
return ffmpeg_process v4l2_ctl_process = subprocess.Popen(cmd.split(' '))
return v4l2_ctl_process
def apply_setting(self, to_set:list=None): def apply_setting(self, to_set:list=None, inc:bool=False):
self.cmd, self.args = self.build_v4l2_cmd(to_set) cmd = self.build_v4l2_cmd(to_set)
run_v4l2_ctl(self.cmd) self.run_v4l2_ctl(cmd)
return self.camera_current_settings return self.camera_current_settings
def flip_image(self): def flip_image(self):
self.apply_setting(['vertical_flip','horizontal_flip']) self.frame = cv2.flip(self.frame, -1)
self.og_frame = cv2.flip(self.og_frame, -1)
def focus(self, direction:str='-'): def focus(self, direction:str='-'):
pass pass
@ -196,24 +224,45 @@ class showmewebcam(webcam):
def __init__(self): def __init__(self):
self.serialutils = __import__('serialutils') self.serialutils = __import__('serialutils')
super().__init__() super().__init__()
self.camera_current_settings = {
'auto_exposure': dict(min=0, max=1, step=1, default=camera_settings['auto_exposure'], value=camera_settings['auto_exposure']),
'white_balance_auto_preset': dict(min=0, max=9, step=1, default=camera_settings['white_balance_auto_preset'], value=camera_settings['white_balance_auto_preset']),
'horizontal_flip': dict(min=0, max=1, step=1, default=camera_settings['hflip'], value=camera_settings['hflip']),
'vertical_flip': dict(min=0, max=1, step=1, default=camera_settings['vflip'], value=camera_settings['vflip']),
'video_bitrate': dict(min=25000000, max=25000000, step=10000, default=camera_settings['video_bitrate'], value=camera_settings['video_bitrate']),
}
def apply_setting(self, to_set:list=None): def apply_setting(self, to_set:list=None, inc:bool=False):
self.cmd, self.args = self.build_v4l2_cmd(to_set) self.cmd, self.args = self.build_v4l2_cmd(to_set)
self.serialutils.send_serial_cmd(self.serialutils.find_cam_port(), self.cmd.format(*self.args)) self.serialutils.send_serial_cmd(self.serialutils.find_cam_port(), self.cmd.format(*self.args))
return self.camera_current_settings return self.camera_current_settings
class picam(): class picam():
def __init__(self): def __init__(self):
self.camera_current_settings = { self.camera_current_settings = {
'auto_exposure': dict(min=0, max=4, default=camera_settings['auto_exposure'], value=camera_settings['auto_exposure']), 'auto_exposure': dict(min=0, max=4, step=1, 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']), 'white_balance_auto_preset': dict(min=0, max=7, step=1, 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, step=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, step=1, default=camera_settings['vflip'], value=camera_settings['vflip']),
'anti_flicker': dict(min=0, max=2, default=1, value=1), 'anti_flicker': dict(min=0, max=2, step=1, default=1, value=1),
} }
# Map generic config name to specific picamera setting name
self.cam_settings_map = {
'white_balance_auto_preset': 'AwbMode',
'auto_exposure':'AeExposureMode',
'anti_flicker' : 'AeFlickerMode',
'lenspos' : 'LensPosition',
}
self.has_liveview = True self.has_liveview = True
# UI frame
self.frame = None self.frame = None
# Onionskin_frame
self.o_frame = None
# Overlay frame
self.overlay = None self.overlay = None
# Original frame for saving
self.og_frame = None
self.onionskin = project_settings['onion_skin_onstartup'] self.onionskin = project_settings['onion_skin_onstartup']
self.onionskin_was_on = self.onionskin self.onionskin_was_on = self.onionskin
self.liveview_only = False self.liveview_only = False
@ -251,29 +300,23 @@ class picam():
# ~ 'FrameDurationLimits':(16666,83333,None) # ~ 'FrameDurationLimits':(16666,83333,None)
} }
self.cam.set_controls(self.camera_default_settings) self.cam.set_controls(self.camera_default_settings)
# Map generic config name to specific picamera setting name
self.cam_settings_map = {
'white_balance_auto_preset': 'AwbMode',
'auto_exposure':'AeExposureMode',
'anti_flicker' : 'AeFlickerMode',
'lenspos' : 'LensPosition',
}
except: except:
pass pass
def test_device(self, source): def test_device(self, source):
pass pass
# Same as in webcam() class
def capture_preview(self): def capture_preview(self):
ret, overlay = self.cam.read() ret, overlay = self.cam.read()
if not ret: if not ret:
print(_("Failed to grab frame.")) print(_("Failed to grab frame."))
return False return False
# Resize preview # Resize preview to fit screen
self.frame = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h'])) overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
if self.liveview_only: if self.liveview_only:
# Don't mix it # Don't mix it
frame = self.frame self.frame = overlay
return True return True
if self.onionskin: if self.onionskin:
# Keep original pic in memory # Keep original pic in memory
@ -281,10 +324,12 @@ class picam():
# calculate and apply alpha # calculate and apply alpha
alpha = project_settings['onionskin_alpha_default'] alpha = project_settings['onionskin_alpha_default']
beta = (1.0 - alpha) beta = (1.0 - alpha)
frame = cv2.addWeighted(self.frame, alpha, overlay, beta, 0) self.frame = cv2.addWeighted(self.o_frame, alpha, overlay, beta, 0)
# ~ self.frame = frame return True
# ~ return frame self.frame = self.o_frame
return True
# Same as in webcam() class
def capture_frame(self, img_path): def capture_frame(self, img_path):
if project_settings['file_extension'] == 'jpg': if project_settings['file_extension'] == 'jpg':
capture_ok = cv2.imwrite(img_path, self.og_frame, [int(cv2.IMWRITE_JPEG_QUALITY), project_settings['jpg_quality']]) capture_ok = cv2.imwrite(img_path, self.og_frame, [int(cv2.IMWRITE_JPEG_QUALITY), project_settings['jpg_quality']])
@ -293,28 +338,30 @@ class picam():
return capture_ok return capture_ok
def increment_setting(self, setting:str): def increment_setting(self, setting:str):
if self.camera_current_settings[setting]['value']+1 in range(self.camera_current_settings[setting]['min'],self.camera_current_settings[setting]['max']+1): if setting in self.camera_current_settings:
self.camera_current_settings[setting]['value'] += 1 if self.camera_current_settings[setting]['value'] + self.camera_current_settings[setting]['step'] in range(self.camera_current_settings[setting]['min'],self.camera_current_settings[setting]['max']+1):
else: self.camera_current_settings[setting]['value'] += self.camera_current_settings[setting]['step']
self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['min'] else:
# Special cases self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['min']
# Autoexposure # Special cases
if setting == 'autoexposure' and self.camera_current_settings['autoexposure']['value'] == 4: # Autoexposure
self.cam.set_controls({'AeEnable': 1}) if setting == 'autoexposure' and self.camera_current_settings['autoexposure']['value'] == 4:
else: self.cam.set_controls({'AeEnable': 1})
self.cam.set_controls({'AeEnable': 0}) else:
self.cam.set_controls({"AeExposureMode": self.camera_current_settings['auto_exposure']['value']}) self.cam.set_controls({'AeEnable': 0})
# Antiflicker self.cam.set_controls({"AeExposureMode": self.camera_current_settings['auto_exposure']['value']})
if setting == 'anti_flicker' and self.camera_current_settings['anti_flicker']['value'] == 0: # Antiflicker
self.cam.set_controls({'AeFlickerMode': 0}) if setting == 'anti_flicker' and self.camera_current_settings['anti_flicker']['value'] == 0:
elif self.camera_current_settings['anti_flicker']['value'] == 1: self.cam.set_controls({'AeFlickerMode': 0})
self.cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':8333}) elif self.camera_current_settings['anti_flicker']['value'] == 1:
else: self.cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':8333})
self.cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':10000}) else:
self.cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':10000})
def apply_setting(self, to_set:list=None): def apply_setting(self, to_set:list=None, inc:bool=False):
for setting in to_set: for setting in to_set:
self.increment_setting(setting) if inc:
self.increment_setting(setting)
self.cam.set_controls({self.cam_settings_map[setting] : self.camera_current_settings[setting]['value']}) self.cam.set_controls({self.cam_settings_map[setting] : self.camera_current_settings[setting]['value']})
def flip_image(self): def flip_image(self):
@ -361,7 +408,14 @@ class dslr():
'anti_flicker' : 'imagesize', 'anti_flicker' : 'imagesize',
'lenspos' : 'shutterspeed', 'lenspos' : 'shutterspeed',
} }
# UI frame
self.frame = None self.frame = None
# Onionskin_frame
self.o_frame = None
# Overlay frame
self.overlay = None
# Original frame for saving
self.og_frame = None
self.has_liveview = False self.has_liveview = False
# TODO: check if DSLR has live feed and set accordingly # TODO: check if DSLR has live feed and set accordingly
# ~ self.onionskin = project_settings['onion_skin_onstartup'] # ~ self.onionskin = project_settings['onion_skin_onstartup']
@ -438,9 +492,11 @@ class dslr():
return False return False
# ~ camera.exit() # ~ camera.exit()
# Update frame # Update frame
frame = cv2.imread(img_path) cam.frame = cv2.imread(img_path)
# ~ frame = cv2.resize(frame, (project_settings['screen_w'], project_settings['screen_h'])) # ~ frame = cv2.resize(frame, (project_settings['screen_w'], project_settings['screen_h']))
return capture_ok # ~ if capture_ok is None:
# ~ return True
return True
def apply_gphoto_setting(self, setting:str): def apply_gphoto_setting(self, setting:str):
# Get corresponding setting name if possible # Get corresponding setting name if possible
@ -476,8 +532,8 @@ class dslr():
def increment_setting(self, setting:str): def increment_setting(self, setting:str):
if setting in self.camera_current_settings: if setting in self.camera_current_settings:
if self.camera_current_settings[setting]['value']+1 in range(self.camera_current_settings[setting]['min'],self.camera_current_settings[setting]['max']+1): if self.camera_current_settings[setting]['value'] + self.camera_current_settings[setting]['step'] in range(self.camera_current_settings[setting]['min'],self.camera_current_settings[setting]['max']+1):
self.camera_current_settings[setting]['value'] += 1 self.camera_current_settings[setting]['value'] += self.camera_current_settings[setting]['step']
else: else:
self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['min'] self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['min']
@ -520,8 +576,11 @@ class dslr():
def close(self): def close(self):
self.cam.exit() self.cam.exit()
def get_cam_class(camera_type): def get_cam_class(camera_type):
if camera_type == 'showmewebcam': if camera_type == 'webcam':
return webcam()
elif camera_type == 'showmewebcam':
return showmewebcam() return showmewebcam()
elif camera_type == 'picam': elif camera_type == 'picam':
return picam() return picam()
@ -903,7 +962,8 @@ def main(args):
cam.apply_setting() cam.apply_setting()
frame = get_onionskin_frame(savepath) cam.frame = get_onionskin_frame(savepath)
cam.o_frame = cam.frame.copy()
loop_delta = 0 loop_delta = 0
while True: while True:
@ -936,8 +996,8 @@ def main(args):
if not playback: if not playback:
if cam.has_liveview: if cam.has_liveview:
frame = cam.capture_preview() cam.capture_preview()
cv2.imshow("StopiCV", frame) cv2.imshow("StopiCV", cam.frame)
k = cv2.waitKey(1) k = cv2.waitKey(1)
# Key l / kp 5 # Key l / kp 5
@ -971,6 +1031,7 @@ def main(args):
if playback: if playback:
playback = False playback = False
index, frame = last_frame(index) index, frame = last_frame(index)
cam.o_frame = cam.frame.copy()
# Key down , kp 2 # Key down , kp 2
elif (k%256 == 84) or (k%256 == 50) or (k%256 == 178): elif (k%256 == 84) or (k%256 == 50) or (k%256 == 178):
print(_("First frame")) print(_("First frame"))
@ -978,6 +1039,7 @@ def main(args):
if playback: if playback:
playback = False playback = False
index, frame = first_frame(index) index, frame = first_frame(index)
cam.o_frame = cam.frame.copy()
# Key left, kp 4 # Key left, kp 4
elif (k%256 == 81) or (k%256 == 52) or (k%256 == 180): elif (k%256 == 81) or (k%256 == 52) or (k%256 == 180):
print(_("Prev. frame")) print(_("Prev. frame"))
@ -985,7 +1047,8 @@ def main(args):
if len(img_list): if len(img_list):
if playback: if playback:
playback = False playback = False
index, frame = previous_frame(index) index, cam.frame = previous_frame(index)
cam.o_frame = cam.frame.copy()
# Key right, kp 6 # Key right, kp 6
elif (k%256 == 83) or (k%256 == 54) or (k%256 == 182): elif (k%256 == 83) or (k%256 == 54) or (k%256 == 182):
print(_("Next frame")) print(_("Next frame"))
@ -993,7 +1056,8 @@ def main(args):
if len(img_list): if len(img_list):
if playback: if playback:
playback = False playback = False
index, frame = next_frame(index) index, cam.frame = next_frame(index)
cam.o_frame = cam.frame.copy()
# Key r / keypad 9 - reset wb,exp # Key r / keypad 9 - reset wb,exp
elif (k%256 == 114) or (k%256 == 57) or (k%256 == 185) : elif (k%256 == 114) or (k%256 == 57) or (k%256 == 185) :
print(_("Reset camera settings")) print(_("Reset camera settings"))
@ -1012,7 +1076,8 @@ def main(args):
elif (k%256 == 8) or (k%256 == 45) or (k == 255) or (k%256 == 173) : 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, cam.frame = remove_frame(img_list, index)
cam.o_frame = cam.frame.copy()
# Focus +/- with a,z # Focus +/- with a,z
elif (k%256 == 97): elif (k%256 == 97):
cam.focus('+') cam.focus('+')
@ -1036,14 +1101,15 @@ def main(args):
img_list[index] = img_name img_list[index] = img_name
else: else:
index += 1 index += 1
print(index)
# Display a message if capture was not successfull # Display a message if capture was not successfull
if capture_ok is not None: if not capture_ok:
frame = generate_text_image(_("Error during capture."), cam.frame = generate_text_image(_("Error during capture."),
project_settings['screen_w'], project_settings['screen_h'] project_settings['screen_w'], project_settings['screen_h']
) )
cam.o_frame = cam.frame.copy()
else: else:
frame = get_onionskin_frame(savepath) cam.frame = get_onionskin_frame(savepath)
cam.o_frame = cam.frame.copy()
# ~ frame = cam.frame # ~ frame = cam.frame
# Quit app # Quit app
elif k%256 == 27: elif k%256 == 27:

View File

@ -8,7 +8,7 @@
<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/src/branch/picamera). 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 libcamera.Elle fonctionne avec une webcam ou un module vidéo Picamera (v1,v2 ou v3). 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 :
@ -33,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 libopenblas-dev libatlas-base-dev libhdf5-dev libhdf5-serial-dev libatlas-base-dev libjasper-dev libqtgui4 libqt4-test sudo apt install --no-install-recommends --no-install-suggests git ffmpeg 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 v4l-utils
``` ```
- (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`