Fixing a number of issues from the merge and refactor.

This commit is contained in:
Julian Stirling 2025-06-26 18:29:12 +01:00
parent 61dd5e4958
commit 6a87805b47
3 changed files with 13 additions and 38 deletions

View file

@ -20,9 +20,7 @@ from pydantic import BaseModel, computed_field
from labthings_fastapi.thing import Thing from labthings_fastapi.thing import Thing
from labthings_fastapi.dependencies.blocking_portal import BlockingPortal from labthings_fastapi.dependencies.blocking_portal import BlockingPortal
from labthings_fastapi.decorators import thing_action, thing_property from labthings_fastapi.decorators import thing_action, thing_property
from labthings_fastapi.dependencies.metadata import GetThingStates
from labthings_fastapi.types.numpy import NDArray from labthings_fastapi.types.numpy import NDArray
from labthings_fastapi.dependencies.invocation import InvocationLogger
from .camera import RawCameraDependency as Camera from .camera import RawCameraDependency as Camera
from .camera import CameraDependency as WrappedCamera from .camera import CameraDependency as WrappedCamera
@ -108,7 +106,7 @@ class StackParams(BaseModel):
This is 15 images more then the minimum number that are captured. This is 15 images more then the minimum number that are captured.
""" """
return self.min_images_to_test return self.min_images_to_test + 15
def slice_to_save(self, sharpest_index): def slice_to_save(self, sharpest_index):
"""Return the slice of images to save given the index of the sharpest image""" """Return the slice of images to save given the index of the sharpest image"""
@ -131,7 +129,7 @@ class CaptureInfo:
@property @property
def filename(self) -> str: def filename(self) -> str:
"""The filename for this image generated from the poistion""" """The filename for this image generated from the poistion"""
return f"{self.position[0]}_{self.position[1]}_{self.position[2]}.jpeg" return f"{self.position['x']}_{self.position['y']}_{self.position['z']}.jpeg"
def _get_capture_by_id(captures: list[CaptureInfo], buffer_id: int) -> CaptureInfo: def _get_capture_by_id(captures: list[CaptureInfo], buffer_id: int) -> CaptureInfo:
@ -408,8 +406,6 @@ class AutofocusThing(Thing):
self, self,
cam: WrappedCamera, cam: WrappedCamera,
stage: Stage, stage: Stage,
logger: InvocationLogger,
metadata_getter: GetThingStates,
sharpness_monitor: SharpnessMonitorDep, sharpness_monitor: SharpnessMonitorDep,
images_dir: str, images_dir: str,
autofocus_dz: int, autofocus_dz: int,
@ -450,15 +446,13 @@ class AutofocusThing(Thing):
stack_parameters=stack_parameters, stack_parameters=stack_parameters,
stage=stage, stage=stage,
cam=cam, cam=cam,
logger=logger,
metadata_getter=metadata_getter,
) )
if success: if success:
break break
# The z position of the first images in the previous attempt. # The z position of the first images in the previous attempt.
initial_z_pos = captures[0].position[2] initial_z_pos = captures[0].position["z"]
# If a stack is not successful, move to the start and autofocus # If a stack is not successful, move to the start and autofocus
self.reset_stack( self.reset_stack(
initial_z_pos, initial_z_pos,
@ -473,11 +467,10 @@ class AutofocusThing(Thing):
captures=captures, captures=captures,
stack_parameters=stack_parameters, stack_parameters=stack_parameters,
cam=cam, cam=cam,
logger=logger,
) )
# Return the z position of the sharpest image, for path planning and tracking # Return the z position of the sharpest image, for path planning and tracking
return _get_capture_by_id(captures, sharpest_id).position[2] return _get_capture_by_id(captures, sharpest_id).position["z"]
def reset_stack( def reset_stack(
self, self,
@ -508,7 +501,6 @@ class AutofocusThing(Thing):
captures: list[list], captures: list[list],
stack_parameters: StackParams, stack_parameters: StackParams,
cam: WrappedCamera, cam: WrappedCamera,
logger: InvocationLogger,
) -> int: ) -> int:
"""Save the required captures to disk. Will save the sharpest image, """Save the required captures to disk. Will save the sharpest image,
and any images either side of focus. and any images either side of focus.
@ -521,14 +513,13 @@ class AutofocusThing(Thing):
calling action calling action
""" """
sharpest_index = _get_capture_index_by_id(sharpest_id) sharpest_index = _get_capture_index_by_id(captures, sharpest_id)
slice_to_save = stack_parameters.slice_to_save(sharpest_index) slice_to_save = stack_parameters.slice_to_save(sharpest_index)
# Loop through the range, saving each capture to disk # Loop through the range, saving each capture to disk
for capture in captures[slice_to_save]: for capture in captures[slice_to_save]:
cam.save_from_memory( cam.save_from_memory(
jpeg_path=os.path.join(stack_parameters.images_dir, capture.filename), jpeg_path=os.path.join(stack_parameters.images_dir, capture.filename),
logger=logger,
save_resolution=stack_parameters.capture_resolution, save_resolution=stack_parameters.capture_resolution,
buffer_id=capture.buffer_id, buffer_id=capture.buffer_id,
) )
@ -540,8 +531,6 @@ class AutofocusThing(Thing):
stack_parameters: StackParams, stack_parameters: StackParams,
stage: Stage, stage: Stage,
cam: WrappedCamera, cam: WrappedCamera,
logger: InvocationLogger,
metadata_getter: GetThingStates,
) -> tuple[bool, list[CaptureInfo], Optional[int]]: ) -> tuple[bool, list[CaptureInfo], Optional[int]]:
"""Capture a series of images offset by stack_parameters.stack_dz, and test whether """Capture a series of images offset by stack_parameters.stack_dz, and test whether
the sharpest image is towards the centre of the stack. the sharpest image is towards the centre of the stack.
@ -582,8 +571,6 @@ class AutofocusThing(Thing):
self.capture_stack_image( self.capture_stack_image(
cam, cam,
stage, stage,
logger,
metadata_getter,
buffer_max=stack_parameters.min_images_to_test, buffer_max=stack_parameters.min_images_to_test,
) )
) )
@ -605,8 +592,6 @@ class AutofocusThing(Thing):
self, self,
cam: WrappedCamera, cam: WrappedCamera,
stage: Stage, stage: Stage,
logger: InvocationLogger,
metadata_getter: GetThingStates,
buffer_max: int, buffer_max: int,
) -> list: ) -> list:
"""Capture another image and return the capture information. """Capture another image and return the capture information.
@ -614,9 +599,7 @@ class AutofocusThing(Thing):
The capture is stored by the camera Thing, and can be saved by ID. The capture is stored by the camera Thing, and can be saved by ID.
""" """
stage_location = stage.position stage_location = stage.position
buffer_id = cam.capture_to_memory( buffer_id = cam.capture_to_memory(buffer_max=buffer_max)
logger, metadata_getter, buffer_max=buffer_max
)
return CaptureInfo( return CaptureInfo(
buffer_id=buffer_id, buffer_id=buffer_id,
position=stage_location, position=stage_location,

View file

@ -221,8 +221,8 @@ class BaseCamera(Thing):
"""Capture an image and save it to disk """Capture an image and save it to disk
save_resolution can be set to resize the image before saving. By default this is None save_resolution can be set to resize the image before saving. By default this
meaning that the image is saved at original resoltion. is None meaning that the image is saved at original resoltion.
""" """
image, metadata = self._robust_image_capture( image, metadata = self._robust_image_capture(
metadata_getter, metadata_getter,
@ -239,7 +239,7 @@ class BaseCamera(Thing):
@thing_action @thing_action
def capture_to_memory( def capture_to_memory(
self, logger: InvocationLogger, metadata_getter: GetThingStates, buffer_max self, logger: InvocationLogger, metadata_getter: GetThingStates, buffer_max: int
) -> None: ) -> None:
""" """
Capture an image to memory. This can be saved later with `save_from_memory` Capture an image to memory. This can be saved later with `save_from_memory`
@ -272,6 +272,9 @@ class BaseCamera(Thing):
logger=logger, logger=logger,
save_resolution=save_resolution, save_resolution=save_resolution,
) )
@thing_action
def clear_buffers(self) -> None:
self._memory_buffer.clear() self._memory_buffer.clear()
def _robust_image_capture( def _robust_image_capture(

View file

@ -656,6 +656,7 @@ class SmartScanThing(Thing):
focused_height = self._autofocus.run_smart_stack( focused_height = self._autofocus.run_smart_stack(
images_dir=self._ongoing_scan_images_dir, images_dir=self._ongoing_scan_images_dir,
autofocus_dz=self._scan_data["autofocus_dz"], autofocus_dz=self._scan_data["autofocus_dz"],
capture_resolution=self._scan_data["capture_resolution"],
) )
current_pos_xyz = ( current_pos_xyz = (
@ -668,18 +669,6 @@ class SmartScanThing(Thing):
current_pos_xyz, imaged=True, focused=True current_pos_xyz, imaged=True, focused=True
) )
site_folder = os.path.join(
self._ongoing_scan_images_dir,
"stacks",
f"{new_pos_xyz[0]}_{new_pos_xyz[1]}",
)
os.makedirs(site_folder, exist_ok=True)
self._autofocus.run_z_stack(
images_dir=self._ongoing_scan_images_dir,
stack_dir=site_folder,
capture_resolution=self._scan_data["capture_resolution"],
)
# increment capure counter as thread has completed # increment capure counter as thread has completed
self._scan_images_taken += 1 self._scan_images_taken += 1
# Add it to the incremental zip # Add it to the incremental zip