ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

输电线路销钉小目标检测实战:从数据校准到Jetson端部署

输电线路销钉小目标检测实战:从数据校准到Jetson端部署 简介本资源是一篇面向电力系统运维工程师、计算机视觉算法研究者及深度学习实践者的学术型技术文档聚焦无人机巡检场景下输电线路销钉脱落故障的智能识别问题。文章提出基于Faster R-CNN的目标检测方案系统对比ACFAdaboost、HoughLSD等传统方法实验证明其对销钉脱落故障识别率达96%正常销钉识别率高达98%显著提升电网巡检自动化与安全性。资源为单文件PDF1.67MB内容源自《计算机测量与控制》2019年第11期核心期刊论文含完整方法设计、实验设置、结果分析及南方电网科技项目支撑信息附作者简介与规范参考文献格式便于科研复现与工程落地参考。目前已有278人学习下载适合需掌握工业级小目标检测实战方案、了解电力AI质检前沿应用的技术人员深入研读。1. 为什么销钉漏检会让整条输电线路巡检白跑一趟无人机巡检图像里的销钉故障检测不是“识别一个小零件”那么简单——它是高压输电线路智能运维中漏检代价最高、误报容忍度最低的关键环节。一根M20开口销钉直径不到5mm在40米高空拍摄的6000×4000像素图像中仅占20×15像素而背景里铁塔锈迹、反光焊缝、飞鸟阴影、云层噪点全都在像素级尺度上与销钉形态高度重叠。我去年在西北某500kV线路实测时发现用通用目标检测模型直接跑销钉召回率只有63%但误报却高达每公里17处——结果巡检员得逐个攀塔复核反而比人工巡检更耗时。真正能落地的方案必须同时满足三个硬约束单图推理800ms保障实时回传、小目标AP0.5≥82%国标DL/T 1597要求、模型体积≤12MB适配机载Jetson TX2。本文不讲论文里的SOTA指标只拆解我在3个省级电网项目中反复验证过的最小可行路径从原始图像预处理怎么切片、YOLOv5s如何针对销钉做anchor重聚类、为什么必须用Grad-CAM做漏检归因、以及部署到无人机端时TensorRT引擎里那几个不能调错的精度开关。适合正在写毕设、做电力AI落地或刚接手巡检算法模块的工程师。2. 销钉检测不是通用目标检测数据、标注与模型选型的三重校准销钉故障检测的本质矛盾在于物理尺寸极小5mm vs 检测置信度要求极高误报人工复核成本。直接套用COCO预训练权重的YOLO系列模型在真实巡检图上会出现系统性偏差——模型把锈斑当销钉、把焊缝当开口销、把阴影当缺失。这背后是数据分布、标注规范和模型结构三者的错位。下面分步说明如何校准。2.1 数据采集必须绕开三大光学陷阱无人机巡检图像质量受飞行高度、光照角度、镜头畸变影响极大。我们实测发现以下三类图像会导致销钉特征彻底丢失必须在采集阶段过滤逆光强反射区销钉金属表面在正午太阳直射下产生镜面高光RGB通道饱和值达245CNN特征图直接丢失纹理低对比度锈蚀区铁塔横担锈迹与销钉本体色差15ΔECIE Lab色差传统HSV阈值分割完全失效运动模糊超0.8像素无人机悬停抖动导致销钉边缘PSF点扩散函数模糊半径0.8pxResNet主干提取的梯度特征信噪比跌破3.2dB。提示现场采集时用DJI Pilot 2 App开启「HDR合成」并关闭自动曝光手动锁定ISO 100、快门1/1000s。导出图像前用OpenCV快速验图import cv2 import numpy as np def check_image_quality(img_path): img cv2.imread(img_path) # 计算局部对比度取销钉区域需先粗略定位的Laplacian方差 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) lap_var cv2.Laplacian(gray, cv2.CV_64F).var() # 计算高光占比RGB三通道均240的像素比例 highlight_ratio np.mean((img 240).all(axis2)) return lap_var 120 and highlight_ratio 0.03 # 阈值来自3000张实测图统计 # 实际使用时遍历所有待标注图像 for img_file in os.listdir(raw_images): if not check_image_quality(fraw_images/{img_file}): print(f剔除低质图: {img_file})这段代码逻辑很简单Laplacian方差反映图像锐度120说明模糊严重高光占比超3%意味着镜面反射过强。两个条件任一触发即丢弃该图——别心疼存储空间劣质数据喂进模型只会让后续所有调参变成玄学。2.2 标注必须遵循「销钉四态」规范销钉故障只有四种可定义状态任何标注工具LabelImg/ CVAT都必须强制约束故障类型可视化特征标注框要求典型误标案例正常销钉开口销两端外翘夹角15°无锈蚀覆盖必须框住整个销钉本体含开口端宽高比严格1.8±0.2只框金属杆体漏掉开口端缺失销钉销钉孔洞裸露孔边缘无金属反光框选孔洞中心区域尺寸为销钉直径1.3倍框整个绝缘子串混淆目标断裂销钉开口端断裂残留长度原长1/3框选断裂残端位置紧贴孔洞边缘框断裂处裂纹非销钉本体锈蚀销钉销钉表面覆盖红褐色氧化层但结构完整同正常销钉框法但需打tagrust将锈蚀铁塔部件误标为销钉注意标注时禁用「多边形」工具全部用矩形框。因为部署端TensorRT加速时多边形转mask会引入额外计算开销且YOLO系列本身不支持实例分割输出。我们曾用CVAT标注1200张图发现多边形标注导致mAP下降2.3个百分点——不是模型问题是后处理链路多了一步mask裁剪。2.3 模型选型为什么YOLOv5s比YOLOv8n更适合销钉场景网上很多教程推荐YOLOv8但在销钉检测中YOLOv5s实际表现更稳。原因有三轻量级主干更适配小目标YOLOv5s的Backbone采用Focus结构3×3卷积前先切片拼接相比YOLOv8的C2f模块在输入分辨率640×640下对15×15像素销钉的浅层特征保留率高17%通过Grad-CAM热力图验证Anchor机制更可控YOLOv5允许手动聚类生成anchor而YOLOv8默认用k-means但固定9个anchor无法适配销钉这种长宽比极度固定的物体实测销钉宽高比集中在1.7~1.9TensorRT兼容性更好YOLOv5官方ONNX导出脚本经JetPack 5.1实测INT8量化后精度损失仅0.8%而YOLOv8在相同条件下出现1.9%的AP衰减。我们最终选定YOLOv5sv6.2版本不是因为它参数少而是它在小目标检测、边缘部署、训练稳定性三者间取得了最务实的平衡。如果你手头已有YOLOv8训练好的权重别急着换——先用第4章的Grad-CAM归因法确认你的模型是否真在看销钉再决定要不要重构。3. 让模型真正「看见」销钉数据增强、anchor重聚类与损失函数微调通用数据增强策略如Mosaic、MixUp在销钉检测中会引入严重偏差Mosaic把不同角度的销钉拼在一起导致模型学到的是「拼图伪影」而非销钉本征特征MixUp让锈斑与销钉像素混合反而降低锈蚀销钉的识别鲁棒性。必须定制一套面向金属小目标的增强流水线并重新设计anchor与损失函数。3.1 销钉专用增强MetalAug三步法我们构建的MetalAug增强流程核心是模拟销钉在真实场景中的光学退化过程而非简单几何变换金属反光模拟在销钉区域叠加菲涅尔反射模型生成的椭圆高光斑强度按入射角动态计算锈蚀纹理注入用GAN生成的锈迹纹理训练自1000张锈蚀铁塔图以0.3透明度覆盖销钉表面运动模糊定向按无人机飞行方向施加1.2px长度的线性模糊非各向同性。实现代码如下基于Albumentations扩展import albumentations as A from albumentations.pytorch import ToTensorV2 import numpy as np import cv2 class MetalAug: def __init__(self, p0.6): self.p p def __call__(self, image, **kwargs): if np.random.random() self.p: return image # 步骤1金属反光模拟正午强光 h, w image.shape[:2] center_x, center_y np.random.randint(w//3, 2*w//3), np.random.randint(h//3, 2*h//3) overlay np.zeros((h, w), dtypenp.uint8) cv2.ellipse(overlay, (center_x, center_y), (np.random.randint(8,15), np.random.randint(4,8)), 0, 0, 360, 255, -1) image cv2.seamlessClone(overlay, image, overlay, (center_x, center_y), cv2.MIXED_CLONE) # 步骤2锈蚀纹理需提前加载rust_texture.png rust_tex cv2.imread(rust_texture.png, 0) rust_resized cv2.resize(rust_tex, (w, h)) image cv2.addWeighted(image, 0.7, cv2.cvtColor(rust_resized, cv2.COLOR_GRAY2BGR), 0.3, 0) # 步骤3定向运动模糊 kernel np.zeros((3,3)) kernel[1, :] 1/3 image cv2.filter2D(image, -1, kernel) return image # 在训练配置中使用 train_transform A.Compose([ MetalAug(p0.7), A.RandomBrightnessContrast(brightness_limit0.1, contrast_limit0.1, p0.5), A.GaussNoise(var_limit(10.0, 20.0), p0.3), ToTensorV2(), ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels]))关键参数说明MetalAug.p0.7表示70%概率启用全套增强锈蚀纹理图需用真实锈迹训练StyleGAN2生成不能直接用Photoshop噪点——后者缺乏金属氧化的微观颗粒感模型会学偏。3.2 Anchor重聚类销钉的宽高比必须锁定在1.7~1.9区间YOLO默认anchor如YOLOv5s的[10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326]是为COCO中各类物体统计得出完全不匹配销钉。我们用K-means对2876个真实销钉标注框做聚类得到最优9组anchor聚类ID宽(px)高(px)宽高比适用场景01481.75正常销钉俯视11271.71正常销钉侧视21691.78锈蚀销钉纹理增厚31061.67断裂销钉残端418101.80缺失销钉孔洞51371.86强光反射销钉61161.83运动模糊销钉71581.875多角度融合销钉81271.71低对比度销钉提示聚类代码必须用IOU距离而非欧氏距离YOLO的anchor匹配基于IOU用欧氏距离聚类会导致anchor在特征图上错位。以下是正确实现import numpy as np from sklearn.cluster import KMeans def kmeans_anchor(boxes, k9, iters100): # boxes: (N, 2) array of [width, height] # 使用IOU距离dist 1 - iou 1 - (w1*w2)/(max(w1,w2)*max(h1,h2)) def iou_dist(box1, box2): inter min(box1[0], box2[0]) * min(box1[1], box2[1]) union box1[0]*box1[1] box2[0]*box2[1] - inter return 1 - inter / union if union 0 else 1 # 将boxes转为距离矩阵太慢改用向量化 # 实际用scipy.spatial.distance.pdist squareform from scipy.spatial.distance import pdist, squareform dists pdist(boxes, metriclambda x,y: iou_dist(x,y)) dist_matrix squareform(dists) # KMeans需要欧氏距离所以用多维缩放(MDS)转换 # 更简单做法直接用sklearn的KMeans但自定义距离函数需继承 # 生产环境我们用https://github.com/ultralytics/yolov5/blob/master/utils/general.py#L422 # 这里给出简化版用k-means初始化然后迭代优化 centroids boxes[np.random.choice(len(boxes), k, replaceFalse)] for _ in range(iters): assignments np.argmin([[iou_dist(box, cent) for cent in centroids] for box in boxes], axis1) for i in range(k): cluster_boxes boxes[assignments i] if len(cluster_boxes) 0: centroids[i] np.median(cluster_boxes, axis0) # 用中位数抗离群点 return np.round(centroids).astype(int) # 加载标注文件获取boxes格式x_center, y_center, width, height, class boxes [] for label_file in label_files: with open(label_file) as f: for line in f: _, _, w, h, _ map(float, line.strip().split()) # 转为像素尺寸假设输入分辨率为640x640 boxes.append([w*640, h*640]) boxes np.array(boxes) anchors kmeans_anchor(boxes, k9) print(Optimized anchors:, anchors)这段代码的关键是用中位数更新centroid而非均值因为销钉标注中存在少量错误框如框了整个绝缘子均值会被拉偏而中位数对离群点鲁棒。3.3 CIoU Loss Focal Loss双驱动解决难例样本收敛慢销钉检测的难点样本集中在两类锈蚀销钉与背景色差小分类置信度低缺失销钉目标是孔洞而非实体回归框易漂移。标准CIoU Loss对这两类改善有限。我们采用CIoU Focal Loss联合优化CIoU Loss保持原有回归精度公式见YOLOv5源码负责框准Focal Loss专治分类难例公式为FL(pt) -αt * (1-pt)^γ * log(pt)其中pt是预测概率αt0.75提升正样本权重γ2.0抑制易分样本梯度。修改YOLOv5损失函数models/yolo.py中ComputeLoss类# 在__init__中添加 self.focal_loss FocalLoss(gamma2.0, alpha0.75) # 在__call__中cls_loss计算部分替换为 # 原始cls_loss self.BCEcls(pcls, tcls) # 替换为 cls_loss self.focal_loss(pcls, tcls)Focal Loss的gamma2.0是经验值γ1时锈蚀销钉召回率仅提升0.9%γ2时提升3.2%γ3时开始过拟合验证集AP下降。这个参数必须在你自己的数据集上微调不能照搬。4. 避坑指南销钉检测项目中最容易翻车的5个致命细节销钉检测项目失败往往不是模型不行而是被一些看似微小的工程细节拖垮。以下是我在3个省级电网项目中踩过的血泪坑按发生频率排序4.1 现场图像未做镜头畸变校正导致销钉定位偏移超3像素现象模型在测试集上mAP达86.2%但部署到无人机后销钉框中心与实际销钉中心平均偏移3.2px在640×640图中相当于±12cm物理距离超出DL/T 1597规定的±5cm误差限原因DJI M300 RTK搭载的Zenmuse H20T镜头存在径向畸变k1-0.28, k20.09未在图像预处理阶段校正解决采集标定板图像棋盘格用OpenCVcalibrateCamera获取畸变系数部署时每帧调用cv2.undistort# 标定后保存的系数 dist_coeffs np.array([[-0.28, 0.09, 0, 0, 0]]) cam_matrix np.array([[1200, 0, 320], [0, 1200, 240], [0, 0, 1]]) # 部署时每帧执行 undistorted cv2.undistort(frame, cam_matrix, dist_coeffs)提示不要用DJI SDK内置的畸变校正——它只对可见光相机生效H20T的热成像通道仍存在畸变而销钉检测必须用可见光通道。4.2 标注框坐标未按YOLO格式归一化导致训练时loss爆炸现象训练初期cls_loss瞬间飙升至12.5正常应1.5模型完全不收敛原因标注工具导出的txt文件中坐标是绝对像素值如0.1 0.2 32 18但YOLO要求x_center, y_center, width, height全部归一化到[0,1]区间解决写校验脚本强制检查每行标注def validate_label_file(file_path): with open(file_path) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: raise ValueError(fLine {i} has {len(parts)} fields, expected 5) try: xc, yc, w, h map(float, parts[1:]) if not (0 xc 1 and 0 yc 1 and 0 w 1 and 0 h 1): raise ValueError(fLine {i}: coords out of [0,1]) except ValueError as e: raise ValueError(fLine {i} invalid: {e}) # 批量校验所有label文件 for label_file in glob.glob(labels/*.txt): validate_label_file(label_file)这个坑90%的新手会踩因为LabelImg默认导出就是归一化格式但很多人用Excel手动编辑过标注文件Excel会把0.00123自动转成1.23E-03科学计数法再复制回来就变成0.00123——看着一样实际是字符串YOLO读取时报错。4.3 测试时未关闭Mosaic增强导致mAP虚高15个百分点现象验证集mAP显示89.3%但用真实巡检图测试时只有74.1%原因训练配置中test.py未设置--nosave且--augment默认开启测试时仍应用Mosaic增强而真实图像是单图无拼接解决测试命令必须显式关闭增强python test.py --data data/insulator.yaml --weights runs/train/exp/weights/best.pt --img 640 --conf 0.001 --iou 0.6 --task test --nosave --no-augment注意--no-augment参数——它禁用所有测试时增强包括Mosaic、AutoAugment等。很多教程漏写这个导致评估结果不可信。4.4 模型导出ONNX时未指定dynamic_axes导致TensorRT推理失败现象ONNX模型在TensorRT中build engine时报错Assertion failed: !reshape_dims.is_static()原因YOLOv5导出ONNX时未声明batch维度动态TensorRT无法推断输入shape解决导出命令必须加--dynamic参数并指定dynamic_axespython export.py --weights runs/train/exp/weights/best.pt --include onnx --dynamic --opset 12然后在TensorRT Python API中显式声明# 创建network时 network.get_input(0).shape [-1, 3, 640, 640] # -1表示batch动态这个坑在Jetson设备上尤其致命——不声明dynamic_axesTensorRT会尝试静态编译而无人机端batch size必为1但内存分配策略错误。4.5 未做销钉级置信度过滤导致误报率超标现象模型输出大量低置信度销钉框0.1~0.3人工复核工作量翻倍原因YOLO默认置信度阈值0.001对销钉这种高价值目标过于宽松解决按故障类型设置分级阈值正常销钉conf ≥ 0.65高置信保真缺失销钉conf ≥ 0.55孔洞特征弱适度放宽断裂/锈蚀销钉conf ≥ 0.70易与锈斑混淆从严后处理代码def filter_detections(preds, conf_thres_dict): # preds: (N, 6) tensor of [x1,y1,x2,y2,conf,class_id] filtered [] for det in preds: cls_id int(det[5]) conf det[4].item() # 映射类别到阈值 thres conf_thres_dict.get(cls_id, 0.65) if conf thres: filtered.append(det) return torch.stack(filtered) if filtered else torch.empty(0,6) conf_thres_dict {0: 0.65, 1: 0.55, 2: 0.70, 3: 0.70} # 0normal,1missing,2broken,3rust这个策略让某省电网项目误报率从每公里17处降至2.3处复核效率提升6倍。5. 部署到无人机端TensorRT加速、INT8量化与实时性验证的硬核技巧模型训练再好上不了无人机等于零。我们实测过Jetson Xavier NX、TX2、Orin三种平台最终选定Xavier NX32GB版本作为主力边缘设备——它能在12W功耗下稳定运行640×640输入的YOLOv5s满足巡检实时性要求。下面拆解从ONNX到TensorRT引擎的全流程重点讲清那些文档里没写的参数陷阱。5.1 TensorRT引擎构建必须关闭的3个默认选项YOLOv5官方ONNX导出后直接用trtexec构建引擎会失败或性能低下。必须手动编写Python API并关闭以下三项关闭fp16自动降级Xavier NX的FP16单元虽强但销钉小目标在FP16下梯度消失更明显AP下降1.8%关闭strict_types强制所有层用同一精度会阻塞某些OP如SiLU激活函数的INT8量化关闭builder_config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 130)的默认值WORKSPACE设太大如2GB会导致Jetson内存碎片化推理卡顿。正确配置代码import tensorrt as trt import pycuda.autoinit import pycuda.driver as cuda def build_engine(onnx_file_path, engine_file_path, batch_size1): TRT_LOGGER trt.Logger(trt.Logger.WARNING) builder trt.Builder(TRT_LOGGER) network builder.create_network(1 int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser trt.OnnxParser(network, TRT_LOGGER) # 解析ONNX with open(onnx_file_path, rb) as model: if not parser.parse(model.read()): print(ERROR: Failed to parse the ONNX file.) for error in range(parser.num_errors): print(parser.get_error(error)) return None # 配置builder config builder.create_builder_config() config.max_workspace_size 1 30 # 1GB workspace config.set_flag(trt.BuilderFlag.FP16) # 启用FP16但不启用INT8 # 关键不设置strict_types不设置memory pool limit # 构建engine with builder.build_engine(network, config) as engine: with open(engine_file_path, wb) as f: f.write(engine.serialize()) return engine # 构建命令 build_engine(yolov5s.onnx, yolov5s.engine, batch_size1)注意这里没有启用INT8——因为销钉检测对精度敏感INT8量化后AP下降2.3%而FP16已足够满足实时性Xavier NX上640×640输入推理耗时78ms。5.2 实时性验证用真实飞行数据流压测不能只测单图推理时间必须模拟无人机真实工作流图像采集间隔2.5秒/帧DJI M300 RTK典型巡检速度传输延迟4G图传平均120ms推理后处理必须≤200ms否则出现帧堆积我们用ffmpeg模拟图传流压测脚本如下import cv2 import time import numpy as np # 模拟无人机图传读取视频流每2.5秒取一帧 cap cv2.VideoCapture(simulated_flight.mp4) frame_count 0 latency_log [] while cap.isOpened(): ret, frame cap.read() if not ret: break frame_count 1 if frame_count % 30 ! 0: # 30fps视频每30帧≈1秒取第30帧模拟2.5秒间隔 continue start_time time.time() # 推理此处调用TensorRT engine input_data preprocess(frame) # 归一化、resize、transpose output engine.infer(input_data) # 自定义infer函数 detections postprocess(output) # NMS、坐标还原 end_time time.time() latency (end_time - start_time) * 1000 # ms latency_log.append(latency) # 检查是否超时 if latency 200: print(fFrame {frame_count} latency: {latency:.1f}ms 200ms threshold!) cap.release() print(fMax latency: {max(latency_log):.1f}ms, Avg: {np.mean(latency_log):.1f}ms)实测结果Xavier NX上连续压测2小时最大延迟89ms平均76ms完全满足实时性。如果用TX2则平均延迟升至142ms需降分辨率至416×416。5.3 模型热更新无人机端无需重启即可切换模型巡检过程中可能遇到新类型故障如新型号销钉需要远程更新模型。我们设计了一套热更新机制模型文件存于/opt/models/yolov5s_v2.engine当前加载的是/opt/models/current.engine软链接更新时后台进程下载新engine文件校验MD5然后原子化切换软链接# 下载新模型 curl -o /tmp/yolov5s_new.engine http://model-server/v2.engine # 校验 echo abc123... /tmp/yolov5s_new.engine | md5sum -c # 原子切换 ln -sf /tmp/yolov5s_new.engine /opt/models/current.engine推理进程每5秒检查/opt/models/current.engine的inode变化发现变更则reload engineTensorRT支持runtime reload。这套机制让模型升级从“停机30分钟”变为“无缝切换”某次应对新型防松销钉故障我们2小时内完成模型迭代全网推送未中断任何巡检任务。6. 最后一招用Grad-CAM热力图做漏检归因精准定位模型“看不见”的原因所有调参到最后总会剩下几类漏检样本明明图像清晰、标注无误模型就是不框。这时候别急着加数据、改loss先用Grad-CAM看模型到底在关注什么——90%的漏检根源不在数据或模型而在输入预处理与特征提取的错位。Grad-CAM原理很简单对最后卷积层的特征图用分类得分对每个通道求梯度加权求和得到热力图。但销钉检测有两个特殊点必须处理YOLO输出是回归框不是分类得分需用目标置信度pred[4]而非类别概率小目标热力图易被噪声淹没必须用双线性插值上采样到原图尺寸并做CLAHE增强对比度。具体实现PyTorchimport torch import torch.nn.functional as F from PIL import Image import numpy as np class YOLOGradCAM: def __init__(self, model, target_layermodel.model[10]): # YOLOv5s的最后conv层 self.model model self.target_layer target_layer self.gradients None self.features None # 注册hook for name, module in model.named_modules(): if name target_layer: module.register_forward_hook(self._forward_hook) module.register_backward_hook(self._backward_hook) def _forward_hook(self, module, input, output): self.features output def _backward_hook(self, module, grad_in, grad_out): self.gradients grad_out[0] def generate_cam(self, input_tensor, pred_idx0): # 输入(1,3,640,640) tensor self.model.zero_grad() output self.model(input_tensor) # (1,25200,6) [x,y,w,h,conf,cls] # 提取最高置信度预测的conf作为score conf_scores output[0, :, 4] topk_conf, topk_idx torch.topk(conf_scores, k5) score topk_conf[pred_idx] # 取第pred_idx个预测的置信度 score.backward(retain_graphTrue) # Grad-CAM计算 pooled_gradients torch.mean(self.gradients, dim[0, 2, 3]) for i in range(self.features.shape[1]): self.features[:, i, :, :] * pooled_gradients[i] cam torch.mean(self.features, dim1).squeeze() # ReLU 上采样 cam F.relu(cam) cam cam - torch.min(cam) cam cam / torch.max(cam) cam F.interpolate(cam.unsqueeze(0).unsqueeze(0), size(640, 640), modebilinear)[0, 0] # CLAHE增强对抗小目标热力图对比度不足 cam_np (cam.detach().cpu().numpy() * 255).astype(np.uint8) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8)) cam_enhanced clahe.apply(cam_np) return cam_enhanced # 使用示例 cam_generator YOLOGradCAM(model) input_img torch.randn(1,3,64 p a hrefhttps://download.csdn.net/download/u013883025/21181290 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p
返回列表