Fixed description and linted

This commit is contained in:
Richard Bowman 2021-02-11 15:54:58 +00:00
parent 5527c4eb7b
commit 4c27d88b37
2 changed files with 30 additions and 27 deletions

View file

@ -2,8 +2,6 @@ import logging
from contextlib import contextmanager from contextlib import contextmanager
import labthings.fields as fields import labthings.fields as fields
import numpy as np
import picamerax
from flask import abort from flask import abort
from labthings import find_component from labthings import find_component
from labthings.extensions import BaseExtension from labthings.extensions import BaseExtension
@ -13,12 +11,10 @@ from openflexure_microscope.camera.base import BaseCamera
from openflexure_microscope.microscope import Microscope from openflexure_microscope.microscope import Microscope
from .recalibrate_utils import ( from .recalibrate_utils import (
auto_expose_and_freeze_settings,
flat_lens_shading_table,
get_channel_percentiles,
recalibrate_camera,
adjust_shutter_and_gain_from_raw, adjust_shutter_and_gain_from_raw,
adjust_white_balance_from_raw, adjust_white_balance_from_raw,
flat_lens_shading_table,
get_channel_percentiles,
lst_from_camera, lst_from_camera,
) )
@ -82,11 +78,9 @@ class LSTExtension(BaseExtension):
"/auto_white_balance_from_raw", "/auto_white_balance_from_raw",
endpoint="auto_white_balance_from_raw", endpoint="auto_white_balance_from_raw",
) )
def find_microscope(): def find_microscope() -> Microscope:
"""Locate the microscope and raise a sensible error if it's missing.""" """Locate the microscope and raise a sensible error if it's missing."""
microscope = find_component("org.openflexure.microscope") microscope = find_component("org.openflexure.microscope")
@ -96,9 +90,7 @@ def find_microscope():
) )
if not hasattr(microscope.camera, "picamera"): if not hasattr(microscope.camera, "picamera"):
abort( abort(503, "The PiCamera calibration plugin requires a Raspberry Pi camera.")
503, "The PiCamera calibration plugin requires a Raspberry Pi camera."
)
return microscope return microscope
@ -106,10 +98,15 @@ def find_microscope():
class RecalibrateView(ActionView): class RecalibrateView(ActionView):
args = { args = {
"skip_auto_exposure": fields.Bool( "skip_auto_exposure": fields.Bool(
missing=False, missing=False,
description="Whether to " description=(
"By default we perform an auto-exposure and AWB "
"step before updating the lens shading table. Set "
"this argument to True to disable those steps."
),
) )
} }
def post(self, args): def post(self, args):
"""Reset the camera's settings. """Reset the camera's settings.
@ -184,8 +181,7 @@ class AutoExposureFromRawView(ActionView):
def post(self, args): def post(self, args):
camera = find_component("org.openflexure.microscope").camera.picamera camera = find_component("org.openflexure.microscope").camera.picamera
adjust_shutter_and_gain_from_raw( adjust_shutter_and_gain_from_raw(
camera, camera, **args # I'm relying on the schema to fill in missing values
**args # I'm relying on the schema to fill in missing values
) )
@ -206,8 +202,7 @@ class AutoWhiteBalanceFromRawView(ActionView):
def post(self, args): def post(self, args):
camera = find_component("org.openflexure.microscope").camera.picamera camera = find_component("org.openflexure.microscope").camera.picamera
adjust_white_balance_from_raw( adjust_white_balance_from_raw(
camera, camera, **args # I'm relying on the schema to fill in missing values
**args # I'm relying on the schema to fill in missing values
) )

View file

