diff --git a/openflexure_microscope/api/v2/blueprints/actions/camera.py b/openflexure_microscope/api/v2/blueprints/actions/camera.py index 198dc1ba..3e21658e 100644 --- a/openflexure_microscope/api/v2/blueprints/actions/camera.py +++ b/openflexure_microscope/api/v2/blueprints/actions/camera.py @@ -87,13 +87,7 @@ class CaptureAPI(MicroscopeView): ) # Inject system metadata - system_metadata = { - "microscope_settings": self.microscope.read_settings(), - "microscope_state": self.microscope.state, - "microscope_id": self.microscope.id, - "microscope_name": self.microscope.name, - } - output.system_metadata.update(system_metadata) + output.system_metadata.update(self.microscope.metadata) # Insert custom metadata output.put_metadata(metadata) diff --git a/openflexure_microscope/microscope.py b/openflexure_microscope/microscope.py index 6be22766..8432ac56 100644 --- a/openflexure_microscope/microscope.py +++ b/openflexure_microscope/microscope.py @@ -10,7 +10,9 @@ from openflexure_microscope.stage.base import BaseStage from openflexure_microscope.stage.mock import MockStage from openflexure_microscope.camera.base import BaseCamera from openflexure_microscope.camera.mock import MockStreamer +from openflexure_microscope.camera.pi import PiCameraStreamer +from openflexure_microscope.utilities import serialise_array_b64 from openflexure_microscope.plugins import PluginLoader from openflexure_microscope.task import TaskOrchestrator from openflexure_microscope.common.lock import CompositeLock @@ -270,3 +272,30 @@ class Microscope: Please use apply_settings method instead." ) self.apply_settings(config) + + @property + def metadata(self): + """ + Microscope system metadata, to be applied to basically all captures + """ + system_metadata = { + "microscope_settings": self.read_settings(), + "microscope_state": self.state, + "microscope_id": self.id, + "microscope_name": self.name, + } + + # Store an encoded copy of the PiCamera lens shading table, if it exists + if self.camera and isinstance(self.camera, PiCameraStreamer): + # Read LST. Returns None if no LST is active + lst_arr = self.camera.read_lens_shading_table() + + b64_string, dtype, shape = serialise_array_b64(lst_arr) + + system_metadata["lens_shading_table"] = { + "b64_string": b64_string, + "dtype": dtype, + "shape": shape + } + + return system_metadata \ No newline at end of file diff --git a/openflexure_microscope/plugins/default/scan/plugin.py b/openflexure_microscope/plugins/default/scan/plugin.py index a4048e6b..6cd7a698 100644 --- a/openflexure_microscope/plugins/default/scan/plugin.py +++ b/openflexure_microscope/plugins/default/scan/plugin.py @@ -100,13 +100,7 @@ class ScanPlugin(MicroscopePlugin): tags.append("scan") # Inject system metadata - system_metadata = { - "microscope_settings": self.microscope.read_settings(), - "microscope_state": self.microscope.state, - "microscope_id": self.microscope.id, - "microscope_name": self.microscope.name, - } - output.system_metadata.update(system_metadata) + output.system_metadata.update(self.microscope.metadata) # Insert custom metadata output.put_metadata(metadata) diff --git a/openflexure_microscope/utilities.py b/openflexure_microscope/utilities.py index 0551790e..20a543ad 100644 --- a/openflexure_microscope/utilities.py +++ b/openflexure_microscope/utilities.py @@ -1,11 +1,23 @@ import re import copy import operator +import base64 +import numpy as np from collections import abc from functools import reduce from contextlib import contextmanager +def deserialise_array_b64(b64_string, dtype, shape): + flat_arr = np.fromstring(base64.b64decode(b64_string), dtype) + return flat_arr.reshape(shape) + +def serialise_array_b64(npy_arr): + b64_string = base64.b64encode(npy_arr).decode('ascii') + dtype = str(npy_arr.dtype) + shape = npy_arr.shape + return b64_string, dtype, shape + def get_by_path(root, items): """Access a nested object in root by item sequence.""" return reduce(operator.getitem, items, root)