Extended features of MLX90640 infrared camera plugin

This commit is contained in:
Fabio Manganiello 2019-09-25 15:36:56 +02:00
parent d1d842ae95
commit 755c8b52ec
3 changed files with 84 additions and 4 deletions

View file

@ -224,6 +224,7 @@ autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers',
'gps', 'gps',
'picamera', 'picamera',
'pwm3901', 'pwm3901',
'PIL',
] ]
sys.path.insert(0, os.path.abspath('../..')) sys.path.insert(0, os.path.abspath('../..'))

View file

@ -1,7 +1,11 @@
import base64
import math
import os import os
import subprocess import subprocess
import time import time
from PIL import Image, ImageCms
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action
@ -24,15 +28,20 @@ class CameraIrMlx90640Plugin(Plugin):
$ make bcm2835 $ make bcm2835
$ make examples/rawrgb I2C_MODE=LINUX $ make examples/rawrgb I2C_MODE=LINUX
Requires:
* **mlx90640-library** installation (see instructions above)
* **PIL** image library (``pip install Pillow``)
""" """
_img_size = (24, 32) _img_size = (24, 32)
def __init__(self, fps=16, skip_frames=2, scale_factor=10, rawrgb_path=None, **kwargs): def __init__(self, fps=16, skip_frames=2, scale_factor=10, rotate=0, rawrgb_path=None, **kwargs):
""" """
:param fps: Frames per seconds (default: 16) :param fps: Frames per seconds (default: 16)
:param skip_frames: Number of frames to be skipped on sensor initialization/warmup (default: 2) :param skip_frames: Number of frames to be skipped on sensor initialization/warmup (default: 2)
:param scale_factor: The camera outputs 24x32 pixels artifacts. Use scale_factor to scale them up to a larger image (default: 10) :param scale_factor: The camera outputs 24x32 pixels artifacts. Use scale_factor to scale them up to a larger image (default: 10)
:param rotate: Rotation angle in degrees (default: 0)
:param rawrgb_path: Specify it if the rawrgb executable compiled from :param rawrgb_path: Specify it if the rawrgb executable compiled from
https://github.com/pimoroni/mlx90640-library is in another folder than https://github.com/pimoroni/mlx90640-library is in another folder than
`<directory of this file>/lib/examples`. `<directory of this file>/lib/examples`.
@ -47,19 +56,25 @@ class CameraIrMlx90640Plugin(Plugin):
assert os.path.isfile(rawrgb_path) assert os.path.isfile(rawrgb_path)
self.fps = fps self.fps = fps
self.rotate = rotate
self.skip_frames = skip_frames self.skip_frames = skip_frames
self.scale_factor = scale_factor self.scale_factor = scale_factor
self.rawrgb_path = rawrgb_path self.rawrgb_path = rawrgb_path
@action @action
def capture(self, frames=1, skip_frames=None): def capture(self, frames=1, fps=None, skip_frames=None):
""" """
Capture one or multiple frames and return them as raw RGB Capture one or multiple frames and return them as raw RGB
:param frames: Number of frames to be captured (default: 1) :param frames: Number of frames to be captured (default: 1)
:param fps: If set it overrides the fps parameter specified on the object (default: None)
:param skip_frames: If set it overrides the skip_frames parameter specified on the object (default: None) :param skip_frames: If set it overrides the skip_frames parameter specified on the object (default: None)
:returns: list[str]. Each item is a base64 encoded raw RGB representation of a frame
""" """
if fps is None:
fps = self.fps
if skip_frames is None: if skip_frames is None:
skip_frames = self.skip_frames skip_frames = self.skip_frames
@ -71,16 +86,77 @@ class CameraIrMlx90640Plugin(Plugin):
stderr=subprocess.PIPE) as camera: stderr=subprocess.PIPE) as camera:
while len(captured_frames) < frames: while len(captured_frames) < frames:
frame = camera.stdout.read(input_size) frame = camera.stdout.read(input_size)
size = len(frame)
if skip_frames > 0: if skip_frames > 0:
time.sleep(sleep_time) time.sleep(sleep_time)
skip_frames -= 1 skip_frames -= 1
continue continue
frame = base64.encodebytes(frame).decode()
captured_frames.append(frame) captured_frames.append(frame)
time.sleep(sleep_time)
return frames camera.terminate()
return captured_frames
@action
def capture_to_file(self, output_image, frames=1, grayscale=False, fps=None, skip_frames=None, scale_factor=None, rotate=None):
"""
Capture one or multiple frames to one or multiple image files.
:param output_image: Can be either the path to a single image file or a format string (e.g. 'snapshots/image-{:04d}') in case of multiple frames
:param fps: If set it overrides the fps parameter specified on the object (default: None)
:param frames: Number of frames to be captured (default: 1)
:param grayscale: Save the image as grayscale - black pixels will be colder, white pixels warmer (default: False)
:param skip_frames: If set it overrides the skip_frames parameter specified on the object (default: None)
:param scale_factor: If set it overrides the scale_factor parameter specified on the object (default: None)
:param rotate: If set it overrides the rotate parameter specified on the object (default: None)
:returns: list[str] containing the saved image file names
"""
if scale_factor is None:
scale_factor = self.scale_factor
if rotate is None:
rotate = self.rotate
files = []
for i in range(0, frames):
encoded_frame = self.capture(frames=1, fps=fps, skip_frames=skip_frames).output[0]
frame = base64.decodebytes(encoded_frame.encode())
size = (self._img_size[1], self._img_size[0])
image = Image.frombytes('RGB', size, frame)
new_image = Image.new('L', image.size)
if grayscale:
for i in range(0, image.size[0]):
for j in range(0, image.size[1]):
r, g, b = image.getpixel((i, j))
value = int(2.0*r - 0.5*g - 1.5*b)
if value > 255:
value = 255
if value < 0:
value = 0
new_image.putpixel((i, j), value)
image = new_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)
filename = os.path.abspath(os.path.expanduser(output_image.format(i)))
image.save(filename)
files.append(filename)
return files
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -165,3 +165,6 @@ pyScss
# Support for PWM3901 2-Dimensional Optical Flow Sensor # Support for PWM3901 2-Dimensional Optical Flow Sensor
# pwm3901 # pwm3901
# Support for MLX90640 thermal camera
# Pillow