Moved hardware config to a runtime config YAML file in home
This commit is contained in:
parent
7a58b4e95e
commit
3925ef8cfe
10 changed files with 182 additions and 146 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
__all__ = ['Microscope']
|
__all__ = ['Microscope', 'config']
|
||||||
__version__ = "0.1.0"
|
__version__ = "0.1.0"
|
||||||
|
|
||||||
from .microscope import Microscope
|
from .microscope import Microscope
|
||||||
|
from . import config
|
||||||
|
|
@ -261,7 +261,7 @@ class PositionAPI(MicroscopeView):
|
||||||
return jsonify(self.microscope.state['position'])
|
return jsonify(self.microscope.state['position'])
|
||||||
|
|
||||||
app.add_url_rule(
|
app.add_url_rule(
|
||||||
uri('/position/'),
|
uri('/position/'),
|
||||||
view_func=PositionAPI.as_view('position', microscope=api_microscope))
|
view_func=PositionAPI.as_view('position', microscope=api_microscope))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
import yaml
|
|
||||||
|
|
||||||
TYPES = {
|
|
||||||
'stream_resolution': tuple,
|
|
||||||
'video_resolution': tuple,
|
|
||||||
'image_resolution': tuple,
|
|
||||||
'numpy_resolution': tuple,
|
|
||||||
'jpeg_quality': int,
|
|
||||||
'framerate': int,
|
|
||||||
'awb_mode': str,
|
|
||||||
'red_gain': float,
|
|
||||||
'blue_gain': float,
|
|
||||||
'shutter_speed': int,
|
|
||||||
'saturation': int,
|
|
||||||
'analog_gain': float,
|
|
||||||
'digital_gain': float,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def convert_config(config: dict) -> dict:
|
|
||||||
"""Convert datatype of config based on type dictionary."""
|
|
||||||
global TYPES
|
|
||||||
|
|
||||||
for key in config:
|
|
||||||
if key in TYPES:
|
|
||||||
config[key] = TYPES[key](config[key])
|
|
||||||
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(yaml_path: str) -> dict:
|
|
||||||
"""Load YAML file, pass through dictionary conversion, and return."""
|
|
||||||
with open(yaml_path) as config_file:
|
|
||||||
return yaml.load(config_file)
|
|
||||||
|
|
||||||
|
|
||||||
def save_config(config: dict, yaml_path: str):
|
|
||||||
with open('yaml_path', 'w') as outfile:
|
|
||||||
yaml.dump(config, outfile)
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
# Exposure mode
|
|
||||||
exposure_mode: 'off'
|
|
||||||
|
|
||||||
# The analog gain offers higher sensitivity and less noise than using digital gain only
|
|
||||||
analog_gain: 1.
|
|
||||||
digital_gain: 1.
|
|
||||||
|
|
||||||
# When queried, the shutter_speed property returns the shutter speed of the camera in microseconds,
|
|
||||||
# or 0 which indicates that the speed will be automatically determined.
|
|
||||||
# If high value does not work, need to decrease the fps for streaming
|
|
||||||
shutter_speed: 30000
|
|
||||||
|
|
||||||
# Auto white balance: The red and blue values are returned Fraction instances.
|
|
||||||
# The values will be between 0.0 and 8.0.
|
|
||||||
awb_mode: 'off'
|
|
||||||
|
|
||||||
# If not using auto, then you can change the awb_gains
|
|
||||||
red_gain: 1.3
|
|
||||||
blue_gain: 1.2
|
|
||||||
|
|
||||||
# Color saturation of the camera as an integer between -100 and 100.
|
|
||||||
saturation: 0
|
|
||||||
|
|
||||||
# ISO Valid values are between 0 (auto) and 800 (1600 is not available?).
|
|
||||||
# ISO value is not used anyway as we are fixing the gains
|
|
||||||
iso: 500
|
|
||||||
|
|
||||||
# Resolutions for streaming and capture
|
|
||||||
video_resolution: [832, 624]
|
|
||||||
image_resolution: [2592, 1944]
|
|
||||||
numpy_resolution: [1312, 976]
|
|
||||||
|
|
||||||
# Capture quality
|
|
||||||
jpeg_quality: 75
|
|
||||||
framerate: 24
|
|
||||||
|
|
@ -47,21 +47,27 @@ import threading
|
||||||
from .base import BaseCamera, StreamObject
|
from .base import BaseCamera, StreamObject
|
||||||
# Richard's fix gain
|
# Richard's fix gain
|
||||||
from .set_picamera_gain import set_analog_gain, set_digital_gain
|
from .set_picamera_gain import set_analog_gain, set_digital_gain
|
||||||
# Manage config
|
|
||||||
from .config import load_config, save_config, convert_config
|
|
||||||
|
|
||||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
|
||||||
DEFAULT_CONFIG_PATH = os.path.join(HERE, 'config_picamera.yaml')
|
|
||||||
|
|
||||||
|
|
||||||
class StreamingCamera(BaseCamera):
|
class StreamingCamera(BaseCamera):
|
||||||
"""Raspberry Pi camera implementation of StreamingCamera."""
|
"""Raspberry Pi camera implementation of StreamingCamera.
|
||||||
def __init__(self):
|
|
||||||
|
Args:
|
||||||
|
config (dict): Dictionary of config parameters to apply on init. If None, will default to basic config.
|
||||||
|
"""
|
||||||
|
def __init__(self, config: dict=None):
|
||||||
# Run BaseCamera init
|
# Run BaseCamera init
|
||||||
BaseCamera.__init__(self)
|
BaseCamera.__init__(self)
|
||||||
# Attach to Pi camera
|
# Attach to Pi camera
|
||||||
self.camera = picamera.PiCamera() #: :py:class:`picamera.PiCamera`: Picamera object
|
self.camera = picamera.PiCamera() #: :py:class:`picamera.PiCamera`: Picamera object
|
||||||
|
|
||||||
|
# Store state of StreamingCamera
|
||||||
|
self.state.update({
|
||||||
|
'stream_active': False,
|
||||||
|
'record_active': False,
|
||||||
|
'preview_active': False,
|
||||||
|
})
|
||||||
|
|
||||||
# Default camera config
|
# Default camera config
|
||||||
self.config.update({
|
self.config.update({
|
||||||
'video_resolution': (832, 624),
|
'video_resolution': (832, 624),
|
||||||
|
|
@ -70,13 +76,11 @@ class StreamingCamera(BaseCamera):
|
||||||
'jpeg_quality': 75,
|
'jpeg_quality': 75,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Store state of StreamingCamera
|
# Load config dictionary if passed
|
||||||
self.state.update({
|
if config:
|
||||||
'stream_active': False,
|
self.update_settings(config)
|
||||||
'record_active': False,
|
|
||||||
'preview_active': False,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
# Start streaming
|
||||||
self.start_worker()
|
self.start_worker()
|
||||||
|
|
||||||
def initialisation(self):
|
def initialisation(self):
|
||||||
|
|
@ -91,74 +95,82 @@ class StreamingCamera(BaseCamera):
|
||||||
if self.camera:
|
if self.camera:
|
||||||
self.camera.close()
|
self.camera.close()
|
||||||
|
|
||||||
|
|
||||||
# HANDLE SETTINGS
|
# HANDLE SETTINGS
|
||||||
def load_config(self, config_path: str=None):
|
@property
|
||||||
|
def supports_lens_shading(self):
|
||||||
|
"""Determine whether the picamera module supports lens shading.
|
||||||
|
|
||||||
|
As of March 2018, picamera did not wrap the necessary MMAL commands to
|
||||||
|
set the lens shading table, or to write the value of analog or digital
|
||||||
|
gain. I have a forked version of the library that does support these.
|
||||||
|
For ease of use by people who don't want those features, this library
|
||||||
|
does not have a hard dependency on lens shading. However, we need to
|
||||||
|
check in some places whether it's available.
|
||||||
"""
|
"""
|
||||||
Open config_picamera.yaml file and write to camera.
|
return hasattr(self.camera, "lens_shading_table")
|
||||||
|
|
||||||
Args:
|
def update_lens_shading(self, shading_array: np.ndarray):
|
||||||
config_path (str): Path to the config YAML file. If `None`, defaults to `DEFAULT_CONFIG_PATH`
|
if not self.supports_lens_shading:
|
||||||
"""
|
logging.error("the currently-installed picamera library does not support all "
|
||||||
global DEFAULT_CONFIG_PATH
|
"the features of the openflexure microscope software. These features "
|
||||||
if not config_path:
|
"include lens shading control and setting the analog/digital gain.\n"
|
||||||
config_data = load_config(DEFAULT_CONFIG_PATH)
|
"\n"
|
||||||
else:
|
"See the installation instructions for how to fix this:\n"
|
||||||
config_data = load_config(config_path)
|
"https://github.com/rwb27/openflexure_microscope_software")
|
||||||
|
|
||||||
self.update_settings(config_data)
|
|
||||||
|
|
||||||
def save_config(self, config_path: str=None):
|
|
||||||
"""
|
|
||||||
Save current config dictionary to a YAML file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
config_path (str): Path to the config YAML file. If `None`, defaults to `DEFAULT_CONFIG_PATH`
|
|
||||||
"""
|
|
||||||
global DEFAULT_CONFIG_PATH
|
|
||||||
if not config_path:
|
|
||||||
config_path = DEFAULT_CONFIG_PATH
|
|
||||||
|
|
||||||
save_config(self.config, config_path)
|
|
||||||
|
|
||||||
def update_settings(self, config: dict) -> None:
|
def update_settings(self, config: dict) -> None:
|
||||||
"""
|
"""
|
||||||
Write a config dictionary to the StreamingCamera config.
|
Write a config dictionary to the StreamingCamera config.
|
||||||
|
|
||||||
|
The passed dictionary may contain other parameters not relevant to
|
||||||
|
camera config. Eg. Passing a general config file will work fine.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config (dict): Dictionary of config parameters.
|
config (dict): Dictionary of config parameters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.config = convert_config(config) # Convert loaded dictionary to valid config dictionary
|
|
||||||
logging.debug(self.config)
|
|
||||||
|
|
||||||
paused_stream = False
|
paused_stream = False
|
||||||
|
|
||||||
# Apply valid config params to Picamera object
|
# Apply valid config params to Picamera object
|
||||||
if not self.state['record_active']: # If not recording a video
|
if not self.state['record_active']: # If not recording a video
|
||||||
|
|
||||||
|
logging.debug("Applying config:")
|
||||||
|
logging.debug(config)
|
||||||
|
|
||||||
|
# Pause stream while changing settings
|
||||||
if self.state['stream_active']: # If stream is active
|
if self.state['stream_active']: # If stream is active
|
||||||
logging.info("Pausing stream to update config.")
|
logging.info("Pausing stream to update config.")
|
||||||
self.pause_stream_for_capture() # Pause stream
|
self.pause_stream_for_capture() # Pause stream
|
||||||
paused_stream = True # Remember to unpause stream when done
|
paused_stream = True # Remember to unpause stream when done
|
||||||
|
|
||||||
# Camera AWB
|
# PiCamera parameters (applied directly to PiCamera object)
|
||||||
if 'awb_mode' in config:
|
picamera_keys = [
|
||||||
self.camera.awb_mode = config['awb_mode']
|
'exposure_mode',
|
||||||
if 'red_gain' in config and 'blue_gain' in config:
|
'awb_mode',
|
||||||
self.camera.awb_gains = (
|
'awb_gains',
|
||||||
config['red_gain'],
|
'framerate',
|
||||||
config['blue_gain'])
|
'shutter_speed',
|
||||||
|
'saturation',
|
||||||
|
'led'
|
||||||
|
]
|
||||||
|
if 'picamera_params' in config:
|
||||||
|
for key in picamera_keys:
|
||||||
|
if key in config['picamera_params']:
|
||||||
|
logging.debug("Setting parameter {}: {}".format(key, config['picamera_params'][key]))
|
||||||
|
setattr(self.camera, key, config['picamera_params'][key])
|
||||||
|
|
||||||
|
# StreamingCamera parameters (applied via StreamingCamera config)
|
||||||
|
config_keys = [
|
||||||
|
'video_resolution',
|
||||||
|
'image_resolution',
|
||||||
|
'numpy_resolution',
|
||||||
|
'jpeg_quality', ]
|
||||||
|
|
||||||
|
for key in config_keys:
|
||||||
|
if key in config:
|
||||||
|
logging.debug("Setting parameter {}: {}".format(key, config[key]))
|
||||||
|
self.config[key] = config[key]
|
||||||
|
|
||||||
# Camera framerate
|
|
||||||
if 'framerate' in config:
|
|
||||||
self.camera.framerate = config['framerate']
|
|
||||||
# Camera exposure
|
|
||||||
if 'shutter_speed' in config:
|
|
||||||
self.camera.shutter_speed = config['shutter_speed']
|
|
||||||
if 'saturation' in config:
|
|
||||||
self.camera.saturation = config['saturation']
|
|
||||||
# Camera misc.
|
|
||||||
self.camera.led = False
|
|
||||||
# Richard's library to set analog and digital gains
|
# Richard's library to set analog and digital gains
|
||||||
if 'analog_gain' in config:
|
if 'analog_gain' in config:
|
||||||
set_analog_gain(self.camera, config['analog_gain'])
|
set_analog_gain(self.camera, config['analog_gain'])
|
||||||
|
|
@ -464,8 +476,6 @@ class StreamingCamera(BaseCamera):
|
||||||
|
|
||||||
self.wait_for_camera()
|
self.wait_for_camera()
|
||||||
|
|
||||||
# Load config file
|
|
||||||
self.load_config()
|
|
||||||
# Set stream resolution
|
# Set stream resolution
|
||||||
self.camera.resolution = self.config['video_resolution']
|
self.camera.resolution = self.config['video_resolution']
|
||||||
|
|
||||||
|
|
@ -490,7 +500,7 @@ class StreamingCamera(BaseCamera):
|
||||||
self.stream.seek(0)
|
self.stream.seek(0)
|
||||||
self.stream.truncate()
|
self.stream.truncate()
|
||||||
# to stream, read the new frame
|
# to stream, read the new frame
|
||||||
time.sleep(1/self.config['framerate']*0.1)
|
time.sleep(1/self.camera.framerate*0.1)
|
||||||
# yield the result to be read
|
# yield the result to be read
|
||||||
frame = self.stream.getvalue()
|
frame = self.stream.getvalue()
|
||||||
|
|
||||||
|
|
|
||||||
71
openflexure_microscope/config.py
Normal file
71
openflexure_microscope/config.py
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import yaml
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
DEFAULT_CONFIG_PATH = os.path.join(HERE, 'openflexurerc.default.yaml')
|
||||||
|
USER_CONFIG_PATH = os.path.join(os.path.expanduser("~"), "openflexurerc.yaml")
|
||||||
|
|
||||||
|
TYPES = {
|
||||||
|
'stream_resolution': tuple,
|
||||||
|
'video_resolution': tuple,
|
||||||
|
'image_resolution': tuple,
|
||||||
|
'numpy_resolution': tuple,
|
||||||
|
'jpeg_quality': int,
|
||||||
|
'analog_gain': float,
|
||||||
|
'digital_gain': float,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def convert_config(config: dict) -> dict:
|
||||||
|
"""Convert datatype of config based on type dictionary."""
|
||||||
|
global TYPES
|
||||||
|
|
||||||
|
for key in config:
|
||||||
|
if key in TYPES:
|
||||||
|
config[key] = TYPES[key](config[key])
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def load_config(config_path: str=None) -> dict:
|
||||||
|
"""
|
||||||
|
Open openflexurerc.yaml file and write to the microscope devices.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_path (str): Path to the config YAML file. If `None`, defaults to `DEFAULT_CONFIG_PATH`
|
||||||
|
"""
|
||||||
|
global DEFAULT_CONFIG_PATH, USER_CONFIG_PATH
|
||||||
|
|
||||||
|
if not config_path:
|
||||||
|
if os.path.exists(USER_CONFIG_PATH): # If user config file already exists
|
||||||
|
config_path = USER_CONFIG_PATH # Load it
|
||||||
|
else: # If user config file doesn't yet exist
|
||||||
|
logging.warning("No user config found. Loading system defaults...")
|
||||||
|
logging.info("Copying default config to user config...")
|
||||||
|
shutil.copyfile(DEFAULT_CONFIG_PATH, USER_CONFIG_PATH)
|
||||||
|
logging.info("Loading user config...")
|
||||||
|
config_path = USER_CONFIG_PATH # Load defaults in
|
||||||
|
|
||||||
|
with open(config_path) as config_file:
|
||||||
|
config_data = yaml.load(config_file)
|
||||||
|
|
||||||
|
# Store config dictionary to self
|
||||||
|
return convert_config(config_data)
|
||||||
|
|
||||||
|
|
||||||
|
def save_config(self, config_dict: dict, config_path: str=None):
|
||||||
|
"""
|
||||||
|
Save current config dictionary to a YAML file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_dict (dict): Dictionary of config data to save.
|
||||||
|
config_path (str): Path to the config YAML file. If `None`, defaults to `DEFAULT_CONFIG_PATH`
|
||||||
|
"""
|
||||||
|
global USER_CONFIG_PATH
|
||||||
|
if not config_path:
|
||||||
|
config_path = USER_CONFIG_PATH
|
||||||
|
|
||||||
|
with open(config_path, 'w') as outfile:
|
||||||
|
yaml.dump(config_dict, outfile)
|
||||||
|
|
@ -3,12 +3,14 @@
|
||||||
Defines a microscope object, binding a camera and stage with basic functionality.
|
Defines a microscope object, binding a camera and stage with basic functionality.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from openflexure_stage import OpenFlexureStage
|
from openflexure_stage import OpenFlexureStage
|
||||||
from .camera.pi import StreamingCamera
|
from .camera.pi import StreamingCamera
|
||||||
|
|
||||||
from .plugins import PluginMount, load_plugin, search_plugin_paths
|
from .plugins import PluginMount, load_plugin, search_plugin_dirs
|
||||||
|
from .config import load_config, save_config, convert_config
|
||||||
|
|
||||||
|
|
||||||
class Microscope(object):
|
class Microscope(object):
|
||||||
|
|
@ -20,8 +22,11 @@ class Microscope(object):
|
||||||
Args:
|
Args:
|
||||||
camera (:py:class:`openflexure_microscope.camera.pi.StreamingCamera`): camera object
|
camera (:py:class:`openflexure_microscope.camera.pi.StreamingCamera`): camera object
|
||||||
microscope (:py:class:`openflexure_stage.stage.OpenFlexureStage`): stage object
|
microscope (:py:class:`openflexure_stage.stage.OpenFlexureStage`): stage object
|
||||||
|
load_config (bool): Should a config file be automatically loaded on init?
|
||||||
|
config_path (str): Path to the config YAML file to be loaded. If None, defaults to USER_CONFIG_PATH.
|
||||||
"""
|
"""
|
||||||
def __init__(self, camera: StreamingCamera, stage: OpenFlexureStage):
|
def __init__(self, camera: StreamingCamera, stage: OpenFlexureStage):
|
||||||
|
|
||||||
self.attach(camera, stage)
|
self.attach(camera, stage)
|
||||||
|
|
||||||
# Create plugin mountpoint
|
# Create plugin mountpoint
|
||||||
|
|
@ -40,7 +45,7 @@ class Microscope(object):
|
||||||
self.camera.close()
|
self.camera.close()
|
||||||
self.stage.close()
|
self.stage.close()
|
||||||
|
|
||||||
def attach(self, camera: StreamingCamera, stage: OpenFlexureStage):
|
def attach(self, camera: StreamingCamera, stage: OpenFlexureStage, apply_config: bool=True):
|
||||||
"""
|
"""
|
||||||
Retroactively attaches a camera and stage to the microscope object.
|
Retroactively attaches a camera and stage to the microscope object.
|
||||||
|
|
||||||
|
|
@ -50,6 +55,7 @@ class Microscope(object):
|
||||||
Args:
|
Args:
|
||||||
camera (:py:class:`openflexure_microscope.camera.pi.StreamingCamera`): camera object
|
camera (:py:class:`openflexure_microscope.camera.pi.StreamingCamera`): camera object
|
||||||
microscope (:py:class:`openflexure_stage.stage.OpenFlexureStage`): stage object
|
microscope (:py:class:`openflexure_stage.stage.OpenFlexureStage`): stage object
|
||||||
|
apply_config (bool): Should the microscope config dictionary be applied to the attached hardware?
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.camera = camera #: :py:class:`openflexure_microscope.camera.pi.StreamingCamera`: Picamera object
|
self.camera = camera #: :py:class:`openflexure_microscope.camera.pi.StreamingCamera`: Picamera object
|
||||||
|
|
@ -69,7 +75,8 @@ class Microscope(object):
|
||||||
plugin_paths (list): List of strings of plugin directories.
|
plugin_paths (list): List of strings of plugin directories.
|
||||||
include_default (bool): Also load plugins from the module default directory (DEFAULT_PLUGIN_PATH)
|
include_default (bool): Also load plugins from the module default directory (DEFAULT_PLUGIN_PATH)
|
||||||
"""
|
"""
|
||||||
plugins_list = search_plugin_paths(plugin_paths, include_default=include_default)
|
# TODO: Get paths from rc file
|
||||||
|
plugins_list = search_plugin_dirs(plugin_paths, include_default=include_default)
|
||||||
|
|
||||||
for i in plugins_list:
|
for i in plugins_list:
|
||||||
module = load_plugin(i)
|
module = load_plugin(i)
|
||||||
|
|
|
||||||
20
openflexure_microscope/openflexurerc.default.yaml
Normal file
20
openflexure_microscope/openflexurerc.default.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# The analog gain offers higher sensitivity and less noise than using digital gain only
|
||||||
|
analog_gain: 1.
|
||||||
|
digital_gain: 1.
|
||||||
|
|
||||||
|
# Resolutions for streaming and capture
|
||||||
|
video_resolution: [832, 624]
|
||||||
|
image_resolution: [2592, 1944]
|
||||||
|
numpy_resolution: [1312, 976]
|
||||||
|
|
||||||
|
# Capture quality
|
||||||
|
jpeg_quality: 75
|
||||||
|
|
||||||
|
picamera_params:
|
||||||
|
exposure_mode: 'off'
|
||||||
|
awb_mode: 'off'
|
||||||
|
awb_gains: [1.3, 1.2]
|
||||||
|
framerate: 24
|
||||||
|
shutter_speed: 30000
|
||||||
|
saturation: 0
|
||||||
|
led: false
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
-e git://github.com/rwb27/openflexure_nano_motor_controller.git#egg=openflexure_stage
|
-e git://github.com/rwb27/openflexure_nano_motor_controller.git#egg=openflexure_stage
|
||||||
|
-e git://github.com/rwb27/picamera.git#egg=picamera
|
||||||
|
|
||||||
flask >= 0.12.3
|
flask >= 0.12.3
|
||||||
picamera==1.13
|
|
||||||
pyyaml==3.13
|
pyyaml==3.13
|
||||||
numpy
|
numpy
|
||||||
Pillow
|
Pillow
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from openflexure_microscope.camera.pi import StreamingCamera
|
from openflexure_microscope.camera.pi import StreamingCamera
|
||||||
from openflexure_stage import OpenFlexureStage
|
from openflexure_stage import OpenFlexureStage
|
||||||
from openflexure_microscope import Microscope
|
from openflexure_microscope import Microscope, config
|
||||||
from openflexure_microscope.plugins import PluginMount, load_plugin, search_plugin_paths
|
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import logging, sys
|
import logging, sys
|
||||||
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
microscope = Microscope(StreamingCamera(), OpenFlexureStage("/dev/ttyUSB0"))
|
openflexurerc = config.load_config()
|
||||||
|
|
||||||
|
microscope = Microscope(StreamingCamera(openflexurerc), OpenFlexureStage("/dev/ttyUSB0"))
|
||||||
|
|
||||||
microscope.find_plugins() # Automatically find microscope plugins
|
microscope.find_plugins() # Automatically find microscope plugins
|
||||||
|
|
||||||
|
|
@ -18,4 +19,4 @@ if __name__ == '__main__':
|
||||||
microscope.plugin.test1.run()
|
microscope.plugin.test1.run()
|
||||||
microscope.plugin.test2.run()
|
microscope.plugin.test2.run()
|
||||||
|
|
||||||
microscope.close()
|
microscope.close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue