Finalized camera.ir.mlx90640 web interface

This commit is contained in:
Fabio Manganiello 2019-09-26 18:33:44 +02:00
parent d7dc74beed
commit 168b1b0e5a
6 changed files with 109 additions and 28 deletions

View file

@ -0,0 +1,60 @@
import base64
import os
import tempfile
import time
from flask import Response, request, Blueprint, send_from_directory
from platypush.backend.http.app import template_folder
from platypush.backend.http.app.utils import authenticate, send_request
camera_ir_mlx90640 = Blueprint('camera.ir.mlx90640', __name__, template_folder=template_folder)
# Declare routes list
__routes__ = [
camera_ir_mlx90640,
]
def get_feed(**args):
try:
while True:
frame = send_request(action='camera.ir.mlx90640.capture', **args).output[0]
frame = base64.decodebytes(frame.encode())
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
finally:
send_request(action='camera.ir.mlx90640.stop')
@camera_ir_mlx90640.route('/camera/ir/mlx90640/frame', methods=['GET'])
@authenticate()
def get_frame_route():
f = tempfile.NamedTemporaryFile(prefix='ir_camera_frame_', suffix='.jpg', delete=False)
args = {
'grayscale': bool(int(request.args.get('grayscale', 0))),
'scale_factor': int(request.args.get('scale_factor', 1)),
'rotate': int(request.args.get('rotate', 0)),
'output_file': f.name,
}
send_request(action='camera.ir.mlx90640.capture', **args)
return send_from_directory(os.path.dirname(f.name),
os.path.basename(f.name))
@camera_ir_mlx90640.route('/camera/ir/mlx90640/stream', methods=['GET'])
@authenticate()
def get_feed_route():
args = {
'grayscale': bool(int(request.args.get('grayscale', 0))),
'scale_factor': int(request.args.get('scale_factor', 1)),
'rotate': int(request.args.get('rotate', 0)),
'format': 'jpeg',
}
return Response(get_feed(**args),
mimetype='multipart/x-mixed-replace; boundary=frame')
# vim:sw=4:ts=4:et:

View file

@ -1,9 +1,9 @@
@import 'common/vars';
.camera {
height: 90%;
margin-top: 7%;
overflow: hidden;
min-height: 90%;
margin-top: 4%;
overflow: auto;
display: flex;
flex-direction: column;
align-items: center;

View file

@ -17,22 +17,43 @@ Vue.component('camera-ir-mlx90640', {
return;
this.capturing = true;
while (this.capturing) {
const img = await request('camera.ir.mlx90640.capture', {
format: 'png',
rotate: this.rotate,
grayscale: this.grayscale,
});
this.$refs.frame.setAttribute('src', 'data:image/png;base64,' + img);
}
this.$refs.frame.setAttribute('src', '/camera/ir/mlx90640/stream?rotate='
+ this.rotate + '&grayscale=' + (this.grayscale ? 1 : 0) + '&t='
+ (new Date()).getTime());
},
stopStreaming: async function() {
await request('camera.ir.mlx90640.stop');
this.$refs.frame.removeAttribute('src');
this.capturing = false;
},
onRotationChange: function() {
this.rotate = parseInt(this.$refs.rotate.value);
const cameraContainer = this.$el.querySelector('.camera-container');
switch (this.rotate) {
case 0:
case 180:
cameraContainer.style.width = '640px';
cameraContainer.style.minWidth = '640px';
cameraContainer.style.height = '480px';
cameraContainer.style.minHeight = '480px';
break;
case 90:
case 270:
cameraContainer.style.width = '480px';
cameraContainer.style.minWidth = '480px';
cameraContainer.style.height = '640px';
cameraContainer.style.minHeight = '640px';
break;
}
},
},
mounted: function() {
this.onRotationChange();
},
});

View file

@ -14,7 +14,7 @@
<i class="fa fa-stop"></i>&nbsp; Stop streaming
</button>
<select ref="rotate" @change="rotate = $event.target.value" :disabled="capturing">
<select ref="rotate" @change="onRotationChange" :disabled="capturing">
<option value="0" :selected="rotate == 0">0 degrees</option>
<option value="90" :selected="rotate == 90">90 degrees</option>
<option value="180" :selected="rotate == 180">180 degrees</option>

View file

@ -36,6 +36,11 @@ class CameraIrMlx90640Plugin(Plugin):
"""
_img_size = (32, 24)
_rotate_values = {
90: Image.ROTATE_90,
180: Image.ROTATE_180,
270: Image.ROTATE_270,
}
def __init__(self, fps=16, skip_frames=2, scale_factor=1, rotate=0, rawrgb_path=None, **kwargs):
"""
@ -74,7 +79,7 @@ class CameraIrMlx90640Plugin(Plugin):
return self._capture_proc
@action
def capture(self, output_file=None, frames=1, grayscale=False, fps=None, skip_frames=None, scale_factor=None, rotate=None, format=None):
def capture(self, output_file=None, frames=1, grayscale=False, fps=None, skip_frames=None, scale_factor=None, rotate=None, format='jpeg'):
"""
Capture one or multiple frames and return them as raw RGB
@ -100,18 +105,18 @@ class CameraIrMlx90640Plugin(Plugin):
:param rotate: If set it overrides the rotate parameter specified on the object (default: None)
:type rotate: int
:param format: Output image format if output_file is not specified(default: None, raw RGB).
:param format: Output image format if output_file is not specified (default: jpeg).
It can be jpg, png, gif or any format supported by PIL
:type format: str
:returns: list[str]. Each item is a base64 encoded raw RGB representation of a frame if output_file is not set, otherwise a list with
:returns: list[str]. Each item is a base64 encoded representation of a frame in the specified format if output_file is not set, otherwise a list with
the captured image files will be returned.
"""
fps = self.fps if fps is None else fps
skip_frames = self.skip_frames if skip_frames is None else skip_frames
scale_factor = self.scale_factor if scale_factor is None else scale_factor
rotate = self.rotate if rotate is None else rotate
rotate = self._rotate_values.get(self.rotate if rotate is None else rotate, 0)
size = self._img_size
sleep_time = 1.0 / self.fps
@ -132,21 +137,16 @@ class CameraIrMlx90640Plugin(Plugin):
if grayscale:
image = self._convert_to_grayscale(image)
if rotate:
image = image.rotate(rotate)
if scale_factor != 1:
size = tuple(i*scale_factor for i in size)
image = image.resize(size, Image.ANTIALIAS)
frame = image.getdata()
if rotate:
image = image.transpose(rotate)
if not output_file:
if format:
temp = io.BytesIO()
image.save(temp, format=format)
frame = temp.getvalue()
frame = base64.encodebytes(frame).decode()
frame = base64.encodebytes(temp.getvalue()).decode()
captured_frames.append(frame)
else:
image_file = os.path.abspath(os.path.expanduser(output_file.format(n_captured_frames)))