Panasonic 赤外線アレイセンサ Grid-EYE AMG8833からの温度データを、Raspberr PiからI2C通信で取得します。
データの取得自体は、Adafruit_AMG88xxをimportして、self._sensor = Adafruit_AMG88xx()などとして、インスタンス化すると、self._sensor.readPixels()で取得出来ます。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
AMG8833 script.
===============
Human-detectable distance: MAX 7[m]
3.3[V] I2C(68h or 69h)
8x8 array 0~80[deg]
Nick name: Grid-EYE
"""
i2c_enable = False
# Raspberry Pi以外の環境でのディバック用です
try:
from Adafruit_AMG88xx import Adafruit_AMG88xx
i2c_enable = True
except:
i2c_enable = False
class Sensor():
def __init__(self, *args, **kwargs):
self.enable = False
self._sensor = None
if i2c_enable:
self.enable = True
try:
self._sensor = Adafruit_AMG88xx()
except:
self.enable = False
@property
def high(self):
return 80.0
@property
def low(self):
return 0.0
@property
def pixels(self):
result = None
if self._sensor is not None:
result = self._sensor.readPixels()
return result
class Sensorには、high,lowプロパティがありますが、amg8833.pyをimportするThermoクラスに必要です。
thermo.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
MH Image process Thermo script.
===============================
Temperature data processing from device.
AMG8833
D6T-44L-06
"""
import numpy as np
import random
cv2_installed = False
try:
import cv2
cv2_installed = True
except ModuleNotFoundError:
cv2_installed = False
# mhipはMH ソフトウェア&サービスの画像処理用パッケージです
import mhip
class Thermo(mhip.Method):
def __init__(self, sensor, *args, **kwargs):
"""
sensor='amg8833' or 'd6t_44l_06'
Temepature adjust formula is,
temp = (a*length^2 + b*length + c) * temp
この計算式は、距離に対する温度を補正します
"""
# sensorを指定する事で、OMRON D6T-44L-06とPanasonic AMG8833が変更できます
if sensor.lower() == 'd6t_44l_06':
# 通常、importは先頭に書きますが、条件分岐がある為、ここでimportします
# さらに、単独でこのスクリプトを動かす場合とimportされる時で、importする場所を変更しています
if __name__ == '__main__':
from d6t_44l_06 import Sensor
else:
from .d6t_44l_06 import Sensor
elif sensor.lower() == 'amg8833':
if __name__ == '__main__':
from amg8833 import Sensor
else:
from .amg8833 import Sensor
super().__init__(*args, **kwargs)
self.sensor = Sensor(*args, **kwargs)
self.a = kwargs.get('a', 0)
self.b = kwargs.get('b', 1)
self.c = kwargs.get('c', 0)
self._length = kwargs.get('length', 1)
self.map_max = kwargs.get('map_max', 35.0)
self.map_mix = kwargs.get('map_min', 9.5)
self._size = kwargs.get('size', (320, 320))
self._shutdowning = False
# 分析結果は、mhipで必要です
self._analysis = {
'en': {'Max Temp.':
self.sensor.high, 'Min Temp.': self.sensor.low},
'ja': {'最高温度':
self.sensor.high, '最低温度': self.sensor.low}}
self._min = 0
self._max = 0
self.gain = 10
self.offset_x = 0.2
self.offset_green = 0.6
@property
def a(self):
return self._a
@a.setter
def a(self, value):
self._a = value
@property
def b(self):
return self._b
@b.setter
def b(self, value):
self._b = value
@property
def c(self):
return self._c
@c.setter
def c(self, value):
self._c = value
def colorBarRGB(self, x):
# 2020/6/24: red and blue is reversed...
x = (x * 2) - 1
blue = self.sigmoid(x, self.gain, -1 * self.offset_x)
red = 1 - self.sigmoid(x, self.gain, self.offset_x)
green = self.sigmoid(x, self.gain, self.offset_green) \
+ (1 - self.sigmoid(x, self.gain, -1 * self.offset_green))
green = green - 1.0
blue = blue * 255
green = green * 255
red = red * 255
return [blue, green, red]
def __del__(self):
self._shutdowning = True
# Rapebrry Pi以外の環境でのディバック用の温度データです
def _dummy(self):
result_64 = [
[22.75, 23.5, 24.75, 24.5, 24.5, 23.75, 23.0, 23.75, 22.5, 23.5, 27.75, 27.25, 24.25, 22.75, 22.5, 23.0, 22.75, 24.25, 28.25, 27.5, 26.75, 24.0, 22.25, 22.25, 24.0, 26.5, 28.5, 28.0, 27.25, 24.25, 22.75, 21.75, 27.0, 27.75, 27.75, 28.25, 28.5, 24.75, 23.25, 23.5, 28.0, 27.0, 27.0, 28.75, 29.25, 26.75, 24.0, 23.75, 28.25, 27.0, 27.0, 27.5, 28.25, 26.5, 24.25, 24.0, 27.25, 27.25, 25.75, 25.5, 26.0, 25.75, 24.5, 24.25],
[24.5, 25.0, 25.5, 26.5, 25.5, 25.5, 24.75, 25.5, 24.25, 25.0, 27.75, 29.25, 26.75, 25.0, 24.25, 24.75, 24.75, 27.0, 29.5, 30.5, 29.25, 28.75, 26.5, 26.0, 28.5, 30.0, 31.0, 37.75, 31.0, 31.0, 31.0, 31.0, 29.75, 30.75, 31.0, 31.0, 37.75, 31.5, 37.75, 31.5, 30.5, 30.5, 37.75, 31.5, 31.5, 31.5, 31.75, 37.75, 30.25, 30.25, 30.75, 37.75, 37.75, 31.75, 37.75, 32.0, 30.25, 30.5, 37.75, 31.0, 31.5, 31.5, 31.5, 37.75],
[22.75, 22.75, 22.75, 24.25, 24.5, 24.75, 24.0, 24.0, 22.25, 22.5, 23.0, 24.0, 24.5, 24.25, 23.75, 23.75, 22.0, 22.25, 23.0, 24.0, 24.5, 24.0, 23.5, 23.0, 21.5, 22.25, 22.75, 26.5, 25.25, 22.75, 23.25, 22.5, 21.75, 21.75, 22.5, 26.75, 25.25, 22.75, 22.25, 22.0, 22.0, 22.25, 24.75, 26.0, 25.75, 24.5, 21.75, 21.25, 21.75, 22.0, 24.25, 24.5, 24.75, 25.0, 22.0, 22.0, 21.25, 21.75, 24.0, 24.5, 25.25, 24.75, 21.5, 21.5]
]
result = [
[22.75, 23.5, 24.75, 24.5, 24.5, 23.75, 23.0, 23.75, 22.5, 23.5, 27.75, 26.25, 24.25, 22.75, 22.5, 23.0],
[24.5, 25.0, 25.5, 26.5, 25.5, 25.5, 24.75, 25.5, 24.25, 25.0, 27.75, 27.25, 26.75, 25.0, 24.25, 24.75],
[22.75, 22.75, 22.75, 25.25, 26.5, 26.75, 24.0, 24.0, 22.25, 22.5, 23.0, 24.0, 24.5, 24.25, 23.75, 23.75]
]
for i in range(len(result)):
for j in range(len(result[i])):
result[i][j] = result[i][j] * 1.15
return result[random.randint(0, 2)]
@property
def enable(self):
return self.sensor.enable
@property
def length(self):
return self._length
@length.setter
def length(self, value):
self._length = value
self.sensor.length = self._length
@property
def max(self):
return self._max
@property
def min(self):
return self._min
class Parameter():
def __init__(self):
pass
# mhipで使用する処理済画像を作成します
@property
def processed_image(self):
result = None
pixels = []
if self.sensor.enable:
pixels = self.sensor.pixels
temp_width = self.map_max - self.map_mix
if pixels is None:
# Rainbow!!!
#pixels = []
#_ratio = temp_width / (self.sensor.x * self.sensor.y)
#for i in range(self.sensor.x * self.sensor.y):
# #pixels.append(round(self.sensor.high * random.uniform(0.0, 0.475), 1))
# pixels.append(i * _ratio + self.map_mix)
pixels = self._dummy()
elif len(pixels) == 0:
pixels = self._dummy()
for i, val in enumerate(pixels):
pixels[i] = \
(
self._a * self._length ** 2 \
+ self._b * self._length \
+ self._c
) * val
self._min = min(pixels)
self._max = max(pixels)
self._analysis = {
'en': {'Max Temp.': self._max, 'Min Temp.': self._min},
'ja': {'最高温度': self._max, '最低温度': self._min}}
# vol.4 熱画像のバージョン
# 色々とweb上の処理を試させていただきました ありがとうございました
# 最終的に、自分で作ったこの処理がシンプルで、まあまあの熱画像になると思います
# やはりnumpy処理は速いです
temp = np.array(pixels)
temp = temp - self.map_mix
temp = temp / temp_width
sqrt = int(len(temp)**0.5)
temp = temp.reshape(sqrt, sqrt)
img = np.zeros(
(sqrt, sqrt, 3),
dtype='uint8')
img[:, :, 0] = self.colorBarRGB(temp)[0]
img[:, :, 1] = self.colorBarRGB(temp)[1]
img[:, :, 2] = self.colorBarRGB(temp)[2]
img = cv2.resize(img, (self.size[0], self.size[1]), cv2.INTER_CUBIC)
return img
def sigmoid(self, x, gain=1, offset_x=0):
return ((np.tanh(((x + offset_x) * gain) / 2) + 1) / 2)
@property
def size(self):
return self._size
@size.setter
def size(self, value):
self._size = value
def stop(self):
self._shutdowning = True
self.sensor.stop()
def main():
# 単体で動かして、カメラ画像に熱画像を足しています
th = Thermo(
#sensor='d6t_44l_06',
sensor='amg8833',
map_max=35.0,
map_min=10.0,
a=0.000001,
b=0.00025,
c=1.186,
size=(160, 160),
)
vcap = cv2.VideoCapture(0)
while True:
_, capture = vcap.read()
ratio = 1
#capture = cv2.resize(
# capture,
# (
# int(capture.shape[1] * ratio),
# int(capture.shape[0] * ratio)
# ))
thermo = th.processed_image
thermo = thermo[:,:,::-1]
thermo = np.rot90(thermo, 1)
# attachはカメラ画像に、引数最後の座標に熱画像を足します
image = attach(capture, thermo, (0,0))
# full_blendは、カメラ画像と熱画像をブレンドします
# 熱画像のサイズを調整すると、カメラ画像と合わせられます
#image = full_blend(capture, thermo)
cv2.imshow('thermo', image)
cv2.waitKey(50)
print(f'{th.max:0.1f}', f'{th.min:0.1f}')
pass
def attach(large, small, offset):
result = large
result[
offset[1]: offset[1] + small.shape[0],
offset[0]: offset[0] + small.shape[1]] = small
return result
def full_blend(large, small):
small = cv2.resize(
small,
(large.shape[1], large.shape[0]))
alpha = 0.3
result = cv2.addWeighted(
large, alpha,
small, 1 - alpha, 0)
return result
if __name__ == '__main__':
main()
mhip.Methodクラスです。AMG8833、D6T-44L-06を扱うThermoクラスも、画像を扱います。
Methodクラスを継承します。
class Method():
def __init__(self, *args, **kwargs):
self.area = [0, 0, 0, 0]
self.judge = True
self.output = 0
self.analysis = {
'en': {'Info': 'None'},
'ja': {'検査結果': 'ありません'}
}
self.color_channel = kwargs.get('color_channel', 'rgb')
self.source = kwargs.get('source', None)
self.parameter = self.Parameter()
@property
def analysis(self):
return self._analysis
@analysis.setter
def analysis(self, value):
self._analysis = value
@property
def judge(self):
return self._judge
@judge.setter
def judge(self, value):
if type(value) == bool:
self._judge = value
@property
def output(self):
return self._output
@output.setter
def output(self, value):
if mhfn.isnumeric(value):
self._output = value
@property
def processed_image(self):
return self.source
@property
def source(self):
return self._source
@source.setter
def source(self, value):
source = Image(source=value, color_channel=self.color_channel)
self._source = source.numpy
YouTube: サーマルカメラ(サーモ AI デバイス TiD) Python編
web: サーモ AI デバイス TiD Python D6T編 (URLが変更されました)