Exemple #1
0
    def __init__(self, resolution, rate, callbacks):
        # type: (CameraResolution, int, List[Callable[[AbstractImage], None]]) -> None

        # Extract Image Dimensions from CameraResolution
        self._resolution = resolution
        self._width = self._resolution.value[1]
        self._height = self._resolution.value[0]
        self._shape = np.array([self.height, self.width, self.channels])

        # Store Camera Rate and Callbacks
        self._rate = rate
        self._callbacks = callbacks

        # Variables to do some performance statistics
        self._dt_buffer = deque([], maxlen=10)
        self._true_rate = rate
        self._t0 = time()

        # Create Mailbox and Image Processor:
        #   Each time an image is captured it is put in the mailbox, overriding whatever there might currently be.
        #   In a separate thread, the _processor worker takes an image and calls all registered callbacks.
        #   This way the processing of images does not block the acquisition of new images,
        #   while at the same new images don't build up a queue, but are discarded when the _processor is too busy.
        self._mailbox = Mailbox()
        self._processor_scheduler = Scheduler(self._processor,
                                              name="CameraThread")
        self._processor_scheduler.start()

        # Default behaviour is to not run by default. Calling AbstractApplication.run() will activate the camera
        self._running = False

        self._log = logger.getChild(self.__class__.__name__)
Exemple #2
0
    def __init__(self, resolution, rate, callbacks=[], index=0):
        """
        System Camera

        Parameters
        ----------
        resolution: pepper.framework.CameraResolution
        rate: int
        callbacks: list of callable
        index: int
        """
        super(SystemCamera, self).__init__(resolution, rate, callbacks)

        # Get Camera and request resolution
        self._camera = cv2.VideoCapture(index)

        if not self.resolution == CameraResolution.NATIVE:
            self._camera.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
            self._camera.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)

        # Check if camera is working
        if not self._camera.isOpened():
            raise RuntimeError("{} could not be opened".format(
                self.__class__.__name__))

        # Run Image acquisition in Thread
        self._scheduler = Scheduler(self._run, name="SystemCameraThread")
        self._scheduler.start()

        self._log.debug("Booted")
Exemple #3
0
    def __init__(self, rate, channels, callbacks):
        # type: (int, int, List[Callable[[np.ndarray], None]]) -> None

        self._rate = rate
        self._channels = channels
        self._callbacks = callbacks

        # Variables to do some performance statistics
        self._dt_buffer = deque([], maxlen=32)
        self._true_rate = rate
        self._t0 = time()

        # Create Queue and Sound Processor:
        #   Each time audio samples are captured it is put in the audio processing queue
        #   In a separate thread, the _processor worker takes these samples and calls all registered callbacks.
        #   This way, samples are not accidentally skipped (NAOqi has some very strict timings)
        self._queue = Queue()
        self._processor_scheduler = Scheduler(self._processor,
                                              0,
                                              name="MicrophoneThread")
        self._processor_scheduler.start()

        # Default behaviour is to not run by default. Calling AbstractApplication.run() will activate the microphone
        self._running = False

        self._log = logger.getChild(self.__class__.__name__)
Exemple #4
0
class SystemCamera(AbstractCamera):
    """
    System Camera

    Parameters
    ----------
    resolution: pepper.framework.CameraResolution
    rate: int
    callbacks: list of callable
    index: int
    """
    def __init__(self, resolution, rate, callbacks=[], index=0):
        # type: (CameraResolution, int, List[Callable[[AbstractImage], None]], int) -> None
        super(SystemCamera, self).__init__(resolution, rate, callbacks)

        # Get Camera and request resolution
        self._camera = cv2.VideoCapture(index)

        if not self.resolution == CameraResolution.NATIVE:
            self._camera.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
            self._camera.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)

        # Check if camera is working
        if not self._camera.isOpened():
            raise RuntimeError("{} could not be opened".format(
                self.__class__.__name__))

        # Run Image acquisition in Thread
        self._scheduler = Scheduler(self._run, name="SystemCameraThread")
        self._scheduler.start()

        self._log.debug("Booted")

    def _run(self):
        t0 = time()

        # Get frame from camera
        status, image = self._camera.read()

        if status:
            if self._running:

                # Resize Image and Convert to RGB
                image = cv2.resize(image, (self.width, self.height))
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

                # Call On Image Event
                self.on_image(
                    SystemImage(
                        image,
                        Bounds(-0.55, -0.41 + np.pi / 2, 0.55,
                               0.41 + np.pi / 2)))
        else:
            self._camera.release()
            raise RuntimeError("{} could not fetch image".format(
                self.__class__.__name__))

        # Maintain frame rate
        sleep(max(0, 1. / self.rate - (time() - t0)))
