Multiespectral Térmica (PAG7936)¶
A variante PAG7936 do Módulo de Câmera Multiespectral Térmica combina um sensor de cor de 1 MP com global shutter e um núcleo térmico FLIR Lepton, de modo que a OpenMV Cam pode executar pipelines de visão colorida e térmicos lado a lado.
Para o datasheet completo, fotos e informações de compra, consulte a página do produto Multispectral Thermal.
Nota
Suportada apenas na OpenMV N6.
Destaques¶
PAG7936: global shutter de 1 MP
Aceita núcleos térmicos FLIR Lepton 1.x / 2.x / 3.x
Processamento simultâneo térmico + colorido em um único módulo
Enxerga na escuridão total, suporta medição de temperatura
O global shutter lida com movimento rápido sem artefatos de rolling shutter
Uso¶
O sensor de cor e o FLIR Lepton recebem cada um sua própria instância csi.CSI. A primeira chamada usa por padrão o sensor primário (o PAG7936); a segunda se vincula ao Lepton passando cid= csi.LEPTON. Faça um hard-reset do sensor de cor com csi.CSI.reset (hard=True) para ativar o barramento de alimentação, e configure o Lepton com hard=False para que seu driver apenas reprograme o chip sem reativar o reset.
csi.CSI.framesize ( csi.QVGA ) faz a saída do Lepton corresponder à da câmera de cor, de modo que cada snapshot() retorna um quadro de 320x240. O driver do Lepton internamente faz upscale de seu quadro nativo de 80x60 (1.x/2.x) ou 160x120 (3.x) para o tamanho solicitado — em QVGA cada pixel do Lepton cobre uma célula 4x4 ou 2x2 no quadro de cor.
Dois buffers de rascunho permanecem constantes ao longo do laço de quadros — uma paleta alpha de 256x1 armazenada como uma image.Image, de modo que os pixels frios do Lepton se tornam transparentes e os pixels quentes se tornam opacos (a rampa quadrática suprime os detalhes do fundo sem achatar a faixa média), e um frame buffer do Lepton pré-alocado com image.Image, de modo que csi.CSI.snapshot (blocking=False, image=...) possa preenchê-lo no local a cada iteração sem realocar:
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())
Cada iteração captura um snapshot de cor bloqueante e um snapshot do Lepton não bloqueante — o Lepton roda a 9 Hz, então bloquear nele estrangularia o pipeline de cor. Image.draw_image então compõe os dois: color_palette= image.PALETTE_IRONBOW mapeia a escala de cinza do Lepton para uma rampa de cor quente estilo FLIR, alpha_palette= mescla cada pixel usando o mapa alpha quadrático, e hint= image.BILINEAR suaviza o upscale.
Medição de temperatura¶
Leptons radiométricos (Lepton 2.5 / 3.5) reportam dados de temperatura calibrados por pixel. Ative o modo de medição através de csi.CSI.ioctl com csi.IOCTL_LEPTON_SET_MODE, e então limite a janela de temperatura com csi.IOCTL_LEPTON_SET_RANGE (min_celsius, max_celsius). O driver do Lepton mapeia linearmente o valor de pixel em escala de cinza 0 para min_celsius e 255 para max_celsius, de modo que cada pixel se torna uma consulta de temperatura dentro da janela configurada. Pixels mais frios que min_celsius saturam em 0, pixels mais quentes que max_celsius saturam em 255.
csi.IOCTL_LEPTON_SET_MODE recebe dois sinalizadores. O primeiro ativa a medição; o segundo seleciona a faixa de temperatura do sensor:
Faixa baixa —
(True, False)— alcance do sensor de-10 °Ca+140 °C(cenas em escala de ambiente). Limite a janela à área de interesse, por exemplo(20.0, 40.0)para rastreamento de calor corporal:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
Faixa alta —
(True, True)— alcance do sensor de-10 °Ca~+450 °Ctípico (~+400 °Cà temperatura ambiente) para objetos quentes. Limite a, por exemplo,(0.0, 400.0)para rastreamento de fornalhas ou elementos quentes:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, True) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 0.0, 400.0)
Para converter um pixel em escala de cinza de volta para Celsius:
def p_to_temp(p, min_t, max_t):
return (p * (max_t - min_t)) / 255.0 + min_t
Isso funciona em pixels individuais ou em estatísticas agregadas (por exemplo, stats.mean() de Image.get_statistics) dentro de uma ROI ao localizar regiões quentes/frias com Image.find_blobs.
Alinhamento acelerado por GPU¶
Image.draw_image aceita um argumento transform= — uma matriz de homografia 3x3 como um array ulab.numpy 2-D. Na OpenMV N6 a GPU executa a projeção por pixel durante o mesmo desenho, de modo que o quadro do Lepton pode ser realinhado em relação à perspectiva da câmera de cor sem uma passagem de warp separada. Calibre a matriz por câmera com a ferramenta 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())
Observe que esta variante roda a câmera de cor em csi.VGA (640x480) e o Lepton em csi.QQVGA (160x120) — a homografia projeta o quadro menor do Lepton no quadro maior de cor como parte do desenho, de modo que o fator de upscale fica embutido na própria matriz em vez de ser aplicado separadamente.