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.
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__}

View file

@ -718,6 +718,11 @@ class StreamingPiCamera2(BaseCamera):
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
def set_static_green_equalisation(self, offset: int = 65535) -> None:
"""Set the green equalisation to a static value.
@ -931,5 +936,6 @@ class StreamingPiCamera2(BaseCamera):
"exposure_time": self.exposure_time,
"colour_gains": self.colour_gains,
"analogue_gain": self.analogue_gain,
"gamma_correction": self.gamma_correction,
}
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]:
"""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.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.stage.dummy import DummyStage
@ -138,6 +141,7 @@ def test_picamera_adds_metadata(mock_picam_thing):
camera.exposure_time = 1234
camera.colour_gains = (1.1, 1.2)
camera.analogue_gain = 2.5
camera.tuning = tf_utils.set_gamma_curve(camera.tuning, {1: 5, 2: 10})
state = camera.thing_state
@ -147,6 +151,7 @@ def test_picamera_adds_metadata(mock_picam_thing):
"exposure_time": 1234,
"colour_gains": (1.1, 1.2),
"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.colour_gains = (1.1, 1.2)
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_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_board"] == "imx219"
# gamma_correction keys are cast to strings
assert user_comment["tuning"] == {
"exposure_time": 1234,
"colour_gains": [1.1, 1.2],
"analogue_gain": 2.5,
"gamma_correction": {"1": 5, "2": 10},
}