Exemple #5
0
    def __init__(self, language):
        self._language = language

        self._queue = Queue()
        self._talking_jobs = 0

        self._scheduler = Scheduler(self._worker, name="TextToSpeechThread")
        self._scheduler.start()

        self._log = logger.getChild(self.__class__.__name__)
Exemple #6
0
    def __init__(self, backend):
        super(StatisticsComponent, self).__init__(backend)

        # Require Speech Recognition Component and Get Information from it
        speech_recognition = self.require(
            StatisticsComponent,
            SpeechRecognitionComponent)  # type: SpeechRecognitionComponent
        vad, asr = speech_recognition.vad, speech_recognition.asr

        def worker():

            # Create Voice Activation Bar
            activation = int(vad.activation * 10)
            activation_print = "|" * activation + "." * (10 - activation)
            voice_print = ("<{:10s}>" if vad._voice else
                           "[{:10s}]").format(activation_print)
            empty_voice_print = "[          ]"

            # Get Microphone Related Information
            mic_running = self.backend.microphone.running
            mic_rate = self.backend.microphone.rate
            mic_rate_true = self.backend.microphone.true_rate

            # Get Camera Related Information
            cam_rate = self.backend.camera.rate
            cam_rate_true = self.backend.camera.true_rate

            # If Camera and/or Microphone are not running as fast as expected -> show stderr message instead of stdout
            error = (
                cam_rate_true < cam_rate * self.PERFORMANCE_ERROR_THRESHOLD
                or mic_rate_true <
                float(mic_rate) * self.PERFORMANCE_ERROR_THRESHOLD)

            # Show Speech to Text Transcript 'live' as it happens
            if asr.live:
                self.LIVE_SPEECH = asr.live
                self.LIVE_SPEECH_TIME = time()
            elif time() - self.LIVE_SPEECH_TIME > self.LIVE_SPEECH_TIMEOUT:
                self.LIVE_SPEECH = ""

            # Display Statistics
            print(
                "\rThreads {:2d} | Cam {:4.1f} Hz | Mic {:4.1f} kHz | TTS {:12s} >>> {}"
                .format(threading.active_count(), cam_rate_true,
                        mic_rate_true / 1000.0,
                        voice_print if mic_running else empty_voice_print,
                        self.LIVE_SPEECH),
                end="",
                file=(stderr if error else stdout))

        # Run 10 times a second
        # TODO: Bit Much?
        schedule = Scheduler(worker, 0.1)
        schedule.start()
Exemple #7
0
    def __init__(self, backend):
        super(TextToSpeechComponent, self).__init__(backend)

        self._microphone_lock = Lock()

        def worker():
            with self._microphone_lock:
                # If talking is over & microphone is not yet running -> Start Microphone
                if not self.backend.text_to_speech.talking and not self.backend.microphone.running:
                    self.backend.microphone.start()

        schedule = Scheduler(worker, name="TextToSpeechComponentThread")
        schedule.start()
Exemple #8
0
    def __init__(self, backend):
        super(TextToSpeechComponent, self).__init__(backend)

        # Prevent Racing Conditions
        self._microphone_lock = Lock()

        def worker():
            # type: () -> None
            """Make sure Microphone is not listening when Text to Speech is Live"""

            # Acquire Microphone Lock
            with self._microphone_lock:
                # If robot is not talking & microphone is not yet running -> Start Microphone
                if not self.backend.text_to_speech.talking and not self.backend.microphone.running:
                    self.backend.microphone.start()

        schedule = Scheduler(worker, name="TextToSpeechComponentThread")
        schedule.start()
Exemple #9
0
    def __init__(self, rate, channels, callbacks):
        self._rate = rate
        self._channels = channels
        self._callbacks = callbacks

        self._dt_threshold_multiplier = 1.5
        self._dt_buffer = deque([], maxlen=32)
        self._true_rate = rate
        self._t0 = time()

        self._queue = Queue()
        self._processor_scheduler = Scheduler(self._processor,
                                              0,
                                              name="MicrophoneThread")
        self._processor_scheduler.start()

        self._log = logger.getChild(self.__class__.__name__)

        self._running = False
Exemple #10
0
    def __init__(self, resolution, rate, callbacks=[], index=0):
        # type: (CameraResolution, int, List[Callable[[AbstractImage], None]], int) -> None
        super(SystemCamera, self).__init__(resolution, rate, callbacks)

        # Get Camera and request resolution
        self._camera = cv2.VideoCapture(index)

        if not self.resolution == CameraResolution.NATIVE:
            self._camera.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
            self._camera.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)

        # Check if camera is working
        if not self._camera.isOpened():
            raise RuntimeError("{} could not be opened".format(
                self.__class__.__name__))

        # Run Image acquisition in Thread
        self._scheduler = Scheduler(self._run, name="SystemCameraThread")
        self._scheduler.start()

        self._log.debug("Booted")
Exemple #11
0
    def __init__(self, backend):
        """
        Construct Statistics Component

        Parameters
        ----------
        backend: Backend
        """
        super(StatisticsComponent, self).__init__(backend)

        speech_recognition = self.require(StatisticsComponent, SpeechRecognitionComponent)  # type: SpeechRecognitionComponent
        vad = speech_recognition.vad

        def worker():

            # Create Activation Bar
            activation = int(vad.activation * 10)
            activation_print = "|" * activation + "." * (10 - activation)
            voice_print = ("<{:10s}>" if vad._utterance else "[{:10s}]").format(activation_print)
            empty_voice_print = "[          ]"

            mic_running = self.backend.microphone.running

            mic_rate = self.backend.microphone.rate
            mic_rate_true = self.backend.microphone.true_rate

            cam_rate = self.backend.camera.rate
            cam_rate_true = self.backend.camera.true_rate

            error = (cam_rate_true < cam_rate * self.PERFORMANCE_ERROR_THRESHOLD or
                     mic_rate_true < float(mic_rate) * self.PERFORMANCE_ERROR_THRESHOLD)

            print("\rMicrophone {:3.1f} kHz | Camera {:4.1f} Hz | Voice {:12s} {:4.0%}".format(
                mic_rate_true / 1000.0, cam_rate_true,
                voice_print if mic_running else empty_voice_print,
                vad.activation if mic_running else 0),
                end="", file=(stderr if error else stdout))

        schedule = Scheduler(worker, 0.1)
        schedule.start()
Exemple #12
0
    def __init__(self, resolution, rate, callbacks):
        self._resolution = resolution
        self._width = self._resolution.value[1]
        self._height = self._resolution.value[0]

        self._rate = rate
        self._callbacks = callbacks

        self._shape = np.array([self.height, self.width, self.channels])

        self._dt_buffer = deque([], maxlen=10)
        self._true_rate = rate
        self._t0 = time()

        self._mailbox = Mailbox()

        self._processor_scheduler = Scheduler(self._processor,
                                              name="CameraThread")
        self._processor_scheduler.start()

        self._running = False

        self._log = logger.getChild(self.__class__.__name__)
Exemple #13
0
    def __init__(self, backend):
        super(ObjectDetectionComponent, self).__init__(backend)

        # Public List of On Object Callbacks:
        # Allowing other Components to Subscribe to it
        self.on_object_callbacks = []

        # Create Object Detection Client and a Mailbox per Target
        # Make sure the corresponding server @ pepper_tensorflow is actually running
        clients = [ObjectDetectionClient(target) for target in ObjectDetectionComponent.TARGETS]
        mailboxes = {client: Mailbox() for client in clients}  # type: Dict[ObjectDetectionClient, Mailbox]

        def on_image(image):
            # type: (AbstractImage) -> None
            """
            Raw On Image Event. Called every time the camera yields a frame.

            Parameters
            ----------
            image: AbstractImage
            """
            for client in clients:
                mailboxes[client].put(image)

        def worker(client):
            # type: (ObjectDetectionClient) -> None
            """Object Detection Worker"""

            # Get Image from Mailbox Corresponding with Client
            image = mailboxes[client].get()

            # Classify Objects in this Image using Client
            objects = [obj for obj in client.classify(image) if obj.confidence > config.OBJECT_RECOGNITION_THRESHOLD]

            if objects:

                # Call on_object Callback Functions
                for callback in self.on_object_callbacks:
                    callback(objects)

                # Call on_object Event Function
                self.on_object(objects)

        # Initialize & Start Object Workers
        schedule = [Scheduler(worker, args=(client,), name="{}Thread".format(client.target.name)) for client in clients]
        for s in schedule:
            s.start()

        # Add on_image to Camera Callbacks
        self.backend.camera.callbacks += [on_image]
