☰
大疆热红外RJPG工程化处理:TSDK解析与Pix4D温度正射影像生成
2026/9/29 17:48:40 网站建设 项目流程

1. 热红外数据工程化处理的整体设计思路

1.1 为什么需要工程化处理

大疆行业级无人机挂载热红外相机(如Zenmuse H20T、XT2、H30T等)采集回来的原始数据,默认输出的是RJPG格式。RJPG本质上是"带温度信息的JPEG"——它在标准JPEG的APP段里嵌入了R-JPEG私有数据块,包含原始辐射值、发射率参数、环境温度、距离、湿度等元数据。直接用普通看图软件打开,你看到的只是一张伪彩色图,温度信息完全读不出来。

很多人第一次接触RJPG,会以为用Pix4D直接拖进去就能出温度正射影像。实测下来,Pix4D对RJPG的支持是"能读伪彩图,但读不出绝对温度"。也就是说,你拿到的正射影像只有颜色,没有温度值。要得到真正可用的温度正射影像(每个像素对应一个摄氏度数值),必须先把RJPG里的辐射数据解出来,转成Pix4D能识别的带温度信息的TIFF,再走空三和正射流程。

这套工作流的核心价值在于:把"只能看"的热红外图,变成"能算"的温度数据。农业估产、建筑热损检测、光伏板热斑定位、电力巡检、地暖漏水排查,这些场景要的不是一张好看的伪彩图,而是能导出温度矩阵、能做阈值分析、能生成温度等值线的正射成果。

1.2 整体流程拆解

整个工作流我把它拆成四个阶段,每个阶段都有明确的输入输出:

阶段输入核心操作输出
数据提取RJPG原始文件TSDK解析辐射数据带温度TIFF + 元数据JSON
数据校验温度TIFF温度范围检查、坏帧剔除合格影像集
空三与正射温度TIFFPix4D空三、正射生成温度正射影像
成果应用温度正射温度矩阵导出、分析温度报告/等值线

这个拆法的逻辑是:把"数据解析"和"摄影测量"彻底分开。TSDK负责把物理量(辐射值)还原成温度,Pix4D负责把二维影像还原成三维空间位置。两者各司其职,中间用标准TIFF做接口。这样做的好处是,任何一步出问题都能单独排查,不会混在一起。

1.3 工具选型背后的考量

为什么用TSDK而不是自己解析RJPG?

RJPG的私有数据块格式大疆没有完全公开,网上能找到的解析代码大多是逆向出来的,版本兼容性很差。TSDK(Thermal SDK)是大疆官方提供的,支持Windows和Linux,提供C++接口和Python绑定。它内部处理了不同相机型号(XT2、H20T、H30T)的差异,你只需要调用irdata相关接口就能拿到原始辐射值。自己逆向的话,换个固件版本可能就崩了。

为什么用Pix4D而不是其他空三软件?

热红外影像有个特点:分辨率低(通常640×512)、纹理弱、对比度差。普通可见光空三软件在热红外图上经常匹配失败。Pix4D的Aerial Grid模式和自定义模板对低纹理影像的匹配策略更成熟,而且它支持导入带地理信息的TIFF,能直接读取温度波段。另一个原因是Pix4D的成果导出格式灵活,能输出GeoTIFF,方便后续用Python做温度分析。

为什么中间要转TIFF而不是直接用RJPG?

Pix4D读RJPG时只取伪彩图,温度信息丢失。转成TIFF时,我们把温度值写入像素值(比如温度×100存为16位整数),同时把地理坐标、相机参数写进TIFF的元数据。这样Pix4D既能看到影像,又能保留温度数值。用16位整数而不是浮点,是因为Pix4D对浮点TIFF的支持不稳定,16位整数范围-32768到32767,按温度×100存,能覆盖-327.68℃到327.67℃,足够所有常规场景。

2. TSDK环境搭建与RJPG解析核心细节

2.1 TSDK安装与Python环境配置

TSDK的Python绑定安装是第一个坑。官方文档写得比较简略,实际配置时容易卡在依赖上。

Windows环境:

# 建议用conda建独立环境,避免和系统Python冲突 conda create -n thermal python=3.9 conda activate thermal # 安装TSDK Python包,注意版本要和相机固件匹配 pip install dji-thermal-sdk # 核心依赖 pip install numpy opencv-python pillow gdal

这里Python版本建议3.8到3.10,3.11以上有些依赖轮子还没跟上。dji-thermal-sdk安装后,还需要把TSDK的动态库路径加到系统PATH里,否则import时会报找不到dll。

Linux环境:

# Ubuntu 20.04/22.04实测可用 sudo apt install libusb-1.0-0-dev libopencv-dev pip install dji-thermal-sdk

Linux下要注意权限问题,TSDK访问相机USB设备需要udev规则,但纯离线解析RJPG文件不需要连相机,所以这一步可以跳过。

