Commit cf663595 authored by Joel Collins's avatar Joel Collins
Browse files

Reimplemented serialising LST

parent ccd5e9b8
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -146,10 +146,6 @@ class BaseCamera(metaclass=ABCMeta):
        """Return the current settings as a dictionary"""
        return {"paths": self.paths}

    def save_settings(self):
        """(Optional) Save any settings to disk that need to be stored"""
        return

    def __enter__(self):
        """Create camera on context enter."""
        return self
+26 −55
Original line number Diff line number Diff line
@@ -47,7 +47,11 @@ from .base import BaseCamera, CaptureObject
from .set_picamera_gain import set_analog_gain, set_digital_gain

from openflexure_microscope.paths import settings_file_path
from openflexure_microscope.utilities import serialise_array_b64
from openflexure_microscope.utilities import (
    serialise_array_b64,
    ndarray_to_json,
    json_to_ndarray,
)


# MAIN CLASS
@@ -154,9 +158,6 @@ class PiCameraStreamer(BaseCamera):
                "image_resolution": self.image_resolution,
                "numpy_resolution": self.numpy_resolution,
                "jpeg_quality": self.jpeg_quality,
                "picamera_lst_path": self.picamera_lst_path
                if (self.picamera_lst_path and os.path.isfile(self.picamera_lst_path))
                else None,
                "picamera": {},
            }
        )
@@ -170,12 +171,16 @@ class PiCameraStreamer(BaseCamera):
            except AttributeError:
                logging.debug("Unable to read PiCamera attribute {}".format(key))

        return conf_dict
        # Include a serialised lens shading table
        if (
            hasattr(self.camera, "lens_shading_table")
            and getattr(self.camera, "lens_shading_table") is not None
        ):
            conf_dict["picamera"]["lens_shading_table"] = ndarray_to_json(
                getattr(self.camera, "lens_shading_table")
            )

    def save_settings(self):
        """Save lens-shading table to disk"""
        logging.info("Saving picamera_lst to {}".format(self.picamera_lst_path))
        self.save_lens_shading_table()
        return conf_dict

    def update_settings(self, config: dict):
        """
@@ -209,22 +214,23 @@ class PiCameraStreamer(BaseCamera):
                        config["picamera"], pause_for_effect=True
                    )

                    # Handle lens shading if camera supports it
                    if (
                        hasattr(self.camera, "lens_shading_table")
                        and "lens_shading_table" in config["picamera"]
                    ):
                        try:
                            self.camera.lens_shading_table = json_to_ndarray(
                                config["picamera"].get("lens_shading_table")
                            )
                        except KeyError as e:
                            logging.error(e)

                # PiCameraStreamer parameters
                for key, value in config.items():  # For each provided setting
                    if (key != "picamera") and hasattr(self, key):
                        setattr(self, key, value)

                # Handle lens shading if camera supports it
                if ("picamera_lst_path" in config) and hasattr(
                    self.camera, "lens_shading_table"
                ):
                    logging.debug(
                        "Applying lens_shading_table from file: {}".format(
                            config["picamera_lst_path"]
                        )
                    )
                    self.apply_lens_shading_table(config["picamera_lst_path"])

                # If stream was paused to update config, unpause
                if paused_stream:
                    logging.info("Resuming stream.")
@@ -293,41 +299,6 @@ class PiCameraStreamer(BaseCamera):
        if pause_for_effect:
            time.sleep(0.2)

    def read_lens_shading_table(self):
        """
        Read the current lens shading table as a numpy array, if it exists. Return None otherwise.
        """
        if hasattr(self.camera, "lens_shading_table"):
            return self.camera.lens_shading_table
        else:
            return None

    def save_lens_shading_table(self):
        """
        Save the current lens shading table to an .npy file, if it exists. 
        """
        logging.debug(self.read_lens_shading_table())
        if self.read_lens_shading_table() is not None:
            np.save(self.picamera_lst_path, self.read_lens_shading_table())
        else:
            logging.warning("Unable to save a nonexistant lens shading table")

    def apply_lens_shading_table(self, lst_array_or_path):
        """
        Apply a lens shading table from an .npy file, or numpy array.

        Args:
            lst_array_or_path: Numpy array, or path to .npy file, describing the lens-shading table
        """
        if isinstance(lst_array_or_path, np.ndarray):
            self.camera.lens_shading_table = lst_array_or_path
        elif (type(lst_array_or_path) == str) and os.path.isfile(lst_array_or_path):
            self.camera.lens_shading_table = np.load(lst_array_or_path)
        else:
            logging.error(
                "Unsupported or missing data for camera lens_shading_table. Must be numpy ndarray, or .npy file path string. Skipping."
            )

    def set_zoom(self, zoom_value: float = 1.0) -> None:
        """
        Change the camera zoom, handling re-centering and scaling.
+0 −4
Original line number Diff line number Diff line
@@ -205,10 +205,6 @@ class Microscope:
        # Read curent config
        current_config = self.read_settings()
        # Save config to file
        if self.camera:
            self.camera.save_settings()
        if self.stage:
            self.stage.save_settings()
        self.settings_file.save(current_config, backup=True)

    @property
+0 −4
Original line number Diff line number Diff line
@@ -23,10 +23,6 @@ class BaseStage(metaclass=ABCMeta):
        """Return the current settings as a dictionary"""
        pass

    def save_settings(self):
        """(Optional) Save any settings to disk that need to be stored"""
        return

    @property
    @abstractmethod
    def state(self):
+22 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import operator
import base64
from uuid import UUID
import numpy as np
import logging
from collections import abc
from functools import reduce
from contextlib import contextmanager
@@ -21,6 +22,27 @@ def serialise_array_b64(npy_arr):
    return b64_string, dtype, shape


def ndarray_to_json(arr: np.ndarray):
    b64_string, dtype, shape = serialise_array_b64(arr)
    return {
        "@type": "ndarray",
        "dtype": dtype,
        "shape": shape,
        "base64": b64_string
    }


def json_to_ndarray(json_dict: dict):
    if not json_dict.get("@type") != "ndarray":
        logging.warning("No valid @type attribute found. Conversion may fail.")
    for required_param in ("dtype", "shape", "base64"):
        if not json_dict.get(required_param):
            raise KeyError(f"Missing required key {required_param}")
    
    return deserialise_array_b64(json_dict.get("base64"), json_dict.get("dtype"), json_dict.get("shape"))



@contextmanager
def set_properties(obj, **kwargs):
    """A context manager to set, then reset, certain properties of an object.