Split loading, saving, and applying camera config file

This commit is contained in:
Joel Collins 2018-11-23 12:14:10 +00:00
parent b73a8f7ec5
commit c887f990b5
3 changed files with 62 additions and 55 deletions

View file

@ -97,7 +97,7 @@ class BaseCamera(object):
self.event = CameraEvent() self.event = CameraEvent()
self.state = {} #: dict: Dictionary for capture state self.state = {} #: dict: Dictionary for capture state
self.settings = {} #: dict: Dictionary of camera settings self.config = {} #: dict: Dictionary of camera settings
self.paths = { self.paths = {
'image': BASE_CAPTURE_PATH, 'image': BASE_CAPTURE_PATH,
'video': BASE_CAPTURE_PATH, 'video': BASE_CAPTURE_PATH,

View file

@ -17,18 +17,23 @@ TYPES = {
} }
def convert_config(config): def convert_config(config: dict) -> dict:
"""Convert datatype of config based on type dictionary.""" """Convert datatype of config based on type dictionary."""
global TYPES global TYPES
for key in config: for key in config:
if key in TYPES: if key in TYPES:
config[key] = TYPES[key](config[key]) config[key] = TYPES[key](config[key])
return config return config
def load_config(yaml_path): def load_config(yaml_path: str) -> dict:
"""Load YAML file, pass through dictionary conversion, and return.""" """Load YAML file, pass through dictionary conversion, and return."""
with open(yaml_path) as config_file: 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)

View file

@ -48,7 +48,7 @@ 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 # Manage config
from .config import load_config from .config import load_config, save_config, convert_config
HERE = os.path.abspath(os.path.dirname(__file__)) HERE = os.path.abspath(os.path.dirname(__file__))
DEFAULT_CONFIG = os.path.join(HERE, 'config_picamera.yaml') DEFAULT_CONFIG = os.path.join(HERE, 'config_picamera.yaml')
@ -62,8 +62,8 @@ class StreamingCamera(BaseCamera):
# 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
# Camera settings # Default camera config
self.settings.update({ self.config.update({
'video_resolution': (832, 624), 'video_resolution': (832, 624),
'image_resolution': (2592, 1944), 'image_resolution': (2592, 1944),
'numpy_resolution': (1312, 976), 'numpy_resolution': (1312, 976),
@ -92,53 +92,55 @@ class StreamingCamera(BaseCamera):
self.camera.close() self.camera.close()
# HANDLE SETTINGS # HANDLE SETTINGS
def load_config(self, config_path: str=None):
def update_settings(self, config_path: str=None) -> None:
""" """
Open config_picamera.yaml file and write to camera. Open config_picamera.yaml file and write to camera.
Todo: Args:
TODO: Handle exceptions config_path (str): Path to the config YAML file.
TODO: Have this take a dictionary (not a config file)
TODO: Web API entry point to send settings as JSON to this method
TODO: Separate method to store current settings back to YAML file
TODO: API entry point to get settings to JSON
""" """
global DEFAULT_CONFIG global DEFAULT_CONFIG
if not config_path:
config_data = load_config(DEFAULT_CONFIG)
else:
config_data = load_config(config_path)
self.update_settings(config_data)
def save_config(self, config_path: str=None):
"""
Open config_picamera.yaml file and write to camera.
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 paused_stream = False
# 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
if self.state['stream_active']: # If stream is active 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 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
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 # Camera AWB
if 'awb_mode' in config: if 'awb_mode' in config:
self.camera.awb_mode = config['awb_mode'] self.camera.awb_mode = config['awb_mode']
@ -163,17 +165,17 @@ class StreamingCamera(BaseCamera):
if 'digital_gain' in config: if 'digital_gain' in config:
set_digital_gain(self.camera, config['digital_gain']) 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.") logging.info("Resuming stream.")
self.resume_stream_for_capture() self.resume_stream_for_capture()
else: else:
raise Exception( 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: def change_zoom(self, zoom_value: int=1) -> None:
"""Change the camera zoom, handling recentering and scaling. """Change the camera zoom, handling recentering and scaling.
Todo: Todo:
TODO: Needs to be re-implemented TODO: Needs to be re-implemented
@ -259,7 +261,7 @@ class StreamingCamera(BaseCamera):
target, target,
format=fmt, format=fmt,
splitter_port=2, splitter_port=2,
resize=self.settings['video_resolution'], resize=self.config['video_resolution'],
quality=quality) quality=quality)
# Update state dictionary # Update state dictionary
@ -297,7 +299,7 @@ class StreamingCamera(BaseCamera):
logging.debug("Pausing stream") logging.debug("Pausing stream")
# If no resolution is specified, default to image_resolution # If no resolution is specified, default to image_resolution
if not resolution: if not resolution:
resolution = self.settings['image_resolution'] resolution = self.config['image_resolution']
# Stop the camera video recording on port 1 # Stop the camera video recording on port 1
self.camera.stop_recording(splitter_port=splitter_port) self.camera.stop_recording(splitter_port=splitter_port)
@ -318,7 +320,7 @@ class StreamingCamera(BaseCamera):
""" """
logging.debug("Unpausing stream") logging.debug("Unpausing stream")
if not resolution: if not resolution:
resolution = self.settings['video_resolution'] resolution = self.config['video_resolution']
# Reduce the resolution for video streaming # Reduce the resolution for video streaming
self.camera.resolution = resolution self.camera.resolution = resolution
@ -327,7 +329,7 @@ class StreamingCamera(BaseCamera):
self.camera.start_recording( self.camera.start_recording(
self.stream, self.stream,
format='mjpeg', format='mjpeg',
quality=self.settings['jpeg_quality'], quality=self.config['jpeg_quality'],
splitter_port=splitter_port) splitter_port=splitter_port)
def capture( def capture(
@ -416,9 +418,9 @@ class StreamingCamera(BaseCamera):
resize ((int, int)): Resize the captured image. resize ((int, int)): Resize the captured image.
""" """
if use_video_port: if use_video_port:
resolution = self.settings['video_resolution'] resolution = self.config['video_resolution']
else: else:
resolution = self.settings['numpy_resolution'] resolution = self.config['numpy_resolution']
if resize: if resize:
size = resize size = resize
@ -462,10 +464,10 @@ class StreamingCamera(BaseCamera):
self.wait_for_camera() self.wait_for_camera()
# Settings config # Load config file
self.update_settings() self.load_config()
# Set stream resolution # Set stream resolution
self.camera.resolution = self.settings['video_resolution'] self.camera.resolution = self.config['video_resolution']
# Create stream # Create stream
self.stream = io.BytesIO() self.stream = io.BytesIO()
@ -474,7 +476,7 @@ class StreamingCamera(BaseCamera):
self.camera.start_recording( self.camera.start_recording(
self.stream, self.stream,
format='mjpeg', format='mjpeg',
quality=self.settings['jpeg_quality'], quality=self.config['jpeg_quality'],
splitter_port=1) splitter_port=1)
# Update state # Update state
@ -488,7 +490,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.settings['framerate']*0.1) time.sleep(1/self.config['framerate']*0.1)
# yield the result to be read # yield the result to be read
frame = self.stream.getvalue() frame = self.stream.getvalue()