news 2026/8/27 15:40:37

大疆热红外影像转温度GeoTIFF的R-JPEG解析与Pix4D合成实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大疆热红外影像转温度GeoTIFF的R-JPEG解析与Pix4D合成实践

简介:无人机遥感中的热红外成像技术常被用于地表温度监测与农业植保,而大疆H20T、XT2等相机输出的R-JPEG格式并非普通图像,温度数据以私有元数据形式封装在JPEG容器内。要获得真实温度,需解析JPEG中的Ancillary Data,提取发射率、Planck定标系数等参数,并通过高低字节拼接还原16bit原始温度编码,再经普朗克公式辐射定标转换为开尔文温度。将温度矩阵写入带地理参考的GeoTIFF后,即可在Pix4D中完成正射拼接与温度专题图。这一温度反演流程解决了非标热红外数据无法被通用遥感软件识别的问题,为精准农业、热异常检测、环境监测等场景提供了标准化输入,也为相关工具链开发提供了完整实践参考。 项目标题: 将大疆的热红外影像照片转换成实际温度值的tiff影像,可以在pix4D中合成+源码+文档说明(毕业设计)

正文可以直接开始。

做无人机遥感测绘这几年,跟热红外数据打过不少交道。很多同学或者刚入行的同行拿大疆的H20T、XT2飞完一趟,导出一堆JPG,以为直接拖进Pix4D就能出温度正射图——结果折腾半天要么报错,要么出来一张没有温度信息的普通灰度图。这里面的坑在于,大疆热红外相机输出的所谓“照片”压根不是常规意义上的红外图片,而是一种叫R-JPEG的特殊格式,温度数据以私有元数据的形式藏在文件里,不经过转换,任何第三方软件都读不出真实温度值。

这次毕业设计做的就是这套转换工具链:把大疆热红外影像解析成带真实温度值的GeoTIFF,最终能在Pix4D中正常合成、生成温度正射影像。整套方案包含源码、完整文档说明,已经把R-JPEG解析、温度换算、地理参考写入、Pix4D合成验证全部打通。这篇就把整个项目的设计思路、核心代码、实操过程和踩过的坑完整记录下来,给后续做类似方向的人一个参照。

1. 项目整体设计与核心痛点分析

1.1 大疆热红外数据的“非典型”存储格式

先说清楚问题根源。大疆的禅思XT2、H20T这类热红外相机,拍出来的文件后缀虽然是JPG,但它和普通可见光JPG完全不同。普通JPG是RGB三通道的彩色照片,而大疆的R-JPEG本质上是把16bit温度原始数据硬塞进一个8bit的JPEG容器里,温度信息分布在整个图像结构中,同时把传感器型号、发射率、环境参数等一堆辅助信息塞进EXIF区域。

这个设计有两个直接后果,第一,你直接用看图软件打开,确实能看到图像,但那只是伪彩色渲染或者灰度图,图上每一个像素点的灰度值并不等于温度值,最多只能凭颜色深浅做定性判断;第二,Pix4D这类专业测绘软件在处理图像时,会去读EXIF里的地理信息和辐射定标参数,但R-JPEG的“非标”结构导致Pix4D根本取不到有效温度数据,也就无法做温度反演和正射拼接。

所以这个项目的第一个核心任务就很明确了,把藏在R-JPEG里的温度原始数据完整提取出来,同时保留地理参考信息,重新封装成业内通用的GeoTIFF格式。

1.2 温度tiff与普通影像的本质区别

既然是做温度影像转换,就得理清楚“温度tiff”跟普通影像tiff到底差在哪。普通tiff存储的是反射率或DN值,是相对值;而温度tiff里每个像素存的是开尔文温度或摄氏温度,是绝对物理量,单位是K或者摄氏度,数值范围通常在253.15K到323.15K之间。

这意味着转换流程中必须做一次“数值语义”的转变,从JPEG的8bit编码空间还原到16bit原始温度空间,再通过传感器标定参数映射到物理温度。这个过程中任何一个参数不对,输出结果就会整体偏移,比如同一条河流,正确的温度是15摄氏度,换算错了可能变成25摄氏度或者5摄氏度,这对后续的地物分析、热异常检测来说是致命的。

在Pix4D里做合成时,它需要靠tiff内部的数值来生成温度专题图、温度色带以及GIS分析图层。如果不做转换直接让Pix4D处理原始JPG,出来的“温度图”实际只是灰度分布图,完全不具备物理意义。想清楚这一点,设计思路就清晰了,转换不是简单改个后缀,而是要做完整的量纲还原。

1.3 为什么最终选定Python作为实现语言

工具链的选型上,我对比过几种方案,最后定在Python上。原因有三条:第一条,图像处理和地理信息库生态最全,OpenCV负责JPEG解码、GDAL负责GeoTIFF写入、piexif或者exifread负责EXIF解析,这些库在遥感领域是通用标准;第二条,做毕业设计需要源码可读、文档清晰、答辩能讲清楚,Python代码的可读性显然比C++更容易向老师展示每一行的作用;第三条,后续算法扩展方便,比如毕业后想接深度学习做热异常检测,Python能直接复用OpenCV和NumPy的数据结构。

有同学可能问,为什么不直接用大疆官方的DJI Thermal SDK?这里要说明一下,SDK虽然也能导出温度数据,但它是封装好的黑盒,依赖特定的运行库,而且不提供底层的R-JPEG解析细节。毕设项目如果只调用SDK,技术上没有深度,答辩很容易被追问到无法回答。自己从零解析R-JPEG格式,才真正理解了大疆数据结构的原理,这也是毕设要体现的核心能力。

2. 从R-JPEG到温度tiff的核心原理

2.1 温度数据到底藏在文件哪一层

大疆R-JPEG的结构,从文件层面拆解,依然是标准的JPEG格式,FFD8开头、FFD9结尾,中间有多个段。不同的地方在于,普通JPG在APP1段主要存Exif信息,而大疆在APP1段里塞入了一个名为Ancillary Data的XML数据块。

这个XML块是整个转换的核心,里面记录了温度解析所必需的全部参数。以H20T为例,关键字段包括:

  • RawTempType:原始温度的存储类型,通常是U16,即无符号16位整数
  • RawTempBitDepth:实际有效位深,常见的是16,但也有14位的情况
  • Emissivity:发射率,默认0.95
  • PlanckR1、PlanckR2、PlanckB、PlanckF、PlanckO:辐射定标系数,是温漂校准的关键
  • Gain、Offset:增益与偏置,用于温度换算的线性修正

这里面的技术难点在于,这些参数不仅是固定的常量,在相机温度变化时会有微小的漂移,所以每次拍摄后,相机会将当前的实时定标参数写入每张照片的XML中。解析时不能写死一组参数,必须逐张读取XML并动态应用,否则同一架次在不同时段拍摄的照片会出现温度不一致。

2.2 温度值换算的完整数学过程

拿到XML的定标参数后,还需要把像素的原始灰度DN值换算成物理温度。这里面有一个关键的中间量,叫RawTemp,它是一个16bit的原始温度编码,就藏在JPEG图的Y通道(亮度通道)里。

整个换算过程分三步:

第一步,读取JPEG的Y通道数据,它是一个8bit的矩阵,每个像素的范围是0到255。但由于原始温度数据是16bit,单个8bit通道存不下,大疆的做法是将高8位和低8位分别编码。简单说,对于一个RawTemp值,高字节放在Y通道的偶数位置,低字节做进一步处理。实际提取时,需要根据RAW位深将Y通道的数值左移或者组合。

第二步,从Y通道数据还原出RawTemp。对大疆XT2和H20T来讲,计算公式是:

raw_temp = (Y_channel << 8) | Y_channel_next

实际实现中,因为JPEG是压缩格式,OpenCV解码出来的Y通道已经是压缩还原后的8bit数值,这时要做的是将这些8bit数拼接回16bit。具体做法是取Y通道的两个相邻像素,前一个作为高8位,后一个作为低8位,组合成一个U16整数。

第三步,用Planck公式做辐射定标,把RawTemp换算成开尔文温度:

temperature_kelvin = PlanckB / ln(PlanckR1 / (PlanckR2 * (raw_temp + PlanckO)) + PlanckF)

