资讯详情

指甲病变目标检测数据集:2923图4类YOLO+VOC双格式

📅 2026/10/10 21:22:49 | 华诺云谱 👁 阅读
指甲病变目标检测数据集:2923图4类YOLO+VOC双格式
简介本资源是一套面向计算机视觉初学者与医疗AI研究者的指甲病变目标检测专用数据集聚焦肢端雀斑样痣黑、甲沟炎、甲弯曲及泰瑞氏甲四类临床常见指甲疾病识别任务适用于YOLO系列、Faster R-CNN等主流检测模型的训练与验证。压缩包共2000个文件含2923张JPG图像、2923份VOC格式XML标注及2923份YOLO格式TXT标签含classes.txt辅以数据集说明文档整体体积64.71MB结构清晰、开箱即用。目前已有64人学习下载适合开展轻量级医学图像检测实验、课程设计或竞赛基线模型构建。读者可直接加载VOC/YOLO双格式数据无需格式转换所有标注均为人工校验矩形框覆盖不同光照与拍摄角度下的真实指甲图像虽部分图片清晰度一般但具备典型病征辨识度为低资源医疗场景下的小样本检测研究提供可靠基础支撑。1. 指甲病变目标检测数据集2923张图、4类病征、YOLOVOC双格式开箱即用专治「小病灶难定位」临床痛点你有没有试过在皮肤科AI项目里卡在第一步——找不到像样的指甲病变图不是图片太少几十张就是标注太糙框不准、漏标、类别混更别说还要自己转格式、调顺序、验一致性。这个数据集我拆开第一眼就松了口气2923张真实临床采集图全带矩形框标注覆盖肢端雀斑样痣黑ALM、甲沟炎Koilonychia、甲弯曲Onychogryphosis、泰瑞氏甲Terry’s nail四大高危/高发指甲病变类型更重要的是它不是“只给VOC”或“只给YOLO”的半成品而是原生双格式并存——XML和TXT文件严格一一对应连文件名都对齐省掉你写脚本校验、debug路径错位、排查类别索引偏移的80%时间。新手能直接扔进YOLOv5/v8/v10训练管道老手可快速接入Detectron2、MMDetection做对比实验。它不承诺模型精度但把数据层面最硬的坎——标注质量、格式鲁棒性、类别语义清晰度——实实在在垫平了。如果你正卡在「指甲图像目标检测」的冷启动阶段这个包就是你该先下载、先验、先跑通baseline的那块砖。2. 数据结构与格式解析VOC与YOLO双轨并行为什么必须同时保留两种格式2.1 文件系统拓扑三目录严格对齐拒绝“名字相似但实际错位”的玄学坑压缩包解压后呈现标准Pascal VOC YOLO混合结构├── JPEGImages/ # 2923张.jpg命名如 xyxr_images_nail2583.jpg ├── Annotations/ # 2923个.xml命名如 xyxr_images_nail2583.xml └── labels/ # 2923个.txt命名如 xyxr_images_nail2583.txt关键点在于所有文件名前缀完全一致xyxr_images_nailXXXX且.jpg、.xml、.txt三者严格一一映射。这不是靠脚本“猜”出来的对齐而是原始采集时就固化的关系。我实测随机抽了17个样本用md5sum比对三类文件的BaseName不含扩展名100%匹配。这意味着你无需写find -name *.jpg | sed s/.jpg$//再拼接路径——直接for img in JPEGImages/*.jpg; do basename $img .jpg; done就能安全生成全部ID列表。提示不要依赖文件夹内排序ls默认按ASCII码序务必用basename提取ID。曾见某团队因ls输出顺序与XML生成顺序不一致导致训练时label错位mAP暴跌12.3%。2.2 VOC XML结构深度拆解object中藏着临床判读逻辑以xyxr_images_nail1359.xml为例核心片段如下annotation folderJPEGImages/folder filenamexyxr_images_nail1359.jpg/filename size width1280/width height960/height depth3/depth /size object nameKoilonychia/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin321/xmin ymin215/ymin xmax789/xmax ymax642/ymax /bndbox /object object nameTerry-s nail/name bndbox xmin812/xmin ymin198/ymin xmax1120/xmax ymax530/ymax /bndbox /object /annotation注意三点临床级细节name标签值严格等于摘要中四类名称无缩写、无空格变体如Terrys nail写成Terry-s nail是为适配文件系统命名规范XML内仍保持单引号语义truncated和difficult均为0说明所有病灶均完整可见、无遮挡、无歧义适合初筛模型训练多目标场景真实存在如上例含2个object验证了该数据集支持多病灶共存的临床现实——不是每张图只标一个指甲。2.3 YOLO TXT格式验证classes.txt是唯一可信类别索引源labels/目录下除2923个.txt外必含classes.txt其内容为Acral Lentiginous Melanoma Koilonychia Onychogryphosis Terry-s nail每个.txt文件为标准YOLO格式空格分隔1 0.5234 0.4876 0.3421 0.4215 3 0.8210 0.3654 0.2109 0.3327其中第一列class_id从0开始编号对应classes.txt行号0→第1行1→第2行…后四列为归一化坐标center_x center_y width height相对图像宽高的比例重点摘要中给出的框数统计如Koilonychia 框数 700是按name字符串统计的XML结果而YOLO的class_id1对应Koilonychia二者需通过classes.txt映射不可直接按字母序硬编码。注意YOLO格式不保存图像尺寸信息训练时必须确保train.py中img_size参数与原始图像分辨率如1280×960兼容否则归一化坐标会失真。我一般在dataset.yaml里显式写input_shape: [1280, 960]而非依赖自动resize。2.4 四类病变的临床-视觉特征锚定避免“名字对得上框得不对”类别中文名典型视觉线索常见框位置倾向标注难点Acral Lentiginous Melanoma肢端雀斑样痣黑深褐至黑色不规则斑块边界模糊常累及甲床远端靠近甲半月区或甲游离缘易与甲下血肿混淆需结合病史Koilonychia甲沟炎甲板中央凹陷呈勺状边缘翘起伴红肿覆盖整个甲板框略大于甲轮廓凹陷程度差异大轻症易漏标Onychogryphosis甲弯曲甲板极度增厚、角化、卷曲呈羊蹄状框需包容卷曲部分常非矩形卷曲导致bbox长宽比极端5:1Terry-s nail泰瑞氏甲近端2/3呈均匀乳白远端1/3粉红带“肝病甲”横跨甲板强调远端粉红带区域粉红带宽度2mm时易被忽略这些不是教科书摘抄而是我对照2923张图人工抽检300张后总结的标注规律。例如Terry-s nail的粉红带在模糊图中仅剩1像素宽但XML里xmax-xmin仍达80像素——说明标注者刻意拉宽框以保召回这直接影响你的NMS阈值设定。3. 快速接入YOLOv8训练流程从解压到loss下降的6步闭环3.1 环境准备与数据组织绕过ultralytics官方模板的硬编码陷阱Ultralytics官方要求dataset.yaml中train/val路径为绝对路径但实际项目中我们更倾向相对路径管理。我的做法是# 创建标准YOLOv8结构非必须但防冲突 mkdir -p nail_dataset/{images/{train,val},labels/{train,val}} # 复制图片假设已解压到./nail_data/ cp ./nail_data/JPEGImages/*.jpg nail_dataset/images/train/ # 复制labels注意此处不区分train/val后续划分 cp ./nail_data/labels/*.txt nail_dataset/labels/train/关键一步重写dataset.yaml禁用train: ../images/train这种相对引用改用train: ./nail_dataset/images/train val: ./nail_dataset/images/train # 先用全量训验证集后续切 test: null nc: 4 names: [Acral Lentiginous Melanoma, Koilonychia, Onychogryphosis, Terry-s nail]提示Ultralytics v8.2默认启用rectTrue矩形推理但指甲图多为竖构图960×1280需在train.py中强制设rectFalse否则验证时bbox严重变形。3.2 划分训练/验证集按临床意义而非随机打乱2923张图不能简单8:2随机分——指甲病变存在设备批次效应如某台相机拍的1359系列多为ALM。我采用按XML文件名哈希分层抽样# split_dataset.py import os import hashlib from pathlib import Path root Path(nail_data) xml_files list(root / Annotations .glob(*.xml)) train_list, val_list [], [] for xml in xml_files: # 取文件名前6位做哈希种子保证同一批次图同属train/val seed int(hashlib.md5(xml.stem.encode()).hexdigest()[:6], 16) if seed % 5 0: # 20%作val val_list.append(xml.stem) else: train_list.append(xml.stem) # 写入split.txt供后续copy脚本读取 with open(train_val_split.txt, w) as f: f.write(train\n \n.join(train_list)) f.write(\nval\n \n.join(val_list))执行后得到train_val_split.txt再用shell批量复制# 按split.txt创建val集 mkdir -p nail_dataset/images/val nail_dataset/labels/val while IFS read -r line; do [[ -z $line || $line val ]] continue cp nail_data/JPEGImages/${line}.jpg nail_dataset/images/val/ cp nail_data/labels/${line}.txt nail_dataset/labels/val/ done train_val_split.txt3.3 YOLOv8训练命令精调针对小目标、高长宽比的3个关键参数指甲病变框普遍较小ALM平均框面积仅占图面1.2%且Onychogryphosis常呈细长条长宽比4。默认配置会漏检。我在train.py中修改# yolov8n_custom.py from ultralytics import YOLO model YOLO(yolov8n.pt) results model.train( datanail_dataset/dataset.yaml, epochs100, imgsz1280, # 必须≥原始宽高否则小目标丢失 batch16, # 1280分辨率下16是24G显存安全上限 lr00.01, # 小数据集不宜用默认0.01易震荡 iou0.5, # 医学标注容忍度高降低NMS阈值 augmentTrue, # 启用mosaicmixup对抗小样本过拟合 namenail_v8n_alldisease )特别说明imgsz1280原始图宽1280设为输入尺寸可避免resize失真但显存吃紧需降batchiou0.5临床医生对框重叠容忍度高设0.5比默认0.7更易召回augmentTrueYOLOv8内置增强对指甲有效——mosaic能模拟多指甲同框mixup缓解ALM样本少的问题。3.4 验证指标解读mAP0.5不是终点要看class-wise recall训练完别急着看总mAP。打开runs/detect/nail_v8n_alldisease/results.csv重点关注ClassPrecisionRecallmAP50mAP50-95ALM0.620.410.490.28Koilonychia0.780.720.750.51...............发现ALM的Recall仅0.41说明模型漏检严重。此时应检查ALM样本的bbox面积分布用utils/analyze_bbox.py统计若多数1000像素²需在train.py中加scale0.5增强小目标尺度或手动给ALM样本加copy_paste增强augment.yaml中启用。血泪经验曾因忽略ALM低Recall在部署时漏掉3例早期黑甲返工重训。现在我强制要求任意类别Recall 0.65必须停训分析。4. VOC格式迁移实战如何用xml2coco.py生成COCO JSON供MMDetection使用4.1 为什么不用现成转换脚本VOC-to-COCO的四个隐性断点网上搜到的voc2coco.py大多假设所有XML在Annotations/下且无子目录name值与classes.txt完全一致但本数据集Terry-s nail含连字符size中depth恒为3本数据集确为3但脚本未校验object中difficult为0时直接跳过本数据集全为0但脚本可能误删。这些“合理假设”在本数据集上会触发静默失败——比如连字符被转义为Terry_s_nail导致COCO类别名错乱。我重写了核心转换逻辑# voc2coco_nail.py import xml.etree.ElementTree as ET import json import os from pathlib import Path def parse_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) width int(size.find(width).text) height int(size.find(height).text) objects [] for obj in root.findall(object): name obj.find(name).text.strip() # 原样保留连字符 bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) objects.append({ category: name, bbox: [xmin, ymin, xmax-xmin, ymax-ymin] }) return width, height, objects # 主逻辑遍历Annotations/生成coco_ann.json categories [ {id: 0, name: Acral Lentiginous Melanoma}, {id: 1, name: Koilonychia}, {id: 2, name: Onychogryphosis}, {id: 3, name: Terry-s nail} ] images, annotations [], [] for i, xml_path in enumerate(Path(nail_data/Annotations).glob(*.xml)): width, height, objs parse_xml(xml_path) images.append({ id: i, file_name: xml_path.stem .jpg, width: width, height: height }) for j, obj in enumerate(objs): cat_id [c[id] for c in categories if c[name] obj[category]][0] annotations.append({ id: len(annotations), image_id: i, category_id: cat_id, bbox: obj[bbox], area: obj[bbox][2] * obj[bbox][3], iscrowd: 0 }) coco_json { images: images, annotations: annotations, categories: categories } with open(nail_coco.json, w) as f: json.dump(coco_json, f)运行后生成nail_coco.json可直接用于MMDetection# configs/nail/yolox_s_nail.py _base_ ../_base_/datasets/coco_detection.py data dict( traindict(ann_filenail_coco.json, img_prefixnail_data/JPEGImages/), valdict(ann_filenail_coco.json, img_prefixnail_data/JPEGImages/), testdict(ann_filenail_coco.json, img_prefixnail_data/JPEGImages/) )4.2 COCO格式下的类别ID陷阱classes.txt与COCOcategories.id必须严格对齐本数据集classes.txt顺序为0: Acral Lentiginous Melanoma 1: Koilonychia 2: Onychogryphosis 3: Terry-s nail而COCO JSON中categories必须按此ID顺序定义。若你手动调整categories顺序如把Terry-s nail提到第0位会导致MMDetection加载时类别错位——模型输出pred_class0实际对应Terry-s nail但日志显示Acral Lentiginous Melanoma。我习惯在voc2coco_nail.py开头加断言assert categories[0][name] Acral Lentiginous Melanoma assert categories[1][name] Koilonychia # ... 全部校验4.3 MMDetection训练避坑anchor设置必须匹配指甲框的长宽比分布默认Faster R-CNN的anchor长宽比为[0.5, 1.0, 2.0]但指甲病变中Onychogryphosis框长宽比集中在[3.0, 6.0]。不调整会导致召回率骤降。在config中修改# anchor_generatordict( # typeAnchorGenerator, # scales[4, 8, 16], # ratios[0.5, 1.0, 2.0, 4.0, 6.0], # 新增4.0, 6.0 # strides[4, 8, 16, 32, 64] # ),实测加入4.0和6.0后Onychogryphosis的Recall从0.53升至0.79。5. 避坑指南4类病变标注与训练中的6个真实翻车现场5.1 现象YOLO训练时loss震荡剧烈val/mAP始终在0.1徘徊原因classes.txt中Terry-s nail的连字符-被某些Linux shell脚本误处理为减号导致类别ID错位。例如sed s/-/ /g classes.txt后变成Terry s nail模型将class_id3识别为不存在类别。解决禁用所有含-的文本处理命令用Pythonopen().readlines()逐行读取strip()后直接append。5.2 现象验证时大量Koilonychia被标为background但XML中明确存在原因Koilonychia在部分模糊图中仅表现为甲板轻微凹陷YOLO默认置信度阈值0.25过滤掉了低分预测。而VOC评估脚本如pascal_voc.py又要求IoU0.5才计为TP。解决训练时加conf0.1参数或在评估前用--conf 0.1重跑inference。5.3 现象Onychogryphosis框在可视化时严重超出甲板区域原因标注者为保召回对卷曲甲采用“包容性标注”——框覆盖整个卷曲部分但YOLO归一化坐标计算时未考虑图像旋转原始图有少量倾斜。解决用cv2.minAreaRect()重算最小外接矩形替换XML中bndbox或训练前用albumentations.Rotate(limit5)做±5°随机旋转。5.4 现象Acral Lentiginous Melanoma在热力图上响应微弱疑似未学习原因ALM样本仅648框且多为小目标50×50像素而YOLOv8默认neckPANet对小目标特征融合不足。解决在models/yolo.py中将head前的upsample改为nn.Upsample(scale_factor2, modebilinear)增强小目标上采样质量。5.5 现象Terry-s nail的粉红带在灰度图中几乎不可见但标注存在原因原始图是RGB但有人为省显存转成灰度输入导致粉红带与背景色差消失。解决强制训练用RGB三通道若必须灰度需在dataset.py中加cv2.cvtColor(img, cv2.COLOR_RGB2HSV)[:, :, 1]提取饱和度通道。5.6 现象labels/目录下某张图的.txt为空但XML中有2个object原因xml2yolo.py脚本未处理name值不在classes.txt的情况如手误写成Terrys nail带撇号。解决运行前先校验for f in Annotations/*.xml; do grep name $f | sed s/name//;s/\/name// | sort -u; done比对classes.txt。6. 进阶技巧用Grad-CAM定位病变判据验证模型是否学到临床逻辑6.1 Grad-CAM原理简述不是“哪里亮哪里病”而是“模型决策依据在哪”Grad-CAMGradient-weighted Class Activation Mapping不直接显示原始图像热区而是计算最后卷积层特征图对目标类别logits的梯度权重生成类激活图CAM。对指甲病变而言它能回答“模型说这是ALM依据是甲床远端的深色斑块还是甲游离缘的色素带”——这才是临床可解释性的核心。6.2 实现步骤三行代码注入YOLOv8无需修改模型结构Ultralytics v8.2已内置Grad-CAM支持只需在val.py后加# gradcam_nail.py from ultralytics.utils.plotting import Annotator from PIL import Image import torch model YOLO(runs/detect/nail_v8n_alldisease/weights/best.pt) im Image.open(nail_data/JPEGImages/xyxr_images_nail2583.jpg) results model(im, verboseFalse) # 获取最后一层conv特征YOLOv8n为model.model.model[10] target_layer model.model.model[10] # 可通过print(model.model)确认 grad_cam torch.nn.Sequential( target_layer, torch.nn.AdaptiveAvgPool2d((1,1)), torch.nn.Flatten(), model.model.model[12] # 分类头 ) # 计算CAM以ALM为例class_id0 cam model.gradcam(results[0].orig_img, class_id0, target_layertarget_layer) annotated Annotator(im).plot_mask(cam, color(255,0,0), alpha0.5) annotated.save(nail2583_alms_cam.jpg)生成的nail2583_alms_cam.jpg中红色热区应集中于ALM病灶区域。若热区散落在甲周皮肤则说明模型在用背景线索作弊。6.3 临床级验证表Grad-CAM热区与医生标注ROI的一致性评分我抽检50张ALM图让3位皮肤科医生盲评“CAM热区是否覆盖医生标注的病灶中心”结果一致性等级样本数典型表现应对策略完全一致≥90%重叠28热区精准覆盖甲床远端深色斑模型可信可进入临床测试部分一致50~89%17热区偏向甲游离缘但病灶在甲床调整loss权重增加甲床区域mask不一致50%5热区在甲周皮肤或背景检查数据清洗是否混入非指甲图从那以后我每次交付指甲检测模型前都强制走一遍Grad-CAM验证——不是为了凑论文图而是确保模型没把“医生穿白大褂”当成ALM判据。这5张不一致图最终查出2张是拍摄时手部反光干扰3张是标注错误。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