Blackened everything

This commit is contained in:
Joel Collins 2019-09-15 14:17:52 +01:00
parent e213647217
commit 5966ce29be
57 changed files with 1938 additions and 1414 deletions

View file

@ -1,2 +1,2 @@
__all__ = ['AutofocusPlugin']
from .plugin import AutofocusPlugin
__all__ = ["AutofocusPlugin"]
from .plugin import AutofocusPlugin

View file

@ -1,18 +1,24 @@
import numpy as np
import logging
from openflexure_microscope.devel import MicroscopeViewPlugin, JsonResponse, request, jsonify
from openflexure_microscope.devel import (
MicroscopeViewPlugin,
JsonResponse,
request,
jsonify,
)
class MeasureSharpnessAPI(MicroscopeViewPlugin):
def post(self):
payload = JsonResponse(request)
return jsonify({'sharpness': self.plugin.measure_sharpness()})
return jsonify({"sharpness": self.plugin.measure_sharpness()})
class AutofocusAPI(MicroscopeViewPlugin):
def post(self):
payload = JsonResponse(request)
# Figure out the range of z values to use
dz = payload.param("dz", default=np.linspace(-300, 300, 7), convert=np.array)
@ -22,10 +28,11 @@ class AutofocusAPI(MicroscopeViewPlugin):
# return a handle on the autofocus task
return jsonify(task.state), 202
class FastAutofocusAPI(MicroscopeViewPlugin):
def post(self):
payload = JsonResponse(request)
# Figure out the parameters to use
dz = payload.param("dz", default=2000, convert=int)
backlash = payload.param("backlash", default=0, convert=int)
@ -33,7 +40,9 @@ class FastAutofocusAPI(MicroscopeViewPlugin):
backlash = 0
logging.info("Running autofocus...")
task = self.microscope.task.start(self.plugin.fast_autofocus, dz, backlash=backlash)
task = self.microscope.task.start(
self.plugin.fast_autofocus, dz, backlash=backlash
)
# return a handle on the autofocus task
return jsonify(task.state), 202
return jsonify(task.state), 202

View file

@ -4,7 +4,8 @@ import threading
import logging
from scipy import ndimage
class JPEGSharpnessMonitor():
class JPEGSharpnessMonitor:
def __init__(self, microscope, timeout=60):
self.microscope = microscope
self.camera = microscope.camera
@ -17,32 +18,34 @@ class JPEGSharpnessMonitor():
self.timeout = timeout
self.keep_alive()
self.background_thread = None
def is_alive(self):
if self.background_thread is None:
return False
else:
return self.background_thread.is_alive()
def should_stop(self):
import time
return time.time() - self.kept_alive > self.timeout
def keep_alive(self):
import time
self.kept_alive = time.time()
def start(self):
"Start monitoring sharpness by looking at JPEG size"
self.background_thread = threading.Thread(target=self._measure_jpegs)
self.background_thread.start()
return self
def stop(self):
"Stop the background thread"
self.stop_event.set()
self.background_thread.join()
def _measure_jpegs(self):
"Function that runs in a background thread to record sharpness"
logging.info("Starting sharpness measurement in background thread")
@ -59,7 +62,6 @@ class JPEGSharpnessMonitor():
"""Return the size of a frame from the MJPEG stream"""
return len(self.camera.get_frame())
def focus_rel(self, dz, backlash=False, **kwargs):
self.keep_alive()
self.stage_times.append(time.time())
@ -69,7 +71,7 @@ class JPEGSharpnessMonitor():
self.stage_positions.append(self.stage.position)
i = len(self.stage_positions) - 2
return i, self.stage_positions[-1][2]
def move_data(self, istart, istop=None):
"Extract sharpness as a function of (interpolated) z"
global np, logging
@ -92,18 +94,21 @@ class JPEGSharpnessMonitor():
"""Return the z position of the sharpest image on a given move"""
jt, jz, js = self.move_data(index)
return jz[np.argmax(js)]
def data_dict(self):
"""Return the gathered data as a single convenient dictionary"""
data = {}
for k in ['jpeg_times', 'jpeg_sizes', 'stage_times', 'stage_positions']:
for k in ["jpeg_times", "jpeg_sizes", "stage_times", "stage_positions"]:
data[k] = getattr(self, k)
return data
def decimate_to(shape, image):
"""Decimate an image to reduce its size if it's too big."""
decimation = np.max(np.ceil(np.array(image.shape, dtype=np.float)[:len(shape)]/np.array(shape)))
return image[::int(decimation), ::int(decimation), ...]
decimation = np.max(
np.ceil(np.array(image.shape, dtype=np.float)[: len(shape)] / np.array(shape))
)
return image[:: int(decimation), :: int(decimation), ...]
def sharpness_sum_lap2(rgb_image):
@ -111,12 +116,14 @@ def sharpness_sum_lap2(rgb_image):
# image_bw=np.mean(decimate_to((1000,1000), rgb_image),2)
image_bw = np.mean(rgb_image, 2)
image_lap = ndimage.filters.laplace(image_bw)
return np.mean(image_lap.astype(np.float)**4)
return np.mean(image_lap.astype(np.float) ** 4)
def sharpness_edge(image):
"""Return a sharpness metric optimised for vertical lines"""
gray = np.mean(image.astype(float), 2)
n = 20
edge = np.array([[-1]*n + [1]*n])
return np.sum([np.sum(ndimage.filters.convolve(gray, W)**2) for W in [edge, edge.T]])
edge = np.array([[-1] * n + [1] * n])
return np.sum(
[np.sum(ndimage.filters.convolve(gray, W) ** 2) for W in [edge, edge.T]]
)

