news 2026/10/19 13:52:07

基于YOLOv5的直肠息肉检测:完整程序、数据集与RK3568量化部署实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLOv5的直肠息肉检测:完整程序、数据集与RK3568量化部署实战

简介:这份资源面向医学影像分析人员、机器学习开发者及疾病筛查研发工程师,提供一套基于YOLOv5的直肠息肉检测系统完整实现方案,用于辅助医疗专家进行息肉的自动检测与早期筛查。内容覆盖环境搭建、数据集创建与配置文件编写、模型训练、ONNX格式导出、性能评估与指标可视化,以及Tkinter图形界面搭建和代码整合等环节,并探讨多类别检测、数据增强、集成学习与云部署等后续升级方向。资源包共1个docx文档,约41KB,以文字说明形式系统梳理项目介绍、特点、详细实现步骤与注意事项,目录结构清晰,便于按模块查阅。已有120人学习关注。读者可据此掌握从数据准备到GUI落地的完整流程,理解精确度、召回率、F1分数等评估指标的运用,并获得可扩展的工程思路与排错参考,适合具备一定深度学习基础、希望切入医疗图像检测方向的开发者研读实践。

1. 直肠息肉检测为什么值得用 YOLOv5 做一遍

肠镜室里最耗神的不是操作本身,而是医生盯着屏幕一帧一帧找息肉的那几分钟。一枚直径 5mm 以下的扁平息肉,在 1080p 画面里可能只占几十个像素,加上肠道蠕动、反光、气泡干扰,漏检率一直下不来。基于 YOLOv5 的直肠息肉检测系统,本质上就是把这件「人眼容易疲劳、标准难以统一」的事,交给一个能在 30FPS 以上实时跑的单阶段检测器。它解决的不是「能不能检出」的学术问题,而是「在普通显卡甚至边缘设备上,能不能稳定跑起来、能不能复现」的工程问题。

这套方案适合三类人:一是手里有肠镜图像或视频、想快速搭一个可演示原型的算法工程师;二是要做医学图像课程设计、需要完整程序和数据集的学生;三是想验证 YOLOv5 在真实医疗场景下量化部署可行性的嵌入式开发者。标题里说的「详细的完整的程序和数据」,落到实操上就是:一份可训练的 YOLOv5 工程、一份标注好的息肉数据集、一套从训练到推理再到量化的脚本。下面按「数据怎么准备 → 模型怎么训 → 指标怎么看 → 坑在哪 → 怎么部署」的顺序,把这条链路走通。

2. 数据集准备与 YOLOv5 格式转换:从原始肠镜图到可训练标签

2.1 直肠息肉数据集的来源与标注策略

公开的直肠息肉数据集常见做法是拿 Kvasir-SEG、CVC-ClinicDB 这类分割数据集改造成检测数据集。它们原本给的是像素级掩码,你需要把掩码转成边界框。我一般会先用 OpenCV 找掩码的外接矩形,再按 YOLO 的归一化格式写标签。标注时有两个原则:一是边界框要紧贴息肉边缘,不要为了「保险」往外扩太多,否则 NMS 阶段容易把相邻息肉合并;二是对于遮挡超过 50% 的息肉,宁可标成困难样本单独放一个子集,也不要强行标全,否则训练时回归损失会被带偏。

数据量方面,Kvasir-SEG 大约 1000 张,CVC-ClinicDB 约 612 张,合并去重后能到 1400 张左右。这个量级对 YOLOv5s 来说偏少,所以数据增强必须开足。常见做法是 HSV 色调扰动、随机缩放、马赛克增强,但医学图像要慎用上下翻转——肠道解剖结构有方向性,翻转后可能引入不存在的伪影。左右翻转相对安全,可以保留。

2.2 把掩码转成 YOLO 标签的脚本与四个边界坑

下面这段脚本做两件事:读掩码图,找轮廓,生成 YOLO 格式的 txt 标签。假设目录结构是images/和masks/一一对应。

import cv2 import os import numpy as np # 输入输出路径 img_dir = "dataset/images" mask_dir = "dataset/masks" label_dir = "dataset/labels" os.makedirs(label_dir, exist_ok=True) for name in os.listdir(mask_dir): mask_path = os.path.join(mask_dir, name) mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) if mask is None: continue # 二值化,掩码里息肉区域通常为白色 _, binary = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY) contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) h, w = mask.shape lines = [] for cnt in contours: # 过滤掉面积过小的噪点,阈值按图像分辨率调整 if cv2.contourArea(cnt) < 30: continue x, y, bw, bh = cv2.boundingRect(cnt) # YOLO 格式:类别 cx cy bw bh,全部归一化到 0-1 cx = (x + bw / 2.0) / w cy = (y + bh / 2.0) / h nw = bw / float(w) nh = bh / float(h) lines.append(f"0 {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}") txt_name = os.path.splitext(name)[0] + ".txt" with open(os.path.join(label_dir, txt_name), "w") as f: f.write("\n".join(lines))

逻辑说明:cv2.findContours用RETR_EXTERNAL只取最外层轮廓,避免掩码内部空洞产生多余框。面积阈值 30 是经验值,1080p 图像下对应约 5×6 像素,再小基本是噪声。归一化时注意cx和cy是中心点坐标,不是左上角,这是新手最容易写错的地方。

四个边界坑:第一,掩码如果是 0/255 但息肉是黑色、背景白色,阈值判断要反过来;第二,轮廓可能贴边,boundingRect返回的框会超出图像边界,训练时 YOLOv5 会做裁剪但最好自己先 clamp;第三,一张图可能有多个息肉,脚本里已经用循环处理,但类别号要确认是否都是 0;第四,文件名必须和图像严格对应,YOLOv5 是按文件名找标签的,差一个后缀就整张图被当负样本。

2.3 数据集划分与 data.yaml 配置

转换完成后按 8:1:1 划分训练、验证、测试。YOLOv5 不强制要求测试集,但医学场景我建议单独留一份测试集,因为验证集会被用来调超参,指标会偏乐观。目录结构建议:

dataset/ images/train/ images/val/ images/test/ labels/train/ labels/val/ labels/test/

对应的polyp.yaml:

path: ./dataset train: images/train val: images/val test: images/test nc: 1 names: ['polyp']

nc是类别数,直肠息肉检测通常只分「息肉」一类,不要自作聪明去分大小或位置,数据量不够时多分类只会让 mAP 掉得更快。names的顺序必须和标签里的类别号一致,写反了训练能跑但结果全错。

3. YOLOv5 训练配置与超参数调优:让 mAP 从 0.6 爬到 0.85

3.1 模型选型:s/m/l 在息肉检测上的取舍

YOLOv5 提供 n/s/m/l/x 五个尺度。直肠息肉检测我一般从 s 起步,原因是数据量小、目标尺度相对集中,大模型容易过拟合。如果你有 5000 张以上标注数据,可以上 m 或 l。下面是一组在 1400 张数据集上的对比,输入 640×640,batch 16,训练 100 epoch:

模型参数量mAP@0.5单帧推理(RTX 3060)显存占用
yolov5n1.9M0.724ms2.1G
yolov5s7.2M0.837ms3.4G
yolov5m21.2M0.8514ms5.8G
yolov5l46.5M0.8424ms9.2G

可以看到 m 相比 s 只涨了 2 个点,但推理时间翻倍。如果最终要部署到树莓派 4B 或 RK3568 这类边缘设备,s 甚至 n 才是现实选择。选型时先问自己:推理硬件是什么?如果答案是 Jetson 或带独显的工控机,s 足够;如果是纯 CPU 或 NPU,直接考虑 n 加量化。

3.2 训练命令与关键超参数含义

python train.py \ --data polyp.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --hyp data/hyps/hyp.scratch-low.yaml \ --optimizer SGD \ --lr0 0.01 \ --lrf 0.01 \ --cos-lr \ --cache

逐项说明:--weights yolov5s.pt用 COCO 预训练权重,医学数据量小时这是涨点最明显的一步,从头训基本没戏。--img 640是输入分辨率,息肉小目标多的话可以提到 1024,但显存和速度要重新权衡。--hyp选 low 增强配置,因为医学图像颜色和纹理敏感,强增强反而有害。--lr0 0.01是初始学习率,SGD 下这个值比较稳,Adam 的话要降到 0.001。--lrf 0.01是最终学习率系数,配合--cos-lr做余弦退火。--cache把图像缓存到内存,小数据集能明显加快 epoch 速度。

训练过程中重点看三个指标:box_loss是否稳定下降、obj_loss有没有震荡、mAP@0.5在第几个 epoch 开始 plateau。如果obj_loss一直不降,大概率是标签格式错了或者正负样本划分有问题。

