Termocamera multispettrale (PAG7936)¶
La variante PAG7936 del modulo Multispectral Thermal Camera abbina un sensore a colori global-shutter da 1 MP a un nucleo termico FLIR Lepton, così la OpenMV Cam può eseguire affiancate pipeline di visione a colori e pipeline termiche.
Per il datasheet completo, le foto e le informazioni d’ordine, consulta la pagina prodotto Multispectral Thermal.
Nota
Supportato solo sulla OpenMV N6.
Punti salienti¶
PAG7936: global shutter da 1 MP
Accetta nuclei termici FLIR Lepton 1.x / 2.x / 3.x
Elaborazione termica + a colori simultanea su un unico modulo
Vede nel buio totale, supporta la misurazione della temperatura
Il global shutter gestisce il movimento rapido senza artefatti da rolling shutter
Utilizzo¶
Il sensore a colori e la FLIR Lepton ottengono ciascuno la propria istanza csi.CSI. La prima chiamata usa per impostazione predefinita il sensore primario (la PAG7936); la seconda si associa alla Lepton passando cid= csi.LEPTON. Esegui un hard-reset del sensore a colori con csi.CSI.reset (hard=True) per attivarne l’alimentazione, e configura la Lepton con hard=False in modo che il suo driver si limiti a riprogrammare il chip senza riattivare il reset.
csi.CSI.framesize ( csi.QVGA ) adatta l’uscita della Lepton alla camera a colori, così ogni snapshot() restituisce un frame da 320x240. Il driver Lepton effettua internamente l’upscaling del suo frame nativo da 80x60 (1.x/2.x) o 160x120 (3.x) alla dimensione richiesta: a QVGA ogni pixel della Lepton copre una cella 4x4 o 2x2 sul frame a colori.
Due buffer di lavoro restano costanti per tutto il ciclo dei frame: una palette alpha da 256x1 memorizzata come image.Image, in modo che i pixel freddi della Lepton diventino trasparenti e quelli caldi opachi (la rampa quadratica attenua i dettagli di sfondo senza schiacciare i toni intermedi), e un frame buffer della Lepton pre-allocato con image.Image, così che csi.CSI.snapshot (blocking=False, image=...) possa riempirlo sul posto a ogni iterazione senza riallocare:
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())
Ogni iterazione acquisisce uno snapshot a colori bloccante e uno snapshot Lepton non bloccante: la Lepton funziona a 9 Hz, quindi bloccarsi su di essa rallenterebbe la pipeline a colori. Image.draw_image poi compone i due: color_palette= image.PALETTE_IRONBOW mappa la scala di grigi della Lepton su una rampa di colori caldi in stile FLIR, alpha_palette= fonde ogni pixel usando la mappa alpha quadratica, e hint= image.BILINEAR ammorbidisce l’upscaling.
Misurazione della temperatura¶
Le Lepton radiometriche (Lepton 2.5 / 3.5) riportano dati di temperatura per pixel calibrati. Abilita la modalità di misurazione tramite csi.CSI.ioctl con csi.IOCTL_LEPTON_SET_MODE, poi limita la finestra di temperatura con csi.IOCTL_LEPTON_SET_RANGE (min_celsius, max_celsius). Il driver Lepton mappa linearmente il valore di pixel in scala di grigi 0 su min_celsius e 255 su max_celsius, così ogni pixel diventa una ricerca di temperatura all’interno della finestra configurata. I pixel più freddi di min_celsius saturano a 0, quelli più caldi di max_celsius saturano a 255.
csi.IOCTL_LEPTON_SET_MODE accetta due flag. Il primo attiva la misurazione; il secondo seleziona l’intervallo di temperatura del sensore:
Intervallo basso —
(True, False)— campo del sensore da-10 °Ca+140 °C(scene a scala ambiente). Limita la finestra all’area di interesse, ad es.(20.0, 40.0)per il tracciamento del calore corporeo:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
Intervallo alto —
(True, True)— campo del sensore da-10 °Ca~+450 °Ctipico (~+400 °Ca temperatura ambiente) per oggetti caldi. Limita ad es. a(0.0, 400.0)per il tracciamento di forni o elementi caldi:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, True) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 0.0, 400.0)
Per riconvertire un pixel in scala di grigi in gradi Celsius:
def p_to_temp(p, min_t, max_t):
return (p * (max_t - min_t)) / 255.0 + min_t
Questo funziona su singoli pixel o su statistiche aggregate (ad es. stats.mean() da Image.get_statistics) all’interno di una ROI quando si individuano regioni calde/fredde con Image.find_blobs.
Allineamento accelerato dalla GPU¶
Image.draw_image accetta un argomento transform=: una matrice di omografia 3x3 come array ulab.numpy bidimensionale. Sulla OpenMV N6 la GPU esegue la proiezione per pixel durante lo stesso disegno, così il frame della Lepton può essere riallineato alla prospettiva della camera a colori senza una passata di warp separata. Calibra la matrice per ciascuna camera con lo strumento thermal-overlay-calibration
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())
Nota che questa variante fa funzionare la camera a colori a csi.VGA (640x480) e la Lepton a csi.QQVGA (160x120): l’omografia proietta il frame più piccolo della Lepton nel frame a colori più grande come parte del disegno, quindi il fattore di upscaling è incorporato nella matrice stessa anziché applicato separatamente.