注意:TSDK的Python包在不同平台上的接口名略有差异,Windows下是dji_thermal_sdk,Linux下可能是dji_thermal,import前先确认。

2.2 RJPG文件结构解析

RJPG文件里其实藏着三层数据:

第一层是标准JPEG图像数据,就是你能看到的伪彩图,分辨率通常是640×512或1280×1024。

第二层是R-JPEG私有段,存在APP1或APP2标记里,包含原始辐射值矩阵(16位)、发射率、反射温度、大气温度、湿度、距离、镜头参数等。

第三层是XMP元数据,记录GPS坐标、云台姿态、拍摄时间。

TSDK解析时,核心是调用irdata接口:

import dji_thermal_sdk as dts # 初始化 dts.init() # 读取RJPG ir_data = dts.irdata_create_from_rjpeg("DJI_0001_R.JPG") # 获取温度矩阵,单位摄氏度 temp_matrix = dts.irdata_get_temperature_matrix(ir_data) # 获取元数据 emissivity = dts.irdata_get_emissivity(ir_data) ambient_temp = dts.irdata_get_ambient_temperature(ir_data) distance = dts.irdata_get_object_distance(ir_data) # 释放 dts.irdata_destroy(ir_data)

temp_matrix是一个numpy数组,形状和影像分辨率一致,每个元素是摄氏度浮点值。这一步拿到的就是"真温度",不是伪彩图的颜色映射。

2.3 温度矩阵转TIFF的关键参数

拿到温度矩阵后,不能直接存成TIFF,要做几个处理:

温度值缩放:Pix4D读16位TIFF时,默认按整数处理。我们把温度×100存为int16,这样0.01℃的精度能保留。读取时再除以100还原。

import numpy as np import rasterio # 温度矩阵转int16 temp_scaled = (temp_matrix * 100).astype(np.int16) # 写入TIFF,带地理信息 with rasterio.open( "DJI_0001_T.TIF", "w", driver="GTiff", height=temp_scaled.shape[0], width=temp_scaled.shape[1], count=1, dtype=np.int16, crs="EPSG:4326", transform=from_origin(lon, lat, pixel_size, pixel_size) ) as dst: dst.write(temp_scaled, 1)

地理信息写入:从XMP里读GPS坐标和云台姿态,计算每个像素的地理位置。如果嫌麻烦,也可以先不写地理信息,让Pix4D从EXIF里读,但实测下来Pix4D对热红外影像的EXIF解析经常出问题,手动写入更稳。

发射率设置:这是最容易忽略的参数。TSDK默认发射率是0.95,但实际场景中,水体发射率约0.98,混凝土约0.92,金属约0.1到0.3。发射率设错,温度能差好几度。如果拍摄时没在相机里设置,后期可以在TSDK里重新计算:

# 重新设置发射率并计算温度 dts.irdata_set_emissivity(ir_data, 0.92) temp_matrix = dts.irdata_get_temperature_matrix(ir_data)

提示:发射率、反射温度、距离、湿度这四个参数,任何一个变了都要重新计算温度矩阵。建议在解析时就把这些参数记到JSON里,方便追溯。

3. Pix4D温度正射影像生成实操

3.1 工程创建与影像导入

Pix4D新建工程时,选"New Project",然后导入转换好的温度TIFF。这里有个关键设置:在"Image Properties"里,把影像类型选为"Thermal"(如果有这个选项),或者选"Multispectral"再手动配置波段。

Pix4D 4.5以上版本对热红外TIFF的支持比较好,但要注意:

  • 不要勾选"Use EXIF GPS",因为热红外影像的EXIF经常不准,用手动写入的GeoTIFF坐标更可靠。
  • 在"Processing Options"里,把"Camera Model"选为"Custom",然后手动输入热红外相机的内参。大疆H20T的热红外镜头焦距是13.5mm,传感器尺寸是640×512,像素间距12μm。这些参数在TSDK的元数据里能读到。
# 从TSDK读取相机内参 focal_length = dts.irdata_get_focal_length(ir_data) # 单位mm sensor_width = dts.irdata_get_sensor_width(ir_data) # 单位mm

3.2 空三处理的关键参数调整

热红外影像空三是整个流程最容易失败的地方。默认参数下,匹配点数量经常不够,导致空三失败或精度很差。我踩过的坑和对应的调整策略:

匹配策略调整:在"Processing Options" → "Matching"里,把"Image Scale"从默认的1/2改成1/1(全分辨率匹配)。热红外影像本身分辨率就低,再降采样就没法匹配了。

关键点数量:把"Keypoint Density"调到"High"。热红外影像纹理弱,需要更多关键点才能找到足够的匹配对。

匹配对数量:把"Minimum Number of Matches"从默认的6降到4。热红外影像对比度低,匹配质量差,降低阈值能增加匹配对,但要注意后续用"Tie Point Editor"手动剔除错误匹配。

