基于YOLO目标检测的帕金森手绘螺旋与波浪识别
简介面向帕金森病辅助诊断的YOLO物体检测数据集包含健康人与帕金森病患者手绘螺旋和波浪图像的完整预处理与注释集合并已划分为训练组和测试组便于监督学习训练与泛化能力验证适合医疗图像分析、模式识别及运动障碍研究。压缩包约817.5MB共2000个文件以1999个txt标注文件为主配套1个yaml配置txt采用YOLO标准格式记录目标类别与归一化坐标yaml定义训练路径与类别参数可直接用于YOLO系列模型的训练与验证。目前已有68人学习浏览。数据集在图像标准化、尺寸调整、去噪等预处理环节做了充分处理并提供精确目标位置注释为复现原始研究实验、评估不同检测网络性能以及开发帕金森早期检测算法提供了可对照的优质素材无论是医学研究者还是计算机视觉入门者都可据此快速搭建实验流程。1. 手绘螺旋和波浪里藏着运动障碍的量化密码帕金森病最直观的运动症状之一是精细动作控制能力下降。让受试者在纸上画一个阿基米德螺旋或一组波浪线健康人的轨迹平滑、间距均匀而患者的手绘曲线会出现震颤锯齿、压力不均和半径收缩。传统量表如UPDRS依赖医生目测打分主观性强且难以复现。把这类图像交给YOLO做物体检测本质是把画得怎么样转成检测框内目标特征的回归问题——模型不再需要对整幅图做全局分类而是先定位出每一段螺旋或波浪区域再基于框内纹理判断是否属于帕金森相关异常。这种思路适合数据集规模小、目标形态固定且有明显局部差异的医疗辅助筛查场景。对于刚接触YOLO目标检测流程的工程师这个数据集最大的价值在于它已经完成了预处理和注释集合可以直接用来训练yolov8或更新的版本而不必从零处理标注格式问题。2. 为什么检测比分类更适合帕金森手绘图2.1 目标检测能同时输出位置和类别而分类只能给出整体概率一张手绘螺旋图可能包含多个独立的螺旋圈或者扫描时把同页多组波形一起录入。用图像分类模型如ResNet只能回答这张图属于患者还是健康人但无法告诉医生异常区域出现在哪里。YOLO将每个螺旋或波浪视为一个独立目标边界框不仅圈出位置还为后续的细粒度分析比如提取框内轨迹的震颤频率提供了ROI。从数据利用角度看一张包含4个波浪的图在分类任务里只能产生1个样本而在检测任务中能产生4个正样本这对样本量有限的医疗数据集尤其重要。2.2 标注协议设计的两个关键决策这个数据集的注释集合通常遵循COCO或YOLO格式但在类别定义上需要格外思考。常见做法是设置两个维度维度类别选项典型YOLO class_id图形类型spiral螺旋、wave波浪0, 1受试者状态healthy健康、pd帕金森2, 3但更推荐合并为四类spiral_healthy、spiral_pd、wave_healthy、wave_pd。原因在于YOLO的类别损失是独立多标签如果拆成两个维度模型可能学到螺旋健康的组合混淆。合并后每个检测框直接回答这是什么图形、来自谁在训练时类别边界更清晰推理后也免去后处理组合逻辑。标注时还有一个注意点不要用整个图像作为单个边界框。因为螺旋内部包含了大量空白背景如果框太大YOLO的锚框匹配会产生大量低IoU的正样本干扰特征学习。正确做法是标紧密包围盒tight bounding box只框住笔迹的外接矩形必要时对特别长的螺旋拆分成2~3个框确保每个框内目标占比超过70%。2.3 完全预处理的数据管线到底做了什么标题提到的完全预处理不是一个营销词汇。从原始纸质扫描到YOLO可训练的格式至少经历了这么几步灰度化与二值化将RGB扫描转灰度用Otsu阈值分离笔迹与纸张背景。这一步消除颜色偏差避免模型在训练时学习到不同纸张的色温差异。去噪与形态学操作用中值滤波去除扫描噪点再用形态学闭运算连接断裂的笔迹线段。帕金森患者画线时力度不均常常出现断笔闭运算的3x3内核能有效修复但注意不要用太大内核否则会让锯齿消失反而丢失了震颤特征。透视矫正与归一化扫描时纸面可能有旋转或倾斜通过检测纸张边缘做透视变换将图像对齐为水平。随后缩放到统一尺寸如640x640这是YOLO训练的标准输入。标注格式转换如果是VOC XML或LabelMe的JSON需要转换成YOLO的txt格式。YOLO每行存储class_id x_center y_center width height其中位置信息都是相对于图像宽度和高度的比例值。Cvat标注工具可以直接导出YOLO格式导出前记得在设置里勾选导入时归一化边界框。预处理完成后建议用Python脚本做一次质量检查import cv2 import numpy as np def check_yolo_annotation(img_path, txt_path): img cv2.imread(img_path) h, w img.shape[:2] valid True with open(txt_path, r) as f: for line in f.readlines(): parts line.strip().split() if len(parts) ! 5: print(f行解析失败: {line}) valid False continue cls, xc, yc, bw, bh map(float, parts) x_min max(0, (xc - bw/2) * w) y_min max(0, (yc - bh/2) * h) x_max min(w, (xc bw/2) * w) y_max min(h, (yc bh/2) * h) if x_max x_min or y_max y_min: print(f空框: {line}) valid False return valid这段代码逐行解析YOLO标注验证边界框是否落在图像范围内且宽高不为零。因为归一化坐标可能因为四舍五入产生负值或超过1训练时会导致损失直接变成NaN。跑一遍检查脚本能在训练前提前暴露标注问题。3. 用YOLOv8训练帕金森手绘数据集从目录到损失曲线3.1 环境准备与数据集目录结构当前YOLO已经迭代到v11但yolov8仍然是最稳健的基线。若你手上是RTX 30系或40系显卡安装ultralytics包即可pip install ultralytics torch torchvisionYOLO训练要求的目录结构严格遵守Ultralytics的约定parkinson_dataset/ ├── images/ │ ├── train/ # 约80%图片 │ └── val/ # 约20%图片 ├── labels/ │ ├── train/ # 与图片同名的.txt文件 │ └── val/ └── data.yaml注意训练集和验证集的划分必须按受试者分而不是按图片分。同一个人的多张手绘图如果同时进入训练集和验证集模型相当于变相记住人而不是学习疾病共性。常见做法是留出5~6个受试者的全部图像作为验证集。data.yaml内容如下path: /path/to/parkinson_dataset train: images/train val: images/val names: 0: spiral_healthy 1: spiral_pd 2: wave_healthy 3: wave_pd这里的关键点是names必须与训练时用的标注类ID完全对齐顺序不能错。Ultralytics会读取所有标签如果某个类在训练集中存在但未在names里声明会直接报错。3.2 训练超参数怎么设手绘数据集规模通常不大几千张简单套用COCO的默认超参容易过拟合。推荐的一组起点参数yolo detect train \ dataparkinson_dataset/data.yaml \ modelyolov8n.yaml \ pretrainedyolov8n.pt \ epochs100 \ batch16 \ imgsz640 \ patience20 \ lr00.001 \ lrf0.01 \ cos_lrTrue \ degrees5 \ translate0.1 \ scale0.3 \ fliplr0.0各项参数的作用modelyolov8n.yaml使用nano结构因为目标类别少、背景简单不需要large模型的计算量。如果验证集mAP仍然偏低再尝试yolov8s。pretrainedyolov8n.pt加载COCO预训练权重。虽然COCO里没有螺旋图像但预训练骨干网已经学会了边缘、纹理等低层特征能显著缩短冷启动时间。patience20超过20轮验证集性能不再提升就早停防止训练后期严重过拟合。cos_lrTrue余弦退火学习率让损失收敛更平滑对小数据集很友好。fliplr0.0注意这里故意禁止左右翻转。螺旋具有方向性帕金森患者画螺旋时往往顺时针或逆时针有一个固定习惯方向翻转后可能让模型学到错误的方向与疾病的虚假关联。3.3 训练过程中的损失曲线与mAP解读训练启动后每轮会输出一组指标关键看两个量box_loss边界框回归损失。健康人的螺旋边界框通常更规则患者因为震颤导致笔迹外扩框面积更大。如果box_loss迟迟不降排查锚框大小是否匹配目标实际尺寸。脊柱数据集里螺旋框的宽高比集中在1.0~1.3而波浪框宽高比可能到3.0YOLOv8的anchor-free机制相对宽容但极端长宽比目标建议用anchor_ratio调整。cls_loss类别损失。因为四类中最容易混淆的是wave_healthy和wave_pd如果这两类频繁互错检查训练集中波浪线的形态差异是否明显。有时预处理阶段的闭运算把患者的锯齿线过度平滑反而抹掉了关键特征。训练结束后验证集上的mAP50通常可以达到0.9以上。但如果你的目标不是学术指标而是后续部署更值得看的是mAP50-95——它计算的是IoU从0.5到0.95的多个阈值下的平均精度对边界框定位精度更敏感。医疗场景要求检测框尽量紧贴笔迹不能像通用物体检测那样容忍松弛框所以即使mAP50很高也要关注mAP50-95是否低于0.7如果是说明框的定位一致性不足需要回看标注框是否过松或过紧。下表是不同模型规模在类似小数据集上的参考表现示意非特定报告数据模型参数量mAP50mAP50-95推理耗时(640x640, RTX3060)yolov8n3.2M0.930.722.1msyolov8s11.2M0.940.753.5msyolov8m25.9M0.950.775.2ms从表中能看到m到l的提升相对有限但推理时间翻倍。实际部署在医生工作站上nano模型已经足够必要时可用TensorRT加速单张推理可以压到1ms以内。4. 数据增强与损失函数调优把小目标找回4.1 针对手绘细线的增强策略手绘螺旋的笔迹宽度在640x640图像中通常只占几个像素属于典型的小目标。Ultralytics默认的增强策略会随机旋转和缩放但这对细线条目标有个副作用经过仿射变换插值后细线可能被直接抹平。因此不建议使用过大的scale和degrees。更有效的是以下三种组合马赛克增强将四张图拼成一张迫使模型在更小尺度上识别螺旋。但马赛克在训练后期应关闭Ultralytics提供了mosaic1.0启动训练最后10%轮次自动关闭mosaic参数设置为0最终阶段。HSV颜色扰动把hsv_h设为0.02hsv_s设为0.3hsv_v设为0.3。手绘图纸可能用蓝笔或黑笔颜色扰动让模型不那么依赖颜色而重点学亮度对比。图像擦拭RandomErasing随机遮挡小部分笔迹模拟扫描污渍或画纸折痕。这对提升泛化特别有帮助因为真实筛查中纸张折叠、笔迹被手指蹭模糊是常态。4.2 YOLO损失函数中的三个部分如何影响螺旋检测YOLO的损失函数由三部分组成box_loss边界框回归、cls_loss类别分类、dfl_loss分布焦点损失。医疗场景中最敏感的是box_loss。YOLOv8默认使用CIoU损失它在IoU基础上加入了中心点距离和宽高比惩罚。对于螺旋这样细长的目标CIoU有一个已知问题预测框如果宽度和高度都偏大但中心点对准了宽高比惩罚不会太显著导致模型倾向于预测偏大的框。解决办法是引入α-CIoU变体你可以直接修改损失权重来缓解box: 7.5 # 默认是7.5 cls: 0.5 # 默认0.5类别相对好分可以降低 dfl: 1.5 # 默认1.5如果发现预测框普遍大于标签框把box权重提高到10左右同时检测bce的梯度。更直接的做法是改用YOLOv8的v8n-seg做实例分割虽然推理稍慢但分割掩码能输出更精确的笔迹区域尤其在螺旋圈与圈重叠时检测框可能把相邻圈合并而掩码不会。4.3 类别不平衡的快速处理帕金森患者的螺旋往往笔画更密分割出的子目标数量更多而健康人螺旋更松散子目标数量少。这会导致患者类别样本多、健康类别少的不平衡。标签统计一跑便知python -c from pathlib import Path for f in Path(parkinson_dataset/labels/train).glob(*.txt): for line in f.read_text().strip().split(\n): if line: counts[int(line.split()[0])] 1 若患者类数量高于健康类1.5倍以上考虑两种修正一是复制健康类样本做简单过采样注意复制时要配合随机增强否则模型只是死记硬背二是用focal_loss替换普通BCE。Ultralytics目前支持在配置文件中设置focalTrue其γ参数默认1.5能显著降低易分类样本的损失权重把小部分难识别健康螺旋拉回注意力。此外YOLOv8的Head层有三个检测尺度P380x80、P440x40、P520x20。手绘细线的宽度较小大部分目标应该由P3层负责。如果训练时发现大量小目标被P5层误捡检查anchors相关参数或者干脆把输入分辨率提高到800让笔迹获得更多像素。不建议直接改成模型结构增加P2层因为会增加约2倍计算量且样本量不足时收益甚微。5. 验证与部署让模型真正走进临床辅助筛查5.1 用混淆矩阵定位误判族训练完成后YOLO会输出混淆矩阵图。不要只盯着总体准确率重点看真实类别spiral_pd被预测成了什么。如果它被误判为spiral_healthy说明模型没有学到震颤导致的笔迹特征如果被误判成wave_pd说明图形识别与状态识别两者耦合度太高。缓解手段是调整类别权重或在标注时将螺旋和波浪分别视为独立任务训练两个单类别模型推理时两者投票。随机抽100张验证集图片手动比对检测框与标注框的差异。注意帕金森患者画线常在中途停顿产生小点状的笔触这些点如果被标注为独立目标会导致模型输出大量小框。一个实用的验证脚本from ultralytics import YOLO model YOLO(best.pt) results model.predict(sourceval_images/, conf0.25, iou0.5, save_txtTrue) for r in results: boxes r.boxes if boxes is None: continue xyxy boxes.xyxy.cpu().numpy() area (xyxy[:,2]-xyxy[:,0]) * (xyxy[:,3]-xyxy[:,1]) # 剔除面积小于20x20的碎片框 keep area 400 print(f{r.path}: 检测到{keep.sum()}个有效目标丢弃{len(area)-keep.sum()}个碎片)conf0.25是推理时的置信度阈值医疗场景建议提高到0.4尽量减少假阳性。而iou0.5是NMS时的IoU阈值两个目标重叠超过0.5会被合并因为螺旋圈可能被分割成两个框重叠度较高时较低的IOU会导致多个框都保留但重复检测会干扰后续统计。5.2 从权重到部署导出ONNX与TensorRT验证满意后用一行命令导出yolo export modelbest.pt formatonnx dynamicTrue如果你的部署环境是AMD显卡或者没有NVIDIA CUDA优先用ONNX Runtime它能在AMD的ROCm上运行。dynamicTrue允许动态输入尺寸这样在不重新转换模型的情况下接受任意分辨率图像。若使用NVIDIA Jetson系列边缘设备进一步导出TensorRTtrtexec --onnxbest.onnx --saveEnginebest.engine --fp16 --minShapesinput:1x3x640x640 \ --optShapesinput:4x3x640x640 --maxShapesinput:16x3x640x640fp16精度在医疗场景可能造成细微数值偏差但手绘检测的物体边缘清晰一般不会导致检测失败。若保守起见用--fp32。5.3 让检测结果更稳的小技巧WBF集成与平均框输出最后分享一个在这类数据集上常见有效的技巧不用NMS改用加权框融合Weighted Box FusionWBF。具体做法是对同一个受试者的多张手绘图分别预测两个模型比如yolov8n和yolov8s得到两个框列表然后取置信度加权平均。实现只有几十行代码但能有效减少锯齿形边界框带来的抖动def wbf_boxes(boxes_a, boxes_b, weights(0.5, 0.5)): # boxes_a, boxes_b: 两组检测框 [x1,y1,x2,y2,conf,cls] all_boxes [] for box in boxes_a: all_boxes.append((box, weights[0])) for box in boxes_b: all_boxes.append((box, weights[1])) # 按类别分组后对高IoU的框求坐标的置信度加权均值 # 这里省略完整实现实际推荐使用ensembbox库 return fused_boxesWBF比简单的NMS对抖动更鲁棒因为NMS是选一个丢其他在螺旋圈边界模糊时容易选到偏移大的框加权融合则综合多个框的位置得到更接近标注的边界。若临床应用要求输出螺旋的直径或颤动幅度等量化指标用融合后的框去做投影会比单模型框稳定得多。框架落到代码层面后别忘了最终验证一遍从原始手绘扫描图到预处理、推理、WBF融合的完整管线用标注工具重新画一遍框对比自动框与人工框的IoU。当IoU稳定在0.85以上时这套基于YOLO的帕金森手绘筛查工具就具备可靠的辅助决策能力了。本文还有配套的精品资源点击获取