资讯动态

YOLOv10实战:飞机蒙皮缺陷检测系统从训练到部署

发布时间:2026/10/18 15:58:48 来源:尧图企业网站定制
去年接了一个航空维修方向的视觉检测需求对方想把手头的人工蒙皮巡检逐步自动化。我基于YOLOv10搭了一套飞机蒙皮缺陷检测系统最终实现了图像、视频和摄像头三路实时检测整套代码跑在PyTorch框架下Python源码从训练到推理一条线打通。这篇文章就是把整个项目的选型、数据、训练、推理和踩坑过程完整复盘一遍给那些也在工业视觉、缺陷检测方向折腾的朋友一个可以直接参考的落地路径。1. 蒙皮缺陷检测在做什么从一个巡检痛点说起1.1 蒙皮缺陷为什么非检不可飞机蒙皮是包裹在机体结构外层的皮肤它的工作环境相当苛刻长期承受气压差、温度交变、气流冲刷和机械应力。蒙皮上一旦出现裂纹、腐蚀、划痕这类缺陷在疲劳载荷下可能扩展成结构隐患甚至影响飞行安全。因此日常维护中蒙皮检查是定检和航前检查的必做项目。传统的检查方式是人工目视加触觉摸排。老师傅拿手电筒照着蒙皮表面一点点找划痕和腐蚀斑点。这个方法有两个天然瓶颈一是效率低一架宽体机的蒙皮面积很大人工逐区域巡检耗时很长二是漏检风险高人的注意力很难在长时间重复性观察中保持稳定细小的裂纹或浅划痕很容易被忽略。飞机维修行业对漏检几乎是零容忍的所以工程团队一直在找更可靠的辅助手段。计算机视觉天然适合做这种表面缺陷筛查。相机拍一张蒙皮图像检测算法在毫秒级时间内就能标记出可疑区域提示给人工复核。这几年我在工业质检项目里试过不少检测框架最后在蒙皮缺陷这个场景上选了YOLOv10下面说说为什么。1.2 蒙皮缺陷长什么样类别定义与成像难点我在项目里把蒙皮缺陷划分为六类方便模型学习和后续维护团队理解缺陷类别典型形态常见位置crack裂纹细长线状可能带分支铆钉孔周围、应力集中区scratch划痕条状痕迹深浅不一机身两侧、机翼表面corrosion腐蚀点状或片状变色、起皮蒙皮接缝、搭接处dent凹坑圆形或椭圆形凹陷外板受力区域wear磨损区域光泽度变化、磨白舱门边缘、勤务口盖附近paint_peeling掉漆不规则剥落斑块蒙皮边缘、修复区域这六类缺陷在成像上有几个共性的难点。首先蒙皮表面是高反光金属材质光照角度一变同一缺陷可能呈现完全不同的视觉效果严重时反光区域会把裂纹完全淹没。其次裂纹和划痕是典型的小目标、细长目标在整机蒙皮照片里可能只占几十个像素。第三腐蚀和掉漆的纹理与蒙皮表面油污、灰尘在视觉上高度相似很容易产生误检。这些问题在后续数据处理和模型调参阶段都需要针对性处理。1.3 为什么是YOLOv10选型复盘我当时在候选列表里同时考虑了Faster R-CNN、YOLOv8、YOLOv10和一个Transformer检测器。Faster R-CNN在两阶段算法里精度优势明显但推理速度很难满足实时检测需求一架飞机拍几百张图每张跑几百毫秒现场根本等不起。YOLOv8成熟稳定部署生态好性能也不错。但YOLOv10发布时主打的无NMS推理和效率-精度联合优化正好切中我的痛点——实时检测场景对延迟极其敏感能省掉NMS后处理这一步对CPU部署和边端设备都有实际价值。YOLOv10的核心改进可以简单概括为两点。第一是训练时采用一致双分配机制让一个one-to-many分支负责训练时的丰富监督信号一个one-to-one分支负责推理时的最终预测训练和推理的分配方式统一推理阶段就不需要NMS了。第二是网络结构上的多个效率优化包括轻量化分类头、解耦下采样和部分大卷积核设计。用官方数据来说YOLOv10n在COCO数据集上能做到约38.5%的mAP模型只有1.8M参数YOLOv10s的mAP在40%出头参数约7.2M。对蒙皮缺陷检测这种需要部署在现场工作站甚至边缘盒子的场景这套参数量的性价比很高。当然我也承认YOLOv10的一个现实问题它的官方仓库维护节奏不如YOLOv8和YOLO11那么持续部分组件还是借用了Ultralytics的框架。但这个项目当时的目标是快速验证并落地一套能跑的实时检测系统v10的精度和速度表现足够选它就顺理成章了。2. 数据准备与标注规范检测效果的胜负手2.1 数据从哪来自采与公开数据混合模型效果的上限由数据质量决定这句话在缺陷检测里尤其成立。蒙皮缺陷检测没有像COCO那样的大规模公开数据集可以直接拿来训练实际项目里几乎都是自采数据 公开缺陷数据集二次筛选的组合方案。我在项目里采用的做法是首先用工业相机在真实飞机维护现场采集蒙皮表面图像覆盖不同机型、不同部位、不同光照角度重点采集蒙皮接缝、铆钉周围等缺陷高发区域。同时补充了一部分公开的金属表面缺陷数据做预训练先用这些通用数据让模型学会什么是划痕、什么是裂纹的基础特征再用自采数据微调。数据量方面我的经验是每个类别至少要有500到800张包含该缺陷的图像六类缺陷总计3000到4000张起步。如果某些类别的真实样本实在难采集比如凹坑在轻型飞机上很少见可以先保证每个类别不低于300张再用增强手段扩充。少于这个量级模型很容易过拟合在真实场景里误检率会高到没法用。标签质量比数量更重要一张标注粗糙的图对模型的伤害比没有这张图还大。2.2 标注规范小目标和细长目标的细节标注工具我用的是LabelImg和X-AnyLabeling两者都支持目标检测框标注并直接导出YOLO格式。YOLO格式的标签是纯文本每行对应一个目标字段依次是类别ID、归一化后的中心点x坐标、中心点y坐标、框宽度、框高度。# 这是一个示例标签文件 img_001.txt 0 0.5234 0.4312 0.0256 0.0038 2 0.6210 0.5823 0.0412 0.0265第一行表示类别0假设是crack的一个目标中心点在图像坐标的52.34%和43.12%处框宽度占整张图的2.56%高度占0.38%。可以看到裂纹的框非常扁长这就是细长目标的典型标注特征。标注蒙皮缺陷时有几个细节特别重要。细长裂纹要尽量把框贴着缺陷边缘收紧宁可框小一点也不要留太多背景凹坑这类圆形缺陷则要保证框完全包住可见区域不能切到凹陷边缘。如果一张图里同一个位置有多层缺陷比如腐蚀区域中间又有一条裂纹我会把它们拆成两个框都标出来让模型学习缺陷可以叠加出现的事实。标注完成后必须做一轮交叉复核建议同一张图让两个人各标一遍再比对差异这能把标注噪声降低一大截。2.3 数据增强与类别不平衡让模型见多识广蒙皮表面的光照变化是现实环境里最大的干扰源。我在项目里使用的增强策略包括随机亮度对比度扰动、HSV颜色抖动、随机旋转±30度以内、左右翻转、Mosaic拼接增强和随机尺度缩放。其中Mosaic增强效果最明显它把四张图拼成一张送进去训练相当于一次让模型看到四种场景对小目标检测和类别平衡都有帮助。类别不平衡的问题我在项目里也遇到了划痕和腐蚀样本多凹坑和掉漆样本少。处理方式分三步走先对少数类做重复采样让每轮训练每个batch里都能见到凹坑和掉漆然后对不同类别在损失函数里配置不同的权重少数类的权重调高一点最后是验证集上单独统计每个类别的AP而不是只看整体mAP防止少数类表现被平均数掩盖。提示必须把增强参数设定在一个合理范围内。我见过有人把旋转角度开到90度甚至180度结果模型学到的全是横七竖八的缺陷方向在真实蒙皮朝向上反而漏检。裂纹和划痕在真实蒙皮上的方向是有物理约束的增强强度过猛就是在给模型灌错误信息。3. 环境配置与源码级安装这里有一个大坑3.1 硬件环境与依赖清单先说运行环境我的训练机器是单张24GB显存的显卡内存32GB训练YOLOv10m级别模型完全够用。如果你只有8GB或12GB显存建议直接用YOLOv10s或者把输入分辨率降一档。软件依赖方面Python版本建议3.8到3.11PyTorch建议1.8以上实测2.0以上版本没有兼容性问题。CUDA建议11.8或12.1。整套项目依赖的核心库包括torch、torchvision、opencv-python、numpy、pandas、matplotlib、tqdm、tensorboard。如果你要导出ONNX做部署还要装onnx和onnxruntime。3.2 YOLOv10官方仓库安装的版本坑这里必须重点说一个坑项目最开始的安装阶段就卡了我大半天。YOLOv10的代码虽然基于Ultralytics框架但它不是直接通过pip install ultralytics就能用的。官方有独立的GitHub仓库正确安装方式是先克隆官方仓库再在仓库根目录执行git clone YOLOv10官方仓库地址 cd yolov10 pip install -r requirements.txt pip install -e .问题在于pip install -r requirements.txt会把Ultralytics也装进site-packages而YOLOv10仓库内部又自带了一套基于Ultralytics改造的源码。如果你直接运行训练脚本解释器很可能优先import到site-packages里的ultralytics而不是仓库内的本地版本此时会报一堆类似No module named ultralytics.nn.tasks的错误。这个问题的本质是包名冲突。我采取的解决方法是在虚拟环境里先不装PyPI上的ultralytics只装YOLOv10仓库requirements里除ultralytics之外的依赖然后通过pip install -e .把仓库本身注册成可导入的本地包。运行脚本时始终在仓库根目录下执行确保本地yolov10和本地ultralytics组件被优先导入。如果仓库运行时不慎装进了ultralytics直接在虚拟环境site-packages里删掉它即可。还有一个坑出在Python版本偏新的时候。我在Python 3.11环境下训练时遇到了loss计算组件的NoneType相关报错具体表现是训练进程刚启动几步就崩溃报错定位在ultralytics/utils/loss.py附近。这是YOLOv10源码与新版PyTorch之间一个已知的兼容性问题。我查看了相关的issue后做了代码修复核心思路是在损失计算的target处理处增加判空逻辑当输入数据为空时跳过当前batch。修复后训练稳定跑完整个epoch。如果你也遇到同样报错可以优先检查loss.py里对data和target的处理逻辑官方仓库后续版本可能已经打过补丁。3.3 项目结构梳理装好环境后我建议先花十分钟把项目目录结构看明白。YOLOv10仓库的核心目录包括ultralytics/cfg/models/v10/存放yolov10n/s/m/b/l/x的模型结构配置文件ultralytics/主要训练与推理的逻辑代码包括数据加载、模型定义、损失函数、验证逻辑yolov10/utils/一些工具函数如锚框计算、日志记录train.py与detect.py训练和推理的入口脚本。把目录结构搞清楚再去改配置不会出现改了文件不知道在哪的尴尬。4. 训练自己的蒙皮缺陷模型4.1 数据集配置文件训练前需要一个数据集配置文件里面写明数据路径和类别列表。我的defect.yaml是这样的path: /data/airplane_defect # 数据集根目录 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 names: 0: crack 1: scratch 2: corrosion 3: dent 4: wear 5: paint_peeling需要注意两点。一是train和val的路径写法是相对于path字段的图片文件夹和标签文件夹要按YOLO格式组织标签放在与images并列的labels目录下二是类别ID必须和标注文件里的数字一一对应一个数字对错就会导致模型张冠李戴。训练集和验证集的划分建议按飞机编号或拍摄批次来做避免同一架飞机的多张图同时出现在训练和验证集里导致验证分数虚高。4.2 训练命令与参数调整在项目根目录执行python train.py --model yolov10m.pt --data defect.yaml --epochs 150 --imgsz 640 --batch 16 --device 0这里我用的预训练权重是yolov10m.pt也就是在COCO上预训练过的模型。在预训练权重基础上做迁移学习比从零训练收敛快得多稳定性和最终精度也更高。各参数的实际调整经验如下参数我的设置调整理由modelyolov10m精度速度折中24G显存下运行流畅imgsz640→1280先用640跑通流程小目标专项优化时升到1280epochs150前100轮收敛明显后50轮微调提升APbatch16显存受限最大化batchoptimizerAdamW缺陷检测任务上比SGD收敛更稳lr00.01适应AdamW的默认学习率策略训练时我开着TensorBoard监控loss曲线和验证集mAP。正常的收敛过程是前20轮loss快速下降mAP缓慢爬升中间50轮mAP曲线开始出现锯齿但整体向上最后50轮收敛到平台期。如果看到loss降到低位但mAP上不去多半是过拟合信号这时需要加强正则化或者关掉部分增强。如果验证集mAP一直低于0.5先回去检查标签文件和类别ID是否对得上。4.3 训练中的显存与中断问题训练时最容易翻车的两个点是显存溢出和训练中断。显存溢出可以通过调小batch或imgsz解决我实测在24G显存下yolov10m配合imgsz640可以跑到batch32升到imgsz1280后只能跑到batch8到16。训练中断最常见的原因是显存被其他进程占用以及系统休眠断掉SSH连接。我习惯用nohup把训练挂在后台nohup python train.py --model yolov10m.pt --data defect.yaml --epochs 150 --batch 16 --device 0 train.log 21 训练日志写到train.log里随时可以查看进度。如果训练中断了YOLOv10支持断点续训用--resume参数加载最近的checkpoint即可。5. 三路推理系统图像、视频、摄像头实时检测5.1 统一推理入口训练得到的最佳权重是best.pt接下来要做的是把它封装成一个可以同时处理图像、视频和摄像头的推理服务。我做了一个统一的推理类核心逻辑是读入图像帧缩放为模型输入尺寸推理得到预测框过滤低置信度目标将结果画回原始帧。推理时两个关键参数是conf_thres和iou_thres。conf_thres是置信度阈值低于这个分数的框会被丢弃。蒙皮缺陷检测中我习惯把conf_thres设置在0.25到0.35之间。阈值设太高容易漏检小裂纹设太低会带来大量误检。iou_thres用于NMS虽然在YOLOv10默认无NMS推理下用不到但如果你开启use_nmsTrue做精度对比就需要注意这个指标。5.2 图像检测实现图像检测是最基础的玩法。加载一张蒙皮照片输出带检测框的标注图import cv2 from ultralytics import YOLO model YOLO(weights/best.pt) img cv2.imread(test_images/defect_001.jpg) results model.predict(img, imgsz1280, conf0.25, device0) for result in results: boxes result.boxes for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) label f{model.names[cls_id]} {conf:.2f} cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow(Detection, img) cv2.waitKey(0)这里有一个细节预测时imgsz默认是训练时的640但如果你的输入是高分辨率蒙皮大图直接用640会让小缺陷缩得很小模型很容易漏检。我在图像检测场景下把imgsz提到1280实测对小裂纹和划痕的召回率提升明显代价是单张推理时间从十几毫秒涨到几十毫秒但这个量级对离线抽检完全可接受。5.3 视频检测实现视频检测与图像检测在思路上没有本质区别只是多了一层视频流解析和逐帧处理。用OpenCV读取视频文件每帧送进模型画框后写入输出视频import cv2 from ultralytics import YOLO model YOLO(weights/best.pt) cap cv2.VideoCapture(defect_video.mp4) fourcc cv2.VideoWriter_fourcc(*mp4v) fps cap.get(cv2.CAP_PROP_FPS) w int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) writer cv2.VideoWriter(output.mp4, fourcc, fps, (w, h)) while True: ret, frame cap.read() if not ret: break results model.predict(frame, imgsz1280, conf0.25, device0) annotated results[0].plot() writer.write(annotated) cap.release() writer.release()这里有一个实际经验如果视频分辨率很高比如4K画面我建议先做等比例缩放把长边缩到1920以内再做检测否则推理耗时成倍上涨画框的位置也会因为缩放而需要坐标变换很容易出错。我的做法是缩放后记录缩放比例画框时再换算回原图坐标。5.4 摄像头实时检测与帧率优化摄像头实时检测是这套系统在演示和现场确认环节最出效果的模式。核心代码很简单import cv2 from ultralytics import YOLO model YOLO(weights/best.pt) cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame cap.read() if not ret: break results model.predict(frame, imgsz640, conf0.25, device0) annotated results[0].plot() cv2.imshow(Real-time Defect Detection, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()但真正跑起来后发现直接这样逐帧推理帧率往往只有10到15FPS画面卡顿感很明显。我从三个方向做了优化第一降低推理分辨率。摄像头画面从1280x720缩到640x640送入模型会损失部分小目标精度但换来20FPS以上的流畅度实测人眼在实时预览时更关注有没有框出来而不是框的精细位置。第二引入跳帧机制每两帧只检测一帧中间帧直接沿用上一帧的检测框视觉上几乎无感但推理吞吐量直接翻倍。第三用半精度推理在PyTorch下把模型转成fp16可以减少大约三成的显存带宽占用对推理速度有一点提升。如果要做成一个正式交付的演示界面我建议用Gradio搭一个简单的Web页面把图像上传、视频上传和摄像头推流三个入口集成在一起操作人员通过浏览器就能使用比直接跑Python脚本直观很多。我在项目里就是这么做的虽然界面很朴素但实际评审演示时反而比终端窗口更受认可。6. 实测效果与问题排查漏检、误检、卡顿的逐一拆解6.1 小缺陷漏检切片检测方案项目初期在整机蒙皮大图上跑检测最容易发现的问题是裂纹和划痕在整图里只占很小面积模型经常会漏掉。这种小目标漏检问题单纯调高imgsz能缓解一部分但真正有效率的方案是切片检测。切片检测的思想是把大图按滑窗切成小块每个小块独立送进模型检测最后再把所有小块的检测结果投回原图坐标系并做合并。比如一张4032x3024的照片按512x512的窗口、256步长滑动会切出上百个块。每个块的缺陷比例大大增加模型检测效果明显提升。如果你不想自己实现这个逻辑可以直接用现成的切片推理工具库它与YOLO系列模型配合很成熟内部帮你把切图、检测、坐标还原、重叠框合并全部处理好了。我实测在同样的模型权重下切片推理比整图推理在小裂纹上的召回率能提升十几个百分点。代价是推理时间变长但用在离线抽检场景完全值得。摄像头实时检测不建议用切片实时性不够现场翻看关键图片时再用切片复核就好。6.2 反光导致的误检增强与后处理双管齐下蒙皮表面的金属反光是误检的主要来源。模型会把高光区域的边缘纹理误认成划痕或腐蚀尤其在窗户光照直射的时候。我在项目里踩过这个坑第一次实景测试时误检框密密麻麻现场拍摄的同事直接笑场了。从这个教训出发我做了一个组合处理。数据层面在训练集里补充了多组不同光照角度的高反光样本并把随机亮度对比度扰动幅度加大让模型在训练时见过足够多的反光纹理。后处理层面除了把conf_thres从0.25提高到0.35还接了一个基于位置和面积的规则过滤蒙皮表面巡检时同一片区域内出现大量小面积同类框且这些框排列成规则的高光条纹形状就把它整体判为疑似反光干扰并过滤掉。这招在实际效果上把误检数量直接压缩了六成以上。6.3 摄像头实时帧率上不去多线程与模型选择摄像头模式还有一个容易忽略的性能瓶颈OpenCV的cap.read()是阻塞式读取如果摄像头采集速度跟不上推理速度主线程会被IO卡住。我采取的办法是开一个独立线程持续读取摄像头帧放进一个队列主线程只管从队列里取最新帧做检测。import cv2 import threading from collections import deque class CameraStream: def __init__(self, src0): self.cap cv2.VideoCapture(src) self.q deque(maxlen2) self.running True threading.Thread(targetself._reader, daemonTrue).start() def _reader(self): while self.running: ret, frame self.cap.read() if ret: self.q.append(frame) def read(self): return self.q[-1] if self.q else None这种生产者-消费者模式能有效把摄像头采集延迟和推理耗时解耦实测帧率提升非常明显。如果还是觉得卡就把模型从yolov10m换到yolov10s参数量只有前者的一半左右实时性提升一大截精度损失在可接受范围内。6.4 部署形态与后续扩展方向系统跑通后我把它导出成了ONNX格式这样可以在不依赖PyTorch的环境里用ONNX Runtime推理部署到现场的工作站时会轻量很多。导出命令很简单model.export(formatonnx, imgsz640, opset12)如果要追求极致性能还可以用TensorRT把模型编译成engine格式在显卡上推理速度能比PyTorch原生再快一倍左右。我当时的落地机器没有对应的部署工具链ONNX Runtime已经足够就没继续深挖TensorRT。从项目后续演进的角度看有几个方向值得做。一是把切片检测固化到整个离线流程中作为大图检测的默认模式二是收集真实巡检现场持续产生的误检数据定期回到训练集里迭代模型这种闭环迭代对工业场景的价值极大三是如果部署环境有国产化要求可以评估把模型迁移到国产训练推理框架上YOLOv10的ONNX接口在这一步会省很多事。最后说几句实在的这套飞机蒙皮缺陷检测系统从数据整理到三路推理跑通前后花了大概三周时间。如果只让我留一句话给准备做同类项目的人缺陷检测项目的时间大头一定在数据和数据相关的问题处理上模型训练本身反而是流程里最顺畅的部分。我在实际项目里反复体会到一个道理——把质量差的标签清理干净、把光照和角度变化在数据层面穷举到位比花时间刷网络结构和调参对整个项目收益更大这个经历一次就会印象深刻。另外实时检测系统务必尽早考虑帧率和部署环境的约束千万别等到模型训好了才想起来现场机器没有对应显卡驱动那种返工是最磨人的。希望这篇文章能帮你在自己的蒙皮缺陷检测项目里少走几段弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