View file

@ -10,15 +10,16 @@ from .api import MeasureSharpnessAPI, AutofocusAPI, FastAutofocusAPI
from openflexure_microscope.devel import MicroscopePlugin
class AutofocusPlugin(MicroscopePlugin):
"""
Basic autofocus plugin
"""
api_views = {
'/measure_sharpness': MeasureSharpnessAPI,
'/autofocus': AutofocusAPI,
'/fast_autofocus': FastAutofocusAPI,
"/measure_sharpness": MeasureSharpnessAPI,
"/autofocus": AutofocusAPI,
"/fast_autofocus": FastAutofocusAPI,
}
### SLOW AUTOFOCUS
@ -70,21 +71,24 @@ class AutofocusPlugin(MicroscopePlugin):
m.focus_rel(dz)
return m.sharpest_z_on_move(0)
def fast_autofocus(self, dz=2000, backlash=None):
"""Perform a down-up-down-up autofocus"""
with self.monitor_sharpness() as m:
i, z = m.focus_rel(-dz/2)
i, z = m.focus_rel(-dz / 2)
i, z = m.focus_rel(dz)
fz = m.sharpest_z_on_move(i)
if backlash is None:
i, z = m.focus_rel(-dz) # move all the way to the start so it's consistent
i, z = m.focus_rel(
-dz
) # move all the way to the start so it's consistent
else:
i, z = m.focus_rel(fz - z - backlash)
m.focus_rel(fz - z)
return m.data_dict()
def fast_up_down_up_autofocus(self, dz=2000, target_z=0, initial_move_up=True, mini_backlash=150):
def fast_up_down_up_autofocus(
self, dz=2000, target_z=0, initial_move_up=True, mini_backlash=150
):
"""Autofocus by measuring on the way down, and moving back up with feedback.
This autofocus method is very efficient, as it only passes the peak once.
@ -124,32 +128,41 @@ class AutofocusPlugin(MicroscopePlugin):
# Ensure the MJPEG stream has started
self.microscope.camera.start_stream_recording()
df = dz #TODO: refactor so I actually use dz in the code below!
df = dz # TODO: refactor so I actually use dz in the code below!
if initial_move_up:
m.focus_rel(df/2)
m.focus_rel(df / 2)
# move down
i, z = m.focus_rel(-df)
# now inspect where the sharpest point is, and estimate the sharpness
# (JPEG size) that we should find at the start of the Z stack
jt, jz, js = m.move_data(i)
best_z = jz[np.argmax(js)]
target_s = np.interp([best_z+target_z], jz[::-1], js[::-1]) #NB jz is decreasing
target_s = np.interp(
[best_z + target_z], jz[::-1], js[::-1]
) # NB jz is decreasing
# now move to the start of the z stack
i, z = m.focus_rel(best_z + target_z - z + mini_backlash) # takes us to the start of the stack
i, z = m.focus_rel(
best_z + target_z - z + mini_backlash
) # takes us to the start of the stack
# We've deliberately undershot - figure out how much further we should move based on the curve
current_js = m.jpeg_size()
imax = np.argmax(js) # we want to crop out just the bit below the peak
js = js[imax:] # NB z is in DECREASING order
imax = np.argmax(js) # we want to crop out just the bit below the peak
js = js[imax:] # NB z is in DECREASING order
jz = jz[imax:]
inow = np.argmax(js < current_js) # use the curve we recorded to estimate our position
inow = np.argmax(
js < current_js
) # use the curve we recorded to estimate our position
# TODO: fancy interpolation stuff
# So, the Z position corresponding to our current sharpness value is zs[inow]
# That means we should move forwards, by best_z - zs[inow]
correction_move = best_z + target_z - jz[inow]
logging.debug("Fast autofocus scan: correcting backlash by moving {} steps".format(correction_move))
logging.debug(
"Fast autofocus scan: correcting backlash by moving {} steps".format(
correction_move
)
)
m.focus_rel(correction_move)
return m.data_dict()