forked from platypush/platypush
Made QR-code scan work also on picamera
This commit is contained in:
parent
2992d5f726
commit
a130edb74f
4 changed files with 60 additions and 18 deletions
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue