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

Remove spline smoothing focus #621

Merged
merged 13 commits into from
Sep 24, 2018
101 changes: 49 additions & 52 deletions pocs/focuser/focuser.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import matplotlib.colors as colours
import matplotlib.pyplot as plt

Expand Down Expand Up @@ -50,9 +51,8 @@ class AbstractFocuser(PanBase):
for the merit function.
autofocus_mask_dilations (int, optional): Number of iterations of dilation to perform on the
saturated pixel mask (determine size of masked regions), default 10
autofocus_spline_smoothing (float, optional): smoothing parameter for the spline fitting to
the autofocus data, 0.0 to 1.0, smaller values mean *less* smoothing, default 0.4
"""

def __init__(self,
name='Generic Focuser',
model='simulator',
Expand All @@ -68,7 +68,6 @@ def __init__(self,
autofocus_merit_function=None,
autofocus_merit_function_kwargs=None,
autofocus_mask_dilations=None,
autofocus_spline_smoothing=None,
*args, **kwargs):
super().__init__(*args, **kwargs)

Expand Down Expand Up @@ -101,7 +100,6 @@ def __init__(self,
self.autofocus_merit_function = autofocus_merit_function
self.autofocus_merit_function_kwargs = autofocus_merit_function_kwargs
self.autofocus_mask_dilations = autofocus_mask_dilations
self.autofocus_spline_smoothing = autofocus_spline_smoothing

self._camera = camera

Expand Down Expand Up @@ -162,11 +160,11 @@ def max_position(self):
##################################################################################################

def move_to(self, position):
""" Move focusser to new encoder position """
""" Move focuser to new encoder position """
raise NotImplementedError

def move_by(self, increment):
""" Move focusser by a given amount """
""" Move focuser by a given amount """
return self.move_to(self.position + increment)

def autofocus(self,
Expand Down Expand Up @@ -222,6 +220,7 @@ def autofocus(self,
Returns:
threading.Event: Event that will be set when autofocusing is complete
"""
self.logger.debug('Starting autofocus')
assert self._camera.is_connected, self.logger.error(
"Camera must be connected for autofocus!")

Expand Down Expand Up @@ -285,35 +284,6 @@ def autofocus(self,
else:
mask_dilations = 10

if spline_smoothing is None:
if self.autofocus_spline_smoothing is not None:
spline_smoothing = self.autofocus_spline_smoothing
else:
spline_smoothing = 0.4

if take_dark:
image_dir = self.config['directories']['images']
start_time = current_time(flatten=True)
file_path = "{}/{}/{}/{}/{}.{}".format(image_dir,
'focus',
self._camera.uid,
start_time,
"dark",
self._camera.file_extension)
self.logger.debug('Taking dark frame {} on camera {}'.format(file_path, self._camera))
try:
dark_thumb = self._camera.get_thumbnail(seconds,
file_path,
thumbnail_size,
keep_file=True,
dark=True)
# Mask 'saturated' with a low threshold to remove hot pixels
dark_thumb = focus_utils.mask_saturated(dark_thumb, threshold=0.3)
except TypeError:
self.logger.warning("Camera {} does not support dark frames!".format(self._camera))
else:
dark_thumb = None

if coarse:
coarse_event = Event()
coarse_thread = Thread(target=self._autofocus,
Expand All @@ -323,7 +293,7 @@ def autofocus(self,
'focus_step': focus_step,
'thumbnail_size': thumbnail_size,
'keep_files': keep_files,
'dark_thumb': dark_thumb,
'take_dark': take_dark,
'merit_function': merit_function,
'merit_function_kwargs': merit_function_kwargs,
'mask_dilations': mask_dilations,
Expand All @@ -332,7 +302,8 @@ def autofocus(self,
'plots': plots,
'start_event': None,
'finished_event': coarse_event,
**kwargs})
**kwargs}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, start_event and finished_event are not params to autofocus(), so it is possible for them to be in **kwargs, which would cause a runtime exception.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the kwargs here is also showing as some kind of linting error in my editor although it doesn't give more information. I'll clean this up a bit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, there is nothing in the underlying _autofocus that is using either args or kwargs. I'm going to do some more cleanup.

)
coarse_thread.start()
else:
coarse_event = None
Expand All @@ -345,7 +316,7 @@ def autofocus(self,
'focus_step': focus_step,
'thumbnail_size': thumbnail_size,
'keep_files': keep_files,
'dark_thumb': dark_thumb,
'take_dark': take_dark,
'merit_function': merit_function,
'merit_function_kwargs': merit_function_kwargs,
'mask_dilations': mask_dilations,
Expand All @@ -355,6 +326,7 @@ def autofocus(self,
'start_event': coarse_event,
'finished_event': fine_event,
**kwargs})