初始对准:如果影像有重叠度不够的区域,可以在"Initial Processing"里勾选"Use GPS for Initial Alignment",用GPS做初始位置估计,减少匹配搜索范围。

实测下来,一套200张的H20T热红外数据,默认参数空三成功率大概60%,调整后能到90%以上。剩下的10%通常是影像重叠度不够或者飞行高度太高导致分辨率不足。

3.3 正射影像生成与温度值保留

空三完成后,生成正射影像时要注意:

输出格式:选GeoTIFF,不要选JPEG或PNG,否则温度值会丢失。

输出分辨率:热红外影像本身分辨率低,正射影像分辨率不要设得太高,否则会插值出很多虚假细节。建议按GSD(地面采样距离)设置,H20T在50米高度飞行时,GSD约4cm,正射影像分辨率设4cm/像素比较合适。

温度值映射:Pix4D生成正射影像时,会把多个影像的温度值做加权平均。这里有个问题:如果不同影像的发射率设置不一致,平均后的温度值没有物理意义。所以前期解析时,一定要确保所有影像的发射率参数一致。

# 正射影像生成后,读取温度值 import rasterio with rasterio.open("orthomosaic.tif") as src: temp_scaled = src.read(1) temp_matrix = temp_scaled / 100.0 # 还原摄氏度 print(f"温度范围: {temp_matrix.min():.2f} ~ {temp_matrix.max():.2f} ℃")

3.4 温度正射影像的质量检查

生成正射影像后,不能直接就用,要做几个检查:

温度范围检查:正常场景温度范围应该在-20℃到150℃之间。如果出现-200℃或500℃这种异常值,说明有坏帧或者解析错误。

空间一致性检查:同一物体在不同影像上的温度应该接近。如果同一栋楼在相邻两张正射图上温度差超过5℃,说明空三精度不够或者发射率设置有问题。

边缘检查:正射影像边缘区域温度值容易异常,因为边缘影像少,加权平均不稳定。建议裁剪掉边缘10%的区域。

4. 常见问题排查与避坑经验

4.1 TSDK解析常见报错

报错信息原因解决方法
irdata_create_from_rjpeg failedRJPG文件损坏或版本不兼容用官方工具确认文件可读,升级TSDK版本
temperature matrix is None相机型号不支持或元数据缺失检查相机型号,确认RJPG包含R-JPEG段
emissivity out of range发射率设置超出0.1-1.0检查元数据,手动设置合理值
dll load failed动态库路径未配置把TSDK的lib目录加到PATH

4.2 Pix4D空三失败排查

空三失败最常见的原因是影像重叠度不够。热红外相机视场角比可见光小,同样飞行航线,热红外影像的重叠度会低10%到20%。建议飞行时把重叠度设到80%以上。

另一个原因是影像纹理太弱。比如拍水面、雪地、均匀墙面,热红外图上几乎没纹理,匹配点找不到。这种情况可以在Pix4D里手动加控制点,或者用可见光影像做空三,然后把热红外影像配准上去。

4.3 温度值偏差排查

如果发现温度值整体偏高或偏低,按这个顺序排查:

  1. 发射率设置是否正确?金属、玻璃、水面要用对应的发射率。
  2. 反射温度是否设置?反射温度是环境背景辐射,室内拍摄时影响很大。
  3. 距离参数是否正确?TSDK计算温度时会用距离做大气衰减校正,距离设错会导致温度偏差。
  4. 湿度参数是否设置?高湿度环境下,大气衰减明显,湿度设错能差1到2℃。

提示:如果拍摄时没记录这些参数,可以用黑体校准。在拍摄现场放一个已知温度的黑体,后期用黑体的温度值反推参数。

4.4 成果应用中的注意事项

温度正射影像导出后,用Python做分析时要注意:

  • 温度矩阵的单位是摄氏度,如果要转开尔文,加273.15。
  • 正射影像的NoData值通常是-32768,分析前要剔除。
  • 温度值有噪声,做阈值分析前建议先做高斯滤波。
import cv2 import numpy as np # 读取温度正射 temp = cv2.imread("orthomosaic.tif", cv2.IMREAD_ANYDEPTH) / 100.0 # 剔除NoData temp[temp < -100] = np.nan # 高斯滤波去噪 temp_smooth = cv2.GaussianBlur(temp, (5, 5), 0) # 阈值分析,找高温区域 hot_spots = temp_smooth > 60 print(f"高温区域面积: {np.sum(hot_spots)} 像素")

这套工作流我从2022年开始用,前后处理过几十个项目,从农业到建筑到电力巡检都跑过。最深的体会是:热红外数据的工程化处理,难点不在软件操作,而在参数设置。发射率、反射温度、距离、湿度这四个参数,任何一个设错,温度就能差好几度。而很多项目现场根本没条件测这些参数,只能靠经验估计。我的建议是,如果项目对温度精度要求高,一定要在现场做黑体校准,哪怕只是用一个已知温度的热水袋,也比完全靠默认参数强。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询