Converted all configs to JSON
This commit is contained in:
parent
94a8774ceb
commit
b81cfaf9e7
13 changed files with 175 additions and 218 deletions
|
|
@ -143,6 +143,10 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
"""Return the current settings as a dictionary"""
|
||||
return {"paths": self.paths}
|
||||
|
||||
def save_config(self):
|
||||
"""(Optional) Save any settings to disk that need to be stored"""
|
||||
return
|
||||
|
||||
def __enter__(self):
|
||||
"""Create camera on context enter."""
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ import shutil
|
|||
import glob
|
||||
import datetime
|
||||
import yaml
|
||||
import json
|
||||
import logging
|
||||
from PIL import Image
|
||||
import atexit
|
||||
|
||||
from openflexure_microscope.camera import piexif
|
||||
from openflexure_microscope.camera.piexif._exceptions import InvalidImageDataError
|
||||
|
||||
from openflexure_microscope.config import JSONEncoder
|
||||
|
||||
PIL_FORMATS = ["JPG", "JPEG", "PNG", "TIF", "TIFF"]
|
||||
EXIF_FORMATS = ["JPG", "JPEG", "TIF", "TIFF"]
|
||||
|
|
@ -30,7 +31,12 @@ def pull_usercomment_dict(filepath):
|
|||
logging.warning("Invalid data at {}. Skipping.".format(filepath))
|
||||
return None
|
||||
if "Exif" in exif_dict and 37510 in exif_dict["Exif"]:
|
||||
return yaml.load(exif_dict["Exif"][37510].decode())
|
||||
try:
|
||||
return json.loads(exif_dict["Exif"][37510].decode())
|
||||
except json.decoder.JSONDecodeError:
|
||||
# TODO: Remove YAML support in a later version
|
||||
logging.warning(f"Capture {filepath} has metadata stored in YAML format. This is now deprecated in favour of JSON.")
|
||||
return yaml.load(exif_dict["Exif"][37510].decode())
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
@ -210,7 +216,7 @@ class CaptureObject(object):
|
|||
# Extract current Exif data
|
||||
exif_dict = piexif.load(self.file)
|
||||
# Serialize metadata
|
||||
metadata_string = yaml.safe_dump(self.metadata)
|
||||
metadata_string = json.dumps(self.metadata, cls=JSONEncoder)
|
||||
# Insert metadata into exif_dict
|
||||
exif_dict["Exif"][piexif.ExifIFD.UserComment] = metadata_string.encode()
|
||||
# Convert new exif dict to exif bytes
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from __future__ import division
|
|||
import io
|
||||
import time
|
||||
import numpy as np
|
||||
import os
|
||||
import logging
|
||||
|
||||
# Pi camera
|
||||
|
|
@ -40,6 +41,7 @@ from .base import BaseCamera, CaptureObject
|
|||
# Richard's fix gain
|
||||
from .set_picamera_gain import set_analog_gain, set_digital_gain
|
||||
|
||||
from openflexure_microscope.config import settings_file_path
|
||||
|
||||
# MAIN CLASS
|
||||
class PiCameraStreamer(BaseCamera):
|
||||
|
|
@ -54,10 +56,20 @@ class PiCameraStreamer(BaseCamera):
|
|||
"awb_mode",
|
||||
"framerate",
|
||||
"saturation",
|
||||
"lens_shading_table",
|
||||
"iso",
|
||||
"brightness",
|
||||
"contrast",
|
||||
"crop",
|
||||
"drc_strength",
|
||||
"exposure_compensation",
|
||||
"image_effect",
|
||||
"meter_mode",
|
||||
"sharpness"
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
global USER_CONFIG_DIR
|
||||
|
||||
# Run BaseCamera init
|
||||
BaseCamera.__init__(self)
|
||||
# Attach to Pi camera
|
||||
|
|
@ -78,11 +90,13 @@ class PiCameraStreamer(BaseCamera):
|
|||
# Reset variable states
|
||||
self.set_zoom(1.0)
|
||||
|
||||
# Update config properties
|
||||
self.image_resolution = tuple(self.camera.MAX_RESOLUTION)
|
||||
self.stream_resolution = (832, 624)
|
||||
self.numpy_resolution = (1312, 976)
|
||||
self.jpeg_quality = 75
|
||||
# Set default settings
|
||||
self.image_resolution = tuple(self.camera.MAX_RESOLUTION) #: tuple: Resolution for image captures
|
||||
self.stream_resolution = (832, 624) #: tuple: Resolution for stream and video captures
|
||||
self.numpy_resolution = (1312, 976) #: tuple: Resolution for numpy array captures
|
||||
self.jpeg_quality = 75 #: int: JPEG quality
|
||||
# Set default lens shading table path
|
||||
self.picamera_lst_path = settings_file_path("picamera_lst.npy") #: str: Path of .npy lens shading table file
|
||||
|
||||
# Update board identifier
|
||||
self.state.update({})
|
||||
|
|
@ -121,12 +135,12 @@ 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 os.path.isfile(self.picamera_lst_path) else None,
|
||||
"picamera_settings": {},
|
||||
}
|
||||
)
|
||||
|
||||
# Include a subset of picamera properties
|
||||
# TODO: Expand this subset so we have more metadata?
|
||||
# Include a subset of picamera properties. Excludes lens shading table
|
||||
for key in PiCameraStreamer.picamera_settings_keys:
|
||||
try:
|
||||
value = getattr(self.camera, key)
|
||||
|
|
@ -137,6 +151,11 @@ class PiCameraStreamer(BaseCamera):
|
|||
|
||||
return conf_dict
|
||||
|
||||
def save_config(self):
|
||||
"""Save lens-shading table to disk"""
|
||||
logging.info("Saving picamera_lst to {}".format(self.picamera_lst_path))
|
||||
self.save_lens_shading_table()
|
||||
|
||||
def apply_config(self, config: dict):
|
||||
"""
|
||||
Write a config dictionary to the PiCameraStreamer config.
|
||||
|
|
@ -174,6 +193,17 @@ class PiCameraStreamer(BaseCamera):
|
|||
if (key != "picamera_settings") 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.")
|
||||
|
|
@ -232,21 +262,40 @@ class PiCameraStreamer(BaseCamera):
|
|||
logging.debug("Applying {}: {}".format(key, settings_dict[key]))
|
||||
setattr(self.camera, key, settings_dict[key])
|
||||
|
||||
# Handle lens shading if camera supports it
|
||||
if ("lens_shading_table" in settings_dict) and hasattr(
|
||||
self.camera, "lens_shading_table"
|
||||
):
|
||||
logging.debug(
|
||||
"Applying lens_shading_table: {}".format(
|
||||
settings_dict["lens_shading_table"]
|
||||
)
|
||||
)
|
||||
self.camera.lens_shading_table = settings_dict["lens_shading_table"]
|
||||
|
||||
# Final optional pause to settle
|
||||
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.
|
||||
"""
|
||||
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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue