Loading openflexure_microscope/camera/base.py +1 −1 Original line number Diff line number Diff line Loading @@ -97,7 +97,7 @@ class BaseCamera(object): self.event = CameraEvent() self.state = {} #: dict: Dictionary for capture state self.settings = {} #: dict: Dictionary of camera settings self.config = {} #: dict: Dictionary of camera settings self.paths = { 'image': BASE_CAPTURE_PATH, 'video': BASE_CAPTURE_PATH, Loading openflexure_microscope/camera/config.py +9 −4 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ TYPES = { } def convert_config(config): def convert_config(config: dict) -> dict: """Convert datatype of config based on type dictionary.""" global TYPES Loading @@ -28,7 +28,12 @@ def convert_config(config): return config def load_config(yaml_path): def load_config(yaml_path: str) -> dict: """Load YAML file, pass through dictionary conversion, and return.""" with open(yaml_path) as config_file: return convert_config(yaml.load(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) No newline at end of file openflexure_microscope/camera/pi.py +49 −47 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ from .base import BaseCamera, StreamObject # Richard's fix gain from .set_picamera_gain import set_analog_gain, set_digital_gain # Manage config from .config import load_config from .config import load_config, save_config, convert_config HERE = os.path.abspath(os.path.dirname(__file__)) DEFAULT_CONFIG = os.path.join(HERE, 'config_picamera.yaml') Loading @@ -62,8 +62,8 @@ class StreamingCamera(BaseCamera): # Attach to Pi camera self.camera = picamera.PiCamera() #: :py:class:`picamera.PiCamera`: Picamera object # Camera settings self.settings.update({ # Default camera config self.config.update({ 'video_resolution': (832, 624), 'image_resolution': (2592, 1944), 'numpy_resolution': (1312, 976), Loading Loading @@ -92,53 +92,55 @@ class StreamingCamera(BaseCamera): self.camera.close() # HANDLE SETTINGS def update_settings(self, config_path: str=None) -> None: def load_config(self, config_path: str=None): """ Open config_picamera.yaml file and write to camera. Todo: TODO: Handle exceptions TODO: Have this take a dictionary (not a config file) Args: config_path (str): Path to the config YAML file. """ global DEFAULT_CONFIG if not config_path: config_data = load_config(DEFAULT_CONFIG) else: config_data = load_config(config_path) TODO: Web API entry point to send settings as JSON to this method self.update_settings(config_data) TODO: Separate method to store current settings back to YAML file def save_config(self, config_path: str=None): """ Open config_picamera.yaml file and write to camera. TODO: API entry point to get settings to JSON Args: config_path (str): Path to the config YAML file. """ global DEFAULT_CONFIG if not config_path: config_path = DEFAULT_CONFIG save_config(self.config, config_path) def update_settings(self, config: dict) -> None: """ Write a config dictionary to the StreamingCamera config. Args: 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 # Apply valid config params to Picamera object if not self.state['record_active']: # If not recording a video if self.state['stream_active']: # If stream is active logging.info("Pausing stream to update settings.") logging.info("Pausing stream to update config.") self.pause_stream_for_capture() # Pause stream paused_stream = True # Remember to unpause stream when done if not config_path: config = load_config(DEFAULT_CONFIG) else: config = load_config(config_path) logging.debug(config) # StreamingCamera settings if 'video_resolution' in config: self.settings['video_resolution'] = config['video_resolution'] if 'image_resolution' in config: self.settings['image_resolution'] = config['image_resolution'] if 'numpy_resolution' in config: self.settings['numpy_resolution'] = config['numpy_resolution'] if 'jpeg_quality' in config: self.settings['jpeg_quality'] = config['jpeg_quality'] if 'framerate' in config: self.settings['framerate'] = config['framerate'] # Camera AWB if 'awb_mode' in config: self.camera.awb_mode = config['awb_mode'] Loading @@ -163,13 +165,13 @@ class StreamingCamera(BaseCamera): if 'digital_gain' in config: set_digital_gain(self.camera, config['digital_gain']) if paused_stream: # If stream was paused to update settings if paused_stream: # If stream was paused to update config logging.info("Resuming stream.") self.resume_stream_for_capture() else: raise Exception( "Cannot update camera settings while recording is active.") "Cannot update camera config while recording is active.") def change_zoom(self, zoom_value: int=1) -> None: """Change the camera zoom, handling recentering and scaling. Loading Loading @@ -259,7 +261,7 @@ class StreamingCamera(BaseCamera): target, format=fmt, splitter_port=2, resize=self.settings['video_resolution'], resize=self.config['video_resolution'], quality=quality) # Update state dictionary Loading Loading @@ -297,7 +299,7 @@ class StreamingCamera(BaseCamera): logging.debug("Pausing stream") # If no resolution is specified, default to image_resolution if not resolution: resolution = self.settings['image_resolution'] resolution = self.config['image_resolution'] # Stop the camera video recording on port 1 self.camera.stop_recording(splitter_port=splitter_port) Loading @@ -318,7 +320,7 @@ class StreamingCamera(BaseCamera): """ logging.debug("Unpausing stream") if not resolution: resolution = self.settings['video_resolution'] resolution = self.config['video_resolution'] # Reduce the resolution for video streaming self.camera.resolution = resolution Loading @@ -327,7 +329,7 @@ class StreamingCamera(BaseCamera): self.camera.start_recording( self.stream, format='mjpeg', quality=self.settings['jpeg_quality'], quality=self.config['jpeg_quality'], splitter_port=splitter_port) def capture( Loading Loading @@ -416,9 +418,9 @@ class StreamingCamera(BaseCamera): resize ((int, int)): Resize the captured image. """ if use_video_port: resolution = self.settings['video_resolution'] resolution = self.config['video_resolution'] else: resolution = self.settings['numpy_resolution'] resolution = self.config['numpy_resolution'] if resize: size = resize Loading Loading @@ -462,10 +464,10 @@ class StreamingCamera(BaseCamera): self.wait_for_camera() # Settings config self.update_settings() # Load config file self.load_config() # Set stream resolution self.camera.resolution = self.settings['video_resolution'] self.camera.resolution = self.config['video_resolution'] # Create stream self.stream = io.BytesIO() Loading @@ -474,7 +476,7 @@ class StreamingCamera(BaseCamera): self.camera.start_recording( self.stream, format='mjpeg', quality=self.settings['jpeg_quality'], quality=self.config['jpeg_quality'], splitter_port=1) # Update state Loading @@ -488,7 +490,7 @@ class StreamingCamera(BaseCamera): self.stream.seek(0) self.stream.truncate() # to stream, read the new frame time.sleep(1/self.settings['framerate']*0.1) time.sleep(1/self.config['framerate']*0.1) # yield the result to be read frame = self.stream.getvalue() Loading Loading
openflexure_microscope/camera/base.py +1 −1 Original line number Diff line number Diff line Loading @@ -97,7 +97,7 @@ class BaseCamera(object): self.event = CameraEvent() self.state = {} #: dict: Dictionary for capture state self.settings = {} #: dict: Dictionary of camera settings self.config = {} #: dict: Dictionary of camera settings self.paths = { 'image': BASE_CAPTURE_PATH, 'video': BASE_CAPTURE_PATH, Loading
openflexure_microscope/camera/config.py +9 −4 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ TYPES = { } def convert_config(config): def convert_config(config: dict) -> dict: """Convert datatype of config based on type dictionary.""" global TYPES Loading @@ -28,7 +28,12 @@ def convert_config(config): return config def load_config(yaml_path): def load_config(yaml_path: str) -> dict: """Load YAML file, pass through dictionary conversion, and return.""" with open(yaml_path) as config_file: return convert_config(yaml.load(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) No newline at end of file
openflexure_microscope/camera/pi.py +49 −47 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ from .base import BaseCamera, StreamObject # Richard's fix gain from .set_picamera_gain import set_analog_gain, set_digital_gain # Manage config from .config import load_config from .config import load_config, save_config, convert_config HERE = os.path.abspath(os.path.dirname(__file__)) DEFAULT_CONFIG = os.path.join(HERE, 'config_picamera.yaml') Loading @@ -62,8 +62,8 @@ class StreamingCamera(BaseCamera): # Attach to Pi camera self.camera = picamera.PiCamera() #: :py:class:`picamera.PiCamera`: Picamera object # Camera settings self.settings.update({ # Default camera config self.config.update({ 'video_resolution': (832, 624), 'image_resolution': (2592, 1944), 'numpy_resolution': (1312, 976), Loading Loading @@ -92,53 +92,55 @@ class StreamingCamera(BaseCamera): self.camera.close() # HANDLE SETTINGS def update_settings(self, config_path: str=None) -> None: def load_config(self, config_path: str=None): """ Open config_picamera.yaml file and write to camera. Todo: TODO: Handle exceptions TODO: Have this take a dictionary (not a config file) Args: config_path (str): Path to the config YAML file. """ global DEFAULT_CONFIG if not config_path: config_data = load_config(DEFAULT_CONFIG) else: config_data = load_config(config_path) TODO: Web API entry point to send settings as JSON to this method self.update_settings(config_data) TODO: Separate method to store current settings back to YAML file def save_config(self, config_path: str=None): """ Open config_picamera.yaml file and write to camera. TODO: API entry point to get settings to JSON Args: config_path (str): Path to the config YAML file. """ global DEFAULT_CONFIG if not config_path: config_path = DEFAULT_CONFIG save_config(self.config, config_path) def update_settings(self, config: dict) -> None: """ Write a config dictionary to the StreamingCamera config. Args: 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 # Apply valid config params to Picamera object if not self.state['record_active']: # If not recording a video if self.state['stream_active']: # If stream is active logging.info("Pausing stream to update settings.") logging.info("Pausing stream to update config.") self.pause_stream_for_capture() # Pause stream paused_stream = True # Remember to unpause stream when done if not config_path: config = load_config(DEFAULT_CONFIG) else: config = load_config(config_path) logging.debug(config) # StreamingCamera settings if 'video_resolution' in config: self.settings['video_resolution'] = config['video_resolution'] if 'image_resolution' in config: self.settings['image_resolution'] = config['image_resolution'] if 'numpy_resolution' in config: self.settings['numpy_resolution'] = config['numpy_resolution'] if 'jpeg_quality' in config: self.settings['jpeg_quality'] = config['jpeg_quality'] if 'framerate' in config: self.settings['framerate'] = config['framerate'] # Camera AWB if 'awb_mode' in config: self.camera.awb_mode = config['awb_mode'] Loading @@ -163,13 +165,13 @@ class StreamingCamera(BaseCamera): if 'digital_gain' in config: set_digital_gain(self.camera, config['digital_gain']) if paused_stream: # If stream was paused to update settings if paused_stream: # If stream was paused to update config logging.info("Resuming stream.") self.resume_stream_for_capture() else: raise Exception( "Cannot update camera settings while recording is active.") "Cannot update camera config while recording is active.") def change_zoom(self, zoom_value: int=1) -> None: """Change the camera zoom, handling recentering and scaling. Loading Loading @@ -259,7 +261,7 @@ class StreamingCamera(BaseCamera): target, format=fmt, splitter_port=2, resize=self.settings['video_resolution'], resize=self.config['video_resolution'], quality=quality) # Update state dictionary Loading Loading @@ -297,7 +299,7 @@ class StreamingCamera(BaseCamera): logging.debug("Pausing stream") # If no resolution is specified, default to image_resolution if not resolution: resolution = self.settings['image_resolution'] resolution = self.config['image_resolution'] # Stop the camera video recording on port 1 self.camera.stop_recording(splitter_port=splitter_port) Loading @@ -318,7 +320,7 @@ class StreamingCamera(BaseCamera): """ logging.debug("Unpausing stream") if not resolution: resolution = self.settings['video_resolution'] resolution = self.config['video_resolution'] # Reduce the resolution for video streaming self.camera.resolution = resolution Loading @@ -327,7 +329,7 @@ class StreamingCamera(BaseCamera): self.camera.start_recording( self.stream, format='mjpeg', quality=self.settings['jpeg_quality'], quality=self.config['jpeg_quality'], splitter_port=splitter_port) def capture( Loading Loading @@ -416,9 +418,9 @@ class StreamingCamera(BaseCamera): resize ((int, int)): Resize the captured image. """ if use_video_port: resolution = self.settings['video_resolution'] resolution = self.config['video_resolution'] else: resolution = self.settings['numpy_resolution'] resolution = self.config['numpy_resolution'] if resize: size = resize Loading Loading @@ -462,10 +464,10 @@ class StreamingCamera(BaseCamera): self.wait_for_camera() # Settings config self.update_settings() # Load config file self.load_config() # Set stream resolution self.camera.resolution = self.settings['video_resolution'] self.camera.resolution = self.config['video_resolution'] # Create stream self.stream = io.BytesIO() Loading @@ -474,7 +476,7 @@ class StreamingCamera(BaseCamera): self.camera.start_recording( self.stream, format='mjpeg', quality=self.settings['jpeg_quality'], quality=self.config['jpeg_quality'], splitter_port=1) # Update state Loading @@ -488,7 +490,7 @@ class StreamingCamera(BaseCamera): self.stream.seek(0) self.stream.truncate() # to stream, read the new frame time.sleep(1/self.settings['framerate']*0.1) time.sleep(1/self.config['framerate']*0.1) # yield the result to be read frame = self.stream.getvalue() Loading