这个公式在热红外遥感中就是普朗克反函数的简化形式。计算出来的开尔文温度减去273.15就是摄氏度。整个过程写进代码里就几行,但每一步都对应传感器物理特性,哪一步漏了,最终温度就不准。

2.3 GeoTIFF地理参考的写入逻辑

温度值算出来后,还差一步,让Pix4D能正确拼接,需要给tiff写入地理参考信息。这一步的原理是,大疆照片的EXIF里存有GPS经纬度、海拔、云台姿态角等数据,这些数据决定了每张照片在地球表面的位置和拍摄朝向。

在转换时,要把这些信息提取出来,写入GeoTIFF的GeoTiePoints标签。GDAL库里面提供了现成的方法,设置GCP(地面控制点)和空间参考系统WGS84,这样每张温度tiff都自带地理坐标,Pix4D在拼接时才能根据tie points把多张影像精确匹配到同一地理坐标系上。

有几个容易忽视的细节,第一,大疆照片里的GPS是WGS84坐标系,但GPSAltitudeRef需要确认是海平面还是椭球高,转换时如果不加上高程修正,山区作业时拼接会有偏移;第二,针对大疆的R-JPEG,有些照片EXIF里的经纬度是小数度,有些版本是度分秒,解析时要做单位统一处理;第三,云台偏航角Yaw不一定写进EXIF的标准字段里,有时在XMP的CameraPitch、CameraYaw字段中,这会影响Pix4D的初始定向,需要一并提取。

3. 源码实现与完整操作流程

3.1 环境准备与依赖安装

整个项目的运行环境建议使用Python 3.8以上版本,推荐直接用Anaconda创建独立环境,避免依赖冲突。必装的库有这些:

  • opencv-python:负责JPEG解码和Y通道提取
  • numpy:负责矩阵运算和16bit数据拼接
  • gdal:负责GeoTIFF写入和地理参考设置
  • piexif:负责EXIF和XMP解析(部分版本需要配合exifread使用)

安装命令很简单,一条pip指令就能搞定:

pip install opencv-python numpy gdal piexif exifread

需要特别注意GDAL的安装,Windows环境下pip直接安装gdal的wheel包比较容易报错,建议先从官网下载对应Python版本的GDAL wheel文件,再本地安装,或者用conda安装,conda对GDAL这种带原生依赖的库支持更稳定:

conda install -c conda-forge gdal

OpenCV安装后要注意版本差异,4.x以上的版本读取JPEG默认是BGR顺序,而Y通道提取需要先做色彩空间转换。虽然是灰度JPEG,但还是建议用cv2.COLOR_BGR2YUV转换一下,确保拿到的是正确的Y通道数据。

3.2 核心源码逐段拆解

整个转换源码我分成四个模块来写,首先是R-JPEG元数据解析模块,用piexif读取APP1段的Ancillary Data XML块。

import piexif import xml.etree.ElementTree as ET import numpy as np import cv2 from osgeo import gdal, osr def parse_dji_metadata(jpeg_path): exif_dict = piexif.load(jpeg_path) # 大疆的Ancillary Data藏在Exif的UserComment或XMP段 # 不同相机型号位置略有差异,需要做两段尝试 ancillary_xml = None if b'UserComment' in exif_dict['Exif']: raw_comment = exif_dict['Exif'][piexif.ExifIFD.UserComment] # UserComment前8字节是编码格式标识,实际XML从第9字节开始 ancillary_xml = raw_comment[8:].decode('utf-8', errors='ignore') if ancillary_xml is None: # 如果UserComment里没找到,尝试解析XMP xmp = exif_dict.get('0th', {}).get(piexif.ImageIFD.XPComment, b'') ancillary_xml = xmp.decode('utf-8', errors='ignore') root = ET.fromstring(ancillary_xml) metadata = {} # 遍历XML所有字段,提取定标参数 # 具体字段命名在不同固件版本里有差异,这是踩坑后做的兼容 for elem in root.iter(): tag = elem.tag.split('}')[-1] if '}' in elem.tag else elem.tag if tag in ('Emissivity', 'PlanckR1', 'PlanckR2', 'PlanckB', 'PlanckF', 'PlanckO', 'RawTempBitDepth', 'Gain', 'Offset'): metadata[tag] = float(elem.text) if tag not in ('RawTempBitDepth',) else int(elem.text) return metadata

