基于深度学习与YOLO的舌苔识别检测系统设计与实现

发布时间:2026/9/28 1:47:20
基于深度学习与YOLO的舌苔识别检测系统设计与实现 简介一套基于深度学习的舌苔识别检测鉴定系统毕业设计项目面向计算机相关专业学生和需要Python实战练习的开发者覆盖舌苔图像识别、检测与鉴定场景可直接用于毕业设计、课程设计或期末大作业。项目经导师指导并获认可评审分高达99分代码完整、运行可靠基础薄弱的学习者也能按文档上手运行。整套资料共109个文件压缩包大小105.44MB核心包括Python源码.py、PyQt5界面文件.ui、预训练模型权重.pth、TensorFlow训练日志events以及图片样本、JSON配置、论文文档.docx等结构清晰便于对照源码理解模型训练与推理流程也可直接加载权重进行识别演示。PyQt5图形界面让操作直观适合答辩展示论文文档可配合撰写设计报告节省整理时间。目前已有150人浏览学习是完成课程项目或毕业设计的实用参考。1. 基于深度学习的舌苔识别检测鉴定系统不是做一个分类器而是做一套能交给医生用的工具看舌苔这事中医讲究望诊但不同医生看同一张舌像结论不一致的情况很常见。基于深度学习的舌苔识别检测鉴定系统要解决的不只是“这张图属于什么苔”而是先把舌体从背景里框出来再对舌苔的颜色、厚薄给出检测结果和置信度最后用PyQt5把这些逻辑封装成桌面软件。这套东西适合两类人一个是准备做毕业设计又不想只交一个demo的学生另一个是想在诊所里做舌苔辅助判读工具的一线工程师。它不算前沿但把数据集、训练、界面串起来比单纯跑通一个模型有说服力得多。2. 数据准备是这系统最耗时的部分从手机图到YOLO标签2.1 为什么选目标检测而不是图像分类来识别舌苔常见误区是直接用图像分类输入一张舌图输出“白苔/黄苔”。但舌苔检测的实际情况是舌体在图片里占比因人而异背景里有嘴唇、牙齿、皮肤甚至还有手机水印。分类模型把整张图一起处理背景干扰直接进特征训练集一旦不干净模型就学会看背景而不是看舌苔。目标检测模型先给出舌体位置的边界框再在框内判断舌苔属性这个顺序符合医生看诊的逻辑。我一般用YOLO系做检测原因是舌体不是小目标它占据画面中心区域YOLO对中大型目标的检测稳定且推理快。Faster R-CNN精度更高但训练慢SSD轻量但小目标差对舌苔这种“目标大、类别差异在纹理和颜色”的问题YOLO性价比最高。你如果论文里要体现深度学习算法的对比可以把Faster R-CNN当作对照组但主力用YOLO跑通成本低答辩时的实时性数据也好看。2.2 自建舌苔数据集拍摄规范、类别定义和labelme标注舌苔没有公开的ImageNet式数据集常见做法是自建。收集阶段注意三点光源尽量接近自然光不要开美颜拍舌头时让患者自然伸舌舌尖不要卷每张图至少包含完整舌体。保存成.jpg按类别分文件夹。类别不是越多越好我建议控制在5类以内比如正常薄白苔、白厚苔、黄薄苔、黄厚苔、剥苔。如果做毕业论文5类足以说明问题超过8类会让标注成本翻倍最后还容易出现类别混淆。标注工具用labelme。安装时有个老坑labelme依赖PyQt5如果你先装了PyQt5再执行pip install labelmepip会按依赖关系重新装PyQt5可能导致版本被改掉。我现在的做法是用独立的conda环境专门做标注conda create -n labelme_env python3.8 -y conda activate labelme_env pip install labelme labelme注意如果你的Python环境是3.10以上PyQt5安装可能报错建议直接用3.8或3.9省得浪费时间。labelme打开后按P键画多边形画完选类别保存json。用矩形还是多边形我建议用矩形虽然粗糙一点但舌体是整体区域边界不需要像素级矩形标注速度是多边形的一半对检测模型足够。如果只标注舌苔区域而不标注舌体模型就不知道“没舌苔的正常舌体”长什么样所以舌体本身也要单独建一个类别。2.3 把labelme的JSON转成YOLO格式转换脚本与四个边界坑YOLO训练需要txt文件内容是每一行的“类别 中心点x 中心点y 宽 高”坐标都是相对于图片宽高的0到1值。下面这段脚本把labelme的json批量转成YOLO标签import json import os import cv2 from glob import glob # 舌苔类别顺序训练时的yaml文件要和这里保持一致 CLASS_NAMES [tongue, normal_thin, white_thick, yellow_thin, yellow_thick] def convert(json_path, out_dir): with open(json_path, r, encodingutf-8) as f: data json.load(f) image_path data[imagePath] # 关键点labelme的json里可能没有imageWidth/imageHeight字段 img cv2.imread(os.path.join(os.path.dirname(json_path), image_path)) if img is None: print(读取原图失败请检查路径, json_path) return img_h, img_w img.shape[:2] lines [] for shape in data[shapes]: if shape[shape_type] ! rectangle: continue label shape[label] if label not in CLASS_NAMES: continue class_id CLASS_NAMES.index(label) p1, p2 shape[points] x1, y1 p1 x2, y2 p2 x_min, x_max min(x1, x2), max(x1, x2) y_min, y_max min(y1, y2), max(y1, y2) if x_max x_min or y_max y_min: continue x_center ((x_min x_max) / 2.0) / img_w y_center ((y_min y_max) / 2.0) / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_name os.path.basename(json_path).replace(.json, .txt) with open(os.path.join(out_dir, out_name), w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: os.makedirs(labels, exist_okTrue) for json_file in glob(os.path.join(annotations, *.json)): convert(json_file, labels) print(转换完成, json_file)逻辑说明脚本读取json的shapes只处理rectangle类型因为我们要的是矩形框。类别名称和训练用的yaml必须一一对应否则类别错位。中心点坐标用了浮点数六位精度足够了。四个边界坑labelme高版本json里没有图片尺寸必须用opencv读原图用json里的imageWidth/imageHeight在旧版本可以新版本一用就崩。图片路径不要在训练集里带中文yaml里train路径带中文会导致opencv读图失败玄学报错。标注时不要把框贴死在舌体边缘留3%到5%的边距模型能学到边界上下文检测更稳。类别合集里一定要加“tongue”这个舌体类不然正常舌体没标签训练时被当成负样本最后白苔黄苔全漏检。转换完成后按8:1:1划分训练集验证集测试集把对应的图片和txt文件分别放到train、val、test目录。划分脚本很简单但记得用随机种子固定不然每次跑结果不同论文实验就没法复现。3. 模型训练与调参让YOLO在舌苔数据上收敛的完整流程3.1 网络权重和backbone选型舌苔图像有很强的医学影像特征没有预训练权重很难从零收敛。常见做法是下载COCO预训练权重比如yolov5s.pt然后用舌苔数据微调。yolov5s参数量小推理速度快适合毕设系统和医生桌面端如果你显卡显存比较大可以换yolov5mmAP能高1到2个点但界面帧率会降。halcon里也有深度学习目标检测它的优点是有图形化训练工具但Halcon的许可证和导出部署不适合与PyQt5界面集成所以从工程角度还是用Python生态更顺。深度学习环境配置是另一个隐形时间杀手。需要用到的包有torch、opencv、numpy、pyqt5、labelme直接pip install到系统Python很容易把依赖搞乱。我一般这样建训练环境conda create -n tongue python3.9 -y conda activate tongue pip install torch torchvision pip install opencv-python numpy pip install PyQt55.15,5.16这里有一个值得说的细节PyQt5固定到5.15系列是因为6.x在部分屏幕缩放适配和旧代码兼容上有问题。torch安装时注意选择匹配你CUDA版本的轮子没有GPU就装CPU版虽然训练慢但先把流程跑通后面再换GPU机器。3.2 最小可跑通的训练命令拿到yolov5源码包后在项目目录里建一个data/tongue.yaml内容如下train: ./data/tongue/train/images val: ./data/tongue/val/images nc: 5 names: [tongue, normal_thin, white_thick, yellow_thin, yellow_thick]然后执行训练命令python train.py --data data/tongue.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0参数说明--img 640是YOLO默认输入尺寸舌体占画面主体不需要按小目标调到1280否则显存翻倍但收益不大。--batch大小取决于显存6G显存用16可能OOM调成8就好。--epochs 100算基础值一般到第60个epoch后Loss趋于稳定如果还在下降就加到150早停机制会帮你判断。--device 0指第一块GPU没有GPU就写cpu但训练时间会很久。训练过程的输出会显示mAP0.5、mAP0.5:0.95、precision、recall等指标。注意mAP0.5达到90%以上不难但mAP0.5:0.95才是对比实验的重要指标。如果mAP0.5:0.95偏低问题多半不是模型而是标签的边界框不够精准或者类别定义有歧义。这时候回头查标注别急着换模型。3.3 三个必须调的参数置信度阈值、IoU阈值和增强策略训练完成后真正影响界面体验的是推理时的置信度阈值和IoU阈值。跑一条推理命令python detect.py --weights runs/train/exp/weights/best.pt \ --source test.jpg \ --conf 0.30 \ --iou 0.45 \ --save-txt --save-conf--conf控制显示哪些框。舌苔检测中如果置信度阈值设到0.5漏检会变多我一般设0.3。因为舌苔类别之间视觉差异很近白厚苔和白薄苔的边界是连续的网络天然会给出0.3到0.6的分数一刀切太高就漏了。--iou是NMS的IOU阈值0.45偏严格0.6会把重叠框合并得更干净。舌体通常只有一个主框NMS不至于敏感。增强策略在训练端控制yolov5的hyp.yaml。舌苔是颜色敏感的任务默认的HSV增强会把白苔调成黄苔导致模型学错特征。我会把hyp.yaml里的hsv_s和hsv_v从默认值调低一半比如hsv_s从0.7调成0.2或者直接设为0。同时保持fliplr水平翻转因为舌苔不存在左右不对称的问题。随机平移和缩放可以保留模拟拍摄角度变化。如果你用yolov8那yaml配置变成你训练代码里的参数方法类似。yolov8比v5好的一点是内置了更多数据增强但对舌苔这种颜色敏感数据同样需要降低增强强度否则黄苔白苔照样混。4. 舌苔识别系统常见问题排查模型、环境和界面的翻车记录4.1 mAP一直不涨Loss也不再下降但结果全是背景框现象训练曲线看起来正常验证集mAP却很低检测出来的框全都框在非舌体区域。原因最常见的不是模型问题而是标签只标注了舌苔区域没有标注“正常舌体”导致模型把没有舌苔的正常舌体当作背景去学习。第二个常见原因是标注rect框只有两个点但转换脚本里用了shape_type ! rectangle过滤有些labelme版本把矩形存成polygon四个点被直接跳过标签数量严重不足。解决先把tongue这一类包含所有舌体矩形再在这个框基础上去做苔质区分。如果一个舌体同时有白苔和黄苔比如舌尖黄苔舌根白苔那就用两个框重叠标注模型允许同一位置有不同类别的框。然后检查标签数量用下面命令看每个类别有多少样本for f in labels/*.txt; do cut -d -f1 $f; done | sort | uniq -c如果某一类的数量为0说明转换脚本或标注过程漏了回到数据准备章节修别急着继续训练。4.2 PyQt5装不上或labelme安装后PyQt5版本被覆盖现象conda环境里明明有PyQt5却import报错labelme装完之后Qt界面样式变了甚至界面代码运行崩。原因PyQt5和labelme都依赖Qt组件但两者对Qt版本的锁定不同。pip解释器在安装依赖时会自动向上兼容把PyQt5升级到最新版而最新版可能与你的界面代码不兼容。解决我的做法是建两个虚拟环境一个专门标注用一个做界面开发。标注环境只装labelme界面环境固定PyQt5到5.15系列conda create -n app python3.9 -y conda activate app pip install PyQt55.15,5.16 python -c from PyQt5.QtWidgets import QApplication; print(ok)如果你已经用了一个环境想同时保留labelme和你的界面代码安装labelme时加--no-deps再手动补它依赖的qtpy和opencv但这样麻烦不如拆环境干净。还有一个Windows上的坑是Qt的缩放和高DPI策略界面模糊时在代码开头加import os os.environ[QT_ENABLE_HIGHDPI_SCALING] 1这行要放在import QApplication之前否则不生效。4.3 检测框抖动同一张图每次结果不一样现象同样的图片重复运行detect.py框的位置和类别忽高忽低偶尔还会多出一个小框。原因最常见的是你用的权重是last.pt而不是best.ptlast.pt是最后一轮权重可能还没收敛到最优。另外推理时如果开了cudnn.benchmark且batch大小不固定也会产生非确定性抖动。解决训练完明确指定best.pt。推理时把batch设为1所有输入保持原尺寸。如果还抖动在代码里显式关闭cudnn benchmarkimport torch torch.backends.cudnn.benchmark False这样可以保证同一张图每次输出一致这在论文复现实验里很重要。4.4 舌苔颜色被增强搞乱黄苔被识别成白苔现象训练集里黄苔clear验证集却大量误判成白苔单独测试几张又没问题整体mAP低。原因数据增强里的HSV扰动过大。YOLO默认hyp.yaml里hsv_h、hsv_s、hsv_v分别对色相、饱和度和明度做随机调整白苔在饱和度和明度上和黄苔接近扰动后网络学到的不是“舌苔本体颜色”而是“颜色变化范围”直接把两类糊在一起。解决训练前把增强参数降到接近零。我用的是hsv_h: 0.01hsv_s: 0.1hsv_v: 0.2或干脆全为0效果立竿见影。另一个提升颜色的手段是在界面端做白平衡预处理推理前用cv2.xphoto或简单灰度世界算法先校色。这个对拍摄端的光源差异有效但不要在训练时对每张图都校色否则模型会依赖校色过程。5. 用PyQt5把模型封装成桌面诊断系统一种最小实现和验证方法把训练好的模型接到PyQt5界面里核心思路是“界面只负责显示推理放到后台线程”。因为YOLO推理虽然快但加载模型和初始化会卡住窗口操作起来像死机。下面是一个可跑通的最小骨架import sys import cv2 import torch from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget, QFileDialog from PyQt5.QtGui import QImage, QPixmap class TongueApp(QWidget): def __init__(self): super().__init__() self.model torch.hub.load(local/yolov5, custom, pathbest.pt, sourcelocal) self.model.conf 0.3 self.model.iou 0.45 self.label QLabel(选择舌像图片) self.btn QPushButton(打开图片) self.btn.clicked.connect(self.open_image) layout QVBoxLayout(self) layout.addWidget(self.label) layout.addWidget(self.btn) def open_image(self): path, _ QFileDialog.getOpenFileName(self, 选择图片, , Image Files (*.jpg *.png)) if path: img cv2.imread(path) results self.model(img) frame results.render()[0] h, w, ch frame.shape qimg QImage(frame.data, w, h, ch * w, QImage.Format_BGR888).copy() self.label.setPixmap(QPixmap.fromImage(qimg).scaled(400, 400)) if __name__ __main__: app QApplication(sys.argv) win TongueApp() win.show() sys.exit(app.exec_())逻辑说明torch.hub.load用本地yolov5目录加载自定义权重避免每次联网。results.render()返回绘制了检测框的BGR图转换为QImage显示。真正做产品还需要把框坐标、类别、置信度存到数据库或导出CSV这样毕业论文的“系统实现”章节才有东西写。验证方法取50张训练时没见过的测试图人工画框同时记录苔质类别。统计三点检测框IoU大于0.5视为正确苔质类别预测准确率单张推理耗时。把这些做成表格就是论文的实验与验证章节。如果你还觉得不够可以加一个“不同光照下识别稳定性”的对比分别用晴天窗边光和室内暖光灯拍摄十组看准确率差异。我做这类项目最深的教训是模型训练占据的时间其实只占三分之一数据标注和界面接入占大头别因为训练提前结束就以为项目完事了。希望帮到你。本文还有配套的精品资源点击获取