Multispectraal thermisch (PAG7936)

De PAG7936-variant van de Multispectral Thermal Camera Module combineert een 1 MP global-shutter kleursensor met een FLIR Lepton thermische kern, zodat de OpenMV Cam tegelijkertijd kleurvisie- en thermische pijplijnen kan uitvoeren.

Multispectraal thermisch (PAG7936)

Voor de volledige datasheet, foto’s en bestelinformatie, zie de Multispectral Thermal-productpagina.

Notitie

Alleen ondersteund op de OpenMV N6.

Hoogtepunten

  • PAG7936: 1 MP global shutter

  • Accepteert FLIR Lepton 1.x / 2.x / 3.x thermische kernen

  • Gelijktijdige thermische + kleurverwerking op één module

  • Ziet in volledige duisternis, ondersteunt temperatuurmeting

  • Global shutter verwerkt snelle beweging zonder rolling-shutter-artefacten

Gebruik

De kleursensor en de FLIR Lepton krijgen elk hun eigen csi.CSI-instantie. De eerste aanroep gebruikt standaard de primaire sensor (de PAG7936); de tweede koppelt aan de Lepton door cid= csi.LEPTON mee te geven. Voer een hard-reset uit op de kleursensor met csi.CSI.reset (hard=True) om de voedingsrail op te brengen, en configureer de Lepton met hard=False zodat zijn driver alleen de chip herprogrammeert zonder de reset opnieuw te schakelen.

csi.CSI.framesize ( csi.QVGA ) stemt de Lepton-uitvoer af op de kleurcamera, zodat elke snapshot() een 320x240-frame teruggeeft. De Lepton-driver schaalt intern zijn 80x60 (1.x/2.x) of 160x120 (3.x) native frame op naar de gevraagde grootte — bij QVGA bestrijkt elke Lepton-pixel een 4x4- of 2x2-cel op het kleurframe.

Twee scratch-buffers blijven constant gedurende de framelus — een 256x1 alpha-palet opgeslagen als een image.Image zodat koele Lepton-pixels transparant worden en hete pixels ondoorzichtig (de kwadratische helling onderdrukt achtergronddetail zonder het middenbereik te pletten), en een Lepton-framebuffer die vooraf is gealloceerd met image.Image zodat csi.CSI.snapshot (blocking=False, image=...) deze elke iteratie ter plaatse kan vullen zonder opnieuw te alloceren:

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())

Elke iteratie maakt een blokkerende kleuropname en een niet-blokkerende Lepton-opname — de Lepton draait op 9 Hz, dus erop blokkeren zou de kleurpijplijn afremmen. Image.draw_image compositeert vervolgens de twee: color_palette= image.PALETTE_IRONBOW mapt de grijswaarden van de Lepton naar een FLIR-achtige warme kleurhelling, alpha_palette= mengt elke pixel met de kwadratische alpha-map, en hint= image.BILINEAR maakt de opschaling vloeiend.

Temperatuurmeting

Radiometrische Leptons (Lepton 2.5 / 3.5) rapporteren gekalibreerde temperatuurgegevens per pixel. Schakel de meetmodus in via csi.CSI.ioctl met csi.IOCTL_LEPTON_SET_MODE, en klem vervolgens het temperatuurvenster vast met csi.IOCTL_LEPTON_SET_RANGE (min_celsius, max_celsius). De Lepton-driver mapt grijswaarde-pixelwaarde 0 lineair naar min_celsius en 255 naar max_celsius, zodat elke pixel een temperatuuropzoeking binnen het geconfigureerde venster wordt. Pixels kouder dan min_celsius verzadigen op 0, pixels heter dan max_celsius verzadigen op 255.

csi.IOCTL_LEPTON_SET_MODE neemt twee vlaggen. De eerste schakelt het meten in; de tweede selecteert het temperatuurbereik van de sensor:

  • Laag bereik(True, False) — sensorbereik -10 °C tot +140 °C (scènes op kamerschaal). Klem het venster vast op het aandachtsgebied, bijv. (20.0, 40.0) voor het volgen van lichaamswarmte:

    csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False)
    csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
    
  • Hoog bereik(True, True) — sensorbereik -10 °C tot typisch ~+450 °C (~+400 °C bij kamertemperatuur) voor hete objecten. Klem vast op bijv. (0.0, 400.0) voor het volgen van ovens of hete elementen:

    csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, True)
    csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 0.0, 400.0)
    

Om een grijswaarde-pixel terug te converteren naar Celsius:

def p_to_temp(p, min_t, max_t):
    return (p * (max_t - min_t)) / 255.0 + min_t

Dit werkt op individuele pixels of op geaggregeerde statistieken (bijv. stats.mean() van Image.get_statistics) binnen een ROI bij het lokaliseren van hete/koele regio’s met Image.find_blobs.

GPU-versnelde uitlijning

Image.draw_image accepteert een transform=-argument — een 3x3-homografiematrix als een 2D ulab.numpy-array. Op de OpenMV N6 voert de GPU de projectie per pixel uit tijdens dezelfde teken-operatie, zodat het Lepton-frame opnieuw kan worden uitgelijnd op het perspectief van de kleurcamera zonder een aparte warp-doorloop. Kalibreer de matrix per camera met de thermal-overlay-calibration tool

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())

Merk op dat deze variant de kleurcamera op csi.VGA (640x480) draait en de Lepton op csi.QQVGA (160x120) — de homografie projecteert het kleinere Lepton-frame in het grotere kleurframe als onderdeel van de teken-operatie, zodat de opschaalfactor in de matrix zelf is verwerkt in plaats van apart te worden toegepast.