More docstrings and comments. Removed json dump to openflexure folder.
This commit is contained in:
parent
4cde2d5cd1
commit
024c74f67b
1 changed files with 43 additions and 15 deletions
|
|
@ -9,12 +9,12 @@ of increasing pixel sizes in the opposite direction until motion is detected. Th
|
||||||
position is taken as the true final position.
|
position is taken as the true final position.
|
||||||
|
|
||||||
Throughout the test, parasitic motion(motion in the axis not being measured)
|
Throughout the test, parasitic motion(motion in the axis not being measured)
|
||||||
is tracked and an error is raised if it exceeds a reasonable amount.
|
is tracked and an error is raised if it exceeds a minimum amount. Currently
|
||||||
|
this is 10% of the expected motion is the measured axis.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import cv2
|
import cv2
|
||||||
import json
|
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import time
|
import time
|
||||||
|
|
@ -54,11 +54,15 @@ def _generate_move_dicts(
|
||||||
return {
|
return {
|
||||||
"x": (fov_perc / 100) * stream_resolution[0] * factor * direction,
|
"x": (fov_perc / 100) * stream_resolution[0] * factor * direction,
|
||||||
"y": (fov_perc / 100) * stream_resolution[1] * factor * direction,
|
"y": (fov_perc / 100) * stream_resolution[1] * factor * direction,
|
||||||
}
|
} # factor used for creating minimum offsets.
|
||||||
|
|
||||||
|
|
||||||
def _predict_z(
|
def _predict_z(
|
||||||
positions: list, axis: Literal["x", "y"], relative_move: float, stage: StageDep, csm: CSMDep
|
positions: list,
|
||||||
|
axis: Literal["x", "y"],
|
||||||
|
relative_move: float,
|
||||||
|
stage: StageDep,
|
||||||
|
csm: CSMDep,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""Predict the next z position for a move using previous positions.
|
"""Predict the next z position for a move using previous positions.
|
||||||
|
|
||||||
|
|
@ -67,6 +71,8 @@ def _predict_z(
|
||||||
:params axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
:params axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
||||||
:params relative_move: The move which the function is trying to predict z for.
|
:params relative_move: The move which the function is trying to predict z for.
|
||||||
Here, this is inputted with units of pixels.
|
Here, this is inputted with units of pixels.
|
||||||
|
:param stage: A direct_thing_client dependency for the the microscope stage.
|
||||||
|
:param csm: A direct_thing_client dependency for camera stage mapping.
|
||||||
:return: A number of pixels the stage needs to move in z.
|
:return: A number of pixels the stage needs to move in z.
|
||||||
"""
|
"""
|
||||||
pixel_step = {
|
pixel_step = {
|
||||||
|
|
@ -74,7 +80,7 @@ def _predict_z(
|
||||||
"y": 1 / csm.image_to_stage_displacement_matrix[1][0],
|
"y": 1 / csm.image_to_stage_displacement_matrix[1][0],
|
||||||
}
|
}
|
||||||
|
|
||||||
lateral_positions = [i[axis] for i in positions]
|
lateral_positions = [i[axis] for i in positions] # x or y positions
|
||||||
z_positions = [i["z"] for i in positions]
|
z_positions = [i["z"] for i in positions]
|
||||||
parameters, _ = curve_fit(quadratic, lateral_positions, z_positions)
|
parameters, _ = curve_fit(quadratic, lateral_positions, z_positions)
|
||||||
z_dest = quadratic(
|
z_dest = quadratic(
|
||||||
|
|
@ -101,6 +107,9 @@ def _move_and_measure(
|
||||||
:params data: The object used to track stage coordinates, correlation and delta.
|
:params data: The object used to track stage coordinates, correlation and delta.
|
||||||
:params image1: An image taken before moving to be correlated with image2.
|
:params image1: An image taken before moving to be correlated with image2.
|
||||||
:params autofocus_proc: If true, looping.autofocus will be used after the stage moves.
|
:params autofocus_proc: If true, looping.autofocus will be used after the stage moves.
|
||||||
|
:param csm: A direct_thing_client dependency for camera stage mapping.
|
||||||
|
:param autofocus: A direct_thing_client dependency for autofocus.
|
||||||
|
:param camera: A raw_thing_client depeendency for the camera.
|
||||||
:return: All required data for the next move. This includes the updated delta value and offset.
|
:return: All required data for the next move. This includes the updated delta value and offset.
|
||||||
Also returns what wrong_axis is i.e. if the direction is 'x', wrong_axis = 'y'.
|
Also returns what wrong_axis is i.e. if the direction is 'x', wrong_axis = 'y'.
|
||||||
"""
|
"""
|
||||||
|
|
@ -144,6 +153,10 @@ def _acquire_z_predict_points(
|
||||||
:param direction: The direction the stage moves.
|
:param direction: The direction the stage moves.
|
||||||
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
||||||
:params data: The object used to track stage coordinates, correlation and delta.
|
:params data: The object used to track stage coordinates, correlation and delta.
|
||||||
|
:param csm: A direct_thing_client dependency for camera stage mapping.
|
||||||
|
:param camera: A raw_thing_client depeendency for the camera.
|
||||||
|
:param stage: A raw_thing_client depeendency for the microscope stage.
|
||||||
|
:param autofocus: A direct_thing_client dependency for autofocus.
|
||||||
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
||||||
Delta is updated and tracked after each move.
|
Delta is updated and tracked after each move.
|
||||||
"""
|
"""
|
||||||
|
|
@ -154,7 +167,7 @@ def _acquire_z_predict_points(
|
||||||
for _loop in range(5):
|
for _loop in range(5):
|
||||||
image1 = cv2.resize(
|
image1 = cv2.resize(
|
||||||
np.array(Image.open(cam.grab_jpeg().open())), dsize=(0, 0), fx=1, fy=1
|
np.array(Image.open(cam.grab_jpeg().open())), dsize=(0, 0), fx=1, fy=1
|
||||||
)
|
) # Captures image with option to resize
|
||||||
offset, wrong_axis = _move_and_measure(
|
offset, wrong_axis = _move_and_measure(
|
||||||
step_size=_generate_move_dicts(medium_step, stream_resolution, direction),
|
step_size=_generate_move_dicts(medium_step, stream_resolution, direction),
|
||||||
axis=axis,
|
axis=axis,
|
||||||
|
|
@ -196,13 +209,17 @@ def _check_stage_operation(
|
||||||
:params data: The object used to track stage coordinates, correlation and delta.
|
:params data: The object used to track stage coordinates, correlation and delta.
|
||||||
:params minimum_offset_small: A dictionary containing the minimum values for
|
:params minimum_offset_small: A dictionary containing the minimum values for
|
||||||
a successful correlation.
|
a successful correlation.
|
||||||
|
:param csm: A direct_thing_client dependency for camera stage mapping.
|
||||||
|
:param camera: A raw_thing_client depeendency for the camera.
|
||||||
|
:param stage: A raw_thing_client depeendency for the microscope stage.
|
||||||
|
:param autofocus: A direct_thing_client dependency for autofocus.
|
||||||
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
||||||
Delta is updated and tracked after each move.
|
Delta is updated and tracked after each move.
|
||||||
"""
|
"""
|
||||||
failure_count = 0
|
failure_count = 0
|
||||||
wrong_axis_max_small = _generate_move_dicts(
|
wrong_axis_max_small = _generate_move_dicts(
|
||||||
small_step, stream_resolution, direction, factor=0.1
|
small_step, stream_resolution, direction, factor=0.1
|
||||||
)
|
) # Dictionary with maximum allowed parasitic motion
|
||||||
|
|
||||||
for _loop in range(3):
|
for _loop in range(3):
|
||||||
image1 = cv2.resize(
|
image1 = cv2.resize(
|
||||||
|
|
@ -220,6 +237,7 @@ def _check_stage_operation(
|
||||||
)
|
)
|
||||||
logger.info(f"Offset measured as {data.delta[axis]}")
|
logger.info(f"Offset measured as {data.delta[axis]}")
|
||||||
|
|
||||||
|
# If correlation is too small, refocuses and capture new image 3 times.
|
||||||
while (
|
while (
|
||||||
np.abs(data.delta[axis]) < np.abs(minimum_offset_small[axis])
|
np.abs(data.delta[axis]) < np.abs(minimum_offset_small[axis])
|
||||||
and failure_count < 3
|
and failure_count < 3
|
||||||
|
|
@ -272,6 +290,9 @@ def _motion_detection(
|
||||||
:params axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
:params axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
||||||
:params direction: The direction in which the stage was moving
|
:params direction: The direction in which the stage was moving
|
||||||
previous to motion detection being used.
|
previous to motion detection being used.
|
||||||
|
:param csm: A direct_thing_client dependency for camera stage mapping.
|
||||||
|
:param stage: A raw_thing_client depeendency for the microscope stage.
|
||||||
|
:param camera: A raw_thing_client depeendency for the camera.
|
||||||
:return: The stage coordinates where motion was detected.
|
:return: The stage coordinates where motion was detected.
|
||||||
"""
|
"""
|
||||||
displacements = [
|
displacements = [
|
||||||
|
|
@ -285,7 +306,7 @@ def _motion_detection(
|
||||||
128,
|
128,
|
||||||
256,
|
256,
|
||||||
512,
|
512,
|
||||||
] # Array of increasing step sizes
|
] # Array of increasing pixel sizes
|
||||||
motion_minimum = 20 # minimum number of pixels for motion to be detected
|
motion_minimum = 20 # minimum number of pixels for motion to be detected
|
||||||
|
|
||||||
this_motion_step = {"x": 0, "y": 0}
|
this_motion_step = {"x": 0, "y": 0}
|
||||||
|
|
@ -353,10 +374,14 @@ class RangeofMotionThing(lt.Thing):
|
||||||
csm: CSMDep,
|
csm: CSMDep,
|
||||||
logger: lt.deps.InvocationLogger,
|
logger: lt.deps.InvocationLogger,
|
||||||
axis: Literal["x", "y"],
|
axis: Literal["x", "y"],
|
||||||
direction: Literal[1,-1],
|
direction: Literal[1, -1],
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Measure the range of motion in a single axis and direction.
|
"""Measure the range of motion in a single axis and direction.
|
||||||
|
|
||||||
|
:param stage: A raw_thing_client depeendency for the microscope stage.
|
||||||
|
:param cam: A raw_thing_client depeendency for the camera.
|
||||||
|
:param csm: A raw_thing_client depeendency for camera stage mapping.
|
||||||
|
:param logger: A raw_thing_client depeendency for the logger.
|
||||||
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
||||||
:params direction: The direction which is being measured. This must be 1 or -1.
|
:params direction: The direction which is being measured. This must be 1 or -1.
|
||||||
:return: Results dictionary containing stage positions,
|
:return: Results dictionary containing stage positions,
|
||||||
|
|
@ -366,11 +391,10 @@ class RangeofMotionThing(lt.Thing):
|
||||||
|
|
||||||
starting_position = list(stage.position.values())
|
starting_position = list(stage.position.values())
|
||||||
|
|
||||||
rom_data = RomDataTracker()
|
rom_data = RomDataTracker() # initialise data tracking object
|
||||||
axis_results = {}
|
axis_results = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Beginning the {axis}-axis in the {'positive' if direction == 1 else 'negative'} direction"
|
f"Beginning the {axis}-axis in the {'positive' if direction == 1 else 'negative'} direction"
|
||||||
)
|
)
|
||||||
|
|
@ -482,6 +506,11 @@ class RangeofMotionThing(lt.Thing):
|
||||||
):
|
):
|
||||||
"""Measures the range of motion of the stage across the x and y axes.
|
"""Measures the range of motion of the stage across the x and y axes.
|
||||||
|
|
||||||
|
:param autofocus: A raw_thing_client dependency for autofocus.
|
||||||
|
:param stage: A raw_thing_client depeendency for the microscope stage.
|
||||||
|
:param cam: A raw_thing_client depeendency for the camera.
|
||||||
|
:param csm: A raw_thing_client depeendency for camera stage mapping.
|
||||||
|
:param logger: A raw_thing_client depeendency for the logger.
|
||||||
:return: Results dictionary separated into keys of each axis and direction.
|
:return: Results dictionary separated into keys of each axis and direction.
|
||||||
"""
|
"""
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|
@ -491,6 +520,7 @@ class RangeofMotionThing(lt.Thing):
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
rom_results = {}
|
rom_results = {}
|
||||||
|
|
||||||
|
# Loop through all axes and directions.
|
||||||
for axis_dir in [["x", 1], ["x", -1], ["y", 1], ["y", -1]]:
|
for axis_dir in [["x", 1], ["x", -1], ["y", 1], ["y", -1]]:
|
||||||
axis_dir_results = self.rom_axis(
|
axis_dir_results = self.rom_axis(
|
||||||
autofocus,
|
autofocus,
|
||||||
|
|
@ -501,6 +531,7 @@ class RangeofMotionThing(lt.Thing):
|
||||||
axis=axis_dir[0],
|
axis=axis_dir[0],
|
||||||
direction=axis_dir[1],
|
direction=axis_dir[1],
|
||||||
)
|
)
|
||||||
|
# Save results from single axis and direction
|
||||||
rom_results[f"{axis_dir}"] = axis_dir_results
|
rom_results[f"{axis_dir}"] = axis_dir_results
|
||||||
|
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
|
|
@ -515,7 +546,7 @@ class RangeofMotionThing(lt.Thing):
|
||||||
- rom_results["['y', -1]"]["final_position"]["y"]
|
- rom_results["['y', -1]"]["final_position"]["y"]
|
||||||
)
|
)
|
||||||
step_range = [x_range, y_range]
|
step_range = [x_range, y_range]
|
||||||
logger.info(f"Range of motion is {x_range} X {y_range}")
|
logger.info(f"Range of motion is {x_range} X {y_range} steps")
|
||||||
|
|
||||||
rom_results["Time"] = total_time
|
rom_results["Time"] = total_time
|
||||||
rom_results["CSM Matrix"] = csm.image_to_stage_displacement_matrix
|
rom_results["CSM Matrix"] = csm.image_to_stage_displacement_matrix
|
||||||
|
|
@ -523,9 +554,6 @@ class RangeofMotionThing(lt.Thing):
|
||||||
|
|
||||||
self.last_calibration = DenumpifyingDict(rom_results).model_dump()
|
self.last_calibration = DenumpifyingDict(rom_results).model_dump()
|
||||||
|
|
||||||
with open("/var/openflexure/ROM_Test_Results.json", "w") as file_object:
|
|
||||||
json.dump(rom_results, file_object, indent=3)
|
|
||||||
|
|
||||||
return rom_results
|
return rom_results
|
||||||
|
|
||||||
last_calibration = lt.ThingSetting(initial_value=None, model=dict, readonly=True)
|
last_calibration = lt.ThingSetting(initial_value=None, model=dict, readonly=True)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue