ARTICLE DETAIL

资讯详情

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

YOLOv7坑洼检测精度提升:ESRGAN图像增强与级联推理实战

YOLOv7坑洼检测精度提升:ESRGAN图像增强与级联推理实战 简介这份资源面向从事道路安全检测、计算机视觉与深度学习应用的研究者与工程师聚焦低分辨率摄像头或低质量行车记录仪画面下坑洼检测精度不足的问题。内容以一篇完整论文形式呈现提出先用ESRGAN对低质图像做超分辨率增强再交由YOLOv7完成坑洼目标检测并与仅使用YOLOv7的基线方案对比速度与准确率涉及CNN、迁移学习等关键技术。压缩包内共1个PDF文件约1.35MB便于直接阅读与存档。论文包含摘要、引言、方法、实验与结论等完整章节配有真实道路场景数据集上的验证结果可帮助读者理解超分辨率预处理对检测性能的实际增益并获取可复现的算法思路与评估指标参考。目前已有254人学习适合希望将超分辨率与目标检测结合落地于道路巡检场景的读者参考。1. 坑洼检测翻车现场为什么 YOLOv7 加上 ESRGAN 才是正解城市道路巡检车拍回来的路面图像分辨率参差不齐光照忽明忽暗坑洼边缘还经常糊成一团。直接拿 YOLOv7 去训mAP 卡在 0.5 上下死活上不去小坑洞漏检率更是高得离谱。这不是模型不行是输入质量拖了后腿。坑洼检测这个任务难点从来不在检测头本身而在图像退化——运动模糊、低照度、压缩伪影三座大山压着再强的 backbone 也白搭。ESRGAN 的价值就在这里它不是简单地把图放大而是用生成对抗的方式把退化图像“修”回接近真实纹理的状态让 YOLOv7 看到的是清晰的路面结构而不是一团像素噪声。这套组合适合谁做道路巡检、市政养护、自动驾驶感知冗余的团队手头有中低分辨率路面图像、标注数据有限、又不想从头训一个大模型的人。下面从原理到代码把这条路走通。2. ESRGAN 预处理管线从退化图像到检测友好输入2.1 为什么选 ESRGAN 而不是双三次插值或 Real-ESRGAN双三次插值是最省事的做法OpenCV 一行cv2.resize就完事但它对坑洼边缘的恢复基本为零——插值只是把像素摊开模糊的还是模糊高频细节该丢还是丢。Real-ESRGAN 是 ESRGAN 的升级版加了高阶退化建模理论上更鲁棒但它的训练数据偏自然场景对路面这种纹理单一、对比度低的图像容易过度平滑把坑洼边缘的锐度也抹掉。ESRGAN 的 RRDB 结构配合感知损失和对抗损失在保留纹理细节上更克制适合路面这种“不需要脑补太多、但边缘必须准”的场景。我一般会先做一个判断如果原始图像短边低于 480px坑洼直径在图像里小于 30px那 ESRGAN 的收益最明显如果原始图像已经是 1080p 以上坑洼清晰可见那预处理环节可以直接跳过省下的算力留给检测端。2.2 用 BasicSR 跑通 ESRGAN 推理的最小命令BasicSR 是 ESRGAN 最常用的开源实现安装和推理都不复杂。先建环境conda create -n esrgan python3.8 -y conda activate esrgan pip install basicsr facexlib gfpgan pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118然后下载预训练权重放到experiments/pretrained_models/下。推理脚本我一般直接改 BasicSR 自带的inference_esrgan.py核心就几行import cv2 import torch from basicsr.archs.rrdbnet_arch import RRDBNet from realesrgan import RealESRGANer # 定义 RRDB 网络num_block23 是 ESRGAN 标准配置 model RRDBNet(num_in_ch3, num_out_ch3, num_feat64, num_block23, num_grow_ch32) # 初始化推理器scale4 表示放大 4 倍 upsampler RealESRGANer( scale4, model_pathexperiments/pretrained_models/ESRGAN_x4.pth, modelmodel, tile400, # 大图分块处理避免显存爆掉 tile_pad10, # 分块重叠像素防止拼接缝 pre_pad0, halfTrue # FP16 推理速度提升约 40% ) img cv2.imread(road_lowres.jpg, cv2.IMREAD_COLOR) output, _ upsampler.enhance(img, outscale4) cv2.imwrite(road_enhanced.png, output)逻辑说明RRDBNet是 ESRGAN 的生成器23 个 RRDB 块是原论文的标准配置改小会掉点改大会爆显存。tile400是关键参数——路面图像往往很大不分块直接推理1080Ti 这种卡直接 OOM。tile_pad10是分块之间的重叠区域太小会有拼接缝太大会拖慢速度10 是经验值。halfTrue开 FP16精度损失肉眼不可见速度提升明显。参数怎么调如果显存充足比如 3090/4090tile可以拉到 800 甚至 1000减少分块数量如果显存紧张降到 200但推理时间会线性增加。outscale不一定非要 4如果原始图像已经不算太差设 2 就够了省一半时间。2.3 增强后的图像怎么和检测管线对接ESRGAN 输出的是 PNGYOLOv7 训练时读的是 JPG 或 LMDB。这里有个坑增强后的图像尺寸是原来的 4 倍如果直接拿去训 YOLOv7输入分辨率暴增训练速度直接崩。我的做法是增强后统一 resize 到 640×640YOLOv7 的标准输入但 resize 用cv2.INTER_AREA而不是默认的双线性INTER_AREA 在缩小图像时能保留更多高频信息对坑洼边缘更友好。import cv2 import os enhanced_dir road_enhanced output_dir road_enhanced_640 os.makedirs(output_dir, exist_okTrue) for fname in os.listdir(enhanced_dir): img cv2.imread(os.path.join(enhanced_dir, fname)) # INTER_AREA 缩小保留高频细节比默认双线性更适合坑洼边缘 resized cv2.resize(img, (640, 640), interpolationcv2.INTER_AREA) cv2.imwrite(os.path.join(output_dir, fname), resized, [cv2.IMWRITE_JPEG_QUALITY, 95])JPEG 质量设 95 而不是默认的 75是因为坑洼边缘的梯度信息在低质量压缩下会再次退化等于 ESRGAN 白跑了。这个细节很多人忽略但实测 mAP 能差 1~2 个点。3. YOLOv7 检测端改造从数据标注到训练参数3.1 坑洼数据集的标注规范与增强策略坑洼检测的标注有个特殊之处坑洼没有固定形状边界模糊不同标注员对同一个坑的框选差异很大。我的经验是标注时框要稍微紧一点贴着坑洼的可见边缘不要往外扩——因为 YOLOv7 学的是边界回归框太松会让模型学到“模糊边界”推理时框会飘。类别就设一个pothole不要按深度或面积分多类数据量不够时分多类就是自找麻烦。数据增强方面YOLOv7 自带的 mosaic 和 mixup 对坑洼检测是双刃剑。mosaic 把四张图拼一起能提升小目标召回但坑洼本身就不是小目标拼太多反而让模型困惑。我一般把 mosaic 概率从默认的 1.0 降到 0.5mixup 直接关掉。另外加一个自定义增强随机调整亮度和对比度模拟不同光照下的路面。import albumentations as A transform A.Compose([ A.RandomBrightnessContrast(brightness_limit0.3, contrast_limit0.3, p0.5), A.GaussNoise(var_limit(10, 50), p0.3), A.MotionBlur(blur_limit7, p0.2), # 模拟巡检车运动模糊 ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels]))brightness_limit0.3是经验值再大就会出现过曝或死黑模型学不到有效特征。MotionBlur的blur_limit7模拟中速行驶的模糊程度太大就糊得连人都认不出坑洼了。3.2 YOLOv7 训练配置anchor 重聚类与超参调整YOLOv7 默认的 anchor 是基于 COCO 数据集聚类的对坑洼这种长宽比不固定的目标直接拿来用效果一般。我一般会在自己的数据集上重新跑一遍 k-means 聚类得到 9 个 anchor。命令如下python utils/autoanchor.py --data data/pothole.yaml --img-size 640 --anchors 9聚类完把输出的 anchor 写进cfg/training/yolov7-pothole.yaml。实测重聚类后小坑洼的召回率能提升 3~5 个点。训练超参方面学习率用余弦退火初始 lr 设 0.01warmup 3 个 epoch。batch size 根据显存来12G 显存跑 640 输入batch 设 8 比较稳。epoch 数不用太多坑洼数据集通常 5000 张图以内300 个 epoch 足够收敛再多就过拟合了。python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7-pothole.yaml \ --data data/pothole.yaml \ --hyp data/hyp.scratch.pothole.yaml \ --epochs 300 \ --batch-size 8 \ --img-size 640 640 \ --cos-lr \ --name pothole_esrgan--cos-lr开余弦退火比默认的 step lr 更平滑坑洼这种小数据集上收敛更稳。--hyp指向自定义的超参文件里面把mosaic概率改成 0.5mixup设 0。3.3 增强前后对比实验mAP 和推理速度的权衡我做过一组对比实验同一批 3000 张路面图像分两组A 组直接用原始低分辨率图训 YOLOv7B 组先过 ESRGAN 增强再训。结果如下指标A 组原始B 组ESRGAN 增强mAP0.50.5120.634mAP0.5:0.950.2870.371小坑洼召回率0.430.61单张推理耗时ms1822预处理耗时ms/张085B 组 mAP 提升 12 个点小坑洼召回提升 18 个点代价是每张图多 85ms 的预处理时间。如果做离线巡检拍完回去慢慢跑这 85ms 完全可接受如果做实时车载检测就得权衡了——要么用更小的 ESRGAN 模型比如 16 个 RRDB 块要么只在检测置信度低于阈值时才触发增强做级联推理。4. 避坑与排查ESRGAN YOLOv7 组合的五个血泪教训4.1 增强后图像出现棋盘格伪影现象ESRGAN 输出的图像在平坦路面区域出现规则的网格状纹理YOLOv7 训练时把这些伪影当成了特征推理时在干净路面上也误检。原因tile参数设得太小分块之间的tile_pad不够拼接时边界像素不连续。或者halfTrue在部分显卡上 FP16 精度溢出导致像素值跳变。解决把tile从 200 提到 400 以上tile_pad从 10 提到 16。如果还有关掉half用 FP32 推理。另外检查输入图像是否有 alpha 通道ESRGAN 只接受三通道四通道图要先转 RGB。4.2 增强后 mAP 反而下降现象ESRGAN 增强后的图像肉眼看着更清晰但 YOLOv7 训出来的 mAP 比原始图还低。原因ESRGAN 的对抗损失会“脑补”纹理在坑洼边缘生成一些不存在的细节这些细节和真实坑洼特征不一致相当于给模型喂了噪声。另外增强后的图像分辨率和训练配置不匹配比如增强到 2560×2560 再硬 resize 到 640高频信息全丢了。解决降低 ESRGAN 的增强倍数从 4 倍降到 2 倍。或者在增强后加一步高斯滤波sigma0.5把对抗生成的伪细节磨掉。更稳妥的做法是只对低分辨率图像做增强高分辨率图像直接跳过。4.3 训练 loss 震荡不收敛现象YOLOv7 训练时 box loss 和 obj loss 剧烈震荡几个 epoch 都不下降。原因ESRGAN 增强后的图像亮度分布和原始图不一致如果数据集里混合了增强图和原始图模型看到的输入分布是双峰的BN 层统计量来回跳。解决要么全用增强图要么全用原始图不要混。如果非要混把 BN 的 momentum 调小从 0.03 降到 0.01让统计量更新更平滑。另外检查学习率ESRGAN 增强后的图像梯度更大初始 lr 要相应降低从 0.01 降到 0.005。4.4 推理时显存溢出现象训练好好的推理时一跑就 OOM。原因ESRGAN 推理和 YOLOv7 推理同时加载到显存里两个模型加起来超过显存上限。或者tile设得太大单块特征图就爆了。解决推理时先跑 ESRGAN把增强图存硬盘再单独跑 YOLOv7。如果非要端到端用torch.cuda.empty_cache()在两步之间清缓存并且把 ESRGAN 的tile降到 200。4.5 增强图训练后模型泛化变差现象在增强后的测试集上 mAP 很高但换一批真实场景的低分辨率图检测效果断崖式下跌。原因ESRGAN 的增强模式比较单一模型过拟合到了 ESRGAN 的输出风格上换一种退化方式比如不同的压缩算法或噪声类型就失效了。解决训练时在 ESRGAN 增强后再加一层随机退化模拟不同的压缩和噪声。或者用 Real-ESRGAN 的退化模型做数据增强让模型见到更多样的退化模式。根本思路是ESRGAN 只是预处理不是万能药检测模型本身要对退化有一定鲁棒性。5. 进阶技巧用级联推理把 ESRGAN 的算力花在刀刃上全图跑 ESRGAN 再跑 YOLOv7预处理耗时 85ms/张对实时巡检来说还是太重。我的做法是级联推理先用一个轻量 YOLOv7-tiny 在原始低分辨率图上跑一遍置信度高于 0.6 的直接输出低于 0.6 的区域裁剪出来只对这些区域跑 ESRGAN 增强再送进 YOLOv7 主模型复检。import torch import cv2 from models.experimental import attempt_load # 加载轻量模型和主模型 tiny_model attempt_load(yolov7-tiny.pt, map_locationcuda) main_model attempt_load(yolov7-pothole.pt, map_locationcuda) def cascade_inference(img, conf_thres0.6): # 第一步轻量模型快速筛查 results tiny_model(img)[0] detections non_max_suppression(results, conf_thres0.3)[0] final_dets [] for det in detections: if det[4] conf_thres: final_dets.append(det) # 高置信度直接保留 else: # 低置信度区域裁剪跑 ESRGAN 增强后复检 x1, y1, x2, y2 map(int, det[:4]) roi img[y1:y2, x1:x2] roi_enhanced esrgan_enhance(roi) # 只对 ROI 增强 roi_det main_model(roi_enhanced)[0] if len(roi_det) 0 and roi_det[0][4] 0.5: final_dets.append(roi_det[0]) return final_dets这个级联策略的核心逻辑是大部分坑洼在低分辨率图上也能被轻量模型以高置信度检出只有边缘模糊、光照差的疑难样本才需要 ESRGAN 介入。实测下来平均预处理耗时从 85ms 降到 28msmAP 只掉了 0.8 个点性价比很高。参数怎么调conf_thres设 0.6 是经验值设太高会导致大量样本走增强分支耗时回升设太低会让轻量模型的误检直接输出mAP 下降。建议在自己的验证集上画一条 conf_thres 对 mAP 和耗时的曲线找拐点。ROI 裁剪时往外扩 10 个像素避免坑洼边缘被切掉。还有一个技巧ESRGAN 的权重可以按场景微调。如果你的数据集主要是水泥路面拿 ESRGAN 原版权重跑增强效果一般。可以用 500 张水泥路面图以原版权重为起点用 L1 损失微调 10 个 epoch增强后的纹理更贴合水泥路面的颗粒感YOLOv7 的 mAP 还能再涨 2~3 个点。微调时学习率设 1e-5太大容易把预训练权重带偏。最后说一个我踩过的坑ESRGAN 增强后的图像颜色空间是 BGR 还是 RGB一定要和 YOLOv7 的训练配置对齐。BasicSR 默认输出 BGR但 YOLOv7 的 dataloader 有时候会做 RGB 转换两边不一致的话颜色通道错位模型学出来的特征全是乱的。我一般会在增强脚本最后加一行cv2.cvtColor(output, cv2.COLOR_BGR2RGB)确保和训练时一致。这个细节不起眼但翻车的时候查半天都找不到原因。这套方案我前后迭代了三个版本从最初的全图增强到现在的级联推理算力省了一半mAP 还涨了。核心体会就一句ESRGAN 不是用来“美化”图像的是用来“修复”检测模型需要的那些边缘和纹理的。别追求视觉上的清晰追求检测指标上的提升。希望帮到你。本文还有配套的精品资源点击获取
返回列表