class documentation

class AutofocusThing(lt.Thing): (source)

View In Hierarchy

The Thing concerned with combinations of z axis movements and the camera.

Actions here involve moving a stage in z, and using the camera to either capture images (generally, z-stacking) and measuring the sharpness of the field of view to assess focus (autofocus and testing the success of a z-stack)

Method capture_stack_image Capture another image and return the capture information.
Method check_stack_result Check if the sharpest image in a list of captures is central enough.
Method fast_autofocus Sweep the stage up and down, then move to the sharpest point.
Method looping_autofocus Repeatedly autofocus the stage until it looks focused.
Method reset_stack Return to the initial z position and run a looping autofocus.
Method run_smart_stack Run a smart stack.
Method save_stack Save the required captures to disk.
Method z_move_and_measure_sharpness Make a move (or a series of moves) and monitor sharpness.
Method z_stack Capture a series of images checking that sharpest image central.
Class Variable stack_dz Distance in steps between images in a z-stack.
Class Variable stack_images_to_save The number of images to save in a stack.
Class Variable stack_min_images_to_test The minimum number of images to capture in a stack.
def capture_stack_image(self, cam: CameraClient, stage: Stage, buffer_max: int) -> CaptureInfo: (source)

Capture another image and return the capture information.

The capture is stored by the camera Thing, and can be saved by ID.

Parameters
cam:CameraClientCamera Dependency to be passed through from the calling action
stage:StageStage Dependency to be passed through from the calling action
buffer_max:intThe maximum number of images to tell the camera to keep in memory for saving once the stack is complete
Returns
CaptureInfoA CaptureInfo object containing the capture information including its camera buffer_id needed for saving.
def check_stack_result(self, captures: list[CaptureInfo]) -> tuple[Literal['success', 'continue', 'restart'], int]: (source)

Check if the sharpest image in a list of captures is central enough.

Parameters
captures:list[CaptureInfo]a list of the capture objects to for testing if the sharpness has converged in the centre
Returns
tuple[Literal['success', 'continue', 'restart'], int]

A tuple with two values:

  • result - which is one of three literal values:

    • success if the sharpest image is towards the centre
    • continue if the sharpest image is in the final two images of the
      list
    • restart if the sharpest image is in the first two images of the
      list
  • capture_id - the buffer id of the sharpest image

@lt.thing_action
def fast_autofocus(self, sharpness_monitor: SharpnessMonitorDep, dz: int = 2000, start: Literal['centre', 'base'] = 'centre') -> SharpnessDataArrays: (source)

Sweep the stage up and down, then move to the sharpest point.

This method will will move down by dz/2, sweep up by dz, and then evaluate the position where the image was sharpest. We'll then move back down, and finally up to the sharpest point.

@lt.thing_action
def looping_autofocus(self, stage: Stage, sharpness_monitor: SharpnessMonitorDep, dz=2000, start: Literal['centre', 'base'] = 'centre'): (source)

Repeatedly autofocus the stage until it looks focused.

This action will run the fast_autofocus action until it settles on a point in the middle 3/5 of its range. Such logic can be helpful if the microscope is close to focus, but not quite within dz/2. It will attempt to autofocus up to 10 times.

def reset_stack(self, initial_z_pos: list[int], autofocus_dz: int, stage: Stage, sharpness_monitor: SharpnessMonitorDep): (source)

Return to the initial z position and run a looping autofocus.

stage and sharpness_monitor are Thing dependencies passed through from the calling action.

Parameters
initial_z_pos:list[int]The initial z positions of previous captures
autofocus_dz:intthe range in steps to autofocus
stage:StageUndocumented
sharpness_monitor:SharpnessMonitorDepUndocumented
@lt.thing_action
def run_smart_stack(self, cam: CameraClient, stage: Stage, sharpness_monitor: SharpnessMonitorDep, images_dir: str, autofocus_dz: int, save_resolution: tuple[int, int]) -> tuple[bool, int]: (source)

Run a smart stack.

A smart stack captures images offset in z, testing whether the sharpest image is towards the centre of the stack.

The sharpest image, and optionally images around the sharpest, will be saved to the images_dir with their coordinates in the filename.

Parameters
cam:CameraClientCamera Dependency supplied by LabThings dependency injection
stage:StageStage Dependency supplied by LabThings dependency injection
sharpness_monitor:SharpnessMonitorDepSharpness Monitor Dependency (for focus detection) supplied by LabThings dependency injection
images_dir:strthe folder to save all images
autofocus_dz:intthe range to autofocus over if a stack fails
save_resolution:tuple[int, int]The resolution the images should be saved at, the images will be resampled if this doesn't match the camera's capture resolution
Returns
tuple[bool, int]

A tuple containing:

  • A boolean, True if stack was successfully
  • The z position of the sharpest image
def save_stack(self, sharpest_id: int, captures: list[list], stack_parameters: StackParams, cam: CameraClient) -> int: (source)

Save the required captures to disk.

This will save the sharpest image, and optionally extra images either side of focus (see stack_parameters.images_to_save).

Parameters
sharpest_id:intthe buffer id index of the sharpest image
captures:list[list]a list of captures, including file name, image data and metadata
stack_parameters:StackParamsa StackParams object holding stack parameters
cam:CameraClientis a Thing dependency passed through from the calling action
Returns
intUndocumented
@lt.thing_action
def z_move_and_measure_sharpness(self, sharpness_monitor: SharpnessMonitorDep, dz: Sequence[int], wait: float = 0) -> SharpnessDataArrays: (source)

Make a move (or a series of moves) and monitor sharpness.

This method will will make a series of relative moves in z, and return the sharpness (JPEG size) vs time, along with timestamps for the moves. This can be used to calibrate autofocus.

Each move is relative to the last one, i.e. we will finish at sum(dz) relative to the starting position.

If wait is specified, we will wait for that many seconds between moves.

def z_stack(self, stack_parameters: StackParams, cam: CameraClient, stage: Stage) -> tuple[bool, list[CaptureInfo], int | None]: (source)

Capture a series of images checking that sharpest image central.

The images are separated in z offset by stack_parameters.stack_dz, as they are captured the last stack_parameters.min_images_to_test images are checked to see if the sharpest image is central enough in the stack. If it is the stack completes.

Parameters
stack_parameters:StackParamsa StackParams object holding stack parameters
cam:CameraClientCamera Dependency to be passed through from the calling action
stage:StageStage Dependency to be passed through from the calling action
Returns
tuple[bool, list[CaptureInfo], int | None]

A tuple of

  • the stack result (True for successful stack, False for failed stack),
  • a list of CaptureInfo objects,
  • the buffer_id of the sharpest image (or None if the stack failed).
stack_dz = (source)

Distance in steps between images in a z-stack.

Suggested values:

  • 50 for 60-100x
  • 100 for 40x
  • 200 for 20x
stack_images_to_save = (source)

The number of images to save in a stack.

Defaults to 1 unless you need to see either side of focus

stack_min_images_to_test = (source)

The minimum number of images to capture in a stack.

This many images are captures and tested for focus, if the focus is not central enough more images may be captured. After new images are captured the number sets the number of images used for checking if focus is central.

Defaults to 9 which balances reliability and speed/