Add exposure control for picam

This commit is contained in:
ABelliqueux 2025-03-01 19:35:25 +01:00
parent df0193a689
commit 85d31def6f
1 changed files with 56 additions and 35 deletions

View File

@ -154,9 +154,9 @@ class webcam():
capture_ok = cv2.imwrite(img_path, self.og_frame)
return capture_ok
def increment_setting(self, setting:str, value:int=-1):
def increment_setting(self, setting:str, inc:int=-1):
# If value has default -1 value, increment setting
if value == -1:
if inc == -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']
@ -202,7 +202,7 @@ class webcam():
v4l2_ctl_process = subprocess.Popen(cmd.split(' '))
return v4l2_ctl_process
def apply_setting(self, to_set:list=None, inc:bool=False):
def apply_setting(self, to_set:list=None, inc:int=0):
cmd = self.build_v4l2_cmd(to_set)
self.run_v4l2_ctl(cmd)
return self.camera_current_settings
@ -233,7 +233,7 @@ class showmewebcam(webcam):
'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, inc:bool=False):
def apply_setting(self, to_set:list=None, inc:int=0):
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))
return self.camera_current_settings
@ -246,13 +246,16 @@ class picam():
'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, 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']),
'anti_flicker': dict(min=0, max=2, step=1, default=1, value=1),
'anti_flicker': dict(min=0, max=20000, step=1000, default=0, value=0),
'exposure' : dict(min=0, max=50000, step=1000, default=0, value=0)
}
# Map generic config name to specific picamera setting name
self.cam_settings_map = {
'white_balance_auto_preset': 'AwbMode',
'auto_exposure':'AeExposureMode',
'anti_flicker' : 'AeFlickerMode',
'exposure':'ExposureTime',
# ~ 'anti_flicker' : 'AeFlickerMode',
'anti_flicker' : 'AeFlickerPeriod',
'lenspos' : 'LensPosition',
}
self.has_liveview = True
@ -269,12 +272,12 @@ class picam():
self.liveview_only = False
# Pi Cam V3 setup
self.Picamera2 = getattr(import_module('picamera2'), 'Picamera2')
self.Metadata = getattr(import_module('picamera2'), 'Metadata')
self.Transform = getattr(import_module('libcamera'), 'Transform')
# Cam setup
self.cam = self.Picamera2()
self.picam_config = self.cam.create_video_configuration(main={"format": 'RGB888',"size": (camera_settings['cam_w'], camera_settings['cam_h'])})
self.picam_config["transform"] = self.Transform(vflip=self.camera_current_settings['vertical_flip']['value'],hflip=self.camera_current_settings['horizontal_flip']['value'])
self.picam_config["transform"] = self.Transform(vflip=self.camera_current_settings['vertical_flip']['value'],hflip=self.camera_current_settings['horizontal_flip']['value'])
self.cam.configure(self.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
@ -286,18 +289,24 @@ class picam():
self.camera_default_settings = {'AfMode': 0,
'AwbEnable': 1,
'AwbMode': self.camera_current_settings['white_balance_auto_preset']['default'],
# Disable Autoexposure
'AeEnable': 1,
'ExposureTime': 0,
'AeExposureMode': self.camera_current_settings['auto_exposure']['default'],
# Enable flicker avoidance due to mains
# AeFlickerModeEnum { FlickerOff = 0, FlickerManual = 1, FlickerAuto = 2 }
'AeFlickerMode': 1,
# Mains 50hz = 10000, 60hz = 8333
# ~ 'AeFlickerPeriod': 8333,
'AeFlickerPeriod': 10000,
'AeFlickerPeriod': self.camera_current_settings['anti_flicker']['default'],
# Format is (min, max, default) in ms
# here: (60fps, 12fps, None)
# ~ 'FrameDurationLimits':(16666,83333,None)
}
self.cam.set_controls(self.camera_default_settings)
# Get current exposure value and store it in settings
metadata = self.Metadata(self.cam.capture_metadata())
self.camera_current_settings['exposure']['value'] = self.camera_current_settings['exposure']['default'] = metadata.ExposureTime
def test_device(self, source):
pass
@ -330,12 +339,18 @@ class picam():
capture_ok = cv2.imwrite(img_path, self.og_frame)
return capture_ok
def increment_setting(self, setting:str):
def increment_setting(self, setting:str, inc:int=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']
if inc == -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'] -= self.camera_current_settings[setting]['step']
else:
self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['max']
elif inc == 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'] += self.camera_current_settings[setting]['step']
else:
self.camera_current_settings[setting]['value'] = self.camera_current_settings[setting]['min']
# Special cases
# Autoexposure
if setting == 'autoexposure' and self.camera_current_settings['autoexposure']['value'] == 4:
@ -343,20 +358,16 @@ class picam():
else:
self.cam.set_controls({'AeEnable': 0})
self.cam.set_controls({"AeExposureMode": self.camera_current_settings['auto_exposure']['value']})
# Antiflicker
if setting == 'anti_flicker' and self.camera_current_settings['anti_flicker']['value'] == 0:
self.cam.set_controls({'AeFlickerMode': 0})
elif self.camera_current_settings['anti_flicker']['value'] == 1:
self.cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':8333})
else:
self.cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':10000})
return True
def apply_setting(self, to_set:list=None, inc:bool=False):
def apply_setting(self, to_set:list=None, inc:int=0):
set_controls = False
if to_set is not None:
for setting in to_set:
if inc:
self.increment_setting(setting)
self.cam.set_controls({self.cam_settings_map[setting] : self.camera_current_settings[setting]['value']})
if inc != 0:
set_controls = self.increment_setting(setting, inc)
if set_controls:
self.cam.set_controls({self.cam_settings_map[setting] : self.camera_current_settings[setting]['value']})
def flip_image(self):
self.cam.stop()
@ -376,8 +387,11 @@ class picam():
print(_("-Lens pos: {}".format(self.lenspos)))
def reset_picture_settings(self):
for setting in self.camera_default_settings:
self.cam.set_controls({setting : self.camera_default_settings[setting]})
# ~ for setting in self.camera_default_settings:
# ~ self.cam.set_controls({setting : self.camera_default_settings[setting]})
self.cam.set_controls(self.camera_default_settings)
metadata = self.Metadata(self.cam.capture_metadata())
self.camera_current_settings['exposure']['value'] = self.camera_current_settings['exposure']['default'] = metadata.ExposureTime
def close(self):
self.cam.close()
@ -535,14 +549,14 @@ class dslr():
except:
print("Configuration error while setting {} to {}".format(setting, select_setting))
def increment_setting(self, setting:str):
def increment_setting(self, setting:str, inc:int=-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']
def apply_setting(self, to_set:list=None, inc:bool=False):
def apply_setting(self, to_set:list=None, inc:int=0):
self.camera_current_config = self.gp.check_result(self.gp.gp_camera_get_config(self.cam))
# iterate over the settings dictionary
if to_set is None:
@ -568,7 +582,7 @@ class dslr():
self.frame = cv2.flip(self.frame, -1)
def focus(self, direction:str='-'):
self.apply_setting(['shutterspeed'], True)
self.apply_setting(['shutterspeed'], 1)
def reset_picture_settings(self):
self.camera_current_config = self.gp.check_result(self.gp.gp_camera_get_config(self.cam))
@ -1020,11 +1034,11 @@ def main(args):
# Key w / 7 - cycle wb
elif (k%256 == 119) or (k%256 == 55) or (k%256 == 183):
print(_("White balance mode"))
cam.apply_setting(['white_balance_auto_preset'], True)
cam.apply_setting(['white_balance_auto_preset'], 1)
# Key x / 1 - cycle exposure
elif (k%256 == 120) or (k%256 == 49) or (k%256 == 177):
print(_("Exp. mode"))
cam.apply_setting(['auto_exposure'], True)
cam.apply_setting(['auto_exposure'], 1)
# Key f / 3 - flip image
elif (k%256 == 102) or (k%256 == 51) or (k%256 == 179):
print(_("Flip image"))
@ -1094,9 +1108,16 @@ def main(args):
elif (k%256 == 113):
print(_("Anti-flicker mode"))
cam.apply_setting(['anti_flicker'], True)
# Unused : key S
elif (k%256 == 115):
pass
print(cam.camera_current_settings['anti_flicker']['value'])
# Exposure : key S or maj A
elif (k%256 == 115) or (k%256 == 65):
print(_("Inc. exposure"))
cam.apply_setting(['exposure'], 1)
print(cam.camera_current_settings['exposure']['value'])
elif (k%256 == 90):
print(_("Dec. exposure"))
cam.apply_setting(['exposure'], -1)
print(cam.camera_current_settings['exposure']['value'])
# SPACE or numpad 0 pressed
elif (k%256 == 32) or (k%256 == 48) or (k%256 == 176):
print(_("Capture frame"))