From 01a883e95c31baa89b7729f55b4b020f48fcdd75 Mon Sep 17 00:00:00 2001 From: Julian Stirling Date: Thu, 30 Oct 2025 13:54:23 +0000 Subject: [PATCH] Reset CCM resets to the CCM in the default tuning file. --- .../things/camera/picamera.py | 48 ++++--------------- .../camera/picamera_tuning_file_utils.py | 19 ++++---- 2 files changed, 20 insertions(+), 47 deletions(-) diff --git a/src/openflexure_microscope_server/things/camera/picamera.py b/src/openflexure_microscope_server/things/camera/picamera.py index 83e2f147..99463d06 100644 --- a/src/openflexure_microscope_server/things/camera/picamera.py +++ b/src/openflexure_microscope_server/things/camera/picamera.py @@ -749,9 +749,6 @@ class StreamingPiCamera2(BaseCamera): It is a 9 value tuple used to specify the 3x3 matrix that the GPU pipeline uses to convert from the camera R,G,B vector to the standard R,G,B. - - The value here is interpolated from the IMX219 defaults for the colour temperatures - above and below our LED temperature of 5000K. """ return tuple(tf_utils.get_static_ccm(self.tuning)[0]["ccm"]) @@ -766,41 +763,14 @@ class StreamingPiCamera2(BaseCamera): with self._streaming_picamera(pause_stream=True): self._initialise_picamera() - # TODO make reset CCM reset from default tuning. @lt.thing_action def reset_ccm(self) -> None: - """Overwrite the colour correction matrix in camera tuning with default values. - - These values are from the Raspberry Pi Camera Algorithm and Tuning Guide, page - 45. - """ - # This is flattened 3x3 matrix. See `colour_correction_matrix` - if self._camera_board == "picamera_v2": - col_corr_matrix = [ - 2.222935, - -0.759672, - -0.463262, - -0.683489, - 2.711882, - -1.028399, - -0.261375, - -0.668016, - 1.929391, - ] - else: - # Note the only other option is the HQ - col_corr_matrix = [ - 2.164374, - -0.97259, - -0.191778, - -0.376957, - 2.099377, - -0.722417, - -0.11787, - -0.489362, - 1.607232, - ] - self.colour_correction_matrix = col_corr_matrix + """Overwrite the colour correction matrix in camera tuning with default values.""" + self.tuning = tf_utils.copy_algo_from_other_tuning( + algo="rpi.ccm", + base_tuning_file=self.tuning, + copy_from=self.default_tuning, + ) @lt.thing_action def set_static_green_equalisation(self, offset: int = 65535) -> None: @@ -1018,8 +988,10 @@ class StreamingPiCamera2(BaseCamera): by the Raspberry Pi camera. """ with self._streaming_picamera(pause_stream=True): - self.tuning = tf_utils.copy_tuning_with_alsc_section_from_other( - base_tuning_file=self.tuning, copy_alsc_from=self.default_tuning + self.tuning = tf_utils.copy_algo_from_other_tuning( + algo="rpi.alsc", + base_tuning_file=self.tuning, + copy_from=self.default_tuning, ) self._initialise_picamera() diff --git a/src/openflexure_microscope_server/things/camera/picamera_tuning_file_utils.py b/src/openflexure_microscope_server/things/camera/picamera_tuning_file_utils.py index 399043e2..14b51e3e 100644 --- a/src/openflexure_microscope_server/things/camera/picamera_tuning_file_utils.py +++ b/src/openflexure_microscope_server/things/camera/picamera_tuning_file_utils.py @@ -30,8 +30,8 @@ def load_default_tuning(sensor_model: str) -> dict: tuning_path = os.path.join(THIS_DIR, "tuning_files", "vc4", fname) try: - with open(tuning_path, "r") as fp: - return json.load(fp) + with open(tuning_path, "r", encoding="utf-8") as file_obj: + return json.load(file_obj) except (json.decoder.JSONDecodeError, IOError) as e: raise TuningFileError(f"Could not load tuning from {tuning_path}.") from e @@ -165,13 +165,14 @@ def ce_enable_is_static(tuning: dict) -> bool: return contrast["ce_enable"] == 0 -def copy_tuning_with_alsc_section_from_other( - *, base_tuning_file: dict, copy_alsc_from: dict +def copy_algo_from_other_tuning( + algo: str, *, base_tuning_file: dict, copy_from: dict ) -> dict: - """Return a copy of tuning_file with the lens shading correction from another file. + """Return a copy of tuning_file with an algorithm copied from another file. - All parameters are keyword only for clarity. + Tuning dict arguments are keyword only for clarity. + :param algo: The algorithm to copy. Eg ``rpi.alsc`` for lens shading correction. :param base_tuning_file: The tuning file to copy. :param copy_alsc_from: The tuning file to take the alsc section from. :return: A deep copy of base_tuning_file with the alsc section copied in from the @@ -179,10 +180,10 @@ def copy_tuning_with_alsc_section_from_other( """ output_tuning = deepcopy(base_tuning_file) # Find the relevant sub-dict for each tuning file - from_i = _index_of_algorithm(copy_alsc_from["algorithms"], "rpi.alsc") - to_i = _index_of_algorithm(base_tuning_file["algorithms"], "rpi.alsc") + from_i = _index_of_algorithm(copy_from["algorithms"], algo) + to_i = _index_of_algorithm(base_tuning_file["algorithms"], algo) # Updating the dictionary in place. - output_tuning["algorithms"][to_i] = deepcopy(copy_alsc_from["algorithms"][from_i]) + output_tuning["algorithms"][to_i] = deepcopy(copy_from["algorithms"][from_i]) return output_tuning