Exemple #14
0
    def __init__(self, backend):
        """
        Construct Face Detection Component

        Parameters
        ----------
        backend: AbstractBackend
        """
        super(FaceDetectionComponent, self).__init__(backend)

        self.on_face_callbacks = []
        self.on_face_known_callbacks = []
        self.on_face_new_callbacks = []

        # Initialize OpenFace
        open_face = OpenFace()

        # Import Face Data
        people = FaceClassifier.load_directory(config.PEOPLE_FRIENDS_ROOT)
        people.update(FaceClassifier.load_directory(config.PEOPLE_NEW_ROOT))

        # Initialize Face Classifier
        self.face_classifier = FaceClassifier(people)

        queue = Queue()

        def on_image(image):
            """
            Raw On Image Event. Called every time the camera yields a frame.

            Parameters
            ----------
            image: np.ndarray
            """
            queue.put([
                self.face_classifier.classify(r, b, image)
                for r, b in open_face.represent(image)
            ])

        def worker():
            on_face = queue.get()

            on_face_known = []
            on_face_new = []

            for face in on_face:
                if face.confidence > config.FACE_RECOGNITION_THRESHOLD:
                    (on_face_new if face.name == FaceClassifier.NEW else
                     on_face_known).append(face)

            if on_face:
                for callback in self.on_face_callbacks:
                    callback(on_face)
                self.on_face(on_face)
            if on_face_known:
                for callback in self.on_face_known_callbacks:
                    callback(on_face_known)
                self.on_face_known(on_face_known)
            if on_face_new:
                for callback in self.on_face_new_callbacks:
                    callback(on_face_new)
                self.on_face_new(on_face_new)

        # Initialize Queue & Worker
        schedule = Scheduler(worker, name="FaceDetectionComponentThread")
        schedule.start()

        # Add on_image to Camera Callbacks
        self.backend.camera.callbacks += [on_image]
Exemple #15
0
class AbstractMicrophone(object):
    """
    Abstract Microphone

    Parameters
    ----------
    rate: int
    channels: int
    callbacks: list of callable
    """
    def __init__(self, rate, channels, callbacks):
        self._rate = rate
        self._channels = channels
        self._callbacks = callbacks

        self._dt_threshold_multiplier = 1.5
        self._dt_buffer = deque([], maxlen=32)
        self._true_rate = rate
        self._t0 = time()

        self._queue = Queue()
        self._processor_scheduler = Scheduler(self._processor,
                                              0,
                                              name="MicrophoneThread")
        self._processor_scheduler.start()

        self._log = logger.getChild(self.__class__.__name__)

        self._running = False

    @property
    def rate(self):
        """
        Audio bit rate

        Returns
        -------
        rate: int
            Audio bit rate
        """
        return self._rate

    @property
    def true_rate(self):
        """
        Actual Audio bit rate

        Audio bit rate after accounting for latency & performance realities

        Returns
        -------
        true_rate:
            Actual Audio bit rate
        """
        return self._true_rate

    @property
    def channels(self):
        """
        Audio channels

        Returns
        -------
        channels: int
            Audio channels
        """
        return self._channels

    @property
    def callbacks(self):
        """
        Get/Set :func:`~AbstractCamera.on_audio` Callbacks

        Returns
        -------
        callbacks: list of callable
        """
        return self._callbacks

    @callbacks.setter
    def callbacks(self, value):
        """
        Get/Set :func:`~AbstractCamera.on_audio` Callbacks

        Parameters
        ----------
        value: list of callable
        """
        self._callbacks = value

    @property
    def running(self):
        """
        Returns whether Microphone is Running

        Returns
        -------
        running: bool
        """
        return self._running

    def on_audio(self, audio):
        """
        On Audio Event, Called for every frame of audio captured by Microphone

        Microphone Modules should call this function for every frame of audio acquired by Microphone

        Parameters
        ----------
        audio: np.ndarray
        """
        self._queue.put(audio)

    def start(self):
        """Start Microphone Stream"""
        self._running = True

    def stop(self):
        """Stop Microphone Stream"""
        self._running = False

    def _processor(self):
        """
        Audio Processor

        Calls each callback for each audio frame, threaded, for higher audio throughput
        """
        audio = self._queue.get()
        if self._running:
            for callback in self.callbacks:
                callback(audio)
        self._update_dt(len(audio))

    def _update_dt(self, n_bytes):
        t1 = time()
        self._dt_buffer.append((t1 - self._t0))
        self._t0 = t1
        self._true_rate = n_bytes / np.mean(self._dt_buffer)
