Source code for server.abstract_camera

"""
abstract_camera.py: Holds the Python definition of a ``Camera`` as defined in ``pepi.thrift``.
"""

from abc import ABCMeta, abstractmethod
from io import BytesIO

import numpy as np
from PIL import Image, ImageOps

__author__ = 'Curtis West'
__copyright__ = 'Copyright 2017, Curtis West'
__version__ = '3.1'
__maintainer__ = 'Curtis West'
__email__ = 'curtis@curtiswest.net'
__status__ = 'Development'


[docs]class AbstractCamera(object): """ AbstractCamera is an abstract base class that defines the interface required from an ``Camera``. ``Camera`` objects are used to capture imagery a physical camera. The means in which this image is obtained does not matter, as long as presented interface is consistent. ``Camera`` objects are intended to be used by ``BaseCameraServer`` subclasses. A concrete ``Camera`` should subclass AbstractCamera and *must* implement all methods marked with @abstractmethod. """ __metaclass__ = ABCMeta def __init__(self): self._streaming_thread = None @abstractmethod
[docs] def still(self): # type: () -> [[int], [int], [int]] """ Captures a still from the camera and returns it as 3-dimensional RGB array representing the image. :return: [[[R, G, B]] NumPy array of Numpy.uint8 0-255 values. """ pass
[docs] def low_res_still(self): # type: () -> [[int], [int], [int]] """ Captures a still from the camera and returns it as 3-dimensional RGB array representing the image. :return: [[[R, G, B]] NumPy array of Numpy.uint8 0-255 values. """ return RGBImage(self.still()).low_res # pragma: no cover
@abstractmethod
[docs] def get_max_resolution(self): # type: () -> [int, int] """ Gets the maximum resolution supported by this camera. :return: a list of length 2 representing the resolution i.e. (x, y) """ pass
@abstractmethod
[docs] def get_current_resolution(self): # type: () -> [int, int] """ Gets the current resolution of this camera. :return: a list of length 2 representing the resolution i.e. (x, y) """ pass
@abstractmethod
[docs] def set_resolution(self, x, y): # type: (int, int) -> None """ If supported, sets the resolution of the camera. :param x: the x component of the desired resolution :param y: the x component of the desired resolution """ pass
[docs]class RGBImage(object): """ A utility object to convert images of different formats to RGB arrays """ @property def array(self): """ The array RGB array that represents this RGBImage :return: """ return np.array(self._array) @array.setter def array(self, value): value = np.array(value, dtype=np.uint8) try: Image.fromarray(value) except Exception as e: try: raise ValueError('Array does not form a valid image: {}'.format(e.message)) except AttributeError: # pragma: no cover raise ValueError('Array does not form a valid image') else: self._array = value def __init__(self, array): """ Initialises a RGBImage with the given array. :raises: ValueError: when the array is malformed for an image :param array: an RGB array """ self.array = np.array(array) @property def list(self): # type: () -> [[[int, int, int]]] """ RGBImage as a native Python list. :return: Returns this RGB as a native Python list. """ return list(self.array) @property def low_res(self): # type: () -> np.ndarray """ Returns this RGB image as a numpy array. :return: this RGB image as a numpy array """ return np.array(ImageOps.fit(Image.fromarray(self.array), size=(640,480))) @classmethod
[docs] def fromstring(cls, string): image_buffer = BytesIO() image_buffer.write(string) image_buffer.seek(0) return cls(array=np.array(Image.open(image_buffer)))
@classmethod
[docs] def frombytes(cls, mode, size, bytes_): # type: (str, (int, int), (str or bytes)) -> RGBImage """ Construct a RGBImage from the pixel data in a buffer. :param mode: the image mode, see https://pillow.readthedocs.io/en/3.1.x/handbook/concepts.html#concept-modes :param size: the image size :param bytes_: a byte buffer containing raw data for the given mode :raises: ValueError: when the bytes are malformed or not an image :return: RGBImage """ return cls(array=np.array(Image.frombytes(mode, size, bytes_)))
@classmethod
[docs] def fromfile(cls, file): # type: (BytesIO or str) -> RGBImage """ Construct a RGB image from the given file :param file: a filename (str) or file object. :raises: ValueError: when the file object is malformed or not an image :return: RGBImage """ return cls(array=np.array(Image.open(file)))