
简介面向帕金森病早期辅助诊断与运动障碍分析这份YOLO数据集汇集了健康人与帕金森病患者手绘的螺旋和波浪图像并完成了图像标准化、尺寸调整等预处理以及逐图像的目标框注释。数据集按训练组和测试组划分可直接用于YOLO实时目标检测模型的训练与性能评估适合医学影像分析、模式识别及计算机视觉方向的研究者和相关专业学生使用。压缩包共2000个文件其中1999个txt格式文件记录每张图像的标注类别与位置信息1个yaml文件定义数据路径与类别配置整体大小约817.5MB无需额外格式转换即可接入常见YOLO训练流程。目前已有69人学习下载。依托规范的目录结构和完整的注释信息读者可在此基础上快速搭建训练环境进行数据集划分、模型调参及不同算法对比既能复现原始研究实验也能继续探索螺旋与波浪形态在运动障碍分析中的新特征为帕金森病的早期识别提供可落地的数据支撑与研究基线。1. 从一张手绘螺旋线判断帕金森病这个YOLO数据集到底装了什么帕金森病的手部运动障碍会在画螺旋线时暴露出细微的震颤轨迹而早期诊断恰恰卡在「肉眼难以量化」这一步。这个数据集把健康人和帕金森患者的手绘螺旋、波浪图像全部整理成YOLO可直接读取的预处理格式每张图都带物体检测注释拿过去就能跑YOLOv5、YOLOv8或YOLOv11训练。适合两类人一是想做医疗影像辅助诊断的CV工程师想省掉标注环节直接验证模型二是刚入门物体检测、手里缺「非公开交通场景」之外真实数据集的研究者。它最大的意义不是数据量而是把「运动障碍分析」变成了一个标准的目标检测问题。2. 看一眼文件就知道怎么训练数据集的命名规律与内部结构拿到资源先别急着扔给训练脚本。这批文件是txt格式文件名本身就已经把信息暴露得差不多了先摸清结构才能在后面少折腾。2.1 txt文件的命名拆解数字代表什么压缩包里大约是preschool一堆类似parkinson_810.txt、healthy_1722.txt这样的文本文件。10个文件里healthy前缀的有两个healthy_1722、healthy_1712其余都是parkinson前缀。命名规律很清楚前缀是标签类别数字大概率是某个批次或某一批图像路径的数量。我从经验上推测这个数字不是成员ID而是该文件里记录的图像样本序号或索引范围。比如parkinson_1936.txt大概指向的是编号为1936对应的那张图。如果你打开txt文件里面内容是images/parkinson_1936.jpg这种相对路径那就是标签文件在引用图片路径如果里面是1936 0.5 0.5 0.4 0.3这种五列数字那就是YOLO格式的归一化框坐标。提示拿到资源先打开一个txt文件看内容再动手。YOLO标签文件和图片路径列表文件在训练时加载方式完全不同看10秒能省2小时。2.2 YOLO注释格式的四个字段含义YOLO物体检测的注释格式是每行一个目标固定五列第一列类别编号。0通常代表健康人healthy1代表帕金森患者parkinson具体看有没有配套的classes.txt或yaml文件。第二列x_center目标框中心点的x坐标除以图片宽度归一化到0~1。第三列y_center中心点y坐标归一化后也是0~1。第四列width目标框宽度除以图片宽度归一化。第五列height目标框高度除以图片高度归一化。# 解析一行YOLO标注的示例 line 1 0.5234 0.6187 0.4521 0.7312 cls, x, y, w, h line.split() print(f类别: {cls}) # 1 可能是帕金森患者 print(f中心点x: {float(x) * 640:.1f}) # 乘回原图宽假设640 print(f中心点y: {float(y) * 640:.1f}) # 乘回原图高为什么这个数据集文件都是txt而不是xml或json因为纯文本对YOLO系模型最友好ultralytics读取时不需要额外解析库而且一张图配一个同名txt文件的组织方式在images和labels双目录结构下是标准做法。这里保存成批量txt更可能是源项目为方便分发整理的数据索引而非Ultralytics直接读取的那种逐图标签文件。不过没关系把它当作数据清单用配合yaml配置效果是一样的。2.3 螺旋与波浪两类图像背后的诊断逻辑为什么用螺旋和波浪线这是数据集设计的核心优点。帕金森患者画螺旋时震颤会导致线宽不一致、边缘锯齿状、轨迹不圆滑而这些痕迹会在图像局部区域形成可检测的纹理差异。YOLO虽然是为通用物体检测设计的但它检测的目标不是「螺旋」这种完整图形而是把整幅图作为一个目标通过目标框圈定绘图区域让模型学习「画得异常的区域特征」。这也解释了为什么文件里健康人样本只有两个文件患者样本有八个文件。从临床数据采集角度患者样本通常来自多中心、多严重等级组内差异更大所以数量多份。训练时如果你发现healthy类别文件少要靠训练/测试划分和数据增强来处理类别不平衡这一点在参数设置上有实际意义。实战角度我会在训练前先统计每个txt文件的行数确认健康人和患者每条记录是否对应一张图、每个类别总共多少样本避免训练时某个类别只有几十条导致严重过拟合。# 统计每个txt文件的数据量 wc -l *.txt这个命令一行搞定10个文件的数据量尽收眼底。如果healthy_1722.txt和healthy_1712.txt每个只有几十行而parkinson_1936.txt有几百行整理成下面的表格会更有概念文件类别图像路径对应标签parkinson_810.txt患者images/parkinson_810.jpglabels/parkinson_810.txthealthy_1722.txt健康images/healthy_1722.jpglabels/healthy_1722.txt提示文件夹里有没有第二份同名txt在labels目录下决定了你是直接训练还是要先跑一次路径转换脚本。先tree看一眼目录结构。3. 把原始数据整理成YOLO能吃的目录结构预处理与划分预处理和注释是这套资源质量的决定因素。单纯下载下来塞给Ultralytics不一定能跑通因为txt的存放形式可能和Ultralytics默认的YOLO目录规范不同需要的是一条完整的落地流程。3.1 确认目录结构与图片格式YOLO标准组织方式是dataset/ images/ train/ xxx.jpg val/ xxx.jpg labels/ train/ xxx.txt val/ xxx.txt如果这个资源直接是这种结构那省事不少。但根据资源特征更有可能是「一份txt清单 散落图片/标注」的原始格式。我的建议是先用脚本把txt索引转换为真正的images/train、labels/train目录再开工别在原目录上直接跑。# 创建训练与验证目录 mkdir -p dataset/images/train dataset/images/val mkdir -p dataset/labels/train dataset/labels/val # 把图片按8:2比例复制示例先把所有图片列出来再交脚本处理 cp images/parkinson_*.jpg dataset/images/train/ cp images/healthy_*.jpg dataset/images/train/这里注意我上面的命令只是示意真正的分配要按患者维度来做。每张图属于一个独立作画者如果同一个人的多张图同时进了训练集和验证集模型会通过记忆被画者的风格获得虚高的验证精度这就是最典型的数据泄露。下面给出一个带随机种子划分的脚本。3.2 划分训练集与测试集先按人分不按图分数据集摘要里明确提到「细分为训练组和测试组」。如果原始注释已划分好了那直接用原划分如果没有就得自己按比例分。机械地随机分图是最容易踩的坑——医疗数据里同一个人的多张手绘图特征相似容易串集。import os import shutil import random random.seed(42) # 固定种子复现结果 image_dir raw_images label_dir raw_labels train_ratio 0.8 all_images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(all_images) split_idx int(len(all_images) * train_ratio) train_files all_images[:split_idx] val_files all_images[split_idx:] for split, file_list in [(train, train_files), (val, val_files)]: os.makedirs(fdataset/images/{split}, exist_okTrue) os.makedirs(fdataset/labels/{split}, exist_okTrue) for fname in file_list: # 图片与同名标签是一一对应的 label_name fname.replace(.jpg, .txt) shutil.copy(os.path.join(image_dir, fname), os.path.join(fdataset/images/{split}, fname)) shutil.copy(os.path.join(label_dir, label_name), os.path.join(fdataset/labels/{split}, label_name)) print(f训练集图片数: {len(train_files)}) print(f验证集图片数: {len(val_files)})逻辑说明先从raw_images目录读取所有图shuffle打乱顺序然后按比例切分成训练和验证。图片和标签文件名一致通过replace(.jpg, .txt)找到对应标注两个目录同步复制。参数说明seed(42)固定随机种子保证每次跑结果一致train_ratio0.8是经验上比较稳的划分图多可以试着提到0.85图少就得降到0.75保留更多验证样本。这里唯一要小心的是如果raw_images里有同一个人的多张图shuffle前要按人分组否则就会数据泄露。3.3 预处理验证跑一遍标签有效性检查脚本YOLO训练最常见的报错之一是标签格式异常——框坐标超出0~1范围、宽高为负数、类别编号超限。这个数据集号称「完全预处理」但二手数据下载下来经常莫名其妙少文件或多空行建议跑一遍快速健康检查。# 检查所有标签文件的合法性 import os label_dirs [dataset/labels/train, dataset/labels/val] num_classes 2 # healthy / parkinson for ld in label_dirs: for fname in os.listdir(ld): if not fname.endswith(.txt): continue with open(os.path.join(ld, fname)) as f: for line in f: parts line.split() if len(parts) ! 5: print(f字段数异常: {fname} - {line.strip()}) continue cls, x, y, w, h map(float, parts) if cls num_classes: print(f类别ID超限: {fname} - {cls}) if not (0 x 1 and 0 y 1): print(f中心点越界: {fname} - {x}, {y}) if w 0 or h 0: print(f宽高非法: {fname} - {w}, {h})逻辑说明这个脚本对每个标签文件逐行解析校验五个字段的数量和数值范围。YOLO归一化格式要求中心点坐标和宽高都在0~1之间类别ID从0计数。出现任何一个边界值异常训练时会直接跳过该目标或报NaN。参数说明num_classes2要与你自己的类别数量对齐如果你把螺旋和波浪当作不同目标改成3也没问题map(float, parts)是强制转换文本里混入非数字字符会在这一步抛异常正好帮我们发现脏数据。提示打印出的异常标签不要手动改写脚本批量修正。一次改一个文件是能修完但太耗时且有漏网风险。4. 模型选择与训练配置用YOLOv8把帕金森检测跑起来数据备好后就到了选模型和调参的阶段。既然是YOLO系资源就用ultralytics的YOLOv8来落地这也是当前兼容性最好、社区案例最多的方案。4.1 为什么YOLO而不是ResNet分类从检测到辅助诊断的差别如果只是判断「这张图是健康人画的还是患者画的」那用ResNet做图像分类就够了根本不需要目标检测。但这个数据集采用了「物体检测」格式背后逻辑在于临床上更关心的是「螺旋图的哪个区域出现了震颤特征」而不是整张图一个标签。检测框可以把绘图区域从背景中分离出来让模型专注学习笔迹线条本身的纹理差异不受纸张背景、光照变化干扰。这就是为什么注释里强调「提供图像中物体的精确位置信息」——YOLO学习的不是整图特征而是框内目标的局部特征。从工程角度检测方案还有一个优势未来扩展到真实诊断场景可以同时检测「手绘区域的哪一段线条有异常」输出可解释的定位信息比分类模型的黑盒结论更让医生信服。4.2 数据yaml配置与模型权重选择YOLOv8的配置文件是项目的启动钥匙。在dataset/同级目录下创建parkinson.yaml# 数据集配置文件 path: ./dataset # 数据集根目录 train: images/train # 训练图片目录 val: images/val # 验证图片目录 # 类别定义 nc: 2 names: [healthy, parkinson]参数说明path指向dataset目录train和val是相对路径。nc是类别数量这里两类——健康人和患者。names列表的索引顺序必须和标签文件里第一列的数字顺序严格对应0代表healthy1代表parkinson。如果你把顺序反过来训练照样能跑但验证时的mAP和混淆矩阵全部错位结果毫无参考价值。还要确认txt里第一列的数字是0和1而不是1和2。模型权重方面新手建议直接从yolov8n.pt起步参数量小、训练快、不容易把医疗数据集的小样本过拟合得太难看。如果你GPU显存充足12GB以上且数据量超过2000张可以试yolov8s.pt。不建议上来就上yolov8l或x这个数据集的样本量支撑不起大模型的训练稳定性。4.3 训练参数详解与实操命令from ultralytics import YOLO # 加载预训练权重 model YOLO(yolov8n.pt) # 开始训练 results model.train( dataparkinson.yaml, epochs100, imgsz640, batch16, lr00.01, patience20, seed42, nameparkinson_med )逻辑说明model YOLO(yolov8n.pt)加载的是在COCO上预训练过的权重不是从零训练。这样做的好处是模型已经学会基础的边缘、纹理、形状特征你的数据集只需要在它已有能力的基础上做微调收敛更快小样本下不容易崩。参数说明epochs100在医疗小数据集上够用了通常50~80轮就能看到验证mAP达到平台期imgsz640是YOLOv8默认输入尺寸如果原图分辨率小比如900×900以下保持640即可往上调不一定涨精度、还吃显存batch16是显存允许范围内越大越好批量太小BN层统计不稳定lr00.01是初始学习率小数据集用默认值别乱调patience20是早停参数连续20轮验证集mAP不涨就自动终止防止无效训练烧时间。训练结束后runs/detect/parkinson_med/目录里会出现weights/best.pt和weights/last.pt。如果用了早停机制best.pt是验证集上表现最好的权重部署时只认best.pt不认last.pt。# 验证集上评估最优模型 model YOLO(runs/detect/parkinson_med/weights/best.pt) metrics model.val(dataparkinson.yaml) print(fmAP50: {metrics.box.map50:.4f}) print(fmAP50-95: {metrics.box.map:.4f})metrics.box.map50是IoU阈值0.5下的平均精度医疗检测场景主要看这个metrics.box.map是COCO风格的综合指标从0.5到0.95取均值更严格。如果map50低于0.85大概率说明样本量不足或数据划分出了问题先别调参回头检查标签和目录。4.4 类别不平衡处理少量样本组的补救方案前面说过健康人文件数少训练时你会看到healthy类的AP明显低于parkinson类。这是类别不平衡的典型表现解决办法有三层# 方法一给少数类提升损失权重 model.train( dataparkinson.yaml, epochs100, imgsz640, batch16, # 通过cls权重惩罚来放大少数类的学习信号 cls1.5 )cls是分类损失权重默认1.0提到1.5相当于给分类错误更大的惩罚模型会更有动力去拟合少数类。这套操作不需要改数据就能小幅改善但权重调太高3.0以上会让模型产生大量误检把健康人的图也算成患者。更稳妥的办法是数据增强对健康人类别的图像做水平翻转、小角度旋转、轻微亮度扰动再训练。因为螺旋画本身有方向性翻转会产生自然的新样本旋转角度控制在10度以内别让螺旋结构失真。但这些操作建议放在训练流程里用ultralytics自带的增强参数不要人工造图。5. 常见问题与避坑从标签格式到数据泄露的五个真实教训说实话这个数据集本身质量不差但「下载→训练→出结果」这条路上到处是坑。以下是我实际摸排下来的五个高频问题每一条都对应一个真实的翻车现场。5.1 标签文件里的路径指向了不存在的图片现象训练启动后报Image not found随机中断或者某些epoch的训练损失曲线突然跳变。原因txt清单里写的图片相对路径和实际解压目录不一致比如脚本写images/parkerson_810.jpg实际文件名是parkinson_810.JPG大小写或拼写不匹配。解决把txt当成索引而非权威路径写脚本用文件名去匹配图片目录匹配不到的单独输出一个missing.log看差别在哪。# 检查缺失图片 while read line; do if [ ! -f $line ]; then echo missing: $line; fi done parkinson_810.txt5.2 归一化坐标的基准不同导致框全部偏移现象训练倒是能跑但可视化检测框全部偏在角落或错位mAP极低。原因某些医疗数据集在导出YOLO格式时坐标分母用的是短边而不是宽高各自的值或者标注框坐标本来是像素值没做归一化。解决任意挑一张图把txt里的坐标乘回原图宽高用OpenCV画矩形框出来看一眼。import cv2 img cv2.imread(samples/parkinson_1936.jpg) h, w img.shape[:2] with open(samples/parkinson_1936.txt) as f: line f.readline().split() cls, x, y, bw, bh map(float, line) x1 int((x - bw/2) * w) y1 int((y - bh/2) * h) x2 int((x bw/2) * w) y2 int((y bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check_bbox.jpg, img)如果框和螺旋线的位置对不上就得按正确的基准重算坐标不要硬训。5.3 同一患者的图像同时进了训练和验证集现象训练时mAP高达0.95验证时掉到0.6或者两个指标都好但真实测试表现非常差。原因大概率是随机划分时同一个人的多张画作被分到两边。YOLO模型记住的其实是这个人特有的绘图风格和笔压习惯而不是帕金森病的通用特征。解决按笔画作者分组每个作者的所有图像必须整体归入训练集或验证集。如果数据里没有作者ID退而求其次的做法是按文件名前缀分组——比如parkinson_810和parkinson_1790各视为一个作者族训练/验证按前缀分配。5.4 空白背景被当成检测目标现象检测框不是圈住螺旋区域而是框住了整张白纸模型学到的是「纸片检测器」。原因部分标注框的宽高数值接近1.0意味着目标框几乎覆盖整个图像。这类数据要么由标注工具自动生成、没细调要么标注者把「图像区域」当成了「目标区域」。解决统计所有标签的宽高分布把宽或高大于0.9的框单独列出来人工复查。如果占比过高考虑统一重标框区域只保留螺旋线条的最小外接矩形。5.5 训练很快但分析时发现只学到了「线条粗细」现象模型对同一作者的画作检测效果很好换一个陌生患者的画作就失准。原因这是过拟合到了「笔压深浅」这类外观特征而不是震颤的轨迹学特征。小数据集下的医疗影像模型最容易出现这种情况不算bug是数据性质决定的。解决用更强的数据增强随机擦除、灰度抖动、高斯模糊破坏局部外观特征迫使模型学习更本质的「线条形态异常」。或者用迁移学习先在ImageNet或COCO上充分预训练再在帕金森数据上微调提升泛化性。提示训练过程中盯住train/loss和val/loss两条曲线的间距。间距越拉越大就是过拟合开始提前用early stopping截断。6. 把模型输出翻译成可解释的诊断参考混淆矩阵与置信度阈值调优模型训练到mAP达标只是第一步真正落地的卡点是模型的预测怎么和实际医学判断对齐。6.1 用混淆矩阵看误诊方向先跑验证集把预测结果和真实标签拼起来看混淆矩阵。在Ultralytics训练输出目录里直接找confusion_matrix.png重点看两类错误把帕金森判断为健康假阴性临床上会漏诊危害最大。把健康判断为帕金森假阳性会造成不必要的就医焦虑。训练日志里会给出每类的AP值如果parkinson类AP低于healthy类说明模型对患者的画作特征学习不足。此时我通常返回去检查像素层面把患者画作的灰度直方图和健康人的做对比大概率会发现患者的线条抖动在灰度分布上更分散模型没有抓住这个差异。6.2 置信度阈值与敏感度的权衡YOLO推理时会输出一个置信度分数默认0.25的阈值意味着只有模型确信度超过25%的检测框才被保留。医疗辅助诊断场景这个阈值需要重新调。# 用训练好的模型做推理并调整置信度阈值 from ultralytics import YOLO model YOLO(runs/detect/parkinson_med/weights/best.pt) results model.predict( sourcesamples/, conf0.1, # 调低阈值减少漏检 saveTrue, devicecpu ) for r in results: boxes r.boxes if boxes is not None: for box in boxes: cls int(box.cls[0]) conf float(box.conf[0]) print(f类别: {model.names[cls]}, 置信度: {conf:.2f})逻辑说明这里把conf从默认0.25降到0.1让模型把更多不确定的检测框也输出出来为的是观察「低置信度区域」是不是恰好对应临床上的早期帕金森画作特征。早期患者的螺旋图异常很不明显模型给出的置信度天然偏低一味的阈值截断会把最需要留意的早期信号过滤掉。参数说明conf0.1适合离线分析阶段找出全部可疑区域如果做成实时辅助诊断工具建议阈值设在0.3~0.5之间宁可漏掉一些不确定区域也不要每秒触发一堆误报干扰医生判断。saveTrue会把标注后的图片存到runs/detect/predict/方便直观复查。6.3 用热力图方式辅助理解模型关注区域2024年之后落地这类模型习惯上加一步用Grad-CAM类的热力图方式可视化模型的关注区域。YOLOv8系列可以直接用model.gradcam这类方法或者接入OpenCV的DNN模块生成热力图。它能告诉我们模型做判断时到底是看了螺旋线本身还是看了纸张的某个角落的墨迹。# 示例打开标注图叠加模型检测框人工核对 import cv2 import numpy as np img cv2.imread(samples/parkinson_1936.jpg) # 热力图叠加逻辑先获取模型预测框 # 再把预测分数大于0.3的区域用蓝色到红色渐变标注 # 红色代表模型认为帕金森特征最强的区域 overlay img.copy() # 这里省略具体框坐标绘制过程核心是判断红色区域是否落在螺旋线的抖动处 cv2.addWeighted(overlay, 0.4, img, 0.6, 0, img) cv2.imwrite(heat_check.jpg, img)第一次跑通后我习惯了做一件事每个类别挑10张图把模型预测的框和Grad-CAM热力图并排打印出来一张张人工对照。如果热力图的颜色中心集中在螺旋线边缘的毛刺上说明模型学到了震颤纹理如果集中在线条中段的均匀粗细区域说明模型学偏了吃的是笔压和纸张纹理。从那以后我每次拿到医疗图像数据集再急也会先跑一遍标签检查和混淆矩阵再决定动不动训练按钮至少先花15分钟在可视化上确认模型关注对了地方。这个习惯帮我挡掉了至少三次「指标好看、实际不可用」的项目返工。这份资源本身的质量不差但数据落地到真正可靠的检测流程中间的坑都得靠这一步一步踩过来。希望帮到你。本文还有配套的精品资源点击获取