Exemple #16
0
    def __init__(self, backend):
        super(FaceRecognitionComponent, self).__init__(backend)

        # Public Lists of Callbacks:
        # Allowing other Components to Subscribe to them
        self.on_face_callbacks = []
        self.on_face_known_callbacks = []
        self.on_face_new_callbacks = []

        # Initialize OpenFace
        open_face = OpenFace()

        # Import Face Data (Friends & New)
        people = FaceClassifier.load_directory(config.PEOPLE_FRIENDS_ROOT)
        people.update(FaceClassifier.load_directory(config.PEOPLE_NEW_ROOT))

        # Initialize Face Classifier
        self.face_classifier = FaceClassifier(people)

        # Initialize Image Mailbox
        mailbox = Mailbox()

        def on_image(image):
            # type: (AbstractImage) -> None
            """
            Private On Image Event. Called every time the camera yields a frame.

            Parameters
            ----------
            image: AbstractImage
            """
            mailbox.put(image)

        def worker():
            # type: () -> None
            """Find and Classify Faces in Images"""

            # Get latest Image from Mailbox
            image = mailbox.get()

            # Get All Face Representations from OpenFace & Initialize Known/New Face Categories
            on_face = [
                self.face_classifier.classify(r, b, image)
                for r, b in open_face.represent(image.image)
            ]
            on_face_known = []
            on_face_new = []

            # Distribute Faces over Known & New (Keeping them in the general on_face)
            for face in on_face:
                if face.name == config.HUMAN_UNKNOWN:
                    if face.confidence >= 1.0:
                        on_face_new.append(face)
                elif face.confidence > config.FACE_RECOGNITION_THRESHOLD:
                    on_face_known.append(face)

            # Call Appropriate Callbacks
            if on_face:
                for callback in self.on_face_callbacks:
                    callback(on_face)
                self.on_face(on_face)
            if on_face_known:
                for callback in self.on_face_known_callbacks:
                    callback(on_face_known)
                self.on_face_known(on_face_known)
            if on_face_new:
                for callback in self.on_face_new_callbacks:
                    callback(on_face_new)
                self.on_face_new(on_face_new)

        # Initialize Worker
        schedule = Scheduler(worker, name="FaceDetectionComponentThread")
        schedule.start()

        # Add on_image to Camera Callbacks
        self.backend.camera.callbacks += [on_image]
Exemple #17
0
class AbstractTextToSpeech(object):
    """
    Abstract Text To Speech

    Parameters
    ----------
    language: str
        `Language Code <https://cloud.google.com/speech/docs/languages>`_
    """
    def __init__(self, language):
        # type: (str) -> None
        self._language = language

        self._queue = Queue()
        self._talking_jobs = 0

        self._scheduler = Scheduler(self._worker, name="TextToSpeechThread")
        self._scheduler.start()

        self._log = logger.getChild(self.__class__.__name__)

    @property
    def language(self):
        # type: () -> str
        """
        `Language Code <https://cloud.google.com/speech/docs/languages>`_

        Returns
        -------
        language: str
            `Language Code <https://cloud.google.com/speech/docs/languages>`_
        """
        return self._language

    @property
    def talking(self):
        # type: () -> bool
        """
        Returns whether system is currently producing speech

        Returns
        -------
        talking: bool
            Whether system is currently producing speech
        """
        return self._talking_jobs >= 1

    def say(self, text, animation=None, block=False):
        # type: (Union[str, unicode], Optional[str], bool) -> None
        """
        Say Text (with optional Animation) through Text-to-Speech

        Parameters
        ----------
        text: str
            Text to say through Text-to-Speech
        animation: str or None
            (Naoqi) Animation to play
        block: bool
            Whether this function should block or immediately return after calling
        """
        # self._log.info(text.replace('\n', ' '))
        self._talking_jobs += 1
        self._queue.put((text, animation))

        while block and self.talking:
            sleep(1E-3)

    def on_text_to_speech(self, text, animation=None):
        # type: (Union[str, unicode], Optional[str]) -> None
        """
        Say something through Text to Speech (Implementation)

        Text To Speech Backends should implement this function
        This function should block while speech is being produced

        Parameters
        ----------
        text: str
        animation: str
        """
        raise NotImplementedError()

    def _worker(self):
        self.on_text_to_speech(*self._queue.get())
        self._talking_jobs -= 1