@ -7,6 +7,12 @@ import numpy as np
from picamerax import PiCamera from picamerax import PiCamera
from picamerax.array import PiBayerArray, PiRGBArray from picamerax.array import PiBayerArray, PiRGBArray
# I have used f strings throughout, for readability.
# The performance implication of using them in logging statements
# really doesn't matter here - also, loglevel is usually set to
# INFO to report progress via the LabThings action API
# pylint: disable=logging-fstring-interpolation
def rgb_image( def rgb_image(
camera: PiCamera, resize: Optional[Tuple[int, int]] = None, **kwargs camera: PiCamera, resize: Optional[Tuple[int, int]] = None, **kwargs
@ -66,6 +72,12 @@ def adjust_exposure_and_gain(
iterations = 0 iterations = 0
while True: while True:
iterations += 1 iterations += 1
if iterations > max_iterations:
logging.warning(
f"Auto exposure is stopping after {max_iterations} "
"but it has not converged."
)
break
with PiBayerArray(camera) as a: with PiBayerArray(camera) as a:
camera.capture(a, format="jpeg", bayer=True) camera.capture(a, format="jpeg", bayer=True)
@ -86,7 +98,7 @@ def adjust_exposure_and_gain(
f"{previous_shutter_speed} to {current_shutter_speed}" f"{previous_shutter_speed} to {current_shutter_speed}"
) )
if current_shutter_speed == previous_shutter_speed: if current_shutter_speed == previous_shutter_speed:
logging.info(f"Shutter speed has saturated, stopping.") logging.info("Shutter speed has saturated, stopping.")
break break
if max_brightness > target_white_level: if max_brightness > target_white_level:
@ -153,7 +165,6 @@ def adjust_shutter_and_gain_from_raw(
# until either the brightness is high enough, or we can't increase the # until either the brightness is high enough, or we can't increase the
# shutter speed any more. # shutter speed any more.
iterations = 0 iterations = 0
shutter_speed_maximised = False
shutter_speed_increments = [10, 2, None] shutter_speed_increments = [10, 2, None]
shutter_speed_increment = shutter_speed_increments.pop(0) shutter_speed_increment = shutter_speed_increments.pop(0)
while iterations < max_iterations: while iterations < max_iterations:
@ -202,14 +213,9 @@ def adjust_shutter_and_gain_from_raw(
if current_shutter_speed == tested_shutter_speed: if current_shutter_speed == tested_shutter_speed:
camera.analog_gain *= 2 camera.analog_gain *= 2
if camera.analog_gain == tested_analog_gain: if camera.analog_gain == tested_analog_gain:
logging.info(f"Shutter speed and gain are both maxed out. Giving up!") logging.info("Shutter speed and gain are both maxed out. Giving up!")
break break
logging.info( logging.info("Shutter speed has maxed out, doubled gain to compensate.")
f"Shutter speed has maxed out at {current_shutter_speed}, doubled gain."
)
max_brightness = np.max(get_channel_percentiles(camera, percentile))
logging.info(f"Brightness {max_brightness} after {iterations} tries.")
return max_brightness return max_brightness
@ -330,6 +336,7 @@ def lst_from_channels(channels: np.ndarray) -> np.ndarray:
lens_shading_table: np.ndarray = gains.astype(np.uint8) lens_shading_table: np.ndarray = gains.astype(np.uint8)
return lens_shading_table[::-1, :, :].copy() return lens_shading_table[::-1, :, :].copy()
def lst_from_camera(camera: PiCamera) -> np.ndarray: def lst_from_camera(camera: PiCamera) -> np.ndarray:
"""Acquire a raw image and use it to calculate a lens shading table.""" """Acquire a raw image and use it to calculate a lens shading table."""
with PiBayerArray(camera) as a: with PiBayerArray(camera) as a:
@ -343,6 +350,7 @@ def lst_from_camera(camera: PiCamera) -> np.ndarray:
channels = channels_from_bayer_array(raw_image) channels = channels_from_bayer_array(raw_image)
return lst_from_channels(channels) return lst_from_channels(channels)
def recalibrate_camera(camera: PiCamera): def recalibrate_camera(camera: PiCamera):
"""Reset the lens shading table and exposure settings. """Reset the lens shading table and exposure settings.