Add CChip workflow to scan_workflows
This commit is contained in:
parent
4190899f17
commit
ffb9a4d509
3 changed files with 142 additions and 12 deletions
|
|
@ -17,6 +17,7 @@
|
||||||
"default_workflow": "histo_scan_workflow"
|
"default_workflow": "histo_scan_workflow"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"CChip_workflow": "openflexure_microscope_server.things.scan_workflows:CChipWorkflow",
|
||||||
"histo_scan_workflow": "openflexure_microscope_server.things.scan_workflows:HistoScanWorkflow",
|
"histo_scan_workflow": "openflexure_microscope_server.things.scan_workflows:HistoScanWorkflow",
|
||||||
"snake_workflow": "openflexure_microscope_server.things.scan_workflows:SnakeWorkflow",
|
"snake_workflow": "openflexure_microscope_server.things.scan_workflows:SnakeWorkflow",
|
||||||
"raster_workflow": "openflexure_microscope_server.things.scan_workflows:RasterWorkflow",
|
"raster_workflow": "openflexure_microscope_server.things.scan_workflows:RasterWorkflow",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"default_workflow": "histo_scan_workflow"
|
"default_workflow": "histo_scan_workflow"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"CChip_workflow": "openflexure_microscope_server.things.scan_workflows:CChipWorkflow",
|
||||||
"histo_scan_workflow": "openflexure_microscope_server.things.scan_workflows:HistoScanWorkflow",
|
"histo_scan_workflow": "openflexure_microscope_server.things.scan_workflows:HistoScanWorkflow",
|
||||||
"snake_workflow": "openflexure_microscope_server.things.scan_workflows:SnakeWorkflow",
|
"snake_workflow": "openflexure_microscope_server.things.scan_workflows:SnakeWorkflow",
|
||||||
"raster_workflow": "openflexure_microscope_server.things.scan_workflows:RasterWorkflow",
|
"raster_workflow": "openflexure_microscope_server.things.scan_workflows:RasterWorkflow",
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ from openflexure_microscope_server.things.autofocus import (
|
||||||
AutofocusParams,
|
AutofocusParams,
|
||||||
AutofocusThing,
|
AutofocusThing,
|
||||||
SmartStackParams,
|
SmartStackParams,
|
||||||
|
StackParams,
|
||||||
)
|
)
|
||||||
from openflexure_microscope_server.things.background_detect import (
|
from openflexure_microscope_server.things.background_detect import (
|
||||||
ChannelDeviationLUV,
|
ChannelDeviationLUV,
|
||||||
|
|
@ -666,7 +667,14 @@ class RegularGridSettingsModel(RectGridSettingsModel):
|
||||||
style: Literal["snake", "raster"]
|
style: Literal["snake", "raster"]
|
||||||
|
|
||||||
|
|
||||||
class RegularGridWorkflow(RectGridWorkflow[RegularGridSettingsModel]):
|
RegGridSettingModelType = TypeVar(
|
||||||
|
"RegGridSettingModelType", bound=RegularGridSettingsModel
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RegularGridWorkflow(
|
||||||
|
RectGridWorkflow[RegGridSettingModelType], Generic[RegGridSettingModelType]
|
||||||
|
):
|
||||||
"""A base workflow for any workflow that uses a regular rectangular grid."""
|
"""A base workflow for any workflow that uses a regular rectangular grid."""
|
||||||
|
|
||||||
x_count: int = lt.setting(default=3, ge=1)
|
x_count: int = lt.setting(default=3, ge=1)
|
||||||
|
|
@ -674,20 +682,20 @@ class RegularGridWorkflow(RectGridWorkflow[RegularGridSettingsModel]):
|
||||||
y_count: int = lt.setting(default=2, ge=1)
|
y_count: int = lt.setting(default=2, ge=1)
|
||||||
"""The number of rows in the scan."""
|
"""The number of rows in the scan."""
|
||||||
|
|
||||||
_settings_model = RegularGridSettingsModel
|
_settings_model: type[RegGridSettingModelType]
|
||||||
_planner_cls = RegularGridPlanner
|
_planner_cls = RegularGridPlanner
|
||||||
_grid_style: Literal["snake", "raster"]
|
_grid_style: Literal["snake", "raster"]
|
||||||
|
|
||||||
def _build_scan_settings(self, base_kwargs: dict) -> RegularGridSettingsModel:
|
def _build_scan_settings(self, base_kwargs: dict) -> RegGridSettingModelType:
|
||||||
"""Construct the SettingModel for all_settings."""
|
"""Construct the SettingModel for all_settings."""
|
||||||
return RegularGridSettingsModel(
|
return self._settings_model(
|
||||||
**base_kwargs,
|
**base_kwargs,
|
||||||
x_count=self.x_count,
|
x_count=self.x_count,
|
||||||
y_count=self.y_count,
|
y_count=self.y_count,
|
||||||
style=self._grid_style,
|
style=self._grid_style,
|
||||||
)
|
)
|
||||||
|
|
||||||
def pre_scan_routine(self, settings: RegularGridSettingsModel) -> None:
|
def pre_scan_routine(self, settings: RegGridSettingModelType) -> None:
|
||||||
"""Perform these steps before starting the scan.
|
"""Perform these steps before starting the scan.
|
||||||
|
|
||||||
In this case, only autofocus.
|
In this case, only autofocus.
|
||||||
|
|
@ -699,11 +707,11 @@ class RegularGridWorkflow(RectGridWorkflow[RegularGridSettingsModel]):
|
||||||
)
|
)
|
||||||
|
|
||||||
def new_scan_planner(
|
def new_scan_planner(
|
||||||
self, settings: RegularGridSettingsModel, position: Mapping[str, int]
|
self, settings: RegGridSettingModelType, position: Mapping[str, int]
|
||||||
) -> ScanPlanner:
|
) -> ScanPlanner:
|
||||||
"""Return a new scan planner object.
|
"""Return a new scan planner object.
|
||||||
|
|
||||||
:param settings: The settings for this scan as a SnakeSettingsModel
|
:param settings: The settings for this scan as the relevant SettingsModel type.
|
||||||
:param position: The starting position as a mapping of axes names to int.
|
:param position: The starting position as a mapping of axes names to int.
|
||||||
"""
|
"""
|
||||||
planner_settings = {
|
planner_settings = {
|
||||||
|
|
@ -719,11 +727,11 @@ class RegularGridWorkflow(RectGridWorkflow[RegularGridSettingsModel]):
|
||||||
)
|
)
|
||||||
|
|
||||||
def acquisition_routine(
|
def acquisition_routine(
|
||||||
self, settings: RegularGridSettingsModel, xyz_pos: tuple[int, int, int]
|
self, settings: RegGridSettingModelType, xyz_pos: tuple[int, int, int]
|
||||||
) -> tuple[bool, Optional[int]]:
|
) -> tuple[bool, Optional[int]]:
|
||||||
"""Autofocus and capture.
|
"""Autofocus and capture.
|
||||||
|
|
||||||
:param settings: The settings for this scan as a RegularGridSettingsModel
|
:param settings: The settings for this scan as the relevant SettingsModel type.
|
||||||
:param xyz_pos: The current position as a tuple or 3 ints.
|
:param xyz_pos: The current position as a tuple or 3 ints.
|
||||||
:return: A tuple of whether an image was taken, and the z-position for focus.
|
:return: A tuple of whether an image was taken, and the z-position for focus.
|
||||||
If failed to find focus, returns for the focus z-position.
|
If failed to find focus, returns for the focus z-position.
|
||||||
|
|
@ -762,7 +770,7 @@ class RegularGridWorkflow(RectGridWorkflow[RegularGridSettingsModel]):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SnakeWorkflow(RegularGridWorkflow):
|
class SnakeWorkflow(RegularGridWorkflow[RegularGridSettingsModel]):
|
||||||
"""A workflow optimised for snaking around samples.
|
"""A workflow optimised for snaking around samples.
|
||||||
|
|
||||||
This workflow generates a list of coordinates in a rectangle, and snakes
|
This workflow generates a list of coordinates in a rectangle, and snakes
|
||||||
|
|
@ -777,10 +785,11 @@ class SnakeWorkflow(RegularGridWorkflow):
|
||||||
),
|
),
|
||||||
readonly=True,
|
readonly=True,
|
||||||
)
|
)
|
||||||
|
_settings_model = RegularGridSettingsModel
|
||||||
_grid_style = "snake"
|
_grid_style = "snake"
|
||||||
|
|
||||||
|
|
||||||
class RasterWorkflow(RegularGridWorkflow):
|
class RasterWorkflow(RegularGridWorkflow[RegularGridSettingsModel]):
|
||||||
"""A workflow optimised for snaking around samples.
|
"""A workflow optimised for snaking around samples.
|
||||||
|
|
||||||
This workflow generates a list of coordinates in a rectangle, and always
|
This workflow generates a list of coordinates in a rectangle, and always
|
||||||
|
|
@ -796,5 +805,124 @@ class RasterWorkflow(RegularGridWorkflow):
|
||||||
),
|
),
|
||||||
readonly=True,
|
readonly=True,
|
||||||
)
|
)
|
||||||
|
_settings_model = RegularGridSettingsModel
|
||||||
_grid_style = "raster"
|
_grid_style = "raster"
|
||||||
|
|
||||||
|
|
||||||
|
class CChipScanSettingsModel(RegularGridSettingsModel):
|
||||||
|
"""The settings for a scan with the CChipWorkflow.
|
||||||
|
|
||||||
|
This includes settings calculated when starting. This will be held by smart scan
|
||||||
|
during a scan and serialised to disk.
|
||||||
|
"""
|
||||||
|
|
||||||
|
stack_params: StackParams
|
||||||
|
|
||||||
|
|
||||||
|
class CChipWorkflow(RegularGridWorkflow[CChipScanSettingsModel]):
|
||||||
|
"""A workflow optimised for scanning the well of a CChip.
|
||||||
|
|
||||||
|
This workflow generates a list of coordinates in a rectangle, and snakes
|
||||||
|
around them from the top left (assuming positive dx and dy), stacking the
|
||||||
|
grid and above.
|
||||||
|
"""
|
||||||
|
|
||||||
|
display_name: str = lt.property(default="C-Chip Scan", readonly=True)
|
||||||
|
ui_blurb: str = lt.property(
|
||||||
|
default=(
|
||||||
|
"This scan workflow is optimised for scanning a C-Chip. It focuses on "
|
||||||
|
"a grid, then stacks images above the grid to complete a volumetric scan."
|
||||||
|
),
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
_grid_style = "snake"
|
||||||
|
_settings_model = CChipScanSettingsModel
|
||||||
|
|
||||||
|
overlap: float = lt.setting(default=0.1, ge=0.1, le=0.7)
|
||||||
|
"""The fraction that adjacent images should overlap in x and y.
|
||||||
|
|
||||||
|
This must be between 0.1 and 0.7.
|
||||||
|
"""
|
||||||
|
x_count: int = lt.setting(default=5, readonly=False)
|
||||||
|
"""The number of columns in the scan."""
|
||||||
|
y_count: int = lt.setting(default=7, readonly=False)
|
||||||
|
"""The number of rows in the scan."""
|
||||||
|
|
||||||
|
stack_images_to_save: int = lt.setting(default=9, readonly=False)
|
||||||
|
"""The number of images to save in a stack.
|
||||||
|
|
||||||
|
Defaults to 1 unless you need to see either side of focus
|
||||||
|
"""
|
||||||
|
|
||||||
|
stack_dz: int = lt.setting(default=500, readonly=False)
|
||||||
|
"""Distance in steps between images in a z-stack."""
|
||||||
|
|
||||||
|
def create_stack_params(
|
||||||
|
self,
|
||||||
|
) -> StackParams:
|
||||||
|
"""Set up the parameters used for all stacks in a scan.
|
||||||
|
|
||||||
|
:returns: A StackSmartParams object with the required parameters.
|
||||||
|
"""
|
||||||
|
return StackParams(
|
||||||
|
stack_dz=self.stack_dz, images_to_save=self.stack_images_to_save
|
||||||
|
)
|
||||||
|
|
||||||
|
def _build_scan_settings(self, base_kwargs: dict) -> CChipScanSettingsModel:
|
||||||
|
"""Construct the SettingModel for all_settings."""
|
||||||
|
stack_params = self.create_stack_params()
|
||||||
|
return self._settings_model(
|
||||||
|
**base_kwargs,
|
||||||
|
x_count=self.x_count,
|
||||||
|
y_count=self.y_count,
|
||||||
|
style=self._grid_style,
|
||||||
|
stack_params=stack_params,
|
||||||
|
)
|
||||||
|
|
||||||
|
def pre_scan_routine(self, settings: CChipScanSettingsModel) -> None:
|
||||||
|
"""No autofocus, a looping autofocus on a CChip could corrupt the entire scan."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def acquisition_routine(
|
||||||
|
self,
|
||||||
|
settings: CChipScanSettingsModel,
|
||||||
|
xyz_pos: tuple[int, int, int], # noqa: ARG002
|
||||||
|
) -> tuple[bool, Optional[int]]:
|
||||||
|
"""Autofocus and capture a z-stack starting at the focused position.
|
||||||
|
|
||||||
|
The routine performs a fast autofocus using the provided ``dz``.
|
||||||
|
The focused z-height becomes the starting position for the stack
|
||||||
|
and is also the height of the first captured image.
|
||||||
|
|
||||||
|
A stack of ``self.stack_images_to_save`` images is then acquired.
|
||||||
|
Each subsequent image is captured after moving the stage upward
|
||||||
|
by ``self.stack_dz`` steps in z.
|
||||||
|
|
||||||
|
:param xyz_pos: The (x, y, z) position associated with this acquisition.
|
||||||
|
:param settings: The settings for this scan as a CChipSettingsModel
|
||||||
|
|
||||||
|
:return: (True, focus_height) where focus_height is the autofocus
|
||||||
|
z-position and the height of the first image in the stack.
|
||||||
|
"""
|
||||||
|
# Perform autofocus
|
||||||
|
self._autofocus.fast_autofocus(dz=settings.autofocus_params.dz)
|
||||||
|
focus_height = self._stage.get_xyz_position()[2]
|
||||||
|
self._autofocus.run_basic_stack(settings.stack_params, settings.capture_params)
|
||||||
|
|
||||||
|
return True, focus_height
|
||||||
|
|
||||||
|
@lt.property
|
||||||
|
def settings_ui(self) -> list[PropertyControl]:
|
||||||
|
"""A list of PropertyControl objects to create the settings in the scan tab."""
|
||||||
|
return [
|
||||||
|
property_control_for(self, "overlap", label="Image Overlap (0.1-0.7)"),
|
||||||
|
property_control_for(self, "x_count", label="Number of columns"),
|
||||||
|
property_control_for(self, "y_count", label="Number of rows"),
|
||||||
|
property_control_for(self, "autofocus_dz", label="Autofocus Range (steps)"),
|
||||||
|
property_control_for(
|
||||||
|
self, "stack_dz", label="Distance in z between images in stack (steps)"
|
||||||
|
),
|
||||||
|
property_control_for(
|
||||||
|
self, "stack_images_to_save", label="Images to save per xy site"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue