3. 测温数据采集:红外热像仪原理、温度数据读取与预处理

各位同学,咱们今天聊点实在的。测温系统里最核心的一环,就是数据采集。你算法再牛,模型再准,原始数据要是脏的、乱的,那后面全是白搭。我这些年调试测温设备,踩过的坑有一半都出在数据采集这一步。所以这一节,咱们把红外热像仪的原理、数据怎么读、怎么洗,一次性讲透。

3.1 红外热像仪的工作原理

说白了,红外热像仪就是个「温度相机」。普通相机拍可见光,它拍的是红外辐射。任何温度高于绝对零度的物体,都会向外辐射红外线。温度越高,辐射越强。热像仪的核心器件是焦平面阵列探测器,它把接收到的红外辐射转换成电信号,再映射成温度值。

我刚开始接触时有个误区:以为热像仪直接输出温度。其实它输出的是原始数字信号(DN值),需要经过标定曲线换算才能得到温度。不同厂家的标定算法不一样,但原理大同小异。

核心公式(简化版):
T = f(DN) —— 原始数字信号 → 温度值
实际工程中,通常用多项式拟合或查表法实现。

3.2 模拟温度数据生成

做开发时,你不可能每次都扛着热像仪调试。所以我习惯先模拟数据。这样算法迭代快,不受硬件限制。下面是我常用的模拟生成方法:

import numpy as np
import random

def generate_temperature_frame(height=24, width=32, base_temp=36.5):
    """
    模拟生成一帧测温数据
    height, width: 热像仪分辨率(常见低分辨率)
    base_temp: 基准温度
    """
    # 生成基础温度场
    frame = np.ones((height, width)) * base_temp
    
    # 模拟人体区域(中心区域升温)
    center_h, center_w = height//2, width//2
    frame[center_h-3:center_h+3, center_w-3:center_w+3] += random.uniform(0.5, 1.5)
    
    # 模拟噪声(传感器固有噪声)
    noise = np.random.normal(0, 0.1, (height, width))
    frame += noise
    
    return frame

# 生成一帧数据
temp_data = generate_temperature_frame()
print(f"温度范围:{temp_data.min():.2f}°C ~ {temp_data.max():.2f}°C")

嗯,这里要注意。模拟数据虽然方便,但噪声模型不能太理想。我曾在项目中直接用高斯噪声模拟,结果算法在真实设备上完全失效。真实热像仪的噪声是空间相关的,还有固定模式噪声。所以模拟时最好加一点「坏像素」和「漂移」。比如:

# 模拟坏像素(死点)
dead_pixels = [(5, 10), (12, 20), (18, 8)]
for h, w in dead_pixels:
    frame[h, w] = -999  # 无效值标记

# 模拟温度漂移(随时间缓慢变化)
drift = np.sin(np.linspace(0, 2*np.pi, width)) * 0.2
frame += drift
我的经验:模拟数据要覆盖三种情况——正常、边界(如高温报警临界值)、异常(如传感器断线)。这样算法才能健壮。

3.3 温度数据预处理

拿到原始数据后,不能直接用。为什么?因为热像仪天生有三大问题:噪声、非均匀性、坏像素。预处理就是解决这些问题的。我一般分三步走:

3.3.1 去噪处理

热像仪的噪声主要是高斯噪声和椒盐噪声。高斯噪声用滤波,椒盐噪声用中值滤波。我个人习惯先做中值滤波,再做高斯滤波。顺序不能反,否则椒盐噪声会扩散。

from scipy.ndimage import median_filter, gaussian_filter

def denoise_temperature(frame):
    # 第一步:中值滤波(去除坏点)
    frame_clean = median_filter(frame, size=3)
    
    # 第二步:高斯滤波(平滑噪声)
    frame_smooth = gaussian_filter(frame_clean, sigma=1.0)
    
    return frame_smooth
避坑指南:我曾经把滤波核设得太大(比如5x5),结果把真正的高温目标给抹平了。测温场景下,滤波核不要超过3x3,sigma不要超过1.5。否则边缘模糊,温度峰值被削。

3.3.2 坏像素修复

热像仪用久了,总会有几个像素坏掉。表现为温度值异常(过高或过低)。修复方法很简单:用周围像素的平均值替代。

def fix_bad_pixels(frame, threshold=5.0):
    """
    修复坏像素
    threshold: 与邻域均值差异超过此值视为坏点
    """
    from scipy.ndimage import uniform_filter
    
    # 计算局部均值
    local_mean = uniform_filter(frame, size=3)
    
    # 检测坏点
    diff = np.abs(frame - local_mean)
    bad_mask = diff > threshold
    
    # 修复
    frame_fixed = frame.copy()
    frame_fixed[bad_mask] = local_mean[bad_mask]
    
    return frame_fixed

3.3.3 归一化处理

归一化是为了让数据落在统一的尺度内,方便后续算法处理。测温场景下,我通常做两种归一化:

归一化类型 公式 适用场景
Min-Max归一化 (x - min) / (max - min) 温度范围已知且稳定
Z-score标准化 (x - mean) / std 温度分布未知,有异常值
def normalize_temperature(frame, method='minmax'):
    if method == 'minmax':
        # 去掉无效值后再归一化
        valid = frame > -100
        min_val = frame[valid].min()
        max_val = frame[valid].max()
        normalized = (frame - min_val) / (max_val - min_val + 1e-8)
        
    elif method == 'zscore':
        valid = frame > -100
        mean = frame[valid].mean()
        std = frame[valid].std()
        normalized = (frame - mean) / (std + 1e-8)
    
    # 无效值置为0
    normalized[~valid] = 0
    return normalized
小技巧:归一化时一定要先剔除无效值(比如坏像素标记的-999)。否则会把正常数据压缩到很小的范围,丢失细节。我吃过这个亏,后来养成了先mask再归一化的习惯。

3.4 知识体系总览

下面这张图,是我梳理的本章核心逻辑。你把它存脑子里,后面几章都会用到。

测温数据采集流程 红外热像仪 红外辐射 → 电信号 → DN值 模拟数据生成 基础温度 + 人体区域 + 噪声 数据预处理 去噪 → 修复 → 归一化 去噪处理 坏像素修复 归一化处理 中值滤波(3x3) 高斯滤波(sigma=1.0) 先中值后高斯 局部均值对比 阈值检测坏点 邻域均值替代 Min-Max / Z-score 先剔除无效值 再归一化

你看,整个流程其实不复杂。但每一步都有细节。我见过很多同学直接拿原始数据跑算法,结果精度一塌糊涂。预处理花的时间,会在后面十倍百倍地省回来。

本章核心要点:
  • 热像仪输出的是DN值,不是温度,需要标定换算
  • 模拟数据要包含噪声、坏像素、漂移,不能太理想
  • 预处理三步走:去噪 → 修复坏像素 → 归一化
  • 滤波核宁小勿大,归一化前先剔除无效值

公众号:蓝海资料掘金营,微信deep3321