恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
光伏组件红外检测图像数据集构建全攻略:从采集到训练
首页
资讯中心
/
光伏组件红外检测图像数据集构建全攻略:从采集到训练
光伏组件红外检测图像数据集构建全攻略:从采集到训练
发布时间:2026/9/28 7:45:59
简介太阳能设备组件红外检测图像数据集是面向光伏组件质检与智能运维场景的图像资源适合深度学习、计算机视觉方向的开发者用于异常检测模型的训练与评估。数据集包含2万张24×40像素的红外图像标注了12类组件状态其中11类对应不同异常类型1类为无异常正常情形能够为图像分类、缺陷识别等任务提供基础样本。压缩包大小仅15.22MB内含2万个jpg图像文件另附1个md说明文档、1个license许可文件及1个json配置文件方便查阅数据集结构和配置实验参数。目前已有814人学习下载特别适合需要异常样本来构建分类器或对比算法性能的研究者。借助该资源用户可快速搭建太阳能设备红外检测的实验流程利用统一尺寸的小图批量训练模型也可基于多类别标注分析不同异常模式为真实光伏电站的组件状态监测与自动巡检提供数据基础同时支持数据集的二次划分与算法对比研究。1. 太阳能设备组件红外检测图像数据集不是把热像仪照片打包发网盘太阳能设备组件红外检测图像数据集听上去像是一堆热像仪照片加个文件夹名但真正让它和普通图片包区分开的是背后那一整套拍摄口径、温度标定和故障标签体系。你在电站现场拿着热像仪扫一圈拍了几百张组件发热照片回到办公室直接扔给深度学习模型训练十有八九会得到一个精度忽高忽低的黑匣子。原因很简单红外图像记录的是辐射温度分布而不是可见光语义模型学到的可能只是某台相机的伪彩色风格。这套数据集要解决的事情是把“组件表面哪里热”变成模型能稳定学习的“故障是什么”。光伏组件热斑、接线盒过热、旁路二极管失效、隐裂与碎片都表现为温度分布异常但它们的形状、尺度、温差幅度各自不同。适合读这篇文章的人是正在做光伏电站运维巡检、无人机红外巡检或者在做工业设备异常检测算法的人。下面按这个顺序展开先把红外图像与设备故障的映射关系讲清再说现场怎么采、标注怎么定最后讲讲用这套数据训练时最容易踩的五个坑和我的习惯做法。2. 红外成像与组件故障的映射数据集里应该出现哪些温度异常形态2.1 红外图像记录的是辐射温度不是“肉眼可见的缺陷”红外检测的原理并不复杂一切高于绝对零度的物体都会向外辐射红外线热像仪通过探测这部分辐射反推出物体表面的辐射温度。和接触式测温不同热像仪测到的温度受两个关键因素影响物体表面的发射率以及周围环境反射到物体表面的反射温度。光伏组件的表面是钢化玻璃加镀膜在长波红外波段发射率并不接近黑体周围天空、地面、云层的冷热辐射都可能被反射进镜头。这些物理因素不是要背的公式而是直接决定数据集质量的天花板。太阳能设备组件的红外检测目前以长波红外也就是 8 到 14 微米波段为主力典型传感器是非制冷微测辐射热计分辨率从 384×288 到 640×512 不等。选择长波的原因很实际非制冷探测器成本可控帧率足够应对手持和无人机巡检而且光伏组件表面玻璃在长波波段的发射率一致性比中波好。中波红外灵敏度更高但价格高一个量级对组分检测场景来说性价比不高。组件故障通常伴随局部电阻变化、焊接异常或旁路二极管导通失效这些异常在工作时产生明显的局部温差这正是红外检测的用武之地。对数据集构建来说核心要记住一件事红外图像的像素灰度值经过相机内部的标定换算才能对应温度而这一过程受人为设置的发射率、环境温度、反射温度补偿影响。不同相机、不同参数设置下同一块组件的红外图温度读数可以差出 10℃以上。所以数据集里每一张图必须能追溯到拍摄时的相机型号、发射率设置和温度量程否则后面做温度归一化时无从下手。2.2 太阳能组件的典型温度异常形态与缺陷类别构建数据集的第一步不是打开标注软件而是确定缺陷类别。类别定义得是否贴近运维动作直接决定模型训练完能不能用。以光伏组件为例比较常见的温度异常形态有下面几类。热斑是最常被提到的缺陷形态表现为组件某个电池片或一小块区域温度明显高于周围通常由电池片内部短路、局部遮挡或者隐裂引起。热斑的成像特征是面积小、温差大在拍摄距离稍远时只有几个到十几个像素是典型的小目标检测问题。旁路二极管失效的表现稍微复杂二极管正常工作时对应子串被旁路失效后子串可能开路或过热在红外图上表现为一整条电池串的温度异常而不是一个点。接线盒过热则是接线盒内部连接电阻增大导致热量集中在组件背面的接线盒位置。线缆和连接器过热在汇流箱、逆变器侧更常见形态是条状或点状高温区。还有一类容易被忽视的是老化和 PID 效应它们往往不是局部热点而是整块组件温度分布不均匀、子串之间温差超标。这类样本在数据集中占比不需要很大但必须存在否则模型会把“局部热点”当成唯一故障判据遇到整体性老化组件就漏检。我的习惯是在标签体系里单独设一个“温度分布异常整体”类别宁可数量少也要让类别边界清楚。与此同时正常样本的数量要占到三成以上包括正常组件、正常接线盒、正常线缆路径以及天空、地面、支架等非组件目标。缺陷类别典型位置红外表现人工复核动作热斑电池片局部小面积高亮温差大检查遮挡、隐裂必要时更换组件旁路二极管异常接线盒内对应子串整条电池串异常升温或低温检查旁路二极管导通性接线盒过热组件背面接线盒局部高温边界清晰打开接线盒检查端子连接线缆/连接器过热组串线缆、MC4接头条状或点状高温重新压接或更换连接器隐裂/碎片电池片区域沿裂纹方向的线状温差透光检测或EL检测确认整体温度分布不均整块组件子串间温差超标排查失配、PID等表格的好处是让标注人员有统一的视觉判据。我见过不少数据集类别名写“defect”和“normal”最后模型训练出来只能区分“有毛病”和“没毛病”却说不清毛病在哪运维人员拿到告警还得重新看一遍原图。标签体系做到缺陷类别和运维动作一一对应数据集的复用价值才会出来。2.3 数据集的构成除了缺陷图还需要正常样本与元数据一个容易犯的错误是把数据集做成“全是故障图”。模型训练需要大量负样本红外场景的负样本尤其重要因为正常组件在阳光照射下也会呈现明显的温度梯度组件边缘、边框、玻璃内部反射都可能形成类似热斑的高亮区域。如果数据集里只有故障样本模型会倾向于把所有温差都判成故障现场误报率高到没法看。数据集的第二个构成要素是元数据。和通用工业图像数据集只关心“缺陷有没有”不同太阳能红外检测数据集还要回答“这个温度异常是在什么环境下产生的”。我在采集时会为每条样本记录环境温度、辐照度、风速、拍摄距离、组件朝向、相机型号、发射率设置、温度量程。这些字段在训练阶段不一定都进模型但模型效果差的时候它们是排查“过拟合到场景”的重要线索。举个例子如果数据集中绝大多数热斑样本都来自同一电站同一天的拍摄模型很可能学的是那块组件的纹理背景而不是热斑本身。这时候回查元数据就能发现辐照度、拍摄时段高度集中数据分布的代表性不足。红外小目标检测里常见的“目标只有几个像素”问题在热斑检测上同样存在因此数据集中还需要标注目标尺度的分布统计看看小目标样本是否足够避免模型对大目标过拟合。3. 现场采集与设备选型怎样拍出能训练的红外样本3.1 热像仪参数取舍分辨率、热灵敏度、测温范围与镜头手持热像仪、无人机挂载云台、在线式红外热像仪是三种常见采集载体。无论用哪种第一步都是确认传感器参数是否匹配检测任务。分辨率是最直观的指标384×288 的红外图拍整块组件时一块组件可能只占几百个像素热斑不过几个像素标注和小目标检测都很吃力。条件允许的话优先选择 640×512 分辨率它让热斑在同样拍摄距离下多出近一倍像素训练时模型更容易学到形状特征。热灵敏度 NETD 决定了相机能分辨的最小温差。组件表面的正常温差和故障温差通常在几摄氏度范围内NETD 小于 50mK 是基本要求实测中 30mK 以下的相机拍出来的图像噪声更小故障区域的边缘更清晰。测温范围需要覆盖光伏场景的极端温度组件白天表面温度可能到 60℃至 80℃接线盒故障时局部可以超过 100℃所以测温量程建议至少覆盖 -20℃到 150℃避免高温区域饱和。镜头视场角决定拍摄距离和覆盖面积的平衡。窄视场角如 22°左右适合从远距离拍单块组件能获得更好的空间分辨率宽视场角更适合巡检大面积阵列但单个热斑会变小。现场推荐的做法是先用广角镜头做大面积普查看到疑似热点后再靠近用窄视场镜头的相机拍细节。这样数据集里会自然形成“远距离普查尺度”和“近距离确认尺度”两类样本模型对不同尺度输入的适应能力会更强。参数建议值说明探测器分辨率640×512 优先小目标热斑需要足够像素支撑NETD 热灵敏度30mK组件表面温差小灵敏度不足会淹没缺陷测温范围-20℃ ~ 150℃覆盖组件正常与故障状态镜头视场角22°~45°兼顾普查与单组件细节采集发射率设置按表面材质逐项设置光伏玻璃、背板、接线盒各不相同帧率25Hz 以上手持足够无人机巡检要求更高3.2 拍摄规范角度、距离、时段和发射率设置红外拍摄的角度直接决定反射干扰的大小。光伏组件玻璃表面比较光滑镜头倾角过大时天空或周边物体的辐射会反射进镜头在组件表面形成一片不规则的“假低温区”或“假亮点”。我一般把拍摄角度控制在垂直于组件表面 30°以内无人机巡检时尽量调整云台姿态让镜头正对组件的法线方向。正午太阳高度角高时地面反射比较强最佳拍摄时段通常是上午十一点前或下午三点后但也要保证辐照度足够否则故障区域与正常区域的温差拉不开。距离控制要服务于目标尺度。持相机站在组串侧面拍整排组件热斑可能只有几个像素做检测还可以做精细的缺陷分级很难。常见做法是分两轮拍第一轮距组件 5 到 8 米拍整串组件的温度分布用于判断哪块组件异常第二轮靠近到 1 到 2 米对准疑似异常组件拍单块细节。数据集里这两种距离的样本都要保留并记录实际距离作为尺度变化的参考。发射率设置是红外检测里最“玄学”的一步但也是最终温度准确度的关键。光伏组件表面的钢化玻璃在长波红外的发射率通常在 0.85 到 0.9 附近组件背板、边框、接线盒外壳材质各异发射率差异较大。如果整张图统一用一个发射率不同部位的真实温度误差会变得很明显标注人员看到的亮度对比也会失真。正确做法是对不同材质分别设置发射率或者用接触式温度计实测几个点反过来校准发射率参数。拍摄时记录使用的发射率值后续任何温度相关的后处理都依赖这个值。3.3 采集程序与元数据记录一个可复用的脚本骨架热像仪联机采集通常使用厂商 SDK不同型号差异较大。更通用、同时也更容易落到数据集的方案是采集时只保存热像仪的原始视频或辐射图序列之后用脚本抽帧生成数据集样本。下面是一个抽帧与元数据记录脚本的骨架核心思路是让后续每个样本都自带可追溯信息。import argparse import csv import cv2 import os from datetime import datetime def extract_frames(video_path, output_dir, interval30, prefixSITE_A): os.makedirs(output_dir, exist_okTrue) cap cv2.VideoCapture(video_path) frame_idx 0 saved 0 if not cap.isOpened(): raise RuntimeError(fcannot open video: {video_path}) while True: ret, frame cap.read() if not ret: break if frame_idx % interval 0: timestamp datetime.now().strftime(%Y%m%d_%H%M%S) fname f{prefix}_{timestamp}_{frame_idx:06d}.png cv2.imwrite(os.path.join(output_dir, fname), frame) saved 1 frame_idx 1 cap.release() return saved def write_metadata_csv(entries, csv_path): fieldnames [filename, site, camera_model, emissivity, temp_range, env_temp, irradiance, wind_speed, distance, defect_type, note] with open(csv_path, w, newline) as f: writer csv.DictWriter(f, fieldnamesfieldnames) writer.writeheader() writer.writerows(entries) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--video, requiredTrue) parser.add_argument(--out, requiredTrue) parser.add_argument(--site, defaultSITE_A) parser.add_argument(--camera, defaultFLIR_T640) parser.add_argument(--emissivity, typefloat, default0.90) parser.add_argument(--temp-range, default-20,150) parser.add_argument(--env-temp, typefloat, default30.0) parser.add_argument(--irradiance, typefloat, default800.0) parser.add_argument(--wind, typefloat, default2.0) parser.add_argument(--distance, typefloat, default5.0) parser.add_argument(--interval, typeint, default30) args parser.parse_args() saved extract_frames(args.video, args.out, args.interval, args.site) meta [{ filename: f{args.site}_{i:06d}.png, site: args.site, camera_model: args.camera, emissivity: args.emissivity, temp_range: args.temp_range, env_temp: args.env_temp, irradiance: args.irradiance, wind_speed: args.wind, distance: args.distance, defect_type: unknown, note: } for i in range(saved)] write_metadata_csv(meta, os.path.join(args.out, metadata.csv))这段脚本做的事情很简单按固定帧间隔抽取视频帧生成带站点和时刻的文件名并同步写一份元数据 CSV。interval 参数控制抽帧密度巡检视频中组件变化很慢30 帧抽 1 帧即可避免大量近重复样本。距离、辐照度、风速这些参数在采集时随手填进命令行后续就不用再猜某张图是哪个工况拍的。光伏组件在工作时温度变化缓慢视频相邻帧之间目标几乎静止过度抽帧只会让训练集的相似度虚高训练出来的模型泛化能力并不好。脚本里的 defect_type 先写成 unknown等标注阶段再补。这样标注人员拿到的是“图像文件 元数据表格”的固定结构不会出现图拍了但不知道拍摄距离、不知道相机型号的情况。采集工作的验收标准也很简单每张样本能回答五个问题——在哪拍、用什么拍、发射率多少、当时辐照度多少、目标距离多少。4. 标注规范与格式转换从温度异常区域到可训练标签4.1 标注方式和标签体系怎么定标注方式上检测模型通常用矩形框分割模型用多边形或者像素级 mask。光伏红外检测的场景里热斑和接线盒过热有相对清晰的边界矩形框够用隐裂呈线状分布矩形框会把大量正常区域包进来用多边形更合适。我采用的折中方案是组件整体用矩形框缺陷区域中的热斑、接线盒过热、连接器过热用紧密矩形框隐裂和整体温度分布异常用多边形。组件框和缺陷框分开保存训练时组件框帮助你判断缺陷是否位于组件有效区域内。标签类别不要拍脑袋定最好根据第 2 章的故障形态表做一次现场核验。先把历史运维记录里的缺陷照片过一遍确认哪些类别在这个电站真正出现过类别多了容易互相混淆类别少了模型无法区分不同故障。还有一个容易忽略的点是“疑似待确认”类别。现场热像图里总有一部分温度异常无法立刻判断是缺陷还是环境反射与其逼标注人员硬选一个类别不如设一个“suspect”类别之后由复核人员用可见光照片或接触式测温确认后再归入正式类别。这个小设计能让标注人员心里有底减少乱标。温差阈值也要写进标注规范里。热斑通常定义为局部温度明显高于同组件正常区域但“明显”是个主观词。具体温差阈值建议从本电站的运维记录里反推统计历史故障件的温差分布取一个能覆盖大多数故障的值作为标注最低阈值低于这个阈值的温差统一标为正常。一旦阈值写进规范标注人员之间的尺度就统一了不会出现同一个热斑有人标有人不标。4.2 标注工具的选用Labelme、X-AnyLabeling 还是 CVAT单兵作战时我用 Labelme它保存为 JSON 格式修改方便离线可用不需要部署服务。X-AnyLabeling 适合已经训练过一版模型的场景它可以加载模型做自动预标注人工只需要修正边界对几百张红外图像来说能省不少时间。团队协作、需要多人并行标注时CVAT 更合适它支持在线协同、支持 COCO/YOLO 格式导出还带有人工抽检工作流。红外图像的显示问题是标注阶段最容易踩的坑。热像仪原图往往是 16 位单通道数据直接转成 8 位 PNG 显示时图像会整体偏暗或大片过曝。标注工具里看到的伪彩色是相机或转换软件自动拉伸后的效果灰度范围和温度不是线性对应。这时候如果将伪彩图直接拿去标注和训练最终模型学到的是颜色风格而非温度分布。正确流程是先做固定温度区间映射把 16 位温度数据映射到 8 位灰度映射范围全数据集统一例如 0℃ 到 120℃ 对应灰度 0 到 255。标注在映射后的灰度图上进行保存的标签坐标再映射回原始 16 位图像。这样每次打开图像看到的亮度是一致的标注的一致性才能保证。4.3 从标注 JSON 到 YOLO/COCO转换脚本与验证脚本Labelme 导出的 JSON 不能直接喂给检测模型需要转换成 YOLO 格式或 COCO 格式。YOLO 格式简单每行一个目标格式为类别序号、中心点 x、中心点 y、宽、高坐标都做归一化COCO 格式适合做实例分割。下面是我常用的 Labelme JSON 转 YOLO Txt 的脚本骨架。import json import os import argparse def labelme_to_yolo(json_path, class_map, output_dir): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_map: print(f[skip] unknown label: {label}) continue points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) x_center (x_min x_max) / 2.0 / img_w y_center (y_min y_max) / 2.0 / img_h box_w (x_max - x_min) / img_w box_h (y_max - y_min) / img_h x_center max(0.0, min(1.0, x_center)) y_center max(0.0, min(1.0, y_center)) box_w max(0.0, min(1.0, box_w)) box_h max(0.0, min(1.0, box_h)) lines.append(f{class_map[label]} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) if not lines: return txt_path os.path.join(output_dir, os.path.splitext(os.path.basename(json_path))[0] .txt) with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--json-dir, requiredTrue) parser.add_argument(--output-dir, requiredTrue) parser.add_argument(--classes, requiredTrue, helpclass list file, one class per line) args parser.parse_args() with open(args.classes, r, encodingutf-8) as f: classes [line.strip() for line in f if line.strip()] class_map {name: idx for idx, name in enumerate(classes)} os.makedirs(args.output_dir, exist_okTrue) for fname in os.listdir(args.json_dir): if fname.endswith(.json): labelme_to_yolo(os.path.join(args.json_dir, fname), class_map, args.output_dir)转换脚本有两个细节值得特别注意。第一个是未知标签直接跳过而不是报错标注过程中总会出现临时新增的类别名脚本一旦中断会打断整个处理流程跳过并打印提示更符合实际工作流的习惯。第二个是坐标裁剪到 0 到 1 之间多边形框的顶点偶尔会落到图像边缘外归一化后可能出现大于 1 的坐标YOLO 训练时这些数值会导致锚框计算异常。裁剪后虽然框的位置有微小偏差但安全性高很多。转换完成后不要急着训练先做一个核查统计转换后每张图的标签数量、类别分布、框的宽度高度分布。如果发现某个类别的框普遍只有几个像素宽说明标注尺度不一致或者小目标占比过大需要回到标注阶段重新审视。红外热斑在 640×512 的原图中确实可能只有 10×10 像素这类小目标在下游模型训练中需要特殊策略比如在组件级检测之外增加子图切块检测而不是指望单模型直接吃原图。5. 构建太阳能红外检测图像数据集的避坑记录五个常见翻车点5.1 伪彩色陷阱不同相机调色板导致同一目标被标成两类现象同一个热斑用 A 相机的火焰色伪彩看起来是亮黄用 B 相机的灰度模式看起来是亮白。实际做训练时模型在这两种图上输出完全不同的置信度仿佛学了两个任务。原因热像仪默认输出的伪彩色映射各不相同更关键的是自动温度拉伸会让同一物理温度在不同照片里呈现不同灰度。模型学到的是调色板风格差异而不是“温度高”这个物理本质。解决所有进入数据集的图像统一转成灰度模式并且灰度与温度的映射关系全局固定。我一般用 0℃ 到 120℃ 映射到 0 到 255 的线性区间超出的温度截断。这样同一温度在任何图像里都是同一个灰度模型才能学到稳定特征。如果相机能输出辐射图最好在原始辐射图上做归一化而不是用相机自动生成的预览图。5.2 热斑与外部反射的混淆现象标注人员在组件玻璃表面框出几十个“热斑”训练后模型在现场疯狂误报最后发现训练集里一半“热斑”其实是反射的太阳光、云层或者周边铁皮房的热辐射。原因光伏组件表面的光滑玻璃在非垂直观测角度下会反射环境中的红外辐射形成与热斑形状、明暗极易混淆的假目标。标注阶段如果环境温度高、天空有云这种反射会频繁出现。解决采集阶段尽量保持镜头垂直于组件表面但要认识到现场不可能每次完美垂直所以数据集中必须有意识保留一部分反射样本。在标签体系里增加一个“环境反射”类别让模型学完能区分“真热”和“反射的热”。标注规范里也要写明疑似反射的区域不标热斑标入反射类或者干脆留给复核人员确认。5.3 正常接线盒温度与故障接线盒的类别不均衡现象模型对“接线盒过热”的误检率居高不下大量正常接线盒被标为故障现场复核人员怨声载道。原因接线盒内部有二极管组件正常发电时接线盒本身就会发热表面温度比旁边的电池片高出一截。如果只把“接线盒温度高”当作标注依据几乎所有正常组件都会中标。解决把接线盒的缺陷判定从绝对温度改成相对温差也就是接线盒表面温度减去同组件的组件背板温度。采集时对同一组件同时拍摄正面和背面或者记录环境温度作为基准标注规范里写明接线盒表面温度与基准的温差超过阈值才算故障。模型输入不能只看局部图像还需要看到接线盒与周边区域的温度对比因此切图时要把接线盒周边一小块组件区域一起包含进去。5.4 红外与可见光图对不齐导致的伪标签现象同时采集可见光图像和红外图像拿着可见光图上标注好的组件位置迁移到红外图上发现框体偏移严重训练出来的模型输出位置系统性偏离。原因可见光和红外两路相机的物理位置、视场角、分辨率都不一样镜头畸变特性也不同简单套用坐标无法对齐。光伏组件本身在一个平面上还好如果拍摄距离近视差导致的位置偏移会非常明显。解决如果数据必须是成对的可以在采集时把可见光和红外相机固定在同一个云台上尽量让两路光轴平行再通过标定板计算两路图像的单应性矩阵做一次几何对齐。但更省事、也更可靠的做法是直接放弃跨模态迁移标注在红外图上重新标注。可见光图像的价值在于人工复核缺陷性质不一定要和红外图共用一套标签坐标。5.5 数据划分泄漏同一组件连续拍摄的帧被分到训练和验证现象离线评估 mAP 达到 0.92模型部署到现场却明显拉胯误检和漏检都比预期严重。原因采集视频时按固定间隔抽帧同一组件连续几十帧的画面几乎相同。如果随机划分训练集和验证集验证集里的图像会和训练集里的高度相似评估结果虚高。模型真正没见过的电站场景、不同光照角度、不同组件型号时表现原形毕露。解决划分数据集时以“采集任务”为单位而不是以单张图像为单位。一个采集任务定义为同一天、同一站点、同一相机、同一拍摄路线的连续视频段。划分时按任务分组验证集里出现的组件实例不能出现在训练集里。更严格的做法是把某一电站的样本整体划入验证集模拟跨现场部署的评估。我在实际项目中用 GroupKFold 比较多按“组件编号”分组能有效防止数据泄漏。6. 用数据集验证检测模型温度归一化、难例与指标怎么设6.1 温度归一化预处理把“像素值”换成“物理量”模型训练之前我习惯先对红外图像做一次温度归一化而不是直接拿原始灰度图进网络。下面这段代码从元数据 CSV 中读取温度量程把 8 位灰度图重新映射到固定的物理温度区间。import csv import cv2 import numpy as np def normalize_by_temperature(image_path, temp_min, temp_max, fixed_min0.0, fixed_max120.0): img cv2.imread(image_path, cv2.IMREAD_GRAYSCALE).astype(np.float32) img_norm (img - temp_min) / (temp_max - temp_min) img_norm np.clip(img_norm, 0.0, 1.0) target_min np.float32(fixed_min) target_max np.float32(fixed_max) img_phys img_norm * (target_max - target_min) target_min img_out (img_phys - fixed_min) / (fixed_max - fixed_min) * 255.0 return np.clip(img_out, 0.0, 255.0).astype(np.uint8) with open(metadata.csv, r) as f: reader csv.DictReader(f) for row in reader: temp_range row[temp_range] t_min, t_max [float(x) for x in temp_range.split(,)] out normalize_by_temperature(row[filename], t_min, t_max) cv2.imwrite(norm_ row[filename], out)参数说明里的 fixed_min 和 fixed_max 是全数据集统一的温度区间的下限和上限。比如固定为 0℃ 到 120℃就意味着 0℃ 对应灰度 0120℃ 对应灰度 255无论原图的温度量程是 -20℃ 到 150℃ 还是 20℃ 到 100℃进模型的灰度图都基于同一个物理标尺。这里的 temp_min 和 temp_max 是相机拍摄时的温度量程不同相机的原始输出范围可能不同通过这个两步映射把不同采集条件下得到的图像拉到同一个物理尺度模型才不会学偏。6.2 验证协议与难例挖掘现场测试比 mAP 靠谱数据集构建完成、模型训练结束之后先看测试集上的 mAP 和 F1 分数没问题但最终还要回到现场验证。我习惯采集两段连续但完全没参与训练的巡检视频跑一遍模型统计连续帧间的检测结果跳变次数。红外视频同一目标在相邻帧中应该持续出现如果检测框闪烁频繁说明模型对温度和噪声的敏感度偏高需要调整置信度阈值或增加时域滤波。难例挖掘的方向也值得多花时间。正常组件边缘、老化组件整体温度不均匀、多个热斑连片、部分遮挡下的半影这些样本最容易让模型出错。训练完成后把这些难例挑出来记录它们的类别、拍摄工况和模型输出回到数据集里补充类似样本比盲目增加总图片数更有效。做数据集这件事我养成的习惯是标注阶段多投一倍精力在正常样本和反射样本上训练阶段就少花两倍时间在调阈值上。温度物理量、元数据、按任务划分验证集这三件事做到位后面的模型迭代才能算是站在一个可靠的地基上希望帮到你。本文还有配套的精品资源点击获取