From caf553db7a5de1327f5cc44979e314b93cdd4839 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Tue, 28 Apr 2020 14:32:56 +0100 Subject: [PATCH] Moved capture management into separate object --- openflexure_microscope/api/app.py | 2 + .../api/default_extensions/autostorage.py | 30 +-- .../api/default_extensions/scan.py | 28 +-- .../custom_element/__init__.py | 2 - openflexure_microscope/api/microscope.py | 2 +- .../api/v2/views/actions/camera.py | 20 +- openflexure_microscope/camera/base.py | 170 +-------------- openflexure_microscope/camera/mock.py | 3 +- openflexure_microscope/camera/pi.py | 3 +- openflexure_microscope/captures/__init__.py | 3 + .../{camera => captures}/capture.py | 0 .../captures/capture_manager.py | 193 ++++++++++++++++++ openflexure_microscope/microscope.py | 67 +++++- .../rescue/check_capture_reload.py | 6 +- 14 files changed, 302 insertions(+), 227 deletions(-) create mode 100644 openflexure_microscope/captures/__init__.py rename openflexure_microscope/{camera => captures}/capture.py (100%) create mode 100644 openflexure_microscope/captures/capture_manager.py diff --git a/openflexure_microscope/api/app.py b/openflexure_microscope/api/app.py index e3cce530..795357cc 100644 --- a/openflexure_microscope/api/app.py +++ b/openflexure_microscope/api/app.py @@ -57,6 +57,7 @@ logger.setLevel(logging.INFO) # Log server paths being used logging.info(f"Running with data path {OPENFLEXURE_VAR_PATH}") +print("Creating app") # Create flask app app, labthing = create_app( __name__, @@ -175,5 +176,6 @@ atexit.register(cleanup) if __name__ == "__main__": from labthings.server.wsgi import Server + print("Starting OpenFlexure Microscope Server...") server = Server(app) server.run(host="::", port=5000, debug=False, zeroconf=True) diff --git a/openflexure_microscope/api/default_extensions/autostorage.py b/openflexure_microscope/api/default_extensions/autostorage.py index 345ca73d..a237b41c 100644 --- a/openflexure_microscope/api/default_extensions/autostorage.py +++ b/openflexure_microscope/api/default_extensions/autostorage.py @@ -6,8 +6,8 @@ from labthings.server.find import find_component from openflexure_microscope.paths import settings_file_path, check_rw from openflexure_microscope.config import OpenflexureSettingsFile -from openflexure_microscope.camera.base import BASE_CAPTURE_PATH -from openflexure_microscope.camera.capture import build_captures_from_exif +from openflexure_microscope.captures.capture_manager import BASE_CAPTURE_PATH +from openflexure_microscope.captures.capture import build_captures_from_exif from openflexure_microscope.api.utilities.gui import build_gui @@ -37,17 +37,17 @@ def get_permissive_locations(): ] -def get_current_location(camera): - return camera.paths.get("default") +def get_current_location(capture_manager): + return capture_manager.paths.get("default") -def set_current_location(camera, location: str): +def set_current_location(capture_manager, location: str): if not os.path.isdir(location): os.makedirs(location) logging.debug("Updating location...") - camera.paths.update({"default": location}) + capture_manager.paths.update({"default": location}) logging.debug("Rebuilding captures...") - camera.rebuild_captures() + capture_manager.rebuild_captures() logging.debug("Capture location changed successfully.") @@ -93,7 +93,7 @@ class AutostorageExtension(BaseExtension): ) # We'll store a reference to a camera object, who's capture paths will be modified - self.camera = None + self.capture_manager = None self.initial_location = get_default_location() @@ -107,9 +107,9 @@ class AutostorageExtension(BaseExtension): logging.debug(f"Autostorage extension bound to camera {self.camera}") # Store a reference to the camera - self.camera = microscope_obj.camera + self.capture_manager = microscope_obj.captures # Store the initial storage location - self.initial_location = get_current_location(self.camera) + self.initial_location = get_current_location(self.capture_manager) # If preferred path does not exist, or cannot be written to self.check_location(self.initial_location) @@ -118,20 +118,20 @@ class AutostorageExtension(BaseExtension): def check_location(self, location=None): if not location: - location = get_current_location(self.camera) + location = get_current_location(self.capture_manager) # If preferred path does not exist, or cannot be written to if not (os.path.isdir(location) and check_rw(location)): logging.error( f"Preferred capture path {location} is missing or cannot be written to. Restoring defaults." ) # Reset the storage location to default - set_current_location(self.camera, get_default_location()) + set_current_location(self.capture_manager, get_default_location()) def get_locations(self): if self.camera: locations = get_all_locations() - current_location = get_current_location(self.camera) + current_location = get_current_location(self.capture_manager) if current_location not in locations.values(): locations.update({"Custom": current_location}) # Add location from the cameras settings file @@ -140,7 +140,7 @@ class AutostorageExtension(BaseExtension): return {} def get_preferred_key(self): - current = get_current_location(self.camera) + current = get_current_location(self.capture_manager) locations = self.get_locations() matches = [k for k, v in locations.items() if v == current] @@ -157,7 +157,7 @@ class AutostorageExtension(BaseExtension): raise KeyError(f"No location named {new_path_key}") location = self.get_locations().get(new_path_key) - set_current_location(self.camera, location) + set_current_location(self.capture_manager, location) def key_to_title(self, path_key: str): if not path_key in self.get_locations().keys(): diff --git a/openflexure_microscope/api/default_extensions/scan.py b/openflexure_microscope/api/default_extensions/scan.py index 30a0baa1..5ba0edcf 100644 --- a/openflexure_microscope/api/default_extensions/scan.py +++ b/openflexure_microscope/api/default_extensions/scan.py @@ -85,27 +85,17 @@ def capture( filename = "{}_{}_{}_{}".format(basename, *microscope.stage.position) folder = "SCAN_{}".format(basename) - # Create output object - output = microscope.camera.new_image( - temporary=temporary, filename=filename, folder=folder + # Do capture + return microscope.capture( + filename=filename, + folder=folder, + temporary=temporary, + use_video_port=use_video_port, resize=resize, bayer=bayer, + annotations=annotations, + tags=tags, + metadata=metadata ) - # Capture - microscope.camera.capture( - output.file, use_video_port=use_video_port, resize=resize, bayer=bayer - ) - - # Inject system metadata - output.put_metadata({"instrument": microscope.metadata}) - - # Insert custom metadata - output.put_metadata(metadata) - - # Insert custom metadata - output.put_annotations(annotations) - # Insert custom tags - output.put_tags(tags) - ### Scanning diff --git a/openflexure_microscope/api/example_extensions/custom_element/__init__.py b/openflexure_microscope/api/example_extensions/custom_element/__init__.py index d8fa14cb..5669464c 100644 --- a/openflexure_microscope/api/example_extensions/custom_element/__init__.py +++ b/openflexure_microscope/api/example_extensions/custom_element/__init__.py @@ -7,8 +7,6 @@ from labthings.core.utilities import path_relative_to from openflexure_microscope.paths import settings_file_path, check_rw from openflexure_microscope.config import OpenflexureSettingsFile -from openflexure_microscope.camera.base import BASE_CAPTURE_PATH -from openflexure_microscope.camera.capture import build_captures_from_exif from openflexure_microscope.api.utilities.gui import build_gui diff --git a/openflexure_microscope/api/microscope.py b/openflexure_microscope/api/microscope.py index d9496684..87773bd4 100644 --- a/openflexure_microscope/api/microscope.py +++ b/openflexure_microscope/api/microscope.py @@ -7,6 +7,6 @@ default_microscope = Microscope() # Restore loaded capture array to camera object logging.debug("Restoring captures...") -default_microscope.camera.rebuild_captures() +default_microscope.captures.rebuild_captures() logging.debug("Microscope successfully attached!") diff --git a/openflexure_microscope/api/v2/views/actions/camera.py b/openflexure_microscope/api/v2/views/actions/camera.py index c9d42e49..9e8c6d8a 100644 --- a/openflexure_microscope/api/v2/views/actions/camera.py +++ b/openflexure_microscope/api/v2/views/actions/camera.py @@ -63,26 +63,16 @@ class CaptureAPI(View): # Explicitally acquire lock (prevents empty files being created if lock is unavailable) with microscope.camera.lock: - output = microscope.camera.new_image( - temporary=args.get("temporary"), filename=args.get("filename") - ) - - microscope.camera.capture( - output.file, + return microscope.capture( + filename=args.get("filename"), + temporary=args.get("temporary"), use_video_port=args.get("use_video_port"), resize=resize, bayer=args.get("bayer"), + annotations=args.get("annotations"), + tags=args.get("tags") ) - # Inject system metadata - output.put_metadata({"instrument": microscope.metadata}) - - # Insert custom metadata - output.put_annotations(args.get("annotations")) - # Insert custom tags - output.put_tags(args.get("tags")) - - return output @ThingAction diff --git a/openflexure_microscope/camera/base.py b/openflexure_microscope/camera/base.py index 821b133d..8ba6ea2b 100644 --- a/openflexure_microscope/camera/base.py +++ b/openflexure_microscope/camera/base.py @@ -10,43 +10,11 @@ import threading import gevent from abc import ABCMeta, abstractmethod -from collections import OrderedDict -from .capture import CaptureObject, build_captures_from_exif -from openflexure_microscope.utilities import entry_by_uuid + from labthings.core.lock import StrictLock from labthings.core.event import ClientEvent -from openflexure_microscope.paths import data_file_path - -BASE_CAPTURE_PATH = data_file_path("micrographs") -TEMP_CAPTURE_PATH = os.path.join(BASE_CAPTURE_PATH, "tmp") - - -def last_entry(object_list: list): - """Return the last entry of a list, if the list contains items.""" - if object_list: # If any images have been captured - return object_list[-1] # Return the latest captured image - else: - return None - - -def generate_basename(): - """Return a default filename based on the capture datetime""" - return datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") - - -def generate_numbered_basename(obj_list: list) -> str: - initial_basename = generate_basename() - basename = initial_basename - # Handle clashing - iterator = 1 - while basename in [obj.basename for obj in obj_list]: - basename = initial_basename + "_{}".format(iterator) - iterator += 1 - - return basename - class BaseCamera(metaclass=ABCMeta): """ @@ -70,12 +38,6 @@ class BaseCamera(metaclass=ABCMeta): self.stream_active = False self.record_active = False - self.paths = {"default": BASE_CAPTURE_PATH, "temp": TEMP_CAPTURE_PATH} - - # Capture data - self.images = OrderedDict() - self.videos = OrderedDict() - @property @abstractmethod def configuration(self): @@ -104,7 +66,7 @@ class BaseCamera(metaclass=ABCMeta): @abstractmethod def read_settings(self) -> dict: """Return the current settings as a dictionary""" - return {"paths": self.paths} + return {} def __enter__(self): """Create camera on context enter.""" @@ -127,134 +89,6 @@ class BaseCamera(metaclass=ABCMeta): self.stop_worker() logging.info("Closed {}".format(self)) - def clear_tmp(self): - """ - Removes all files in the temporary capture directories - """ - - if os.path.isdir(self.paths["temp"]): - logging.info("Clearing {}...".format(self.paths["temp"])) - shutil.rmtree(self.paths["temp"]) - logging.debug("Cleared {}.".format(self.paths["temp"])) - - def rebuild_captures(self): - self.images = build_captures_from_exif(self.paths["default"]) - - # RETURNING CAPTURES - - @property - def image(self): - """Return the latest captured image.""" - return last_entry(self.images.values()) - - @property - def video(self): - """Return the latest recorded video.""" - return last_entry(self.videos.values()) - - def image_from_id(self, image_id): - """Return an image StreamObject with a matching ID.""" - logging.warning("image_from_id is deprecated. Access captures as a dictionary.") - return entry_by_uuid(image_id, self.images.values()) - - def video_from_id(self, video_id): - """Return a video StreamObject with a matching ID.""" - logging.warning("video_from_id is deprecated. Access captures as a dictionary.") - return entry_by_uuid(video_id, self.videos.values()) - - # CREATING NEW CAPTURES - - def new_image( - self, - temporary: bool = True, - filename: str = None, - folder: str = "", - fmt: str = "jpeg", - ): - - """ - Create a new image capture object. - - Args: - temporary (bool): Should the data be deleted after session ends. - Creating the capture with a content manager sets this to true. - filename (str): Name of the stored file. Defaults to timestamp. - folder (str): Name of the folder in which to store the capture. - fmt (str): Format of the capture. - """ - - # Generate file name - if not filename: - filename = generate_numbered_basename(self.images.values()) - logging.debug(filename) - filename = "{}.{}".format(filename, fmt) - - # Generate folder - base_folder = self.paths["temp"] if temporary else self.paths["default"] - folder = os.path.join(base_folder, folder) - - # Generate file path - filepath = os.path.join(folder, filename) - - # Create capture object - output = CaptureObject(filepath=filepath) - # Insert a temporary tag if temporary - if temporary: - output.put_tags(["temporary"]) - - # Update capture list - capture_key = str(output.id) - logging.debug(f"Adding image {output} with key {capture_key}") - self.images[capture_key] = output - - return output - - def new_video( - self, - temporary: bool = False, - filename: str = None, - folder: str = "", - fmt: str = "h264", - ): - - """ - Create a new video capture object. - - Args: - temporary (bool): Should the data be deleted after session ends. - Creating the capture with a content manager sets this to true. - filename (str): Name of the stored file. Defaults to timestamp. - folder (str): Name of the folder in which to store the capture. - fmt (str): Format of the capture. - """ - # TODO: Remove the redundancy here - - # Generate file name - if not filename: - filename = generate_numbered_basename(self.videos.values()) - logging.debug(filename) - filename = "{}.{}".format(filename, fmt) - - # Generate folder - base_folder = self.paths["temp"] if temporary else self.paths["default"] - folder = os.path.join(base_folder, folder) - - # Generate file path - filepath = os.path.join(folder, filename) - - # Create capture object - output = CaptureObject(filepath=filepath) - # Insert a temporary tag if temporary - if temporary: - output.put_tags(["temporary"]) - - # Update capture list - capture_key = str(output.id) - logging.debug(f"Adding video {output} with key {capture_key}") - self.videos[capture_key] = output - - return output - # START AND STOP WORKER THREAD def start_worker(self, timeout: int = 5) -> bool: diff --git a/openflexure_microscope/camera/mock.py b/openflexure_microscope/camera/mock.py index 65e65a32..9dc727c4 100644 --- a/openflexure_microscope/camera/mock.py +++ b/openflexure_microscope/camera/mock.py @@ -17,7 +17,8 @@ import logging # Type hinting from typing import Tuple -from openflexure_microscope.camera.base import BaseCamera, CaptureObject +from openflexure_microscope.camera.base import BaseCamera +from openflexure_microscope.captures import CaptureObject """ diff --git a/openflexure_microscope/camera/pi.py b/openflexure_microscope/camera/pi.py index 29ab938b..a73ea5d1 100644 --- a/openflexure_microscope/camera/pi.py +++ b/openflexure_microscope/camera/pi.py @@ -41,7 +41,8 @@ import picamera.array # Type hinting from typing import Tuple -from .base import BaseCamera, CaptureObject +from openflexure_microscope.camera.base import BaseCamera +from openflexure_microscope.captures import CaptureObject # Richard's fix gain from .set_picamera_gain import set_analog_gain, set_digital_gain diff --git a/openflexure_microscope/captures/__init__.py b/openflexure_microscope/captures/__init__.py new file mode 100644 index 00000000..16cab515 --- /dev/null +++ b/openflexure_microscope/captures/__init__.py @@ -0,0 +1,3 @@ +from .capture_manager import CaptureManager +from .capture import CaptureObject +from . import capture_manager, capture \ No newline at end of file diff --git a/openflexure_microscope/camera/capture.py b/openflexure_microscope/captures/capture.py similarity index 100% rename from openflexure_microscope/camera/capture.py rename to openflexure_microscope/captures/capture.py diff --git a/openflexure_microscope/captures/capture_manager.py b/openflexure_microscope/captures/capture_manager.py new file mode 100644 index 00000000..0ccefc89 --- /dev/null +++ b/openflexure_microscope/captures/capture_manager.py @@ -0,0 +1,193 @@ +import os +import datetime +import shutil +import logging +from collections import OrderedDict + +from labthings.core.lock import StrictLock + +from openflexure_microscope.utilities import entry_by_uuid +from openflexure_microscope.paths import data_file_path + +from .capture import CaptureObject, build_captures_from_exif + +BASE_CAPTURE_PATH = data_file_path("micrographs") +TEMP_CAPTURE_PATH = os.path.join(BASE_CAPTURE_PATH, "tmp") + + +def last_entry(object_list: list): + """Return the last entry of a list, if the list contains items.""" + if object_list: # If any images have been captured + return object_list[-1] # Return the latest captured image + else: + return None + + +def generate_basename(): + """Return a default filename based on the capture datetime""" + return datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + + +def generate_numbered_basename(obj_list: list) -> str: + initial_basename = generate_basename() + basename = initial_basename + # Handle clashing + iterator = 1 + while basename in [obj.basename for obj in obj_list]: + basename = initial_basename + "_{}".format(iterator) + iterator += 1 + + return basename + + +class CaptureManager: + def __init__(self): + self.paths = {"default": BASE_CAPTURE_PATH, "temp": TEMP_CAPTURE_PATH} + + self.lock = StrictLock(timeout=1, name="Captures") + + # Capture data + self.images = OrderedDict() + self.videos = OrderedDict() + + # FILE MANAGEMENT + + def clear_tmp(self): + """ + Removes all files in the temporary capture directories + """ + + if os.path.isdir(self.paths["temp"]): + logging.info("Clearing {}...".format(self.paths["temp"])) + shutil.rmtree(self.paths["temp"]) + logging.debug("Cleared {}.".format(self.paths["temp"])) + + def rebuild_captures(self): + self.images = build_captures_from_exif(self.paths["default"]) + + def update_settings(self, config: dict): + """Update settings from a config dictionary""" + with self.lock: + # Apply valid config params to camera object + for key, value in config.items(): # For each provided setting + if hasattr(self, key): # If the instance has a matching property + setattr(self, key, value) # Set to the target value + + def read_settings(self) -> dict: + """Return the current settings as a dictionary""" + return {"paths": self.paths} + + # RETURNING CAPTURES + + @property + def image(self): + """Return the latest captured image.""" + return last_entry(self.images.values()) + + @property + def video(self): + """Return the latest recorded video.""" + return last_entry(self.videos.values()) + + def image_from_id(self, image_id): + """Return an image StreamObject with a matching ID.""" + logging.warning("image_from_id is deprecated. Access captures as a dictionary.") + return entry_by_uuid(image_id, self.images.values()) + + def video_from_id(self, video_id): + """Return a video StreamObject with a matching ID.""" + logging.warning("video_from_id is deprecated. Access captures as a dictionary.") + return entry_by_uuid(video_id, self.videos.values()) + + # CREATING NEW CAPTURES + + def new_image( + self, + temporary: bool = True, + filename: str = None, + folder: str = "", + fmt: str = "jpeg", + ): + + """ + Create a new image capture object. + + Args: + temporary (bool): Should the data be deleted after session ends. + Creating the capture with a content manager sets this to true. + filename (str): Name of the stored file. Defaults to timestamp. + folder (str): Name of the folder in which to store the capture. + fmt (str): Format of the capture. + """ + + # Generate file name + if not filename: + filename = generate_numbered_basename(self.images.values()) + logging.debug(filename) + filename = "{}.{}".format(filename, fmt) + + # Generate folder + base_folder = self.paths["temp"] if temporary else self.paths["default"] + folder = os.path.join(base_folder, folder) + + # Generate file path + filepath = os.path.join(folder, filename) + + # Create capture object + output = CaptureObject(filepath=filepath) + # Insert a temporary tag if temporary + if temporary: + output.put_tags(["temporary"]) + + # Update capture list + capture_key = str(output.id) + logging.debug(f"Adding image {output} with key {capture_key}") + self.images[capture_key] = output + + return output + + def new_video( + self, + temporary: bool = False, + filename: str = None, + folder: str = "", + fmt: str = "h264", + ): + + """ + Create a new video capture object. + + Args: + temporary (bool): Should the data be deleted after session ends. + Creating the capture with a content manager sets this to true. + filename (str): Name of the stored file. Defaults to timestamp. + folder (str): Name of the folder in which to store the capture. + fmt (str): Format of the capture. + """ + # TODO: Remove the redundancy here + + # Generate file name + if not filename: + filename = generate_numbered_basename(self.videos.values()) + logging.debug(filename) + filename = "{}.{}".format(filename, fmt) + + # Generate folder + base_folder = self.paths["temp"] if temporary else self.paths["default"] + folder = os.path.join(base_folder, folder) + + # Generate file path + filepath = os.path.join(folder, filename) + + # Create capture object + output = CaptureObject(filepath=filepath) + # Insert a temporary tag if temporary + if temporary: + output.put_tags(["temporary"]) + + # Update capture list + capture_key = str(output.id) + logging.debug(f"Adding video {output} with key {capture_key}") + self.videos[capture_key] = output + + return output diff --git a/openflexure_microscope/microscope.py b/openflexure_microscope/microscope.py index d8db1def..f7e06d14 100644 --- a/openflexure_microscope/microscope.py +++ b/openflexure_microscope/microscope.py @@ -5,6 +5,9 @@ Defines a microscope object, binding a camera and stage with basic functionality import logging import pkg_resources import uuid +from typing import Tuple + +from openflexure_microscope.captures import CaptureManager from openflexure_microscope.stage.mock import MissingStage from openflexure_microscope.camera.mock import MissingCamera @@ -33,6 +36,8 @@ class Microscope: self.id = uuid.uuid4() self.name = self.id + self.captures = CaptureManager() + self.fov = [0, 0] #: Microscope field-of-view in stage motor steps # Store settings and configuration files @@ -47,6 +52,7 @@ class Microscope: self.camera = None #: Currently connected camera object self.stage = None #: Currently connected stage object + self.setup(self.configuration_file.load()) # Attach components # Apply settings loaded from file @@ -75,6 +81,7 @@ class Microscope: """ ### Detector + print("Creating camera") if configuration.get("camera"): camera_type = configuration["camera"].get("type") if camera_type in ("PiCamera", "PiCameraStreamer"): @@ -85,6 +92,7 @@ class Microscope: logging.warning("No compatible camera hardware found.") ### Stage + print("Creating stage") if configuration.get("stage"): stage_type = configuration["stage"].get("type") stage_port = configuration["stage"].get("port") @@ -95,6 +103,7 @@ class Microscope: logging.error(e) logging.warning("No compatible Sangaboard hardware found.") + print("Handling fallbacks") ### Fallbacks if not self.camera: self.camera = MissingCamera() @@ -102,6 +111,7 @@ class Microscope: self.stage = MissingStage() ### Locks + print("Creating locks") if hasattr(self.camera, "lock"): self.lock.locks.append(self.camera.lock) if hasattr(self.stage, "lock"): @@ -144,11 +154,14 @@ class Microscope: # If attached to a camera if ("camera" in settings) and self.camera: - self.camera.update_settings(settings["camera"]) + self.camera.update_settings(settings.get("camera", {})) # If attached to a stage if ("stage" in settings) and self.stage: - self.stage.update_settings(settings["stage"]) + self.stage.update_settings(settings.get("stage", {})) + + # Capture manager + self.captures.update_settings(settings.get("captures", {})) # Microscope settings if "id" in settings: @@ -207,6 +220,10 @@ class Microscope: settings_current_stage = self.stage.read_settings() settings_current["stage"] = settings_current_stage + # Capture manager + settings_current_captures = self.captures.read_settings() + settings_current["captures"] = settings_current_captures + settings_full = self.settings_file.merge(settings_current) if full: @@ -260,3 +277,49 @@ class Microscope: } return system_metadata + + def capture( + self, + filename: str = None, + folder: str = "", + temporary: bool = False, + use_video_port: bool = False, + resize: Tuple[int, int] = None, + bayer: bool = True, + fmt: str = "jpeg", + annotations: dict = None, + tags: list = None, + metadata: dict = None + ): + if not annotations: + annotations = {} + if not metadata: + metadata = {} + if not tags: + tags = [] + + with self.camera.lock: + # Create output object + output = self.captures.new_image( + temporary=temporary, filename=filename, folder=folder, fmt=fmt + ) + + # Capture to output object + self.camera.capture( + output.file, + use_video_port=use_video_port, + resize=resize, + bayer=bayer, + fmt=fmt + ) + + # Inject system metadata + output.put_metadata({"instrument": self.metadata}) + # Insert custom metadata + output.put_metadata(metadata) + # Insert custom metadata + output.put_annotations(annotations) + # Insert custom tags + output.put_tags(tags) + + return output \ No newline at end of file diff --git a/openflexure_microscope/rescue/check_capture_reload.py b/openflexure_microscope/rescue/check_capture_reload.py index 3a61c692..c79d76d6 100644 --- a/openflexure_microscope/rescue/check_capture_reload.py +++ b/openflexure_microscope/rescue/check_capture_reload.py @@ -1,6 +1,6 @@ from openflexure_microscope.rescue.monitor_timeout import launch_timeout_test_process -from openflexure_microscope.camera.capture import build_captures_from_exif -from openflexure_microscope.camera.base import BASE_CAPTURE_PATH +from openflexure_microscope.captures.capture_manager import BASE_CAPTURE_PATH +from openflexure_microscope.captures.capture import build_captures_from_exif from openflexure_microscope.config import user_settings import logging @@ -10,7 +10,7 @@ def check_capture_rebuild(timeout=10): logging.info("Loading user settings...") settings = user_settings.load() - cap_path = str(settings.get("camera", {}).get("paths", {}).get("default")) + cap_path = str(settings.get("captures", {}).get("paths", {}).get("default")) logging.info(f"Capture path found: {cap_path}") if not cap_path: logging.error(