Multispektral-Thermal (PAG7936)¶
Die PAG7936-Variante des Multispectral Thermal Camera Module kombiniert einen 1-MP-Global-Shutter-Farbsensor mit einem FLIR-Lepton-Thermalkern, sodass die OpenMV Cam Farbsicht- und Thermalpipelines parallel ausführen kann.
Vollständiges Datenblatt, Fotos und Bestellinformationen finden Sie auf der Produktseite des Multispectral Thermal.
Bemerkung
Nur auf der OpenMV N6 unterstützt.
Highlights¶
PAG7936: 1-MP-Global-Shutter
Nimmt FLIR-Lepton-Thermalkerne der Versionen 1.x / 2.x / 3.x auf
Gleichzeitige Thermal- und Farbverarbeitung auf einem Modul
Sieht in völliger Dunkelheit, unterstützt Temperaturmessung
Der Global-Shutter bewältigt schnelle Bewegungen ohne Rolling-Shutter-Artefakte
Verwendung¶
Der Farbsensor und das FLIR Lepton erhalten jeweils ihre eigene csi.CSI-Instanz. Der erste Aufruf verwendet standardmäßig den primären Sensor (das PAG7936); der zweite bindet das Lepton durch Übergabe von cid= csi.LEPTON ein. Setzen Sie den Farbsensor mit csi.CSI.reset (hard=True) hart zurück, um die Versorgungsschiene hochzufahren, und konfigurieren Sie das Lepton mit hard=False, damit dessen Treiber den Chip nur neu programmiert, ohne den Reset erneut umzuschalten.
csi.CSI.framesize ( csi.QVGA ) passt die Lepton-Ausgabe an die Farbkamera an, sodass jeder snapshot() ein 320x240-Einzelbild zurückgibt. Der Lepton-Treiber skaliert sein natives 80x60-Einzelbild (1.x/2.x) bzw. 160x120-Einzelbild (3.x) intern auf die angeforderte Größe hoch — bei QVGA deckt jedes Lepton-Pixel eine 4x4- oder 2x2-Zelle auf dem Farbbild ab.
Zwei Scratch-Puffer bleiben über die Frame-Schleife hinweg konstant — eine 256x1-Alpha-Palette, gespeichert als image.Image, sodass kühle Lepton-Pixel transparent und heiße Pixel undurchsichtig werden (die quadratische Rampe unterdrückt Hintergrunddetails, ohne den mittleren Bereich zu stark zu komprimieren), und ein mit image.Image vorab allokierter Lepton-Framebuffer, sodass csi.CSI.snapshot (blocking=False, image=...) ihn bei jeder Iteration an Ort und Stelle füllen kann, ohne neu zu allokieren:
import time
import csi
import image
import math
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
alpha_pal[i] = int(math.pow((i / 255), 2) * 255)
# Setup the color camera sensor.
csi0 = csi.CSI()
csi0.reset(hard=True) # force hardware reset.
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False) # no hardware reset - just configure lepton
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QVGA)
# Optional temperature range controls for the LEPTON.
# csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False)
# csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
clock = time.clock()
img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())
while True:
clock.tick()
img0 = csi0.snapshot()
csi1.snapshot(blocking=False, image=img1)
img0.draw_image(img1, 0, 0, color_palette=image.PALETTE_IRONBOW,
alpha_palette=alpha_pal,
hint=image.BILINEAR)
print(clock.fps())
Jede Iteration nimmt einen blockierenden Farb-Schnappschuss und einen nicht blockierenden Lepton-Schnappschuss auf — das Lepton läuft mit 9 Hz, sodass ein Blockieren darauf die Farbpipeline drosseln würde. Image.draw_image setzt die beiden anschließend zusammen: color_palette= image.PALETTE_IRONBOW bildet die Graustufen des Leptons auf eine FLIR-typische warme Farbrampe ab, alpha_palette= blendet jedes Pixel über die quadratische Alpha-Map ein, und hint= image.BILINEAR glättet die Hochskalierung.
Temperaturmessung¶
Radiometrische Leptons (Lepton 2.5 / 3.5) liefern kalibrierte Temperaturdaten pro Pixel. Aktivieren Sie den Messmodus über csi.CSI.ioctl mit csi.IOCTL_LEPTON_SET_MODE und begrenzen Sie anschließend das Temperaturfenster mit csi.IOCTL_LEPTON_SET_RANGE (min_celsius, max_celsius). Der Lepton-Treiber bildet den Graustufen-Pixelwert 0 linear auf min_celsius und 255 auf max_celsius ab, sodass jedes Pixel zu einer Temperaturzuordnung innerhalb des konfigurierten Fensters wird. Pixel, die kälter als min_celsius sind, sättigen bei 0, Pixel, die heißer als max_celsius sind, sättigen bei 255.
csi.IOCTL_LEPTON_SET_MODE nimmt zwei Flags entgegen. Das erste schaltet die Messung ein; das zweite wählt den Temperaturbereich des Sensors:
Niedriger Bereich —
(True, False)— Sensorbereich-10 °Cbis+140 °C(raumgroße Szenen). Begrenzen Sie das Fenster auf den Interessensbereich, z. B.(20.0, 40.0)für die Verfolgung von Körperwärme:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
Hoher Bereich —
(True, True)— Sensorbereich-10 °Cbis typischerweise~+450 °C(~+400 °Cbei Raumtemperatur) für heiße Objekte. Begrenzen Sie z. B. auf(0.0, 400.0)für die Verfolgung von Öfen oder Heizelementen:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, True) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 0.0, 400.0)
So wandeln Sie ein Graustufen-Pixel zurück in Grad Celsius:
def p_to_temp(p, min_t, max_t):
return (p * (max_t - min_t)) / 255.0 + min_t
Dies funktioniert für einzelne Pixel oder für aggregierte Statistiken (z. B. stats.mean() aus Image.get_statistics) innerhalb einer ROI, wenn Sie heiße/kühle Regionen mit Image.find_blobs lokalisieren.
GPU-beschleunigte Ausrichtung¶
Image.draw_image akzeptiert ein transform=-Argument — eine 3x3-Homographiematrix als 2D-ulab.numpy-Array. Auf der OpenMV N6 führt die GPU die Pixel-für-Pixel-Projektion während desselben Zeichenvorgangs aus, sodass das Lepton-Einzelbild ohne separaten Warp-Durchlauf an der Perspektive der Farbkamera neu ausgerichtet werden kann. Kalibrieren Sie die Matrix pro Kamera mit dem Thermal-Overlay-Kalibrierwerkzeug:
import time
import csi
import image
from ulab import numpy as np
import math
# Calibration matrix from the thermal-overlay-calibration tool.
m = np.array([
[3.704807, 0.257018, 37.260564],
[0.052147, 3.609977, -7.831831],
[0.000294, 0.000552, 1.000000],
])
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
alpha_pal[i] = int(math.pow((i / 255), 2) * 255)
# Setup the color camera sensor.
csi0 = csi.CSI()
csi0.reset(hard=True) # force hardware reset.
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False) # no hardware reset - just configure lepton
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QQVGA)
# Optional temperature range controls for the LEPTON.
# csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False)
# csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
clock = time.clock()
img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())
while True:
clock.tick()
img0 = csi0.snapshot()
csi1.snapshot(blocking=False, image=img1)
img0.draw_image(img1, 0, 0, color_palette=image.PALETTE_IRONBOW,
alpha_palette=alpha_pal,
hint=image.BILINEAR,
transform=m)
print(clock.fps())
Beachten Sie, dass diese Variante die Farbkamera mit csi.VGA (640x480) und das Lepton mit csi.QQVGA (160x120) betreibt — die Homographie projiziert das kleinere Lepton-Einzelbild als Teil des Zeichenvorgangs in das größere Farb-Einzelbild, sodass der Hochskalierungsfaktor in die Matrix selbst eingebacken ist, statt separat angewendet zu werden.