3.3 超参数调优:从 hyp.scratch-low 改哪几个值

YOLOv5 的超参数文件里,对息肉检测影响最大的是这几个:

  • mosaic: 1.0马赛克增强概率。小数据集建议保持 1.0,但最后 10 个 epoch 可以关掉,让模型适应真实分布。
  • scale: 0.5随机缩放幅度。息肉尺度变化不大时可以降到 0.3,避免小息肉被缩到看不见。
  • hsv_h: 0.015色调扰动。肠镜图像偏红,色调扰动太大会让模型学到不存在的颜色特征,建议降到 0.01。
  • flipud: 0.0上下翻转。前面说过,医学图像不要开。
  • fliplr: 0.5左右翻转。可以保留,肠道左右结构相对对称。

我一般会先跑 20 epoch 看 loss 曲线,如果box_loss下降太慢,把lr0提到 0.02;如果mAP波动大,把batch从 16 降到 8,同时lr0减半。这些调整没有银弹,但方向是明确的:小数据 + 预训练权重,学习率宁小勿大,增强宁弱勿强。

4. 指标解读与推理验证:mAP 高不代表临床可用

4.1 看懂 YOLOv5 输出的混淆矩阵和 PR 曲线

训练结束后runs/train/exp下会生成confusion_matrix.png和PR_curve.png。混淆矩阵里重点看背景被误判成息肉的 FP 数量。临床场景下,假阳性太多会让医生频繁确认,体验极差;假阴性则是漏检,后果更严重。所以调阈值时,宁可稍微牺牲一点精确率,也要把召回率拉上去。PR 曲线上看mAP@0.5对应的 recall 值,如果 recall 低于 0.8,说明还有不少息肉没检出来,需要检查标注质量或提高输入分辨率。

4.2 用测试集跑推理并可视化结果

python detect.py \ --weights runs/train/exp/weights/best.pt \ --source dataset/images/test \ --img 640 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --save-txt \ --save-conf

--conf-thres 0.25是置信度阈值,医学场景建议从 0.25 起步,不要用默认的 0.25 以上,否则小息肉容易被滤掉。--iou-thres 0.45是 NMS 的 IoU 阈值,如果同一区域出现多个重叠框,可以降到 0.4。--save-txt会把检测结果写成 YOLO 格式,方便后续做定量统计。跑完后重点看两类图:漏检的(真实标签有但预测没有)和误检的(预测有但真实标签没有)。漏检多就查标注是否漏标,误检多就查背景里有没有类似息肉的纹理。

4.3 量化前的精度基线:别急着上 RK3568

很多人一上来就想把模型量化到 RK3568 上跑,结果精度掉得没法看。正确顺序是先在 GPU 上把 FP32 的 mAP 跑到满意,再导出 ONNX,再做 INT8 量化,每步都记录精度。如果 FP32 的 mAP 只有 0.7,量化后掉到 0.5 是正常的,问题不在量化,在模型本身就没训好。我一般要求 FP32 的 mAP@0.5 至少 0.85,量化后不低于 0.80,才认为这套方案有部署价值。

5. 避坑与排查:直肠息肉检测里最容易翻车的五件事

5.1 现象:训练 loss 正常但 mAP 始终为 0

原因:标签类别号或names配置不匹配。YOLOv5 在计算 mAP 时会按类别匹配,如果标签里写的是0但names里只有一个polyp,理论上没问题;但如果标签里出现了1而nc是 1,这类标签会被忽略,导致部分图像没有有效标签。解决:用脚本统计所有标签文件里的类别号,确认最大值小于nc。

5.2 现象:验证集 mAP 很高,测试集一跑就崩

原因:数据划分时没有按患者或视频来源分层。同一患者的肠镜帧之间高度相似,如果随机划分,验证集里可能有和训练集同一患者的图像,指标虚高。解决:按患者 ID 或视频 ID 划分,确保同一来源的图像只出现在一个集合里。这个坑在医学图像里非常普遍,血泪经验。

5.3 现象:推理时小息肉全部漏检

原因:输入分辨率不够或conf-thres太高。640 输入下,5mm 息肉可能只有 10 个像素,YOLOv5 的 P3 特征图下采样 8 倍后只剩 1 个像素,很难激活。解决:把--img提到 1024,或者用--conf-thres 0.1先看召回,再逐步调高。如果硬件不允许提高分辨率,考虑用切片推理,把大图切成小块分别检测。

