From 10a49db9c9d037bfe8b7f6ae8f319c11f7c00831 Mon Sep 17 00:00:00 2001 From: jaknapper Date: Tue, 29 Jul 2025 18:29:15 +0100 Subject: [PATCH] Remove autorecentre --- ofm_config_full.json | 1 - ofm_config_simulation.json | 1 - .../things/auto_recentre_stage.py | 145 ------------------ .../navigateComponents/paneNavigate.vue | 13 -- 4 files changed, 160 deletions(-) delete mode 100644 src/openflexure_microscope_server/things/auto_recentre_stage.py diff --git a/ofm_config_full.json b/ofm_config_full.json index 98a1cbc7..7f4c4077 100644 --- a/ofm_config_full.json +++ b/ofm_config_full.json @@ -2,7 +2,6 @@ "things": { "/camera/": "openflexure_microscope_server.things.camera.picamera:StreamingPiCamera2", "/stage/": "openflexure_microscope_server.things.stage.sangaboard:SangaboardThing", - "/auto_recentre_stage/": "openflexure_microscope_server.things.auto_recentre_stage:RecentringThing", "/autofocus/": "openflexure_microscope_server.things.autofocus:AutofocusThing", "/camera_stage_mapping/": "openflexure_microscope_server.things.camera_stage_mapping:CameraStageMapper", "/system/": "openflexure_microscope_server.things.system:OpenFlexureSystem", diff --git a/ofm_config_simulation.json b/ofm_config_simulation.json index fd9dcae2..4ea1a7ec 100644 --- a/ofm_config_simulation.json +++ b/ofm_config_simulation.json @@ -2,7 +2,6 @@ "things": { "/camera/": "openflexure_microscope_server.things.camera.simulation:SimulatedCamera", "/stage/": "openflexure_microscope_server.things.stage.dummy:DummyStage", - "/auto_recentre_stage/": "openflexure_microscope_server.things.auto_recentre_stage:RecentringThing", "/autofocus/": "openflexure_microscope_server.things.autofocus:AutofocusThing", "/camera_stage_mapping/": "openflexure_microscope_server.things.camera_stage_mapping:CameraStageMapper", "/system/": "openflexure_microscope_server.things.system:OpenFlexureSystem", diff --git a/src/openflexure_microscope_server/things/auto_recentre_stage.py b/src/openflexure_microscope_server/things/auto_recentre_stage.py deleted file mode 100644 index c54270be..00000000 --- a/src/openflexure_microscope_server/things/auto_recentre_stage.py +++ /dev/null @@ -1,145 +0,0 @@ -"""Provide functionality for automatically recentring the Stage.""" - -import numpy as np -import logging - -import labthings_fastapi as lt - -from .stage import StageDependency as StageDep -from openflexure_microscope_server.things.autofocus import AutofocusThing -from openflexure_microscope_server.things.camera_stage_mapping import CameraStageMapper - -CSMDep = lt.deps.direct_thing_client_dependency( - CameraStageMapper, "/camera_stage_mapping/" -) -AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocus/") - - -class RecentringThing(lt.Thing): - """A Thing for recentring the stage by monitoring parasitic z motion of the stage. - - As the stage moves over a sphere-cap there is parasitic motion in z during xy - movement. The highest z position is the centre of motion. - """ - - @lt.thing_action - def recentre( - self, - autofocus: AutofocusDep, - stage: StageDep, - max_steps=15, - lateral_distance=5000, - ): - """Recentre the stage, based on the focal plane. - - Autofocuses at multiple points around the sample to - find the overall maximum (or minimum) height, which - corresponds to the centre of the stage. This exploits the - fact that the OpenFlexure stage moves in an arc, i.e. its - height will vary with X and Y. The point where the variation - of Z with X and Y motion is smallest is the centre of its - XY travel. This routine moves in X and Y, monitoring the - Z value of the focal plane, and attempts to find the point - where Z does not vary with X and Y, which is where it stops. - - max_steps: The maximum number of moves in x or y before - aborting due to a poorly positioned stage or hard to focus - sample - - lateral_distance: The xy distance between areas to check. - Below 3000 becomes less reliable, as focus shouldn't shift - much between these sites, making the procedure more sensitive - to noise or a failed autofocus. - """ - max_steps = 20 - dx = lateral_distance - - centre = list(stage.position.values()) - - # A list of all the positions we've focused - focused_pos = [[], []] - - autofocus.looping_autofocus() - - for direction in [0, 1]: - # Start off with the current position, and moving in the positive direction - focused_pos[direction] = [list(stage.position.values())] - moves = +1 - - stage.move_absolute(x=centre[0], y=centre[1], z=centre[2]) - steps = 0 - all_heights = [] - - # We'll run this for x, then y - while True: - # If we're moving in the positive direction, we want the highest point - # Otherwise, we want the lowest - if moves > 0: - starting_point = np.max( - np.array(focused_pos[direction])[:, direction] - ) - else: - starting_point = np.min( - np.array(focused_pos[direction])[:, direction] - ) - - # Next location is an extra move in the direction we want - destination = centre - destination[direction] = starting_point + moves * dx - stage.move_absolute( - x=int(destination[0]), y=int(destination[1]), z=destination[2] - ) - autofocus.looping_autofocus(autofocus, stage) - position = list(stage.position.values()) - focused_pos[direction].append(position) - - logging.info(focused_pos) - - steps += 1 - if steps > max_steps: - logging.warning( - "Couldn't find a suitable position. Roughly centre the stage and check your sample is suitable for autofocus" - ) - break - - if len(focused_pos[direction]) > 4: - all_heights = [x[2] for x in focused_pos[direction]] - direction_index = [x[direction] for x in focused_pos[direction]] - - sorted_all_heights = [ - x for y, x in sorted(zip(direction_index, all_heights)) - ] - - sorted_lateral = sorted(direction_index) - quad_fit = np.polyfit(sorted_lateral, sorted_all_heights, 2) - quad_fit_func = np.poly1d(quad_fit) - - turning = quad_fit_func.deriv() - - turning_loc = -turning[0] / (turning[1]) - - logging.warning(sorted_all_heights) - if ( - np.argmax(sorted_all_heights) != 0 - and np.argmax(sorted_all_heights) != len(all_heights) - 1 - ): - logging.info( - f"Breaking because the highest point is at {np.argmax(sorted_all_heights)} in the list" - ) - - break - if turning_loc < np.min(sorted_lateral): - moves = -1 - elif turning_loc > np.max(sorted_lateral): - moves = 1 - - # Centre value is replaced by the maximum value recorded in that axis - centre[direction] = focused_pos[direction][np.argmax(all_heights)][ - direction - ] - stage.move_absolute(x=centre[0], y=centre[1], z=centre[2]) - autofocus.looping_autofocus() - - logging.info(f"Centre of ROM is at {centre, stage.position['z']} \n") - - return focused_pos diff --git a/webapp/src/components/tabContentComponents/navigateComponents/paneNavigate.vue b/webapp/src/components/tabContentComponents/navigateComponents/paneNavigate.vue index 6a01545f..d52215bb 100644 --- a/webapp/src/components/tabContentComponents/navigateComponents/paneNavigate.vue +++ b/webapp/src/components/tabContentComponents/navigateComponents/paneNavigate.vue @@ -76,19 +76,6 @@ @finished="updatePosition" @error="modalError" /> -