多光谱热成像(PAG7936)¶
多光谱热成像摄像头模组的 PAG7936 版本将一颗 1 MP 全局快门彩色传感器与 FLIR Lepton 热成像核心相结合,使 OpenMV Cam 能够并行运行彩色视觉和热成像处理流程。
完整的数据手册、照片和订购信息请参阅 多光谱热成像产品页面。
备注
仅在 OpenMV N6 上受支持。
亮点¶
PAG7936:1 MP 全局快门
可搭配 FLIR Lepton 1.x / 2.x / 3.x 热成像核心
在单个模组上同时进行热成像与彩色处理
可在完全黑暗中成像,支持温度测量
全局快门可处理快速运动而不会产生卷帘快门伪影
用法¶
彩色传感器和 FLIR Lepton 各自拥有独立的 csi.CSI 实例。第一次调用默认绑定到主传感器(即 PAG7936);第二次调用通过传入 cid= csi.LEPTON 绑定到 Lepton。使用 csi.CSI.reset (hard=True) 对彩色传感器进行硬复位以拉起供电电源轨,而配置 Lepton 时使用 hard=False,使其驱动仅重新编程芯片而不再次切换复位。
csi.CSI.framesize ( csi.QVGA ) 使 Lepton 输出与彩色摄像头相匹配,因此每次 snapshot() 都返回一个 320x240 的帧。Lepton 驱动会在内部将其 80x60(1.x/2.x)或 160x120(3.x)的原生帧放大到所请求的尺寸——在 QVGA 下,每个 Lepton 像素覆盖彩色帧上的一个 4x4 或 2x2 单元。
有两个临时缓冲区在帧循环中保持不变——一个是存储为 image.Image 的 256x1 alpha 调色板,使较冷的 Lepton 像素变为透明、较热的像素变为不透明(二次方斜坡在不压缩中间区域的前提下抑制背景细节),以及一个用 image.Image 预分配的 Lepton 帧缓冲区,使 csi.CSI.snapshot (blocking=False, image=...) 可以在每次迭代中就地填充它而无需重新分配:
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())
每次迭代会进行一次阻塞式彩色快照和一次非阻塞式 Lepton 快照——Lepton 以 9 Hz 运行,因此对其进行阻塞会拖慢彩色处理流程。随后 Image.draw_image 将两者合成:color_palette= image.PALETTE_IRONBOW 将 Lepton 的灰度映射为 FLIR 风格的暖色斜坡,alpha_palette= 使用二次方 alpha 映射混合每个像素,hint= image.BILINEAR 平滑放大过程。
温度测量¶
辐射式 Lepton(Lepton 2.5 / 3.5)会报告经过校准的逐像素温度数据。通过 csi.CSI.ioctl 配合 csi.IOCTL_LEPTON_SET_MODE 启用测量模式,然后用 csi.IOCTL_LEPTON_SET_RANGE (min_celsius, max_celsius) 限定温度窗口。Lepton 驱动会将灰度像素值 0 线性映射到 min_celsius、将 255 线性映射到 max_celsius,因此每个像素在所配置的窗口内成为一次温度查找。低于 min_celsius 的像素饱和为 0,高于 max_celsius 的像素饱和为 255。
csi.IOCTL_LEPTON_SET_MODE 接受两个标志。第一个打开测量功能;第二个选择传感器的温度范围:
低范围 ——
(True, False)—— 传感器跨度为-10 °C到+140 °C(室内尺度的场景)。将窗口限定到感兴趣区域,例如用(20.0, 40.0)进行体温追踪:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, False) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 20.0, 40.0)
高范围 ——
(True, True)—— 传感器跨度通常为-10 °C到~+450 °C(室温下约为~+400 °C),适用于高温物体。可限定为例如(0.0, 400.0)用于熔炉或热元件追踪:csi1.ioctl(csi.IOCTL_LEPTON_SET_MODE, True, True) csi1.ioctl(csi.IOCTL_LEPTON_SET_RANGE, 0.0, 400.0)
将灰度像素转换回摄氏度:
def p_to_temp(p, min_t, max_t):
return (p * (max_t - min_t)) / 255.0 + min_t
这适用于单个像素,也适用于 ROI 内的聚合统计数据(例如来自 Image.get_statistics 的 stats.mean()),可在使用 Image.find_blobs 定位热/冷区域时使用。
GPU 加速对齐¶
Image.draw_image 接受一个 transform= 参数——一个 3x3 单应性矩阵,以二维 ulab.numpy 数组的形式表示。在 OpenMV N6 上,GPU 会在同一次绘制过程中执行逐像素投影,因此 Lepton 帧无需单独的变形处理过程即可重新对齐到彩色摄像头的视角。请使用 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())
请注意,此版本将彩色摄像头运行在 csi.VGA(640x480)而 Lepton 运行在 csi.QQVGA(160x120)——单应性矩阵在绘制过程中将较小的 Lepton 帧投影到较大的彩色帧中,因此放大系数已内置于矩阵本身,而非单独应用。