5.4 现象:量化后模型输出全乱

原因:RK3568 的 INT8 量化对激活值范围敏感,而 YOLOv5 的 SiLU 激活函数在量化时容易溢出。解决:导出 ONNX 时把 SiLU 换成 ReLU,或者用量化感知训练(QAT)代替训练后量化(PTQ)。PTQ 快但精度损失大,QAT 慢但可控。如果只是做演示,PTQ 加 500 张校准图通常能接受;如果要上临床,QAT 是必须的。

5.5 现象:树莓派 4B 上推理只有 2FPS

原因:树莓派 4B 的 CPU 跑 YOLOv5s 本身就很吃力,没有 NPU 加速。解决:换 yolov5n,输入降到 320,用 ONNX Runtime 的 ARM 优化版本,或者外接 Google Coral USB 加速棒。如果这些都不行,说明硬件选型错了,不是模型的问题。部署前先确认目标硬件的算力,别等训完模型才发现跑不动。

6. 从 PyTorch 到 RK3568:量化部署的实操细节

6.1 导出 ONNX 与 RKNN 模型转换

先在 PC 上导出 ONNX:

python export.py \ --weights runs/train/exp/weights/best.pt \ --include onnx \ --img 640 \ --batch 1 \ --opset 12

--opset 12是 RKNN 工具链比较稳定的版本,不要用太新的 opset。--batch 1是因为边缘设备通常单帧推理。导出后用onnxsim简化一下,去掉多余的算子。

然后在 RK3568 的 SDK 里用rknn-toolkit2转换:

from rknn.api import RKNN rknn = RKNN() rknn.config( mean_values=[[0, 0, 0]], std_values=[[255, 255, 255]], target_platform='rk3568', quantized_dtype='asymmetric_quantized-8' ) rknn.load_onnx(model='best.onnx') rknn.build(do_quantization=True, dataset='calib_list.txt') rknn.export_rknn('best.rknn')

mean_values和std_values要和训练时的归一化一致,YOLOv5 默认是 0-1 归一化,所以这里用 0 和 255。calib_list.txt里放 200-500 张训练集图像路径,校准集要覆盖不同光照和息肉形态,否则量化误差会集中在某些场景。

6.2 量化精度验证与回退策略

转换完成后,在 RK3568 上跑一遍测试集,和 PC 上的 FP32 结果对比。如果 mAP 掉超过 5 个点,先检查校准集是否代表性不足,再检查quantized_dtype是否用了asymmetric_quantized-8。如果还是不行,回退到混合量化,对敏感层保持 FP16。RKNN 支持hybrid_quantization,虽然速度会慢一点,但精度能拉回来。

6.3 一个具体技巧:用切片推理提升小息肉召回

如果最终部署的输入分辨率受限,比如 RK3568 上只能跑 640,但小息肉漏检严重,可以在推理前把图像切成 2×2 的四块,每块缩放到 640 分别检测,再合并结果。代价是推理时间变成 4 倍,但小目标召回能提升 10-15 个点。这个技巧在工业缺陷检测里很常见,直肠息肉同样适用。合并时注意 NMS 的 IoU 阈值要调低到 0.3,避免切片边界的重复框。

我自己的习惯是:每次训完模型,先不急着导出,而是把测试集里漏检的图单独挑出来看一遍,确认是标注问题还是模型问题。这个动作花不了十分钟,但能省下后面几天的瞎调参。希望帮到你。

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

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

最大熵模型预测实战:从原理到栅格生成的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/19 13:50:36

基于LSH的论文相似性快速比对技术实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 14:36:15

PCA9422与MK51DN512CLQ10协同电源管理设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 17:06:08

DeepGEMM:面向AI推理的场景化GEMM加速引擎

1. 项目概述&#xff1a;DeepGEMM不是“又一个矩阵乘法库”&#xff0c;而是AI底层算力调度的重新定义DeepGEMM——光看名字&#xff0c;很多人第一反应是“哦&#xff0c;又是优化GEMM&#xff08;General Matrix Multiplication&#xff09;的开源项目”。但我在某实验室参与…

作者头像 李华
网站建设 2026/10/16 16:17:06

PCA9422+STM32L081CB超低功耗电源管理设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华