Changes based on review, mostly enums and moved stack params
This commit is contained in:
parent
37e3450670
commit
331ceb705d
2 changed files with 54 additions and 19 deletions
|
|
@ -11,6 +11,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import Literal, Mapping, Optional, Self, Sequence
|
from typing import Literal, Mapping, Optional, Self, Sequence
|
||||||
|
|
||||||
|
|
@ -33,11 +34,25 @@ class NotStreamingError(RuntimeError):
|
||||||
"""No images captured from stream. The camera is almost certainly not streaming."""
|
"""No images captured from stream. The camera is almost certainly not streaming."""
|
||||||
|
|
||||||
|
|
||||||
|
class SharpnessMethod(str, Enum):
|
||||||
|
"""The possible SharpnessMethods for autofocus."""
|
||||||
|
|
||||||
|
jpeg = "jpeg"
|
||||||
|
|
||||||
|
|
||||||
class AutofocusParams(BaseModel):
|
class AutofocusParams(BaseModel):
|
||||||
"""A class for running autofocus routines."""
|
"""A class for running autofocus routines."""
|
||||||
|
|
||||||
dz: int
|
dz: int
|
||||||
sharpness_method: str = "jpeg"
|
sharpness_method: SharpnessMethod = SharpnessMethod.jpeg
|
||||||
|
|
||||||
|
|
||||||
|
class StackOrigin(str, Enum):
|
||||||
|
"""The position of the current location in the stack."""
|
||||||
|
|
||||||
|
START = "start"
|
||||||
|
CENTER = "center"
|
||||||
|
END = "end"
|
||||||
|
|
||||||
|
|
||||||
class StackParams(BaseModel):
|
class StackParams(BaseModel):
|
||||||
|
|
@ -52,15 +67,28 @@ class StackParams(BaseModel):
|
||||||
settling_time: float = 0.3
|
settling_time: float = 0.3
|
||||||
"""Time (in seconds) between moving and capturing an image"""
|
"""Time (in seconds) between moving and capturing an image"""
|
||||||
|
|
||||||
|
backlash_correction: int = 250
|
||||||
|
"""
|
||||||
|
Distance (in steps) to overshoot a move and then undo, to account for backlash
|
||||||
|
"""
|
||||||
|
|
||||||
|
origin: StackOrigin = StackOrigin.START
|
||||||
|
"""Where the stack is positioned relative to the current z position."""
|
||||||
|
|
||||||
|
|
||||||
class SmartStackParams(StackParams):
|
class SmartStackParams(StackParams):
|
||||||
"""A class for holding smart stack parameters, and returning computed ones."""
|
"""A class for holding smart stack parameters, and returning computed ones."""
|
||||||
|
|
||||||
min_images_to_test: int
|
min_images_to_test: int
|
||||||
|
|
||||||
backlash_correction: int = 250
|
save_on_failure: bool = False
|
||||||
|
"""Whether to save an image even if no focus was found."""
|
||||||
|
|
||||||
|
check_turning_points: bool = True
|
||||||
"""
|
"""
|
||||||
Distance (in steps) to overshoot a move and then undo, to account for backlash
|
Whether to check the number of turning points in
|
||||||
|
the sharpnesses of the images in the stack is exactly 1.
|
||||||
|
(May fail with thick samples)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stack_height_limit: int = 15
|
stack_height_limit: int = 15
|
||||||
|
|
@ -468,8 +496,6 @@ class AutofocusThing(lt.Thing):
|
||||||
stack_parameters: SmartStackParams,
|
stack_parameters: SmartStackParams,
|
||||||
capture_parameters: CaptureParams,
|
capture_parameters: CaptureParams,
|
||||||
autofocus_parameters: AutofocusParams,
|
autofocus_parameters: AutofocusParams,
|
||||||
save_on_failure: bool = False,
|
|
||||||
check_turning_points: bool = True,
|
|
||||||
) -> tuple[bool, int]:
|
) -> tuple[bool, int]:
|
||||||
"""Run a smart stack.
|
"""Run a smart stack.
|
||||||
|
|
||||||
|
|
@ -481,10 +507,6 @@ class AutofocusThing(lt.Thing):
|
||||||
|
|
||||||
:param stack_parameters: A SmartStackParams object containing the required
|
:param stack_parameters: A SmartStackParams object containing the required
|
||||||
parameters to run a stack.
|
parameters to run a stack.
|
||||||
:param save_on_failure: Whether to save an image even if no focus was found.
|
|
||||||
:param check_turning_points: Whether to check the number of turning points in
|
|
||||||
the sharpnesses of the images in the stack is exactly 1. (May fail with
|
|
||||||
thick samples)
|
|
||||||
|
|
||||||
:returns: A tuple containing:
|
:returns: A tuple containing:
|
||||||
|
|
||||||
|
|
@ -496,13 +518,10 @@ class AutofocusThing(lt.Thing):
|
||||||
attempt += 1
|
attempt += 1
|
||||||
success, captures, sharpest_id = self.smart_z_stack(
|
success, captures, sharpest_id = self.smart_z_stack(
|
||||||
stack_parameters=stack_parameters,
|
stack_parameters=stack_parameters,
|
||||||
check_turning_points=check_turning_points,
|
check_turning_points=stack_parameters.check_turning_points,
|
||||||
)
|
)
|
||||||
|
|
||||||
if success:
|
if success or attempt >= stack_parameters.max_attempts:
|
||||||
break
|
|
||||||
|
|
||||||
if attempt >= stack_parameters.max_attempts:
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# The z position of the first images in the previous attempt.
|
# The z position of the first images in the previous attempt.
|
||||||
|
|
@ -516,7 +535,7 @@ class AutofocusThing(lt.Thing):
|
||||||
# Save stack_parameters.image_to_save images centred on the sharpest capture.
|
# Save stack_parameters.image_to_save images centred on the sharpest capture.
|
||||||
# If the smart_stack failed the exact number of images saved may not be
|
# If the smart_stack failed the exact number of images saved may not be
|
||||||
# stack_parameters.image_to_save
|
# stack_parameters.image_to_save
|
||||||
if success or save_on_failure:
|
if success or stack_parameters.save_on_failure:
|
||||||
self.save_stack(
|
self.save_stack(
|
||||||
sharpest_id=sharpest_id,
|
sharpest_id=sharpest_id,
|
||||||
captures=captures,
|
captures=captures,
|
||||||
|
|
@ -747,6 +766,24 @@ class AutofocusThing(lt.Thing):
|
||||||
captures: list[CaptureInfo] = []
|
captures: list[CaptureInfo] = []
|
||||||
z_positions: list[int] = []
|
z_positions: list[int] = []
|
||||||
|
|
||||||
|
total_range = stack_parameters.stack_dz * (stack_parameters.images_to_save - 1)
|
||||||
|
|
||||||
|
# Determine starting offset based on stack origin
|
||||||
|
if stack_parameters.origin == StackOrigin.CENTER:
|
||||||
|
target_offset = -total_range // 2
|
||||||
|
elif stack_parameters.origin == StackOrigin.END:
|
||||||
|
target_offset = -total_range
|
||||||
|
else:
|
||||||
|
target_offset = 0
|
||||||
|
|
||||||
|
# Apply backlash correction: overshoot and move back
|
||||||
|
# Overshoot past the starting position
|
||||||
|
self._stage.move_relative(
|
||||||
|
z=target_offset - stack_parameters.backlash_correction
|
||||||
|
)
|
||||||
|
# Move back to the exact starting point
|
||||||
|
self._stage.move_relative(z=stack_parameters.backlash_correction)
|
||||||
|
|
||||||
# Capture images_to_save images
|
# Capture images_to_save images
|
||||||
for _ in range(stack_parameters.images_to_save):
|
for _ in range(stack_parameters.images_to_save):
|
||||||
time.sleep(stack_parameters.settling_time)
|
time.sleep(stack_parameters.settling_time)
|
||||||
|
|
|
||||||
|
|
@ -481,6 +481,7 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
|
||||||
stack_dz=self.stack_dz,
|
stack_dz=self.stack_dz,
|
||||||
images_to_save=self.stack_images_to_save,
|
images_to_save=self.stack_images_to_save,
|
||||||
min_images_to_test=self.stack_min_images_to_test,
|
min_images_to_test=self.stack_min_images_to_test,
|
||||||
|
save_on_failure=not self.skip_background,
|
||||||
)
|
)
|
||||||
|
|
||||||
def pre_scan_routine(self, settings: HistoScanSettingsModel) -> None:
|
def pre_scan_routine(self, settings: HistoScanSettingsModel) -> None:
|
||||||
|
|
@ -539,17 +540,14 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
|
||||||
self.logger.info(msg)
|
self.logger.info(msg)
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
save_on_failure = not settings.skip_background
|
|
||||||
|
|
||||||
focus_height: Optional[int]
|
focus_height: Optional[int]
|
||||||
focused, focus_height = self._autofocus.run_smart_stack(
|
focused, focus_height = self._autofocus.run_smart_stack(
|
||||||
stack_parameters=settings.smart_stack_params,
|
stack_parameters=settings.smart_stack_params,
|
||||||
capture_parameters=settings.capture_params,
|
capture_parameters=settings.capture_params,
|
||||||
autofocus_parameters=settings.autofocus_params,
|
autofocus_parameters=settings.autofocus_params,
|
||||||
save_on_failure=save_on_failure,
|
|
||||||
)
|
)
|
||||||
# An image was captured if we are focussed or we are not skipping background.
|
# An image was captured if we are focussed or we are not skipping background.
|
||||||
imaged = focused or save_on_failure
|
imaged = focused or settings.smart_stack_params.save_on_failure
|
||||||
|
|
||||||
if not imaged:
|
if not imaged:
|
||||||
msg = f"Stack failed at {xyz_pos}. Treating as background."
|
msg = f"Stack failed at {xyz_pos}. Treating as background."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue