Add gamma_curve to metadata

This commit is contained in:
jaknapper 2026-03-03 13:59:43 +00:00
parent 17f77e36c4
commit 0173cf912f
4 changed files with 36 additions and 1 deletions

View file

@ -646,7 +646,7 @@ class BaseCamera(lt.Thing):
"""Return camera-specific metadata. """Return camera-specific metadata.
By default, this just adds the subclass name as the camera type. By default, this just adds the subclass name as the camera type.
Subclasses can extend by overriding this property and calling `super()`. Subclasses can extend by overriding this property and calling `super().thing_state`.
""" """
return {"camera": self.__class__.__name__} return {"camera": self.__class__.__name__}

View file

@ -718,6 +718,11 @@ class StreamingPiCamera2(BaseCamera):
copy_from=self.default_tuning, copy_from=self.default_tuning,
) )
@lt.property
def gamma_correction(self) -> float:
"""Return the gamma correction from the tuning file."""
return tf_utils.get_gamma_curve(self.tuning)
@lt.action @lt.action
def set_static_green_equalisation(self, offset: int = 65535) -> None: 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.
@ -931,5 +936,6 @@ class StreamingPiCamera2(BaseCamera):
"exposure_time": self.exposure_time, "exposure_time": self.exposure_time,
"colour_gains": self.colour_gains, "colour_gains": self.colour_gains,
"analogue_gain": self.analogue_gain, "analogue_gain": self.analogue_gain,
"gamma_correction": self.gamma_correction,
} }
return state return state

View file

@ -186,6 +186,27 @@ def get_lst(tuning: dict) -> LensShadingModel:
) )
def get_gamma_curve(tuning: dict) -> dict[int, float]:
"""Return the gamma curve from the rpi.contrast section of the tuning file.
Returns a dictionary mapping input levels to output levels.
Defaults to {} if gamma curve is missing.
"""
contrast = find_tuning_algo(tuning, "rpi.contrast")
return contrast.get("gamma", {})
def set_gamma_curve(tuning: dict, gamma_curve: dict[int, float]) -> dict:
"""Set the gamma curve in the rpi.contrast section of the tuning file.
Returns a new tuning dictionary with the updated gamma curve.
"""
output_tuning = deepcopy(tuning)
contrast = find_tuning_algo(output_tuning, "rpi.contrast")
contrast["gamma"] = {int(k): float(v) for k, v in gamma_curve.items()}
return output_tuning
def get_colour_gains_from_lst(tuning: dict) -> tuple[float, float]: def get_colour_gains_from_lst(tuning: dict) -> tuple[float, float]:
"""Get the colour gains that are needed from the lens shading tables. """Get the colour gains that are needed from the lens shading tables.

View file

@ -13,6 +13,9 @@ from labthings_fastapi.testing import create_thing_without_server
from openflexure_microscope_server.things.background_detect import ChannelDeviationLUV from openflexure_microscope_server.things.background_detect import ChannelDeviationLUV
from openflexure_microscope_server.things.camera import BaseCamera from openflexure_microscope_server.things.camera import BaseCamera
from openflexure_microscope_server.things.camera import (
picamera_tuning_file_utils as tf_utils,
)
from openflexure_microscope_server.things.camera.simulation import SimulatedCamera from openflexure_microscope_server.things.camera.simulation import SimulatedCamera
from openflexure_microscope_server.things.stage.dummy import DummyStage from openflexure_microscope_server.things.stage.dummy import DummyStage
@ -138,6 +141,7 @@ def test_picamera_adds_metadata(mock_picam_thing):
camera.exposure_time = 1234 camera.exposure_time = 1234
camera.colour_gains = (1.1, 1.2) camera.colour_gains = (1.1, 1.2)
camera.analogue_gain = 2.5 camera.analogue_gain = 2.5
camera.tuning = tf_utils.set_gamma_curve(camera.tuning, {1: 5, 2: 10})
state = camera.thing_state state = camera.thing_state
@ -147,6 +151,7 @@ def test_picamera_adds_metadata(mock_picam_thing):
"exposure_time": 1234, "exposure_time": 1234,
"colour_gains": (1.1, 1.2), "colour_gains": (1.1, 1.2),
"analogue_gain": 2.5, "analogue_gain": 2.5,
"gamma_correction": {1: 5, 2: 10},
} }
@ -158,6 +163,7 @@ def test_picamera_metadata_written_to_exif(mock_picam_thing, temp_jpeg, mocker):
camera.exposure_time = 1234 camera.exposure_time = 1234
camera.colour_gains = (1.1, 1.2) camera.colour_gains = (1.1, 1.2)
camera.analogue_gain = 2.5 camera.analogue_gain = 2.5
camera.tuning = tf_utils.set_gamma_curve(camera.tuning, {1: 5, 2: 10})
# Mock the server interface to return the camera's own state # Mock the server interface to return the camera's own state
mock_interface = mocker.Mock() mock_interface = mocker.Mock()
@ -173,8 +179,10 @@ def test_picamera_metadata_written_to_exif(mock_picam_thing, temp_jpeg, mocker):
assert user_comment["camera"] == "StreamingPiCamera2" assert user_comment["camera"] == "StreamingPiCamera2"
assert user_comment["camera_board"] == "imx219" assert user_comment["camera_board"] == "imx219"
# gamma_correction keys are cast to strings
assert user_comment["tuning"] == { assert user_comment["tuning"] == {
"exposure_time": 1234, "exposure_time": 1234,
"colour_gains": [1.1, 1.2], "colour_gains": [1.1, 1.2],
"analogue_gain": 2.5, "analogue_gain": 2.5,
"gamma_correction": {"1": 5, "2": 10},
} }