Apply suggestions from code review of branch jpeg-capture-in-stacking

Co-authored-by: Beth Probert <beth_probert@outlook.com>
This commit is contained in:
Julian Stirling 2025-06-25 15:12:28 +00:00
parent 0751457ed3
commit 83e0e08ccc
3 changed files with 17 additions and 16 deletions

View file

@ -250,6 +250,7 @@ class BaseCamera(Thing):
try: try:
image.save(jpeg_path, quality=95, subsampling=0) image.save(jpeg_path, quality=95, subsampling=0)
try: try:
# Load EXIF metadata from image so it can be added to.
exif_dict = piexif.load(jpeg_path) exif_dict = piexif.load(jpeg_path)
exif_dict["Exif"][piexif.ExifIFD.UserComment] = json.dumps( exif_dict["Exif"][piexif.ExifIFD.UserComment] = json.dumps(
metadata metadata

View file

@ -152,7 +152,7 @@ class StreamingPiCamera2(BaseCamera):
tolerance of current value. This allows ignoring small changes tolerance of current value. This allows ignoring small changes
""" """
if key not in self.persistent_control_tolerances: if key not in self.persistent_control_tolerances:
# Not tolerance range set, so it is not within tollerance # Not tolerance range set, so it is not within tolerance
return False return False
difference = np.abs(self.persistent_controls[key] - value) difference = np.abs(self.persistent_controls[key] - value)
@ -419,7 +419,7 @@ class StreamingPiCamera2(BaseCamera):
) )
@thing_action @thing_action
def stop_streaming(self, stop_web_stream=True) -> None: def stop_streaming(self, stop_web_stream: bool = True) -> None:
""" """
Stop the MJPEG stream Stop the MJPEG stream
""" """
@ -617,7 +617,7 @@ class StreamingPiCamera2(BaseCamera):
self.update_persistent_controls() self.update_persistent_controls()
@thing_action @thing_action
def calibrate_lens_shading(self): def calibrate_lens_shading(self) -> None:
"""Take an image and use it for flat-field correction. """Take an image and use it for flat-field correction.
This method requires an empty (i.e. bright) field of view. It will take This method requires an empty (i.e. bright) field of view. It will take
@ -643,7 +643,7 @@ class StreamingPiCamera2(BaseCamera):
) )
@colour_correction_matrix.setter # type: ignore @colour_correction_matrix.setter # type: ignore
def colour_correction_matrix(self, value): def colour_correction_matrix(self, value) -> None:
self.thing_settings["colour_correction_matrix"] = value self.thing_settings["colour_correction_matrix"] = value
self.calibrate_colour_correction(value) self.calibrate_colour_correction(value)
@ -664,14 +664,14 @@ class StreamingPiCamera2(BaseCamera):
self.colour_correction_matrix = c self.colour_correction_matrix = c
@thing_action @thing_action
def calibrate_colour_correction(self, c: tuple): def calibrate_colour_correction(self, c: tuple) -> None:
"""Overwrite the colour correction matrix in camera tuning""" """Overwrite the colour correction matrix in camera tuning"""
with self.picamera(pause_stream=True): with self.picamera(pause_stream=True):
recalibrate_utils.set_static_ccm(self.tuning, c) recalibrate_utils.set_static_ccm(self.tuning, c)
self.initialise_picamera() self.initialise_picamera()
@thing_action @thing_action
def set_static_green_equalisation(self, offset: int = 65535): def set_static_green_equalisation(self, offset: int = 65535) -> None:
"""Set the green equalisation to a static value. """Set the green equalisation to a static value.
Green equalisation avoids the debayering algorithm becoming confused Green equalisation avoids the debayering algorithm becoming confused
@ -686,7 +686,7 @@ class StreamingPiCamera2(BaseCamera):
self.initialise_picamera() self.initialise_picamera()
@thing_action @thing_action
def full_auto_calibrate(self): def full_auto_calibrate(self) -> None:
"""Perform a full auto-calibration """Perform a full auto-calibration
This function will call the other calibration actions in sequence: This function will call the other calibration actions in sequence:
@ -704,7 +704,7 @@ class StreamingPiCamera2(BaseCamera):
self.calibrate_white_balance() self.calibrate_white_balance()
@thing_action @thing_action
def flat_lens_shading(self): def flat_lens_shading(self) -> None:
"""Disable flat-field correction """Disable flat-field correction
This method will set a completely flat lens shading table. It is not the This method will set a completely flat lens shading table. It is not the
@ -786,7 +786,7 @@ class StreamingPiCamera2(BaseCamera):
) )
@thing_action @thing_action
def flat_lens_shading_chrominance(self): def flat_lens_shading_chrominance(self) -> None:
"""Disable flat-field correction """Disable flat-field correction
This method will set the chrominance of the lens shading table to be This method will set the chrominance of the lens shading table to be
@ -801,7 +801,7 @@ class StreamingPiCamera2(BaseCamera):
self.initialise_picamera() self.initialise_picamera()
@thing_action @thing_action
def reset_lens_shading(self): def reset_lens_shading(self) -> None:
"""Revert to default lens shading settings """Revert to default lens shading settings
This method will restore the default "adaptive" lens shading method used This method will restore the default "adaptive" lens shading method used

