Extended features of MLX90640 infrared camera plugin
This commit is contained in:
parent
d1d842ae95
commit
755c8b52ec
3 changed files with 84 additions and 4 deletions
|
@ -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('../..'))
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue