Ruff formatting and removing all capturing from smart_scan

This commit is contained in:
jaknapper 2025-04-16 11:17:55 +01:00
parent 1f3211e3ee
commit 0b7a817674
2 changed files with 4 additions and 133 deletions

View file

@ -11,7 +11,6 @@ from PIL import Image
from pydantic import BaseModel
from datetime import datetime
from subprocess import CompletedProcess, Popen, PIPE, SubprocessError, STDOUT
from threading import Event
import glob
import json
import piexif
@ -590,9 +589,8 @@ class SmartScanThing(Thing):
current_pos_xyz, imaged=True, focused=focused
)
# wait for the previous capture to be saved, i.e. don't leave more than one image saving in the background
# if self._capture_thread:
# self._wait_for_capture_thread()
self._z_stack.smart_stack(images_dir = self._ongoing_scan_images_dir)
# increment capure counter as thread has completed
self._scan_images_taken += 1
# Add it to the incremental zip
@ -602,14 +600,6 @@ class SmartScanThing(Thing):
download_zip=False,
)
name = f"image_{new_pos_xyz[0]}_{new_pos_xyz[1]}.jpg"
# jpeg_path = os.path.join(self._ongoing_scan_images_dir, name)
self._z_stack.smart_stack(images_dir = self._ongoing_scan_images_dir)
# self._capture_thread = self._start_capture_thread(jpeg_path)
# wait until the image is acquired
# acquired.wait()
@_scan_running
def _try_autofocus(
self,
@ -646,52 +636,6 @@ class SmartScanThing(Thing):
self._scan_logger.warning("Could not autofocus after 3 attempts.")
return False, self._stage.position["z"]
@_scan_running
def _wait_for_capture_thread(self) -> None:
"""
Wait for the capture thread to be complete.
"""
wait_start = time.time()
thread_was_alive = self._capture_thread.is_alive()
# If the capture thread has thrown an exception it will be raised
# when join is called, this will cause the scan to end. If we want
# to retry captures at a later date this is where we will need to
# catch the IOError or CaptureError from the thread.
self._capture_thread.join()
time.sleep(0.2)
if thread_was_alive:
wait_time = time.time() - wait_start
self._scan_logger.info(
f"Waited {wait_time:.1f}s for the previous capture to finish saving."
)
# @_scan_running
# def _start_capture_thread(
# self, jpeg_path: str
# ) -> tuple[ErrorCapturingThread, Event]:
# """
# Start the capture thread.
# Args:
# jpeg_path, the path to save the image once aquired
# Return the thread and an event that will be set when the image is aquired
# """
# time.sleep(0.2)
# # Acquire the image in a thread, and continue once it's acquired
# # (i.e. leave saving in the background) Use ErrorCapturingThread
# # intead of Thread. This will raise errors in the calling thread
# # only when join() is called, allowing us to handle this appropriately.
# capture_thread = ErrorCapturingThread(
# # target=self._capture_and_save,
# target=self._z_stack.smart_stack(),
# kwargs={"images_dir": self._ongoing_scan_images_dir},
# )
# capture_thread.start()
# return capture_thread
@_scan_running
def _return_to_starting_position(self):
self._scan_logger.info("Returning to starting position.")
@ -750,74 +694,6 @@ class SmartScanThing(Thing):
raise HTTPException(404, "File not found")
return FileResponse(path)
@_scan_running
def _capture_and_save(
self,
acquired: Event,
jpeg_path: str,
) -> None:
"""Capture an image and save it to disk
This will set the event `acquired` once the image has been acquired, so
that the stage may be moved while it's saved.
"""
try:
capture_start = time.time()
image, metadata = self._capture_image()
finally:
# Ensure aquired is set even if capture fails or program will hang forever.
acquired.set()
acquisition_time = time.time()
self._save_capture(jpeg_path, image, metadata)
save_time = time.time()
acquisition_duration = round(acquisition_time - capture_start, 1)
saving_duration = round(save_time - acquisition_time, 1)
self._scan_logger.debug(
f"Acquired {jpeg_path} in {acquisition_duration}s then {saving_duration}s saving to disk"
)
@_scan_running
def _capture_image(self) -> tuple[np.ndarray, dict]:
"""Capture an image in memory and return it with metadata
This will set the event `acquired` once the image has been acquired, so
that the stage may be moved while it's saved.
CaptureError raised if the capture fails for any reason
returns tuple with numpy array of image data, and dict of metadata
"""
try:
metadata = self._metadata_getter()
image = self._cam.capture_array()[..., :3]
except Exception as e:
raise CaptureError("An error occurred while capturing") from e
return image, metadata
@_scan_running
def _save_capture(
self,
jpeg_path: str,
image: np.ndarray,
metadata: dict,
) -> None:
"""Saving the captured image and metadata to disk
logger warning (via InvocationLogger) is raised if metadata is failed to be added
IOError is raised if the file cannot be saved
nothing is returned on success"""
try:
Image.fromarray(image.astype("uint8"), "RGB").save(
jpeg_path, quality=95, subsampling=0
)
try:
exif_dict = piexif.load(jpeg_path)
exif_dict["Exif"][piexif.ExifIFD.UserComment] = json.dumps(
metadata
).encode("utf-8")
piexif.insert(piexif.dump(exif_dict), jpeg_path)
except: # noqa: E722
# We need to capture any exception as there are many reasons metadata
# might not be added. We warn rather than log the error.
self._scan_logger.warning(f"Failed to add metadata to {jpeg_path}")
except Exception as e:
raise IOError(f"An error occurred while saving {jpeg_path}") from e
@thing_property
def max_range(self) -> int:

View file

@ -1,10 +1,6 @@
import os
from typing import Mapping, Optional
import cv2
import numpy as np
from PIL import Image
from pydantic import BaseModel
from scipy.stats import norm
import time
import piexif
import json
@ -15,9 +11,7 @@ from labthings_fastapi.decorators import thing_action, thing_property
from .camera import CameraDependency as CamDep
from .stage import StageDependency as StageDep
from labthings_fastapi.dependencies.invocation import (
CancelHook,
InvocationLogger,
InvocationCancelledError,
)
@ -87,7 +81,7 @@ class ZStackThing(Thing):
capture_start = time.time()
image, metadata = self._capture_image(cam, metadata_getter,)
acquisition_time = time.time()
self._save_capture(jpeg_path, image, metadata)
self._save_capture(jpeg_path, image, metadata, logger)
save_time = time.time()
acquisition_duration = round(acquisition_time - capture_start, 1)
saving_duration = round(save_time - acquisition_time, 1)
@ -114,6 +108,7 @@ class ZStackThing(Thing):
jpeg_path: str,
image: np.ndarray,
metadata: dict,
logger: InvocationLogger,
) -> None:
"""Saving the captured image and metadata to disk
logger warning (via InvocationLogger) is raised if metadata is failed to be added