View file

@ -69,13 +69,13 @@ def load_default_tuning(cam: Picamera2) -> dict:
tuning_dir = "/usr/share/libcamera/ipa/raspberrypi" tuning_dir = "/usr/share/libcamera/ipa/raspberrypi"
# from picamera2 v0.3.9 # from picamera2 v0.3.9
# The directory above has been removed from the search path seems # The directory above has been removed from the search path seems
# find odd - as that's where the files currently are on a default # odd - as that's where the files currently are on a default
# Raspbian image. This may need updating if the files have moved # Raspbian image. This may need updating if the files have moved
# in future updates to the system libcamera package # in future updates to the system libcamera package
return cam.load_tuning_file(fname, dir=tuning_dir) return cam.load_tuning_file(fname, dir=tuning_dir)
def set_minimum_exposure(camera: Picamera2): def set_minimum_exposure(camera: Picamera2) -> None:
"""Enable manual exposure, with low gain and shutter speed """Enable manual exposure, with low gain and shutter speed
We set exposure mode to manual, analog and digital gain We set exposure mode to manual, analog and digital gain
@ -135,7 +135,7 @@ def test_exposure_settings(camera: Picamera2, percentile: float) -> ExposureTest
return result return result
def check_convergence(test: ExposureTest, target: int, tolerance: float): def check_convergence(test: ExposureTest, target: int, tolerance: float) -> bool:
"""Check whether the brightness is within the specified target range""" """Check whether the brightness is within the specified target range"""
return abs(test.level - target) < target * tolerance return abs(test.level - target) < target * tolerance
@ -222,7 +222,7 @@ def adjust_shutter_and_gain_from_raw(
# Check the gain is still changing - if not, we have probably hit the maximum # Check the gain is still changing - if not, we have probably hit the maximum
if camera.capture_metadata()["AnalogueGain"] == test.analog_gain: if camera.capture_metadata()["AnalogueGain"] == test.analog_gain:
logging.info(f"Gain has maxed out. at {test.analog_gain}") logging.info(f"Gain has maxed out at {test.analog_gain}")
break break
if check_convergence(test, target_white_level, tolerance): if check_convergence(test, target_white_level, tolerance):
@ -504,7 +504,7 @@ def index_of_algorithm(algorithms: list[dict], algorithm: str) -> int:
raise ValueError(f"Algorithm {algorithm} is not available.") raise ValueError(f"Algorithm {algorithm} is not available.")
def copy_alsc_section(from_tuning: dict, to_tuning: dict): def copy_alsc_section(from_tuning: dict, to_tuning: dict) -> None:
"""Copy the `rpi.alsc` algorithm from one tuning to another. """Copy the `rpi.alsc` algorithm from one tuning to another.
This is done in-place, i.e. modifying to_tuning. This is done in-place, i.e. modifying to_tuning.
@ -544,7 +544,7 @@ def raw_channels_from_camera(camera: Picamera2) -> LensShadingTables:
return channels_from_bayer_array(raw_image) return channels_from_bayer_array(raw_image)
def recreate_camera_manager(): def recreate_camera_manager() -> None:
"""Delete and recreate the camera manager. """Delete and recreate the camera manager.
This is necessary to ensure the tuning file is re-read. This is necessary to ensure the tuning file is re-read.