Made QR-code scan work also on picamera

This commit is contained in:
Fabio Manganiello 2020-03-11 01:06:07 +01:00
parent 2992d5f726
commit a130edb74f
4 changed files with 60 additions and 18 deletions

View file

@ -34,19 +34,22 @@ class StreamingOutput:
return buf.startswith(b'\xff\xd8') return buf.startswith(b'\xff\xd8')
def write(self, buf): def write(self, buf):
if self.is_new_frame(buf): if not self.is_new_frame(buf):
if self.raw: return
with self.ready:
self.raw_frame = buf
self.ready.notify_all()
else:
# New frame, copy the existing buffer's content and notify all clients that it's available
self.buffer.truncate()
with self.ready:
self.frame = self.buffer.getvalue()
self.ready.notify_all()
self.buffer.seek(0)
if self.raw:
with self.ready:
self.raw_frame = buf
self.ready.notify_all()
return
# New frame, copy the existing buffer's content and notify all clients that it's available
self.buffer.truncate()
with self.ready:
self.frame = self.buffer.getvalue()
self.ready.notify_all()
self.buffer.seek(0)
return self.buffer.write(buf) return self.buffer.write(buf)
def close(self): def close(self):

View file

@ -20,6 +20,8 @@ class CameraPiPlugin(CameraPlugin):
Requires: Requires:
* **picamera** (``pip install picamera``) * **picamera** (``pip install picamera``)
* **numpy** (``pip install numpy``)
""" """
_default_resolution = (800, 600) _default_resolution = (800, 600)
@ -64,9 +66,11 @@ class CameraPiPlugin(CameraPlugin):
self._time_lapse_thread = None self._time_lapse_thread = None
self._recording_thread = None self._recording_thread = None
self._streaming_thread = None self._streaming_thread = None
self._capturing_thread = None
self._time_lapse_stop_condition = threading.Condition() self._time_lapse_stop_condition = threading.Condition()
self._recording_stop_condition = threading.Condition() self._recording_stop_condition = threading.Condition()
self._can_stream = False self._can_stream = False
self._can_capture = False
# noinspection PyUnresolvedReferences,PyPackageRequirements # noinspection PyUnresolvedReferences,PyPackageRequirements
def _get_camera(self, **opts): def _get_camera(self, **opts):
@ -88,11 +92,19 @@ class CameraPiPlugin(CameraPlugin):
""" """
Close an active connection to the camera. Close an active connection to the camera.
""" """
import picamera
if self._output and self._camera: if self._output and self._camera:
self._camera.stop_recording() try:
self._camera.stop_recording()
except picamera.PiCameraNotRecording:
pass
if self._camera and not self._camera.closed: if self._camera and not self._camera.closed:
self._camera.close() try:
self._camera.close()
except picamera.PiCameraClosed:
pass
self._camera = None self._camera = None
@ -175,12 +187,38 @@ class CameraPiPlugin(CameraPlugin):
if camera and close: if camera and close:
self.close() self.close()
def _raw_capture(self):
import numpy as np
resolution = self.camera_args['resolution']
camera = self._get_camera()
while self._can_capture:
shape = (resolution[1] + (resolution[1]%16),
resolution[0] + (resolution[0]%32),
3)
frame = np.empty(shape, dtype=np.uint8)
camera.capture(frame, 'bgr')
frame.reshape((shape[0], shape[1], 3))
self._output.write(frame)
def __enter__(self): def __enter__(self):
camera = self._get_camera() camera = self._get_camera()
self._output = StreamingOutput() self._output = StreamingOutput(raw=self.stream_raw_frames)
camera.start_recording(self._output, format='mjpeg') self._can_capture = True
if self.stream_raw_frames:
self._capturing_thread = threading.Thread(target=self._raw_capture)
self._capturing_thread.start()
else:
camera.start_recording(self._output, format='mjpeg')
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
self._can_capture = False
if self._capturing_thread:
self._capturing_thread.join()
self._capturing_thread = None
self.close() self.close()
@action @action

View file

@ -106,7 +106,8 @@ class QrcodePlugin(Plugin):
return QrcodeDecodedResponse(results) return QrcodeDecodedResponse(results)
def _convert_frame(self, frame) -> Image: def _convert_frame(self, frame) -> Image:
assert isinstance(frame, np.ndarray), 'Image conversion only works with numpy arrays for now' assert isinstance(frame, np.ndarray), \
'Image conversion only works with numpy arrays for now (got {})'.format(type(frame))
mode = 'RGB' mode = 'RGB'
if len(frame.shape) > 2 and frame.shape[2] == 4: if len(frame.shape) > 2 and frame.shape[2] == 4:
mode = 'RGBA' mode = 'RGBA'

View file

@ -182,7 +182,7 @@ setup(
# Support for torrents download # Support for torrents download
'torrent': ['python-libtorrent'], 'torrent': ['python-libtorrent'],
# Support for RaspberryPi camera # Support for RaspberryPi camera
'picamera': ['picamera'], 'picamera': ['picamera', 'numpy'],
# Support for inotify file monitors # Support for inotify file monitors
'inotify': ['inotify'], 'inotify': ['inotify'],
# Support for Google Assistant # Support for Google Assistant