Create a stack folder and copy the middle image to image_dir

This commit is contained in:
jaknapper 2025-04-16 18:14:24 +01:00 committed by Julian Stirling
parent a1784941fe
commit 46458ca8a1

View file

@ -4,6 +4,8 @@ from PIL import Image
import time import time
import piexif import piexif
import json import json
import shutil
import glob
from labthings_fastapi.dependencies.metadata import GetThingStates from labthings_fastapi.dependencies.metadata import GetThingStates
from labthings_fastapi.thing import Thing from labthings_fastapi.thing import Thing
@ -18,12 +20,13 @@ from labthings_fastapi.dependencies.invocation import (
class CaptureError(RuntimeError): class CaptureError(RuntimeError):
"""An error trying to capture from Picamera""" """An error trying to capture from Picamera"""
class ZStackThing(Thing): class ZStackThing(Thing):
@thing_property @thing_property
def images_to_capture(self) -> int: def images_to_capture(self) -> int:
"""The number of images to capture and save in a stack """The number of images to capture and save in a stack
Defaults to 1 unless you need to see either side of focus""" Defaults to 1 unless you need to see either side of focus"""
return self.thing_settings.get("stack_height", 9) return self.thing_settings.get("images_to_capture", 1)
@images_to_capture.setter @images_to_capture.setter
def images_to_capture(self, value: int) -> None: def images_to_capture(self, value: int) -> None:
@ -46,9 +49,10 @@ class ZStackThing(Thing):
self, self,
cam: CamDep, cam: CamDep,
stage: StageDep, stage: StageDep,
images_dir: str,
logger: InvocationLogger, logger: InvocationLogger,
metadata_getter: GetThingStates, metadata_getter: GetThingStates,
images_dir: str,
stack_dir: str,
) -> None: ) -> None:
stack_dz = self.stack_dz stack_dz = self.stack_dz
images_to_capture = self.images_to_capture images_to_capture = self.images_to_capture
@ -58,13 +62,19 @@ class ZStackThing(Thing):
for capture_count in range(images_to_capture): for capture_count in range(images_to_capture):
jpeg_path = os.path.join( jpeg_path = os.path.join(
images_dir, stack_dir,
f"{capture_count}.jpeg", f"{capture_count}.jpeg",
) )
self._capture_and_save( self._capture_and_save(
jpeg_path, cam, logger, metadata_getter, jpeg_path=jpeg_path,
cam=cam,
logger=logger,
metadata_getter=metadata_getter,
) )
stage.move_relative(z=stack_dz) stage.move_relative(z=stack_dz)
time.sleep(0.3)
self.copy_central_image(images_dir, stack_dir, logger)
def _capture_and_save( def _capture_and_save(
self, self,
@ -79,7 +89,10 @@ class ZStackThing(Thing):
that the stage may be moved while it's saved. that the stage may be moved while it's saved.
""" """
capture_start = time.time() capture_start = time.time()
image, metadata = self._capture_image(cam, metadata_getter,) image, metadata = self._capture_image(
cam,
metadata_getter,
)
acquisition_time = time.time() acquisition_time = time.time()
self._save_capture(jpeg_path, image, metadata, logger) self._save_capture(jpeg_path, image, metadata, logger)
save_time = time.time() save_time = time.time()
@ -91,8 +104,6 @@ class ZStackThing(Thing):
def _capture_image(self, cam, metadata_getter) -> tuple[np.ndarray, dict]: def _capture_image(self, cam, metadata_getter) -> tuple[np.ndarray, dict]:
"""Capture an image in memory and return it with metadata """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 CaptureError raised if the capture fails for any reason
returns tuple with numpy array of image data, and dict of metadata returns tuple with numpy array of image data, and dict of metadata
""" """
@ -130,3 +141,20 @@ class ZStackThing(Thing):
logger.warning(f"Failed to add metadata to {jpeg_path}") logger.warning(f"Failed to add metadata to {jpeg_path}")
except Exception as e: except Exception as e:
raise IOError(f"An error occurred while saving {jpeg_path}") from e raise IOError(f"An error occurred while saving {jpeg_path}") from e
def copy_central_image(
self,
images_dir: str,
stack_dir: str,
logger: InvocationLogger,
):
"""Gets a list of images in a folder (stack_dir), sorts them, and copies the central image
to images dir."""
image_list = glob.glob(os.path.join(stack_dir, "*"))
image_list.sort()
central_index = (len(image_list) - 1) // 2
central_image = image_list[central_index]
logger.warning(central_image)
xy_location = os.path.basename(stack_dir)
shutil.copy(central_image, os.path.join(images_dir, f"{xy_location}.jpeg"))