Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement O3 autofocus on light-sheet arm #48

Merged
merged 47 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
f98ebd0
adding pythonnet and drift correction
edyoshikun Jun 21, 2023
541b816
removing the pythonnet dependency that should live in copylot
edyoshikun Jun 21, 2023
e75eb99
cleanup the demo code
edyoshikun Jun 21, 2023
6e6b2f1
move drift_correction.py to examples
ieivanov Jun 30, 2023
23d9344
add copylot to dependencies
ieivanov Jun 30, 2023
2f83900
add O3 stage setup
ieivanov Jun 30, 2023
9d6a059
move serial numbers to acq_engine
ieivanov Jun 30, 2023
dd226de
rename drift_correction script
ieivanov Jun 30, 2023
7d3b0d0
add defocus stack acquisition
ieivanov Jun 30, 2023
4a805c4
style
ieivanov Jun 30, 2023
cbf624d
update examples
ieivanov Jul 1, 2023
391bf17
refactor z stage move
ieivanov Jul 1, 2023
a50cc24
Merge branch 'drift_correction' of https://github.com/czbiohub-sf/man…
ieivanov Jul 1, 2023
638f384
add galvo scanning to acquire_ls_defocus_stack
ieivanov Jul 1, 2023
5721485
Update acquire_defocus_stack.py
ieivanov Jul 1, 2023
4465b49
update examples
ieivanov Jul 7, 2023
82ad026
switch to pylablib stage and relative moves
ieivanov Jul 7, 2023
94f47b7
add some logging
ieivanov Jul 7, 2023
f143017
add KIM101 compensation
ieivanov Jul 8, 2023
a5ef657
fix galvo reset position bug
ieivanov Jul 8, 2023
276abf6
add find_focus.py example
ieivanov Jul 9, 2023
46e04de
style
ieivanov Jul 9, 2023
6372a18
ignore tests in examples dir
ieivanov Jul 10, 2023
702e8f3
move o3 refocus to acq_engine
ieivanov Jul 11, 2023
211b49d
add checks and logging
ieivanov Jul 12, 2023
b3b34e7
debug acq engine o3 refocus
ieivanov Jul 12, 2023
838e77b
update example
ieivanov Jul 12, 2023
9177c87
Create separate logs directory
ieivanov Jul 12, 2023
56a4fc4
Merge branch 'main' into drift_correction
ieivanov Jul 12, 2023
6dd197f
move conda env logger to logs
ieivanov Jul 12, 2023
1b7ed37
rename to mantis_acquisition_log
ieivanov Jul 12, 2023
136bd72
save acquired stacks
ieivanov Jul 12, 2023
106609e
implement timed o3 refocus
ieivanov Jul 13, 2023
b263cff
update kim101 calibration
ieivanov Jul 13, 2023
32d1857
add relative O3 travel limits
ieivanov Jul 13, 2023
e5a3e3a
logger fixes
ieivanov Jul 13, 2023
50ae9a1
style
ieivanov Jul 13, 2023
7c1e4e3
add waveorder to deps and format pyproject
ieivanov Jul 13, 2023
9950c50
update kim101 compensation factor
ieivanov Jul 13, 2023
04a35c6
add threshold and plotting to focus finding
ieivanov Jul 17, 2023
8b580df
update waveorder dependency
ieivanov Jul 18, 2023
f4ab651
add microscope_operations documentation
ieivanov Jul 21, 2023
badfdf6
update data structure specs
ieivanov Jul 21, 2023
b5e9766
make acquire_ls_defocus_stack MantisAcquisition static method
ieivanov Jul 21, 2023
8fbfa31
update examples
ieivanov Jul 21, 2023
1f07549
rename_kim101 example
ieivanov Jul 25, 2023
15e9ee0
rename z_range vars to avoid confusion
ieivanov Jul 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/data_structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ Organization of the raw data is constrained by the `pycromanager`-based acquisit

YYYY_MM_DD <experiment_description>
|--- <acq-name>_<n>
| |--- mantis_acquisition_log_YYYYMMDDTHHMMSS.txt
|
| |--- positions.csv
|
| |--- platemap.csv
Expand All @@ -31,6 +29,10 @@ YYYY_MM_DD <experiment_description>
| |--- <acq-name>_lightsheet_NDTiffStack_1.tif
| ...
|
| |--- logs # contains acquisition logs
| |--- mantis_acquisition_log_YYYYMMDDTHHMMSS.txt
| |--- conda_environment_log_YYYYMMDDTHHMMSS.txt
|
|--- <acq-name>_<n> # one experiment folder may contain multiple acquisitions
| ...
|
Expand All @@ -41,7 +43,7 @@ YYYY_MM_DD <experiment_description>

```

An example dataset is provided in: `//ESS/comp_micro/rawdata/mantis/2023_02_21_mantis_dataset_standard/`.
An example dataset is provided in: `//ESS/comp_micro/rawdata/mantis/2023_02_21_mantis_dataset_standard/`. (TODO: this example is now outdates)

Each acquisition will contain a PTCZYX dataset; some dimensions may be singleton.

Expand Down
48 changes: 48 additions & 0 deletions examples/acquire_defocus_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import numpy as np
from pycromanager import Core, Studio
from mantis.acquisition.microscope_operations import (
setup_kim101_stage,
acquire_ls_defocus_stack_and_display,
set_relative_kim101_position,
)
from waveorder.focus import focus_from_transverse_band

mmc = Core()
mmStudio = Studio()
z_start = -105
z_end = 105
z_step = 15
galvo = 'AP Galvo'
galvo_range = [-0.5, 0, 0.5]

z_stage = setup_kim101_stage('74000291')
z_range = np.arange(z_start, z_end + z_step, z_step)