fine_thread.start()

if blocking:
Expand All @@ -368,7 +340,7 @@ def _autofocus(self,
focus_step,
thumbnail_size,
keep_files,
dark_thumb,
take_dark,
wtgee marked this conversation as resolved.
Show resolved Hide resolved
merit_function,
merit_function_kwargs,
coarse,
Expand All @@ -379,6 +351,7 @@ def _autofocus(self,
spline_smoothing,
*args,
**kwargs):

# If passed a start_event wait until Event is set before proceeding
# (e.g. wait for coarse focus to finish before starting fine focus).
if start_event:
Expand All @@ -396,14 +369,31 @@ def _autofocus(self,
# Set up paths for temporary focus files, and plots if requested.
image_dir = self.config['directories']['images']
start_time = current_time(flatten=True)
file_path_root = "{}/{}/{}/{}".format(image_dir,
'focus',
self._camera.uid,
start_time)
file_path_root = os.path.join(image_dir,
'focus',
self._camera.uid,
start_time)

dark_thumb = None
if take_dark:
file_path = os.path.join(file_path_root, '{}.{}'.format(
'dark', self._camera.file_extension))
self.logger.debug('Taking dark frame {} on camera {}'.format(file_path, self._camera))
try:
dark_thumb = self._camera.get_thumbnail(seconds,
file_path,
thumbnail_size,
keep_file=True,
dark=True)
# Mask 'saturated' with a low threshold to remove hot pixels
dark_thumb = focus_utils.mask_saturated(dark_thumb, threshold=0.3)
except TypeError:
self.logger.warning("Camera {} does not support dark frames!".format(self._camera))

# Take an image before focusing, grab a thumbnail from the centre and add it to the plot
file_path = "{}/{}_{}.{}".format(file_path_root, initial_focus,
"initial", self._camera.file_extension)
file_path = os.path.join(file_path_root, "{}_{}.{}".format(
initial_focus, "initial", self._camera.file_extension))

thumbnail = self._camera.get_thumbnail(seconds, file_path, thumbnail_size, keep_file=True)

if plots:
Expand Down Expand Up @@ -456,7 +446,8 @@ def _autofocus(self,

for i, position in enumerate(focus_positions):
thumbnail = np.ma.array(thumbnails[i], mask=master_mask)
metric[i] = focus_utils.focus_metric(thumbnail, merit_function, **merit_function_kwargs)
metric[i] = focus_utils.focus_metric(
thumbnail, merit_function, **merit_function_kwargs)

fitted = False

Expand Down Expand Up @@ -493,14 +484,20 @@ def _autofocus(self,
fitted = True

# Guard against fitting failures, force best focus to stay within sweep range
if best_focus < focus_positions[0]:
self.logger.warning("Fitting failure: best focus {} below sweep limit {}".format(best_focus,
focus_positions[0]))
min_focus = focus_positions[0]
wtgee marked this conversation as resolved.
Show resolved Hide resolved
max_focus = focus_positions[-1]
if best_focus < min_focus:
self.logger.warning("Fitting failure: best focus {} below sweep limit {}",
best_focus,
min_focus)

best_focus = focus_positions[1]

if best_focus > focus_positions[-1]:
self.logger.warning("Fitting failure: best focus {} above sweep limit {}".format(best_focus,
focus_positions[-1]))
if best_focus > max_focus:
self.logger.warning("Fitting failure: best focus {} above sweep limit {}",
best_focus,
max_focus)

best_focus = focus_positions[-2]

else:
Expand Down