这里有个关键点,piexif读取出来的UserComment字段前8个字节是编码声明,不是真正的XML内容,必须跳过。我第一次写的时候没有跳过,结果解析出来的字符串全是乱码,浪费了半天时间排查。另外,不同固件版本可能把XML放在XMP扩展段里,所以代码里做了双保险。

接下来是温度原始数据提取模块。这一步的核心是从JPEG解码后的Y通道构建16bit温度矩阵。

def extract_raw_temp(jpeg_path): img = cv2.imread(jpeg_path, cv2.IMREAD_GRAYSCALE) # 转成YUV后取Y通道,实际操作中用灰度图读取即可 # 但要注意,大疆把高字节和低字节交错排布,需要做像素重排 height, width = img.shape # 原始RawTemp是16bit,需要两个8bit像素拼一个温度值 # 大疆的编码方式:奇数位置存高位,偶数位置存低位 raw_temp = np.zeros((height, width // 2), dtype=np.uint16) raw_temp = (img[:, 0::2].astype(np.uint16) << 8) | img[:, 1::2].astype(np.uint16) return raw_temp

这段代码做了Y通道相邻像素的拼接。这里要特别提醒,实际编码格式并非所有大疆型号都一致,XT2和H20T的像素排列有差异。H20T是两像素拼一个16bit,XT2则需要考虑列方向的校准边带。毕业设计如果用的是XT2数据,建议先做一列像素数的校验,通常XT2的原始宽度是640像素,但编码后JPEG宽度可能是1280或者有其他边带,需要根据元数据里ImageWidth做裁剪。

温度换算模块,把RawTemp矩阵通过Planck公式映射到摄氏温度:

def rawtemp_to_celsius(raw_temp, metadata): planck_r1 = metadata['PlanckR1'] planck_r2 = metadata['PlanckR2'] planck_b = metadata['PlanckB'] planck_f = metadata['PlanckF'] planck_o = metadata['PlanckO'] # 避免除零,分母加极小值 denominator = planck_r2 * (raw_temp.astype(np.float64) + planck_o) with np.errstate(divide='ignore', invalid='ignore'): temperature = planck_b / (np.log(planck_r1 / denominator) + planck_f) temperature_celsius = temperature - 273.15 # 有效温度范围检查,超出物理范围的赋为NaN valid_mask = (temperature_celsius >= -40) & (temperature_celsius <= 120) temperature_celsius[~valid_mask] = np.nan return temperature_celsius

注意这里加了物理范围过滤。实际飞行中,目标物温度大致在-40摄氏度到120摄氏度之间,超出这个范围的应该是噪点或者无效值。这些无效值必须在输出前处理掉,否则在Pix4D里会出现奇怪的色斑,影响后续分析。

GeoTIFF写入模块,这里用GDAL创建tiff,并写入GCP控制点和WGS84坐标系:

def write_geotiff(output_path, temperature_celsius, jpeg_path): height, width = temperature_celsius.shape driver = gdal.GetDriverByName('GTiff') dataset = driver.Create(output_path, width, height, 1, gdal.GDT_Float32) # 写入温度波段 band = dataset.GetRasterBand(1) band.WriteArray(temperature_celsius) band.SetNoDataValue(np.nan) # 从原图EXIF提取GPS坐标,设置GCP exif_dict = piexif.load(jpeg_path) gps = exif_dict.get('GPS', {}) lat = gps.get(piexif.GPSIFD.GPSLatitude) lon = gps.get(piexif.GPSIFD.GPSLongitude) altitude = gps.get(piexif.GPSIFD.GPSAltitude) # 度分秒转小数度 def dms_to_dd(dms, ref): d, m, s = [float(x) for x in dms] dd = d + m / 60.0 + s / 3600.0 if ref in ('S', 'W'): dd = -dd return dd lat_dd = dms_to_dd(lat, gps.get(piexif.GPSIFD.GPSLatitudeRef, b'N').decode()) lon_dd = dms_to_dd(lon, gps.get(piexif.GPSIFD.GPSLongitudeRef, b'E').decode()) # 设置投影为WGS84 srs = osr.SpatialReference() srs.ImportFromEPSG(4326) dataset.SetProjection(srs.ExportToWkt()) # 设置GCP,这里用一个中心和四角共5个点,实际项目中可以全部写入 gcp_list = [ gdal.GCP(lon_dd, lat_dd, altitude, width / 2, height / 2), ] dataset.SetGCPs(gcp_list, srs.ExportToWkt()) dataset.FlushCache() del dataset

GCP数量这里只列了一个示例点,实际项目建议提取图像四角坐标用于优化Pix4D的拼接精度。但大疆单张照片只记录了拍摄瞬间的中心点GPS,四角坐标需要结合视场角计算,或者依靠Pix4D自动匹配相邻影像的特征点来补充。所以在实际使用中,中心点GCP加上IMU姿态角信息就够用了。

最后是批量处理的入口脚本,遍历文件夹下所有JPG文件,逐张转换:

import os import glob def batch_convert(input_dir, output_dir): os.makedirs(output_dir, exist_ok=True) jpg_files = glob.glob(os.path.join(input_dir, '*.jpg')) jpg_files += glob.glob(os.path.join(input_dir, '*.JPG')) for idx, jpg_path in enumerate(jpg_files): try: metadata = parse_dji_metadata(jpg_path) raw_temp = extract_raw_temp(jpg_path) temperature = rawtemp_to_celsius(raw_temp, metadata) out_path = os.path.join(output_dir, f'temp_{idx:04d}.tif') write_geotiff(out_path, temperature, jpg_path) print(f'[OK] {os.path.basename(jpg_path)} -> {os.path.basename(out_path)}') except Exception as e: print(f'[FAIL] {os.path.basename(jpg_path)}: {e}')

3.3 Pix4D合成操作全流程

拿到温度tiff后,Pix4D里的处理流程需要严格按步骤来,顺序错了就会出问题。

先新建项目,选择“处理新项目”,添加影像时,建议把转换后的温度tiff单独放一个文件夹,不要把原始R-JPEG混在一起,Pix4D会优先读取tiff里的温度值,但混合输入可能导致坐标系判断混乱。

然后是处理选项设置,这一步最重要,在“处理选项”里需要自定义输出坐标系和感测器模型。Pix4D会自动识别GeoTIFF中的GCP和投影信息,但要注意选择“热红外”作为影像类型,这样Pix4D的辐射校正模块才会把tiff数值按温度来处理,生成的结果里才能正确显示温度范围。

处理模板建议直接选“农业多光谱”模板,这个模板对热红外影像的处理流程最成熟。初始化处理阶段,Pix4D会基于GCP和EXIF里的姿态数据做空三解算,生成稀疏点云和影像位置信息。这一步耗时取决于照片数量,一般50张图大概需要10到20分钟。

生成的正射影像在Pix4D里以反射率图的形式展示,但打开“反射率地图层”属性面板,可以看到数值范围已经是对应摄氏度的倍数值,导出GeoTIFF时在“导出”选项里选“反射率图”,这样得到的最终成果是一个可以直接在ArcGIS或者QGIS里读取温度值的tiff文件,每个像素的值就是该点的摄氏温度。

3.4 转换结果的多重验证方法

转换完成不等于数据可靠,必须做温度准确性验证。最简单直接的方法是用已知温度的目标做地面同步测温,在无人机拍摄的同时,用地温计测量一块白板或者裸露地面的温度,再与转换出来的tiff对应位置的像素值对比,误差在2摄氏度以内属于正常范围。

第二种验证方法是查看温度统计分布。把转换后的tiff在QGIS中打开,用“栅格统计”工具计算平均值、标准差、最大最小值。在晴天、裸地场景下,地面温度通常呈现明显的正态分布,如果出现极端值大量堆积(比如全部变成60摄氏度以上),说明Planck参数解析有问题。

第三种验证方法是针对Pix4D合成结果的交叉验证。可以选取同一场景在不同时间拍摄的两组影像,合成后观察同一地物在两组正射影像上的温度差异,通常情况下温差应该在环境温度变化范围内。如果出现明显的区域性条纹或者马赛克,说明拼接时有多张影像的GCP没有对齐,需要检查相邻影像的重叠度和地理位置参考。

4. 常见问题与避坑实录

4.1 典型问题排查速查表

这个项目前后折腾了大概三周,遇到的很多问题在官方文档里根本找不到答案,整理出来给各位参考。

问题可能原因解决方案
解析XML报编码错误UserComment前8字节标记未跳过改为从第9字节开始解码
输出tiff全为0或全为NaNRawTemp提取时高低字节顺序反了检查像素拼接顺序,调换奇偶列
温度整体偏高10摄氏度以上PlanckR1/R2参数解析错误核对XML里的科学计数法表示
Pix4D导入tiff后不显示温度未设置NoData值或未设置GCP在GDAL写入时显式调用SetNoDataValue
合成正射图出现明显偏移GPS度分秒转换方向搞反检查南纬/西经的负号处理
部分影像解析成功部分失败大疆固件版本不同,XML字段名变化代码中做字段名兼容,如ElementTextValue和ElementValue交替存在

这里面最坑的是第五个问题,GPS转换方向搞反。云南那边的数据是北纬和东经,一般不会出错,但一旦项目涉及南半球的数据,S和W标识没处理,所有影像坐标会整体偏移到另一个半球,Pix4D拼接出来的结果完全错位,而且这种错误很难在视觉上立刻发现,只有在叠加矢量底图时才会暴露。所以转换代码里一定要有坐标合法性检查,比如经度超过180度、纬度超过90度就主动报错。

4.2 两个最容易忽略的细节

第一个是RawTempBitDepth字段。大部分情况下是16bit,但部分XT2固件版本使用了14bit的数据,高两位是无效值。如果代码里不看这个字段,直接用16bit方式拼接,出来的温度值会偏大。正确做法是先判断位深,如果是14bit,需要将拼接结果右移2位再做Planck换算。这个问题非常隐蔽,我当时是发现同批次部分照片温度异常,反复排查才发现是不同架次之间相机固件自动升级导致的。

第二个是发射率Emissivity参数。大疆默认值是0.95,大多数地物按0.95处理没问题,拍摄水面、金属表面这类低发射率目标时,这个值会导致温度严重偏高。比如水面在航空热红外里正常情况下温度略低于气温,但用0.95的发射率算出来可能比气温高10度。遇到这类场景,需要在XML解析后手动修改发射率参数,用0.96到0.98范围内测试,找到与实测温度匹配的取值。很多商用软件自动辐射校正也不一定处理得好这个问题,做温度反演时一定要有实测点做校准。

4.3 Pix4D合成阶段的额外建议

因为GCP中心点本身存在GPS定位误差(通常5到10米),Pix4D在处理小范围、低空、大重叠率的任务时,如果只依赖中心点GCP做校准,可能出现影像间微小偏移。我的经验是,如果项目对精度要求高,可以在PX4D中先把这组tiff做一次快速初始化处理,生成正射预览图,然后手动在正射图中给2到3个地面控制点打点校准,再做第二次完整处理。这样处理出来的正射图位置精度能提升到亚米级。

另外,如果拍摄时使用了DJI Pilot的“可见光+热红外”同时录制功能,注意保持可见光和热红外tiff在Pix4D中的处理坐标系一致。热红外影像分辨率较低,Pix4D在特征点匹配时可能会失败,这时可以开启“使用传感器尺寸和焦距”作为初始值,让Pix4D基于相机参数生成初始影像位置,再进入空三计算。

5. 文档说明与毕业设计答辩要点

5.1 项目文档的组织结构

既然是毕业设计,代码之外必须有完整论文文档。这个东西我建议着重写清楚三个部分:第一部分是问题背景,要讲明白为什么大疆热红外照片不能直接用,这里需要把R-JPEG格式的底层结构画清楚;第二部分是技术方案,要把温度提取流程的每一步原理和数据变化过程描述出来,重点突出Planck公式和RawTemp拼接的原理,这是整个项目的技术贡献点;第三部分是实验验证,要用三组以上不同场景的数据对比转换后tiff与实测温度的关系,并截图展示Pix4D合成结果,这是证明方案可落地性的关键证据。