Exemple #18
0
class AbstractMicrophone(object):
    """
    Abstract Microphone

    Parameters
    ----------
    rate: int
        Samples per Second
    channels: int
        Number of Channels
    callbacks: list of callable
        Functions to call each time some audio samples are captured
    """
    def __init__(self, rate, channels, callbacks):
        # type: (int, int, List[Callable[[np.ndarray], None]]) -> None

        self._rate = rate
        self._channels = channels
        self._callbacks = callbacks

        # Variables to do some performance statistics
        self._dt_buffer = deque([], maxlen=32)
        self._true_rate = rate
        self._t0 = time()

        # Create Queue and Sound Processor:
        #   Each time audio samples are captured it is put in the audio processing queue
        #   In a separate thread, the _processor worker takes these samples and calls all registered callbacks.
        #   This way, samples are not accidentally skipped (NAOqi has some very strict timings)
        self._queue = Queue()
        self._processor_scheduler = Scheduler(self._processor,
                                              0,
                                              name="MicrophoneThread")
        self._processor_scheduler.start()

        # Default behaviour is to not run by default. Calling AbstractApplication.run() will activate the microphone
        self._running = False

        self._log = logger.getChild(self.__class__.__name__)

    @property
    def rate(self):
        # type: () -> int
        """
        Audio bit rate

        Returns
        -------
        rate: int
            Audio bit rate
        """
        return self._rate

    @property
    def true_rate(self):
        # type: () -> float
        """
        Actual Audio bit rate

        Audio bit rate after accounting for latency & performance realities

        Returns
        -------
        true_rate:
            Actual Audio bit rate
        """
        return self._true_rate

    @property
    def channels(self):
        # type: () -> int
        """
        Audio channels

        Returns
        -------
        channels: int
            Audio channels
        """
        return self._channels

    @property
    def callbacks(self):
        # type: () -> List[Callable[[np.ndarray], None]]
        """
        Get/Set :func:`~AbstractCamera.on_audio` Callbacks

        Returns
        -------
        callbacks: list of callable
        """
        return self._callbacks

    @callbacks.setter
    def callbacks(self, value):
        # type: (List[Callable[[np.ndarray], None]]) -> None
        """
        Get/Set :func:`~AbstractCamera.on_audio` Callbacks

        Parameters
        ----------
        value: list of callable
        """
        self._callbacks = value

    @property
    def running(self):
        # type: () -> bool
        """
        Returns whether Microphone is Running

        Returns
        -------
        running: bool
        """
        return self._running

    def on_audio(self, audio):
        # type: (np.ndarray) -> None
        """
        On Audio Event, Called for every frame of audio captured by Microphone

        Microphone Modules should call this function for every frame of audio acquired by Microphone

        Parameters
        ----------
        audio: np.ndarray
        """
        self._queue.put(audio)

    def start(self):
        """Start Microphone Stream"""
        self._running = True

    def stop(self):
        """Stop Microphone Stream"""
        self._running = False

    def _processor(self):
        """
        Audio Processor

        Calls each callback for each audio frame, threaded, for higher audio throughput
        """

        # Get Audio Samples from Buffer
        audio = self._queue.get()

        # Call each regisered Callback with Samples
        if self._running:
            for callback in self.callbacks:
                callback(audio)

        # Update Statistics
        self._update_dt(len(audio))

    def _update_dt(self, n_bytes):
        t1 = time()
        self._dt_buffer.append((t1 - self._t0))
        self._t0 = t1
        self._true_rate = n_bytes / np.mean(self._dt_buffer)
Exemple #19
0
class AbstractCamera(object):
    """
    Abstract Camera

    Parameters
    ----------
    resolution: CameraResolution
        :class:`~pepper.config.CameraResolution`
    rate: int
    callbacks: list of callable
    """
    def __init__(self, resolution, rate, callbacks):
        self._resolution = resolution
        self._width = self._resolution.value[1]
        self._height = self._resolution.value[0]

        self._rate = rate
        self._callbacks = callbacks

        self._shape = np.array([self.height, self.width, self.channels])

        self._dt_buffer = deque([], maxlen=10)
        self._true_rate = rate
        self._t0 = time()

        self._mailbox = Mailbox()

        self._processor_scheduler = Scheduler(self._processor,
                                              name="CameraThread")
        self._processor_scheduler.start()

        self._running = False

        self._log = logger.getChild(self.__class__.__name__)

    @property
    def resolution(self):
        """
        Returns :class:`~pepper.config.CameraResolution`

        Returns
        -------
        resolution: CameraResolution
        """
        return self._resolution

    @property
    def width(self):
        """
        Image Width

        Returns
        -------
        width: int
            Image width
        """
        return self._width

    @property
    def height(self):
        """
        Image Height

        Returns
        -------
        height: int
            Image height
        """
        return self._height

    @property
    def channels(self):
        """
        Image (Color) Channels

        Returns
        -------
        channels: int
            Image (Color) channels
        """
        return 3

    @property
    def rate(self):
        """
        Image Rate

        Returns
        -------
        rate: int
            Image rate
        """
        return self._rate

    @property
    def true_rate(self):
        """
        Actual Image Rate

        Image rate after accounting for latency & performance realities

        Returns
        -------
        true_rate: float
            Actual Image Rate
        """
        return self._true_rate

    @property
    def shape(self):
        """
        Image Shape

        Returns
        -------
        shape: np.ndarray
            Image Shape
        """
        return self._shape

    @property
    def callbacks(self):
        """
        Get/Set :func:`~AbstractCamera.on_image` Callbacks

        Returns
        -------
        callbacks: list of callable
            on_image callbacks
        """
        return self._callbacks

    @callbacks.setter
    def callbacks(self, value):
        """
        Get/Set :func:`~AbstractCamera.on_image` Callbacks

        Parameters
        ----------
        value: list of callable
        """
        self._callbacks = value

    @property
    def running(self):
        """
        Returns whether Camera is Running

        Returns
        -------
        running: bool
        """
        return self._running

    def on_image(self, image):
        """
        On Image Event, Called for every Image captured by Camera

        Camera Modules should call this function for every frame acquired by the Camera

        Parameters
        ----------
        image: np.ndarray
        """
        self._mailbox.put(image)

    def start(self):
        """Start Streaming Images from Camera"""
        self._running = True

    def stop(self):
        """Stop Streaming Images from Camera"""
        self._running = False

    def _processor(self):
        """
        Image Processor

        Calls each callback for each image, threaded, for higher image throughput
        """
        image = self._mailbox.get()
        if self._running:
            for callback in self.callbacks:
                callback(image)
        self._update_dt()

    def _update_dt(self):
        t1 = time()
        self._dt_buffer.append((t1 - self._t0))
        self._t0 = t1
        self._true_rate = 1 / np.mean(self._dt_buffer)
