简介:这份舌苔数据集面向中医图像识别与深度学习研究者,聚焦中医舌诊中舌苔颜色、质地、厚度等特征的自动分类与标注,高分辨率原图能较好保留舌苔纹理细节。压缩包内含 2000 个 JSON 标注文件,并配有相应 512×512 像素原图,整包约 206MB;数据涵盖黑苔、地图舌、白厚腻苔、紫苔、红厚腻苔、红舌黄腻苔等多种典型证型,可直接用于训练 CNN 实现分类、分割或目标检测,也可为分割模型提供像素级监督信息。JSON 中保存了区域标注与类别信息,文件名也能直观区分不同舌苔类型,便于使用 Python、PyTorch 或 TensorFlow 进行数据预处理、数据增强与模型迭代调优。目前已有 2453 人学习下载,对希望将中医舌诊数字化、构建辅助诊断模型的开发者而言,这是一份标注规范、类别清晰、可直接上手实践的高质量基础数据集。 最近把手头这套舌苔图像数据集完整整理了一遍,两千多张样本图,全部统一成512x512分辨率,原图配上labelme标注好的JSON标签一起存放。这套东西的定位很明确:给中医舌诊客观化、计算机视觉辅助诊断这类方向做训练数据。整理过程中踩了不少坑,从标注规范到格式转换都走了一遍完整流程,正好有朋友问起数据集细节,就把整个构建思路、操作路径和复用方案系统写出来,方便准备做类似医学图像数据集的人直接参考。
这套数据适合两类人:一是想用深度学习做舌象分割、舌诊辅助判断的CV开发者,二是需要把raw图像整理成可训练数据集的初学者,尤其是对labelme标注、JSON转mask、模型输入规范这些链路不熟的朋友。数据本身包含舌体区域的多边形标注,可以直接拿来训练语义分割模型,也可以在此基础上扩展成分类或检测任务。
1. 为什么要整理这套舌苔数据集
1.1 舌诊客观化的直接需求
中医舌诊讲究“望舌质、察舌苔”,但传统方式依赖医生肉眼观察,结果描述主观性强,不同医生之间对同一舌象的判断常常有偏差。这个问题在临床带教、远程问诊、健康管理场景下尤其明显。让深度学习模型自动完成舌体分割、舌苔区域提取、舌色苔色识别,就成了一个非常接地气的落地方向。
可是真做起来才发现,公开渠道几乎没有像样的舌苔分割数据集。医疗数据本身涉及隐私,采集门槛高,很多实验室的数据又不公开,直接导致想训练一个分割模型都找不到合适的训练语料。所以自己构建一套包含原始图像和像素级标签的舌苔数据集,是绕不开的基础工作。
1.2 两千多张图够不够用,为什么定512x512
医学图像数据集的规模普遍偏小,这是行业常态。两千多张图对于语义分割任务来说属于“起步可用”的规模,如果只做二分类(区分有没有某种舌象特征)或者基础分割,配合数据增强和后处理,完全可以把模型训练到能用的程度。
分辨率选了512x512,不是拍脑袋定的。舌苔图像的特点是纹理细节重要,但整体结构并不复杂,不需要像自然图像那样动辄上千的分辨率。512x512在保留舌面纹理细节、舌苔薄厚变化这些关键信息的同时,显存开销可控。拿一张NVIDIA GTX 1080Ti或RTX 3060级别的显卡来说,batch size设到8左右跑一个U-Net基本没有压力。如果直接用原始相机照片训练,分辨率跨度太大,还要处理统一尺寸的问题,反而多一层麻烦。
1.3 labelme标签为什么值得用
labelme是语义分割标注里最常用的工具之一,它生成的是JSON格式的矢量标注文件,里面记录的是多边形关键点坐标,而不是直接输出mask图。这个设计有它的好处:多边形可以反复编辑,修改某个点不影响整张图;标签信息里可以附加额外的属性字段;后续想转换成mask、COCO格式还是YOLO格式都很方便。
很多人在标注工具选型上纠结过labelme和labelimg。简单说,labelimg适合画矩形框做目标检测,labelme适合画多边形做像素级分割。舌苔区域本身形状不规则,舌体边缘、舌苔覆盖区域都不是标准矩形,直接画框会引入大量背景噪声,所以多边形标注是必然选择。
2. 数据集结构与标注规范
2.1 目录结构设计
数据集整体存放结构如下,这个结构也是我实际在用的,简单直观,方便写脚本批量处理。
tongue_dataset/ ├── images/ │ ├── 001.jpg │ ├── 002.jpg │ └── ... ├── labels/ │ ├── 001.json │ ├── 002.json │ └── ... ├── class_names.txt ├── train.txt ├── val.txt └── test.txtimages目录存放统一处理后的512x512原图,labels目录存放同名JSON文件,一一对应。train.txt、val.txt、test.txt记录划分好的样本名,训练时直接读这些列表文件即可,不用重复搬动图片文件。
有个细节值得提一下:文件命名统一用数字序号,不要用中文名,也不要带空格。之前在整理一批数据时,文件名里有中文和空格,训练时每次加载图片都要处理编码问题,数据管道的稳定性受影响,后来全部改成纯数字再没出过幺蛾子。
2.2 labelme标注的类别设计
舌苔数据集的标注类别设计要贴合中医诊断的维度。我实际用的类别主要包括以下几类:
- tongue_body:舌体区域,整个舌头的轮廓
- tongue_coating:舌苔覆盖区域
- crack:裂纹,舌面上的裂纹纹理
- tooth_mark:齿痕,舌体边缘的牙齿压痕
- ecchymosis:瘀斑,舌面上的瘀点瘀斑
其中舌体和舌苔是最核心的类别,裂纹、齿痕、瘀斑是扩展类别。如果你只是想跑通一个分割模型,建议第一版只标舌体和舌苔两个类别,把数据规模和质量做扎实再慢慢扩。
有一点要特别提醒:舌苔和舌体不是互斥关系。舌苔覆盖在舌体之上,两个类别在空间上是重叠的。如果按照严格的语义分割要求,每个像素只能有一个类别,那就需要定义优先级。我的做法是“舌质”指没有舌苔覆盖的舌体区域,“舌苔”指有舌苔覆盖的区域,在标注时先画舌体外轮廓,再画舌苔区域,生成mask时用舌体减去舌苔得到干净的舌质区域,这样能同时保留多层信息。
2.3 512x512图像的处理细节
原始采集到的图片不可能天然就是512x512,这块我统一走了一套预处理流程:
- 读取原始图像,先做白平衡校正,减少不同光源带来的色偏
- 按短边等比缩放,使短边达到512像素
- 中心裁剪到512x512
- 保存时统一用JPEG格式,质量参数设为95
采用缩放加中心裁剪而不是直接拉伸,是为了保持舌体比例不变。直接拉伸会把舌头压扁或拉长,舌形特征变形,模型学到的特征就有偏差。
关于图像通道,这套数据是标准的三通道RGB图像。为什么强调通道?因为有些医学图像是灰度图或特殊成像模态,而舌诊图像依赖颜色信息来判断舌色、苔色,必须保留RGB三通道。模型输入层也相应设置为3通道,常见的ResNet、U-Net结构默认就支持,完全兼容。
3. 从原始标注到可训练数据的关键步骤
3.1 标注质量检查
两千多张图标注完成后,逐张人工检查不现实,但也不能直接拿去训练。我用脚本做了几项自动化检查:
- 检查JSON文件能否正常解析,有没有损坏
- 检查多边形点数量,小于3个点的多边形直接标记为异常
- 检查标注框是否超出图像边界
- 检查是否存在空标注(只有图片没有标注内容)
实际操作时发现最常出现的问题就是多边形边界超出图像范围。用labelme标注时,如果图像比较大,缩放到屏幕外后很容易把点打到画布外面,生成的坐标超出图像尺寸。这类问题必须批量筛查出来,否则转mask时会出现索引越界。
3.2 JSON转mask的方法
labelme的JSON格式不能直接拿来训练分割模型,要转成单通道的mask图,每个像素值对应一个类别编号。核心转换逻辑如下:
import json import numpy as np import cv2 from labelme import utils def json_to_mask(json_path, img_size=(512, 512), class_names=None): with open(json_path, 'r', encoding='utf-8') as f: data = json.load(f) mask = np.zeros(img_size, dtype=np.uint8) for idx, shape in enumerate(data['shapes']): points = np.array(shape['points'], dtype=np.int32) label = shape['label'] class_id = class_names.index(label) if label in class_names else 0 cv2.fillPoly(mask, [points], class_id) return mask这段代码的核心是用cv2.fillPoly把多边形填充成掩码。注意labelme官方还提供了一个utils.shapes_to_label方法,内部逻辑差不多,但自己写一遍能更好理解数据流。
转换过程中一个容易忽略的坑:labelme JSON中记录的是多边形在原始图片上的坐标,如果你的原图在标注后做过resize,坐标也需要同步缩放。这套数据是先统一成512x512再做标注,所以坐标天然对应,省了一件事。
3.3 数据划分与增强
数据划分时要特别注意一个原则:同一个人的多张相似图片不能同时出现在训练集和验证集中。舌苔图像往往是一个人在不同时间采集的连续样本,亮度和舌象状态很接近,如果划分不干净,模型会“记住”特定人的特征,验证集指标虚高,泛化能力却很差。
我按大约7:2:1的比例划分训练集、验证集、测试集,同时保证同一人不同时间的样本划分在同一个集合内。
数据增强方面,舌苔图像有其特殊性。随机旋转、水平翻转、缩放这些常规操作没问题,但颜色类增强要非常克制。舌诊依赖颜色判断,如果过度调整亮度、对比度、色相,模型学到的是“增强后的舌头颜色”,而不是真实舌头颜色。我实际用的增强策略是:旋转范围±10度,亮度调整范围0.8到1.2,仅此而已,不做饱和度、色相的大幅扰动。
4. 基于这套数据集直接跑起来的模型训练路径
4.1 分割模型选型
有了JSON转换后的mask,最直接的任务就是语义分割。几个常见选择的适用场景不同:
- U-Net:经典医学分割网络,参数量适中,两三百张训练图就能正常收敛,是当之无愧的第一选择
- DeepLabV3+:分割精度更高,边界更平滑,但对训练数据量和调参水平要求更高
- nnUNet:自动化程度极高,自带数据预处理、网络配置和训练流程,但配置复杂,且默认流程在设计上更偏向CT、MRI这类医疗影像,直接跑舌苔图像需要适配
我的建议是先用U-Net跑通基线,验证数据质量,再逐步尝试更复杂的模型。
4.2 从分割到分类和检测的扩展
分割模型输出的mask其实还能二次利用。比如要做一个“舌苔厚度分级”的分类任务,可以先用分割模型把舌苔区域裁出来,再训练一个轻量分类模型。这样比直接让分类模型全图判断更准确,因为排除了背景干扰。
如果要做目标检测,可以把分割mask的外接矩形提取出来,转成YOLO需要的txt格式。不过舌体检测的直接价值有限,更推荐直接做分割。分割本身已经提供了比检测更丰富的信息,从这个角度来说,这套数据更偏语义分割场景。
4.3 训练参数参考
我把实际训练中效果比较稳定的参数组合列在这里,按这个配比起步不会出大问题。
| 参数项 | 参考值 | 备注 |
|---|---|---|
| 输入尺寸 | 512x512 | 与原图分辨率一致 |
| 损失函数 | DiceLoss + CrossEntropyLoss | 比例为7:3 |
| 优化器 | AdamW | 初始学习率1e-4 |
| 学习率策略 | CosineAnnealing | 最小学习率1e-6 |
| 训练轮数 | 100 | 配合早停策略 |
| Batch Size | 8 | 视显存大小调整 |
| 数据增强 | 旋转±10度、水平翻转、亮度微调 | 注意不要过度调色 |
评估指标主要看Dice系数和IoU。对于二分类舌头分割任务,Dice达到0.95以上比较理想;舌苔分割的难度稍高,Dice达到0.85以上已经可用。
5. 常见问题与排查技巧实录
5.1 labelme安装和使用高频问题
labelme的安装本身不算麻烦,但在不同环境下确实容易踩坑。早期版本依赖Python的某些包,版本冲突多,建议直接用conda创建独立环境,Python版本3.8到3.10之间都比较稳,然后执行安装:
conda create -n labelme python=3.9 conda activate labelme pip install labelme启动直接用labelme命令即可。如果遇到界面打不开,大多数情况是PyQt5相关依赖没装好,常规做法是重装依赖。
日常标注中几个高频操作的快捷键很实用,用好了效率能提一大截:
- w:开始画多边形
- Ctrl+Z:撤销上一个点
- Ctrl+S:保存当前标注
- D:切换到下一张图
- A:切换到上一张图
5.2 标注和训练环节的几个常见问题
我把整个流程里遇到典型问题整理成一张表,方便对应排查。
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| JSON文件打不开 | 标注时程序异常退出,文件不完整 | 重新标注,或手动修复JSON格式 |
| 生成的mask全黑 | 类别编号没对上 | 检查class_names顺序与标注名是否一致 |
| 训练时图片加载失败 | 文件名带中文或路径含特殊字符 | 统一改为数字文件名 |
| 验证集指标虚高 | 同源图片划分不干净 | 按采集对象分组划分 |
| 分割边缘毛刺多 | 多边形点太密但标注不精确 | 适当增加多边形点数,提高标注精度 |
| labelme标注时图片加载不出来 | 图片格式不受支持或文件损坏 | 统一转为JPG格式存放 |
5.3 一个特别容易被忽视的坑:JSON里的imagePath
labelme在保存JSON时,会在内部记录原始图片路径,即imagePath字段。如果你在标注后移动了图片文件或改了文件名,再用labelme打不开JSON,原因就在这里。
解决方案有两种:一是用文本编辑器打开JSON,手动更新imagePath为正确的文件名;二是写一个批量脚本,遍历所有JSON文件并修改这个字段。这块看似不起眼,但一旦你处理上百个文件就会非常费时间,建议从第一天就保持图片和JSON同名同目录。
另一个容易踩的坑是标注类别名用中文。倒不是完全不能用,但后续转mask、训练、可视化等环节,只要有一处编码没处理好就容易出问题。建议统一用拼音或英文做类别名,显示中文标签的需求可以放到后处理阶段实现。
最后补一句个人的实际心得
整理这套舌苔数据集前后花了几周时间,真正耗时的地方不是标注本身,而是反复检查和修正标准。如果当初在采集阶段就严格控制光源、固定拍摄距离、做好白平衡,后面很多图像增强和预处理的功夫都能省下来。数据质量永远是模型效果的天花板,这个体会在做任何医学图像项目时都适用。标注阶段多花的时间,最后都会以模型精度的形式给你回报。
本文还有配套的精品资源,点击获取