Loading openflexure_microscope/camera/base.py +6 −1 Original line number Diff line number Diff line # -*- coding: utf-8 -*- import time import io import os import threading from PIL import Image import datetime Loading @@ -14,7 +15,7 @@ except ImportError: except ImportError: from _thread import get_ident from .capture import StreamObject from .capture import StreamObject, BASE_CAPTURE_PATH def last_entry(object_list: list): Loading Loading @@ -97,6 +98,10 @@ class BaseCamera(object): self.state = {} #: dict: Dictionary for capture state self.settings = {} #: dict: Dictionary of camera settings self.paths = { 'image': BASE_CAPTURE_PATH, 'video': BASE_CAPTURE_PATH, } #: dict: Dictionary of capture paths # Capture data self.images = [] #: list: List of image capture objects Loading openflexure_microscope/camera/capture.py +35 −21 Original line number Diff line number Diff line Loading @@ -9,18 +9,22 @@ from PIL import Image pil_formats = ['JPG', 'JPEG', 'PNG', 'TIF', 'TIFF'] thumbnail_size = (60, 60) BASE_CAPTURE_PATH = os.path.join(os.path.expanduser('~'), 'micrographs') TEMP_CAPTURE_PATH = os.path.join(BASE_CAPTURE_PATH, 'tmp') class StreamObject(object): """ StreamObject used to store and process capture data, and metadata. Note: Captures cannot be stored in a lower-level directory than BASE_CAPTURE_PATH. """ def __init__( self, write_to_file: bool=False, keep_on_disk: bool=True, filename: str=None, folder: str=None, fmt: str='file') -> None: filename: str='', folder: str='', fmt: str='') -> None: """Create a new StreamObject, to manage capture data.""" # Store a nice ID self.id = uuid.uuid4().hex Loading Loading @@ -80,32 +84,35 @@ class StreamObject(object): """ Construct a full file path, based on filename, folder, and file format. Defaults to datestamp. Defaults to UUID. """ global TEMP_CAPTURE_PATH base_name = filename file_name = "{}.{}".format(base_name, fmt) file_given_name = "{}.{}".format(filename, fmt) # Given file name. May include a relative path # Create folder and file if folder: if not os.path.exists(folder): os.mkdir(folder) self.file = os.path.join(folder, file_given_name) # Full file name by joining given folder to given name file_path = os.path.join(folder, file_name) else: file_path = file_name self.split_file_path(self.file) # Split file path into folder, filename, and basename # Handle path appendix appendix = "" # Check directory is a subdirectory of BASE_CAPTURE_PATH if not os.path.commonprefix([self.file, BASE_CAPTURE_PATH]) == BASE_CAPTURE_PATH: raise Exception("Captures cannot be stored in a lower-level directory than {}.".format(BASE_CAPTURE_PATH)) # Move to tmp directory if not being kept if not self.keep_on_disk: appendix += ".tmp" # TODO: Empty tmp folder on module load and atexit self.file_notmp = self.file # Store originally defined folder self.filefolder = TEMP_CAPTURE_PATH self.file = os.path.join(self.filefolder, self.filename) file_path = file_path + appendix # Create folder and file if not os.path.exists(self.filefolder): os.mkdir(self.filefolder) #self.basename = filename self.file = file_path self.filename = file_name self.basename = base_name def split_file_path(self, filepath): """Takes a full file path, and splits it into separated class properties.""" self.filefolder, self.filename = os.path.split(filepath) # Split the full file path into a folder and a filename self.basename = os.path.splitext(self.filename)[0] # Split the filename out from it's file extension def lock(self): """Set locked flag to True.""" Loading Loading @@ -223,6 +230,13 @@ class StreamObject(object): def save_file(self) -> bool: """Write the StreamObjects stream to a file.""" if not self.keep_on_disk: # If capture is currently temporary self.load_file() # Load data from tmp file into stream, if tmp file exists self.keep_on_disk = True # Flag as kept on disk self.file = self.file_notmp # Reset file path to non-temporary path self.split_file_path(self.file) # Set split properties based on new path logging.info("Moved temporary file out to {}".format(self.file)) if self.stream_exists: # If there's a stream to save with open(self.file, 'ab') as f: # Load file as bytes logging.debug("Writing stream to file {}".format(self.file)) Loading openflexure_microscope/camera/pi.py +2 −6 Original line number Diff line number Diff line Loading @@ -214,7 +214,6 @@ class StreamingCamera(BaseCamera): target=None, write_to_file: bool=True, filename: str=None, folder: str='record', fmt: str='h264', quality: int=15): """Start recording. Loading @@ -225,7 +224,6 @@ class StreamingCamera(BaseCamera): target (str/BytesIO): Target object to write bytes to. write_to_file (bool/NoneType): Should the StreamObject write to a file? filename (str): Name of the stored file. Defaults to timestamp. folder (str): Relative directory to store data file in. fmt (str): Format of the capture. Returns: Loading @@ -242,7 +240,7 @@ class StreamingCamera(BaseCamera): StreamObject( write_to_file=write_to_file, filename=filename, folder=folder, folder=self.paths['video'], fmt=fmt) ) Loading Loading @@ -339,7 +337,6 @@ class StreamingCamera(BaseCamera): keep_on_disk: bool=True, use_video_port: bool=False, filename: str=None, folder: str='capture', fmt: str='jpeg', resize: Tuple[int, int]=None): """ Loading @@ -353,7 +350,6 @@ class StreamingCamera(BaseCamera): write_to_file (bool): Should the StreamObject write to a file, instead of BytesIO stream? use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster. filename (str): Name of the stored file. Defaults to timestamp. folder (str): Relative directory to store data file in. fmt (str): Format of the capture. resize ((int, int)): Resize the captured image. """ Loading @@ -372,7 +368,7 @@ class StreamingCamera(BaseCamera): write_to_file=write_to_file, keep_on_disk=keep_on_disk, filename=filename, folder=folder, folder=self.paths['image'], fmt=fmt) ) target = target_obj.target # Store to the StreamObject BytesIO Loading Loading
openflexure_microscope/camera/base.py +6 −1 Original line number Diff line number Diff line # -*- coding: utf-8 -*- import time import io import os import threading from PIL import Image import datetime Loading @@ -14,7 +15,7 @@ except ImportError: except ImportError: from _thread import get_ident from .capture import StreamObject from .capture import StreamObject, BASE_CAPTURE_PATH def last_entry(object_list: list): Loading Loading @@ -97,6 +98,10 @@ class BaseCamera(object): self.state = {} #: dict: Dictionary for capture state self.settings = {} #: dict: Dictionary of camera settings self.paths = { 'image': BASE_CAPTURE_PATH, 'video': BASE_CAPTURE_PATH, } #: dict: Dictionary of capture paths # Capture data self.images = [] #: list: List of image capture objects Loading
openflexure_microscope/camera/capture.py +35 −21 Original line number Diff line number Diff line Loading @@ -9,18 +9,22 @@ from PIL import Image pil_formats = ['JPG', 'JPEG', 'PNG', 'TIF', 'TIFF'] thumbnail_size = (60, 60) BASE_CAPTURE_PATH = os.path.join(os.path.expanduser('~'), 'micrographs') TEMP_CAPTURE_PATH = os.path.join(BASE_CAPTURE_PATH, 'tmp') class StreamObject(object): """ StreamObject used to store and process capture data, and metadata. Note: Captures cannot be stored in a lower-level directory than BASE_CAPTURE_PATH. """ def __init__( self, write_to_file: bool=False, keep_on_disk: bool=True, filename: str=None, folder: str=None, fmt: str='file') -> None: filename: str='', folder: str='', fmt: str='') -> None: """Create a new StreamObject, to manage capture data.""" # Store a nice ID self.id = uuid.uuid4().hex Loading Loading @@ -80,32 +84,35 @@ class StreamObject(object): """ Construct a full file path, based on filename, folder, and file format. Defaults to datestamp. Defaults to UUID. """ global TEMP_CAPTURE_PATH base_name = filename file_name = "{}.{}".format(base_name, fmt) file_given_name = "{}.{}".format(filename, fmt) # Given file name. May include a relative path # Create folder and file if folder: if not os.path.exists(folder): os.mkdir(folder) self.file = os.path.join(folder, file_given_name) # Full file name by joining given folder to given name file_path = os.path.join(folder, file_name) else: file_path = file_name self.split_file_path(self.file) # Split file path into folder, filename, and basename # Handle path appendix appendix = "" # Check directory is a subdirectory of BASE_CAPTURE_PATH if not os.path.commonprefix([self.file, BASE_CAPTURE_PATH]) == BASE_CAPTURE_PATH: raise Exception("Captures cannot be stored in a lower-level directory than {}.".format(BASE_CAPTURE_PATH)) # Move to tmp directory if not being kept if not self.keep_on_disk: appendix += ".tmp" # TODO: Empty tmp folder on module load and atexit self.file_notmp = self.file # Store originally defined folder self.filefolder = TEMP_CAPTURE_PATH self.file = os.path.join(self.filefolder, self.filename) file_path = file_path + appendix # Create folder and file if not os.path.exists(self.filefolder): os.mkdir(self.filefolder) #self.basename = filename self.file = file_path self.filename = file_name self.basename = base_name def split_file_path(self, filepath): """Takes a full file path, and splits it into separated class properties.""" self.filefolder, self.filename = os.path.split(filepath) # Split the full file path into a folder and a filename self.basename = os.path.splitext(self.filename)[0] # Split the filename out from it's file extension def lock(self): """Set locked flag to True.""" Loading Loading @@ -223,6 +230,13 @@ class StreamObject(object): def save_file(self) -> bool: """Write the StreamObjects stream to a file.""" if not self.keep_on_disk: # If capture is currently temporary self.load_file() # Load data from tmp file into stream, if tmp file exists self.keep_on_disk = True # Flag as kept on disk self.file = self.file_notmp # Reset file path to non-temporary path self.split_file_path(self.file) # Set split properties based on new path logging.info("Moved temporary file out to {}".format(self.file)) if self.stream_exists: # If there's a stream to save with open(self.file, 'ab') as f: # Load file as bytes logging.debug("Writing stream to file {}".format(self.file)) Loading
openflexure_microscope/camera/pi.py +2 −6 Original line number Diff line number Diff line Loading @@ -214,7 +214,6 @@ class StreamingCamera(BaseCamera): target=None, write_to_file: bool=True, filename: str=None, folder: str='record', fmt: str='h264', quality: int=15): """Start recording. Loading @@ -225,7 +224,6 @@ class StreamingCamera(BaseCamera): target (str/BytesIO): Target object to write bytes to. write_to_file (bool/NoneType): Should the StreamObject write to a file? filename (str): Name of the stored file. Defaults to timestamp. folder (str): Relative directory to store data file in. fmt (str): Format of the capture. Returns: Loading @@ -242,7 +240,7 @@ class StreamingCamera(BaseCamera): StreamObject( write_to_file=write_to_file, filename=filename, folder=folder, folder=self.paths['video'], fmt=fmt) ) Loading Loading @@ -339,7 +337,6 @@ class StreamingCamera(BaseCamera): keep_on_disk: bool=True, use_video_port: bool=False, filename: str=None, folder: str='capture', fmt: str='jpeg', resize: Tuple[int, int]=None): """ Loading @@ -353,7 +350,6 @@ class StreamingCamera(BaseCamera): write_to_file (bool): Should the StreamObject write to a file, instead of BytesIO stream? use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster. filename (str): Name of the stored file. Defaults to timestamp. folder (str): Relative directory to store data file in. fmt (str): Format of the capture. resize ((int, int)): Resize the captured image. """ Loading @@ -372,7 +368,7 @@ class StreamingCamera(BaseCamera): write_to_file=write_to_file, keep_on_disk=keep_on_disk, filename=filename, folder=folder, folder=self.paths['image'], fmt=fmt) ) target = target_obj.target # Store to the StreamObject BytesIO Loading