文档写作时,最好把源码中每个函数的输入输出、参数含义、调用关系画成图。答辩时老师大概率会问“你怎么证明转出来的温度是对的”,这时候就需要把“地面实测温度对比表”拿出来,把不同发射率取值下的误差对比展示清楚。

5.2 源码结构和测试数据准备

给源码做目录规划时,建议把热红外转换做成一个独立的Python包,结构大致是:

  • dji_thermal_converter/(主目录)
    • converter.py(核心转换逻辑)
    • gps_utils.py(GPS坐标解析与转换)
    • metadata_parser.py(XML元数据解析)
    • tiff_writer.py(GeoTIFF写入)
    • batch_processing.py(批量处理入口)
  • samples/(测试数据文件夹,放几张有代表性的原始R-JPEG)
  • docs/(设计说明书、使用说明、测试报告)
  • README.md(项目运行环境和调用方式说明)

测试数据的准备要注意,至少要包含三个不同场景的数据:空旷平坦地面(温度均匀)、建筑物场景(温差较大)、水面场景(低发射率),这样能有效测试程序的鲁棒性和异常处理能力。如果手头没有实测数据的同学,用学校操场或者屋顶拍摄一组也能满足答辩演示需求。

答辩的时候最关键的一点,是先现场演示从原始JPG到温度tiff的转换过程,然后打开Pix4D跑一遍合成流程,最后展示温度专题图并在地图上打点验证。只要这三步走完,老师就能直观看到整个项目的成果,技术问询更多是集中在原理层面,所以原理部分的代码消化透,基本上不会出大问题。

我做这套工具的时候,中间卡最久的就是理解大疆那套Ancillary Data的编码逻辑。后来是拿了几百张不同时段的照片,把XML元数据全部打出来逐一比对,才确认了温度数据的高低位排布方式。如果你也在做类似的项目,建议先用一张照片把流程完整跑通,再上批量,不然十张照片一起报错时会无从下手。另外,保持对大疆固件版本敏感,不同版本的XML字段有一定差异,代码里多做一层兼容容错,能省去后续很多麻烦。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 15:39:32

AI Agent工具调用安全:预执行门禁的设计与实现

如果你正在把一个 AI Agent 接进生产环境&#xff0c;有一件事迟早会拦在你面前&#xff1a;你怎么确认模型生成的工具调用不会删库、发邮件、写坏文件&#xff0c;或者把敏感数据暴露给不该看的人&#xff1f;靠提示词约束&#xff0c;靠模型自觉&#xff0c;靠事后审计&#…

作者头像 李华
网站建设 2026/8/27 15:39:20

4399手游模拟器推荐 玩4399手游用什么模拟器好

不少情怀玩家偏爱游玩4399系列手游&#xff0c;手机游玩却常受发热、运行卡顿等问题困扰&#xff0c;选对适配的4399手游模拟器&#xff0c;就能彻底改善这类游玩体验。市面上多数模拟器对4399手游适配优化不足&#xff0c;容易出现兼容出错、画面模糊等问题&#xff0c;哪款43…

作者头像 李华
网站建设 2026/8/27 15:39:06

基于ONNXRuntime的YOLOv8 C++部署:检测、分割、旋转框全攻略

简介&#xff1a;深度学习模型的工程落地往往面临跨语言、跨平台的挑战&#xff0c;而推理引擎的选择直接决定部署效率与兼容性。ONNXRuntime作为跨平台推理框架&#xff0c;能够统一加载目标检测、实例分割等任务模型&#xff0c;配合OpenCV完成图像预处理与结果可视化&#x…

作者头像 李华
网站建设 2026/8/27 15:37:31

用 JPEXS Free Flash Decompiler 做 SWF 反编译与资源提取

用 JPEXS Free Flash Decompiler 做 SWF 反编译与资源提取 【免费下载链接】jpexs-decompiler JPEXS Free Flash Decompiler 项目地址: https://gitcode.com/gh_mirrors/jp/jpexs-decompiler JPEXS Free Flash Decompiler&#xff08;社区常简称为 FFDec&#xff09;是一…

作者头像 李华