Exemple #20
0
class AbstractCamera(object):
    """
    Abstract Camera

    Parameters
    ----------
    resolution: CameraResolution
        :class:`~pepper.config.CameraResolution`
    rate: int
        Camera Frames per Second
    callbacks: List[Callable[[AbstractImage], None]]
        Functions to call each time an AbstractImage is captured
    """
    def __init__(self, resolution, rate, callbacks):
        # type: (CameraResolution, int, List[Callable[[AbstractImage], None]]) -> None

        # Extract Image Dimensions from CameraResolution
        self._resolution = resolution
        self._width = self._resolution.value[1]
        self._height = self._resolution.value[0]
        self._shape = np.array([self.height, self.width, self.channels])

        # Store Camera Rate and Callbacks
        self._rate = rate
        self._callbacks = callbacks

        # Variables to do some performance statistics
        self._dt_buffer = deque([], maxlen=10)
        self._true_rate = rate
        self._t0 = time()

        # Create Mailbox and Image Processor:
        #   Each time an image is captured it is put in the mailbox, overriding whatever there might currently be.
        #   In a separate thread, the _processor worker takes an image and calls all registered callbacks.
        #   This way the processing of images does not block the acquisition of new images,
        #   while at the same new images don't build up a queue, but are discarded when the _processor is too busy.
        self._mailbox = Mailbox()
        self._processor_scheduler = Scheduler(self._processor,
                                              name="CameraThread")
        self._processor_scheduler.start()

        # Default behaviour is to not run by default. Calling AbstractApplication.run() will activate the camera
        self._running = False

        self._log = logger.getChild(self.__class__.__name__)

    @property
    def resolution(self):
        # type: () -> CameraResolution
        """
        Returns :class:`~pepper.config.CameraResolution`

        Returns
        -------
        resolution: CameraResolution
        """
        return self._resolution

    @property
    def width(self):
        # type: () -> int
        """
        Image Width

        Returns
        -------
        width: int
            Image width
        """
        return self._width

    @property
    def height(self):
        # type: () -> int
        """
        Image Height

        Returns
        -------
        height: int
            Image height
        """
        return self._height

    @property
    def channels(self):
        # type: () -> int
        """
        Number of Image (Color) Channels

        Returns
        -------
        channels: int
            Number of Image (Color) channels
        """
        return 3

    @property
    def rate(self):
        # type: () -> int
        """
        Image Rate (Frames per Second)

        Returns
        -------
        rate: int
            Image rate (Frames per Second)
        """
        return self._rate

    @property
    def true_rate(self):
        # type: () -> float
        """
        Actual Image Rate (Frames per Second)

        Image rate after accounting for latency & performance realities

        Returns
        -------
        true_rate: float
            Actual Image Rate (Frames per Second)
        """
        return self._true_rate

    @property
    def shape(self):
        # type: () -> np.ndarray
        """
        Image Shape (height, width, channels)

        Returns
        -------
        shape: np.ndarray
            Image Shape (height, width, channels)
        """
        return self._shape

    @property
    def callbacks(self):
        # type: () -> List[Callable[[AbstractImage], None]]
        """
        Get/Set :func:`~AbstractCamera.on_image` Callbacks

        Returns
        -------
        callbacks: list of callable
            on_image callbacks
        """
        return self._callbacks

    @callbacks.setter
    def callbacks(self, value):
        # type: (List[Callable[[AbstractImage], None]]) -> None
        """
        Get/Set :func:`~AbstractCamera.on_image` Callbacks

        Parameters
        ----------
        value: list of callable
        """
        self._callbacks = value

    @property
    def running(self):
        # type: () -> bool
        """
        Returns whether Camera is Running

        Returns
        -------
        running: bool
        """
        return self._running

    def on_image(self, image):
        # type: (AbstractImage) -> None
        """
        On Image Event, Called for every Image captured by Camera

        Custom Camera Backends should call this function for every frame acquired by the Camera

        Parameters
        ----------
        image: AbstractImage
        """
        self._mailbox.put(image)

    def start(self):
        """Start Streaming Images from Camera"""
        self._running = True

    def stop(self):
        """Stop Streaming Images from Camera"""
        self._running = False

    def _processor(self):
        """
        Image Processor

        Calls each callback for each image, threaded, for higher image throughput and less image latency
        """

        # Get latest image from Mailbox
        image = self._mailbox.get()

        # Call Every Registered Callback
        if self._running:
            for callback in self.callbacks:
                callback(image)

        # Update Statistics
        self._update_dt()

    def _update_dt(self):
        t1 = time()
        self._dt_buffer.append((t1 - self._t0))
        self._t0 = t1
        self._true_rate = 1 / np.mean(self._dt_buffer)