# run 5 times over
for i in range(5):
data = acquire_ls_defocus_stack_and_display(
mmc,
mmStudio,
z_stage,
z_range,
galvo,
galvo_range,
close_display=False,
)

focus_indices = []
for stack in data:
idx = focus_from_transverse_band(
stack, NA_det=1.35, lambda_ill=0.55, pixel_size=6.5/40/1.4
)
focus_indices.append(idx)

valid_focus_indices = [idx for idx in focus_indices if idx is not None]
print(f'Valid focus indices: {valid_focus_indices}')

focus_idx = int(np.median(valid_focus_indices))
o3_displacement = int(z_range[focus_idx])
print(f'O3 displacement: {o3_displacement} steps')

set_relative_kim101_position(z_stage, o3_displacement)

71 changes: 71 additions & 0 deletions examples/calibrate_kim101.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Calibration procedure

# Image a 1 um fluorescent bead with epi illumination and LS detection. Focus O3
# on the bead. This script will defocus on one side of the bead and measure the
# image intensity. The stage calibration factor is determined from the
# difference in slope of average image intensity vs z position when traveling
# in the positive or negative direction

# This calibration procedure works alright, but could be improved

#%%
import numpy as np
from pycromanager import Core, Studio
import matplotlib.pyplot as plt
from mantis.acquisition.microscope_operations import setup_kim101_stage, acquire_ls_defocus_stack_and_display

#%%
mmc = Core()
mmStudio = Studio()
z_stage = setup_kim101_stage('74000291')

z_start = 0
z_end = 105
z_step = 15
galvo = 'AP Galvo'
galvo_range = [0]*5

z_range = np.hstack(
(
np.arange(z_start, z_end + z_step, z_step),
np.arange(z_end, z_start - z_step, -z_step)
)
)

#%%
data = acquire_ls_defocus_stack_and_display(
mmc,
mmStudio,
z_stage,
z_range,
galvo,
galvo_range,
close_display = False
)

# %%
steps_per_direction = len(z_range)//2
intensity = data.max(axis=(-1, -2))

pos_int = intensity[:, :steps_per_direction]
pos_z = z_range[:steps_per_direction]

neg_int = intensity[:, steps_per_direction:]
neg_z = z_range[steps_per_direction:]

A = np.vstack([pos_z, np.ones(len(pos_z))]).T
pos_slope = []
neg_slope = []
for i in range(len(galvo_range)):
m, c = np.linalg.lstsq(A, pos_int[i], rcond=None)[0]
pos_slope.append(m)
m, c = np.linalg.lstsq(np.flipud(A), neg_int[i], rcond=None)[0]
neg_slope.append(m)

compensation_factor = np.mean(pos_slope) / np.mean(neg_slope)
print(compensation_factor)

# %%
plt.plot(intensity.flatten())

# %%
24 changes: 24 additions & 0 deletions examples/test_find_focus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
import tifffile
import glob
import napari
import numpy as np
from waveorder.focus import focus_from_transverse_band

data_path = r'D:\2023_07_07_O3_autofocus'
dataset = 'kidney_rfp_fov0'

viewer = napari.Viewer()
files = glob.glob(os.path.join(data_path, dataset, '*.ome.tif'))

data = []
points = []
for i, file in enumerate(files):
stack = tifffile.imread(file, is_ome=False)
focus_idx = focus_from_transverse_band(stack, NA_det=1.35, lambda_ill=0.55, pixel_size=6.5/(40*1.4))
data.append(stack)
points.append([i, focus_idx, 50, 50])

viewer.add_image(np.asarray(data))
viewer.add_points(np.asarray(points), size=20)
napari.run()
34 changes: 34 additions & 0 deletions examples/test_kim101_copylot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This script tests controlling the KIM101 O3 stage using copylot. Ivan found
# that copylot control of the stage runs into errors after ~100 relative moves
# of the stage. We currently control the stage with pylablib and have not run
# into such problems

from copylot.hardware.stages.thorlabs.KIM001 import KCube_PiezoInertia
import time
from copylot import logger
# from waveorder.focus import focus_from_transverse_band


def test_labelfree_stage():
with KCube_PiezoInertia(serial_number='74000565', simulator=False) as stage_LF:
print(f'LF current position {stage_LF.position}')
stage_LF.move_relative(10)


def test_light_sheet_stage():
### LIGHT SHEET STAGE
with KCube_PiezoInertia(serial_number='74000291', simulator=False) as stage_LS:

# Change the acceleration and step rate
stage_LS.step_rate = 500
stage_LS.step_acceleration = 1000

# Test relative movement
step_size = -10
for i in range(10):
stage_LS.move_relative(10)
# stage_LS.move_relative(-step_size)


if __name__ == '__main__':
test_light_sheet_stage()
15 changes: 15 additions & 0 deletions examples/test_kim101_pylablib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from pylablib.devices import Thorlabs
devices = Thorlabs.list_kinesis_devices()

stage = Thorlabs.KinesisPiezoMotor('74000291')

p = stage.get_position()
for i in range(50):
# stage.move_to(p+25); stage.wait_move()
# stage.move_to(p-25); stage.wait_move()

# relative moves work better
stage.move_by(25); stage.wait_move()
stage.move_by(-25); stage.wait_move()

print('done')
3 changes: 3 additions & 0 deletions mantis/acquisition/AcquisitionSettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,6 @@ class MicroscopeSettings:
use_autofocus: bool = False
autofocus_stage: Optional[str] = None
autofocus_method: Optional[str] = None
use_o3_refocus: bool = False
o3_refocus_config: Optional[ConfigSettings] = None
o3_refocus_interval_min: Optional[int] = None
Loading