Combined stack and tile scans

This commit is contained in:
Joel Collins 2019-03-28 14:18:14 +00:00
parent 2cdc20b08e
commit 6237762309
2 changed files with 95 additions and 26 deletions

View file

@ -10,11 +10,12 @@ class TileScanAPI(MicroscopeViewPlugin):
# Get params
name = payload.param('name')
step_size = payload.param('step_size', default=[2000, 1500], convert=list)
grid = payload.param('grid', default=[3, 3], convert=list)
autofocus_dz = payload.param('autofocus_dz', default=20, convert=int)
step_size = payload.param('step_size', default=[2000, 1500, 100], convert=list)
grid = payload.param('grid', default=[3, 3, 5], convert=list)
style = payload.param('style', default='raster', convert=str)
autofocus_dz = payload.param('autofocus_dz', default=50, convert=int)
use_video_port = payload.param('use_video_port', default=False, convert=bool)
use_video_port = payload.param('use_video_port', default=True, convert=bool)
resize = payload.param('size', default=None)
if resize:
if ('width' in resize) and ('height' in resize):
@ -22,7 +23,7 @@ class TileScanAPI(MicroscopeViewPlugin):
else:
abort(404)
bayer = payload.param('bayer', default=True, convert=bool)
bayer = payload.param('bayer', default=False, convert=bool)
metadata = payload.param('metadata', default={}, convert=dict)
tags = payload.param('tags', default=[], convert=list)
@ -32,6 +33,7 @@ class TileScanAPI(MicroscopeViewPlugin):
basename=name,
step_size=step_size,
grid=grid,
style=style,
autofocus_dz=autofocus_dz,
use_video_port=use_video_port,
resize=resize,

View file

@ -2,12 +2,44 @@ import time
import numpy as np
from typing import Tuple
import uuid
import logging
from openflexure_microscope.camera.base import generate_basename
from openflexure_microscope.plugins import MicroscopePlugin
from .api import TileScanAPI, ZStackAPI
def construct_grid(initial, step_sizes, n_steps, style='raster'):
"""
Given an initial position, step sizes, and number of steps,
construct a 2-dimensional list of scan x-y positions.
"""
arr = []
for i in range(n_steps[0]): # x axis
arr.append([])
for j in range(n_steps[1]): # y axis
# Create a coordinate array
coord = [initial[ax] + [i, j][ax]*step_sizes[ax] for ax in range(2)]
# Append coordinate array to position grid
arr[i].append(tuple(coord))
# Style modifiers
if style == 'snake':
for i, line in enumerate(arr):
if i % 2 != 0:
line.reverse()
return arr
def flatten_grid(grid):
"""
Convert a 3D list of scan positions into a flat list
of sequential positions.
"""
grid = list(itertools.chain(*grid))
return grid
class ScanPlugin(MicroscopePlugin):
"""
@ -61,9 +93,10 @@ class ScanPlugin(MicroscopePlugin):
def tile(
self,
basename: str = None,
step_size: int = [2000, 1500],
grid: list = [3, 3],
autofocus_dz: int = 20,
step_size: int = [2000, 1500, 100],
grid: list = [3, 3, 5],
style='raster',
autofocus_dz: int = 50,
use_video_port: bool = False,
resize: Tuple[int, int] = None,
bayer: bool = False,
@ -86,17 +119,38 @@ class ScanPlugin(MicroscopePlugin):
else:
autofocus_enabled = False
xdirection = 1
# Construct an x-y grid (worry about z later)
x_y_grid = construct_grid(
initial_position,
step_size[:2],
grid[:2],
style=style
)
with self.microscope.lock:
# Now step through each point in the x-y coordinate array
for line in x_y_grid:
# If rastering, rather than snake (or eventually spiral)
if style == 'raster':
# Return focus to initial position
logging.debug("Returning to initial z position")
self.microscope.stage.move_abs([line[0][0], line[0][1], initial_position[2]])
for i in range(grid[0]):
for j in range(grid[1]):
if autofocus_enabled:
self.microscope.plugin.default_autofocus.autofocus(
range(-2 * autofocus_dz, 3 * autofocus_dz, autofocus_dz))
for x_y in line:
current_position = self.microscope.stage.position
# Move to new grid position without changing z
logging.debug("Moving to step {}".format([x_y[0], x_y[1], current_position[2]]))
self.microscope.stage.move_abs([x_y[0], x_y[1], current_position[2]])
# Refocus
if autofocus_enabled:
# TODO: Better autofocus
logging.debug("Running autofocus")
self.microscope.plugin.default_autofocus.autofocus(
range(-3 * autofocus_dz, 4 * autofocus_dz, autofocus_dz))
logging.debug("Finished autofocus")
time.sleep(1) # TODO: Remove
# If we're not doing a z-stack, just capture
if (grid[2] <= 1):
self.capture(
basename,
scan_id,
@ -106,19 +160,28 @@ class ScanPlugin(MicroscopePlugin):
metadata=metadata,
tags=tags
)
else:
logging.debug("Entering z-stack")
self.stack(
basename=basename,
scan_id=scan_id,
step_size=step_size[2],
steps=grid[2],
center=True,
use_video_port=use_video_port,
resize=resize,
bayer=bayer,
metadata=metadata,
tags=tags
)
if j != grid[0] - 1:
self.microscope.stage.move_rel([step_size[0] * xdirection, 0, 0])
xdirection *= -1
if i != grid[1] - 1:
self.microscope.stage.move_rel([256 * xdirection, step_size[1], 0])
self.microscope.stage.move_abs(initial_position)
logging.debug("Returning to {}".format(initial_position))
self.microscope.stage.move_abs(initial_position)
def stack(
self,
basename: str = None,
scan_id: str = None,
step_size: int = 100,
steps: int = 5,
center: bool = True,
@ -133,19 +196,21 @@ class ScanPlugin(MicroscopePlugin):
basename = generate_basename()
# Generate a stack ID
scan_id = uuid.uuid4().hex
if not scan_id:
scan_id = uuid.uuid4().hex
# Store initial position
initial_position = self.microscope.stage.position
# Move to center scan
if center:
logging.debug("Moving to starting position")
self.microscope.stage.move_rel([0, 0, int((-step_size * steps) / 2)])
with self.microscope.lock:
for i in range(steps):
logging.debug("Capturing...")
self.capture(
basename,
scan_id,
@ -157,6 +222,8 @@ class ScanPlugin(MicroscopePlugin):
)
if i != steps - 1:
logging.debug("Moving z by {}".format(step_size))
self.microscope.stage.move_rel([0, 0, step_size])
logging.debug("Returning to {}".format(initial_position))
self.microscope.stage.move_abs(initial_position)