Exemple #21
0
    def __init__(self, backend):
        """
        Construct Object Detection Component

        Parameters
        ----------
        backend: AbstractBackend
        target: ObjectDetectionTarget
        """
        super(ObjectDetectionComponent, self).__init__(backend)

        # Callbacks
        self.on_object_callbacks = []

        clients = [
            ObjectDetectionClient(target)
            for target in ObjectDetectionComponent.TARGETS
        ]
        mailboxes = {client: Mailbox()
                     for client in clients
                     }  # type: Dict[ObjectDetectionClient, Mailbox]

        def on_image(image):
            """
            Raw On Image Event. Called every time the camera yields a frame.

            Parameters
            ----------
            image: np.ndarray
            """
            for client in clients:
                mailboxes[client].put(image)

        def worker(client):
            # type: (ObjectDetectionClient) -> None
            """Object Detection Event Worker"""
            image = mailboxes[client].get()

            objects = [
                obj for obj in client.classify(image)
                if obj.confidence > config.OBJECT_RECOGNITION_THRESHOLD
            ]

            if objects:

                # Call on_object Callback Functions
                for callback in self.on_object_callbacks:
                    callback(image, objects)

                # Call on_object Event Function
                self.on_object(image, objects)

        # Initialize Object Queue & Worker
        schedule = [
            Scheduler(worker,
                      args=(client, ),
                      name="{}Thread".format(client.target.name))
            for client in clients
        ]

        for s in schedule:
            s.start()

        # Add on_image to Camera Callbacks
        self.backend.camera.callbacks += [on_image]
Exemple #22
0
class AbstractTextToSpeech(object):
    """
    Abstract Text To Speech

    Parameters
    ----------
    language: str
        Language Code, See: https://cloud.google.com/speech/docs/languages
    """
    def __init__(self, language):
        self._language = language

        self._queue = Queue()
        self._talking_jobs = 0

        self._scheduler = Scheduler(self._worker, name="TextToSpeechThread")
        self._scheduler.start()

        self._log = logger.getChild(self.__class__.__name__)

    @property
    def language(self):
        """
        Language Code, See: https://cloud.google.com/speech/docs/languages

        Returns
        -------
        language: str
            Language Code, See: https://cloud.google.com/speech/docs/languages
        """
        return self._language

    @property
    def talking(self):
        """
        Returns whether system is currently producing speech

        Returns
        -------
        talking: bool
            Whether system is currently producing speech
        """
        return self._talking_jobs >= 1

    def say(self, text, animation=None, block=False):
        """
        Say something through Text to Speech (Interface)

        Parameters
        ----------
        text: str
        animation: str
        """
        # self._log.info(text.replace('\n', ' '))
        self._talking_jobs += 1
        self._queue.put((text, animation))

        while block and self.talking:
            sleep(1E-3)

    def on_text_to_speech(self, text, animation=None):
        """
        Say something through Text to Speech (Implementation)

        Text To Speech Modules should implement this function
        This function should block while speech is being produced

        Parameters
        ----------
        text: str
        animation: str
        """
        pass

    def _worker(self):
        self.on_text_to_speech(*self._queue.get())
        self._talking_jobs -= 1