Included Richards autofocus plugin in defaults
This commit is contained in:
parent
cc36aa7593
commit
d7e19c40e2
3 changed files with 84 additions and 6 deletions
|
|
@ -1,6 +1,9 @@
|
||||||
from openflexure_microscope.api.v1.views import MicroscopeViewPlugin
|
import numpy as np
|
||||||
|
|
||||||
from flask import request, Response, escape
|
from openflexure_microscope.api.v1.views import MicroscopeViewPlugin
|
||||||
|
from openflexure_microscope.api.utilities import JsonPayload
|
||||||
|
|
||||||
|
from flask import request, Response, escape, jsonify
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
@ -17,3 +20,21 @@ class IdentifyAPI(MicroscopeViewPlugin):
|
||||||
"""
|
"""
|
||||||
data = self.microscope.plugin.default.identify() # Call a method from our plugin, using the full route
|
data = self.microscope.plugin.default.identify() # Call a method from our plugin, using the full route
|
||||||
return Response(escape(data))
|
return Response(escape(data))
|
||||||
|
|
||||||
|
class MeasureSharpnessAPI(MicroscopeViewPlugin):
|
||||||
|
def post(self):
|
||||||
|
payload = JsonPayload(request)
|
||||||
|
return jsonify({'sharpness': self.plugin.measure_sharpness()})
|
||||||
|
|
||||||
|
class AutofocusAPI(MicroscopeViewPlugin):
|
||||||
|
def post(self):
|
||||||
|
payload = JsonPayload(request)
|
||||||
|
|
||||||
|
# Figure out the range of z values to use
|
||||||
|
dz = payload.param("dz", default=np.linspace(-300,300,7), convert=np.array)
|
||||||
|
|
||||||
|
print("Running autofocus...")
|
||||||
|
task = self.microscope.task.start(self.plugin.autofocus, dz)
|
||||||
|
|
||||||
|
# return a handle on the autofocus task
|
||||||
|
return jsonify(task.state, 202)
|
||||||
|
|
|
||||||
21
openflexure_microscope/plugins/default/focus_utils.py
Normal file
21
openflexure_microscope/plugins/default/focus_utils.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import numpy as np
|
||||||
|
from scipy import ndimage
|
||||||
|
|
||||||
|
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), ...]
|
||||||
|
|
||||||
|
def sharpness_sum_lap2(rgb_image):
|
||||||
|
"""Return an image sharpness metric: sum(laplacian(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)
|
||||||
|
|
||||||
|
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]])
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
from openflexure_microscope.plugins import MicroscopePlugin
|
import time
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
from .api import IdentifyAPI
|
from openflexure_microscope.plugins import MicroscopePlugin
|
||||||
|
from openflexure_microscope.utilities import set_properties
|
||||||
|
|
||||||
|
from .focus_utils import sharpness_sum_lap2
|
||||||
|
from .api import IdentifyAPI, MeasureSharpnessAPI, AutofocusAPI
|
||||||
|
|
||||||
|
|
||||||
class Plugin(MicroscopePlugin):
|
class Plugin(MicroscopePlugin):
|
||||||
|
|
@ -10,6 +15,8 @@ class Plugin(MicroscopePlugin):
|
||||||
|
|
||||||
api_views = {
|
api_views = {
|
||||||
'/identify': IdentifyAPI,
|
'/identify': IdentifyAPI,
|
||||||
|
'/measure_sharpness': MeasureSharpnessAPI,
|
||||||
|
'/autofocus': AutofocusAPI,
|
||||||
}
|
}
|
||||||
|
|
||||||
def identify(self):
|
def identify(self):
|
||||||
|
|
@ -18,5 +25,34 @@ class Plugin(MicroscopePlugin):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
response = "My parent camera is {}, and my parent stage is {}.".format(self.microscope.camera, self.microscope.stage)
|
response = "My parent camera is {}, and my parent stage is {}.".format(self.microscope.camera, self.microscope.stage)
|
||||||
print(response)
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def autofocus(self, dz, settle=0.5, metric_fn=sharpness_sum_lap2):
|
||||||
|
"""Perform a simple autofocus routine.
|
||||||
|
The stage is moved to z positions (relative to current position) in dz,
|
||||||
|
and at each position an image is captured and the sharpness function
|
||||||
|
evaulated. We then move back to the position where the sharpness was
|
||||||
|
highest. No interpolation is performed.
|
||||||
|
dz is assumed to be in ascending order (starting at -ve values)
|
||||||
|
"""
|
||||||
|
camera = self.microscope.camera
|
||||||
|
stage = self.microscope.stage
|
||||||
|
|
||||||
|
with set_properties(stage, backlash=256), stage.lock, camera.lock:
|
||||||
|
sharpnesses = []
|
||||||
|
positions = []
|
||||||
|
camera.annotate_text = ""
|
||||||
|
|
||||||
|
for i in stage.scan_z(dz, return_to_start=False):
|
||||||
|
positions.append(stage.position[2])
|
||||||
|
time.sleep(settle)
|
||||||
|
sharpnesses.append(self.measure_sharpness(metric_fn))
|
||||||
|
|
||||||
|
newposition = positions[np.argmax(sharpnesses)]
|
||||||
|
stage.focus_rel(newposition - stage.position[2])
|
||||||
|
|
||||||
|
return positions, sharpnesses
|
||||||
|
|
||||||
|
def measure_sharpness(self, metric_fn=sharpness_sum_lap2):
|
||||||
|
"""Measure the sharpness of the camera's current view."""
|
||||||
|
return metric_fn(self.microscope.camera.array(use_video_port=True, resize=(640,480)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue