ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

YOLOv5中药材显微图像识别:从标注到部署的完整实战指南

YOLOv5中药材显微图像识别:从标注到部署的完整实战指南 简介基于中药材显微图像识别的YOLOV5算法项目源码是一套面向毕业设计、期末大作业及课程设计的完整目标检测实现重点解决中药材显微图像中目标结构识别与标注分类的落地问题适合希望快速搭建深度学习视觉方案的本科生与开发者参考。压缩包共95个文件、约408KB涵盖38个Python脚本、22个YAML配置、17个TXT说明与7个XML标注文件等Python脚本覆盖图像切片与拼接、标注格式转换、类别合并、数据集划分、模型训练与推理检测等完整流程YAML用于设定模型结构与训练参数XML/TXT记录目标标注与类别信息整体模块清晰便于按需调用。目前已有208人学习浏览。代码保留详细注释关键函数和运行流程均有说明新手也能沿线理解下载后简单配置环境即可运行。这份导师认可的高分项目在答辩或课程展示中具备较强参考价值适合需要快速落地中药材显微图像识别方案的读者。1. 中药材显微图像识别为什么选YOLOv5生药显微鉴定的工作流落到图像处理上其实是个目标检测问题一份中药材粉末的视野里可能同时存在淀粉粒、石细胞、导管、纤维束、草酸钙结晶鉴定时要先“找见”这些显微特征再根据它们的有无、大小和排列方式作结论。人工镜检一份样品要二十到四十分钟而显微扫描仪几分钟就能产生一整张高分辨率大图这时候靠人眼逐根移动视野效率瓶颈反而在屏幕前。用YOLOv5来做这件事核心不是“深度学习能不能认出粉末”而是“怎么在几十万像素的大图上稳定框出几十微米的小目标”。这个选题能成为项目源码发布出来说明作者走的是通用目标检测路线而YOLOv5恰好是资料最全、最容易在本地训练出可用模型的一条路径。适合手里已经有一批显微图像、想快速建立识别模型的研究生或质检实验员。2. 显微图像数据集与YOLOv5标注格式的对接2.1 显微图像标注的三个特殊点中药材显微图像和自然场景图像最大的区别在于目标尺寸和密度。普通物体检测中目标可能占图像面积的1%到50%而一个淀粉粒在640像素的训练图上往往只有30到80像素属于典型的小目标。另一个问题是目标堆叠石细胞群、导管碎片经常粘在一起边界模糊。标注时如果只画水平框一个框里可能同时框住两三个目标YOLOv5在训练时只能学会“这里有一坨东西”学不会区分数量。经验上我会在标注前先看三张代表性大图统计目标的长宽范围确认是否需要切patch。常见做法是把4000×3000的原图切成512×512或640×640的小块重叠率设定在10%到15%然后只标注那些完整落在patch里的目标边缘被切掉一半的暂时不标。这样训练时模型不会因为反复出现半个目标而困惑。表显微图像目标尺寸与训练图尺寸的关系目标类型常见长边像素原图建议训练图尺寸是否需要切图淀粉粒2080640×640需要石细胞80200640×640视密度而定导管碎片150500768×768建议纤维束3001000768×768建议这里有一个容易忽略的点YOLOv5里的img参数一旦固定模型会做letterbox缩放把长宽不等的图补齐到正方形。如果你按原图宽高比标注训练时缩放后坐标是跟着归一化数值走的不会错真正会错的是标注时画框越过了图像边界导致归一化后出现大于1或小于0的坐标。所以标注工具里要打开“严格在图片范围内”选项。2.2 将LabelImg标注转为YOLO格式用LabelImg或Label Studio标注后常见输出是Pascal VOC的XML文件而YOLOv5训练需要每个图像对应一个同名TXT每行内容为class x_center y_center width height坐标全部是相对图像的归一化浮点数。显微图像里目标数量多手工改错概率很高我一般会用一段脚本转换并在转换时直接过滤掉那些面积过大或过小的疑似误标框。import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, class_names, out_dir): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls obj.find(name).text if cls not in class_names: continue box obj.find(bndbox) x_min float(box.find(xmin).text) y_min float(box.find(ymin).text) x_max float(box.find(xmax).text) y_max float(box.find(ymax).text) x_center (x_min x_max) / 2 / img_w y_center (y_min y_max) / 2 / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h # 过滤掉疑似标注错误的框宽或高小于图像边的0.5% if w 0.005 or h 0.005: continue lines.append(f{class_names.index(cls)} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_name Path(xml_path).stem .txt Path(out_dir).joinpath(out_name).write_text(\n.join(lines), encodingutf-8) # 用法将某目录下所有XML转成YOLO格式TXT # class_names必须与之后的data.yaml里names顺序一致 labels [starch_grain, stone_cell, vessel, fiber] for xml_file in Path(annotations).glob(*.xml): voc_to_yolo(xml_file, labels, labels)这段脚本做的事情是读取XML里size字段拿到原图宽高遍历每个object框算出中心点和宽高的归一化值写入TXT。第10行附近的面积过滤很重要——显微图像切patch后边缘常常残留一条只有1像素宽的线那通常是标注软件自动保存的无效框。class_names.index(cls)保证了类别ID和data.yaml里的顺序一致否则训练出来的类别会错位。2.3 数据集划分与显微场景数据增强YOLOv5仓库里自带split_train_val.py这类脚本但很多时候我们自己存的数据集目录就是train/和val/两个文件夹里面各放images和labels。我习惯用下面这个脚本按7:2:1划分训练、验证、测试集并保证同一份图像不会同时出现在两个集合避免数据泄漏。# 在yolov5项目根目录执行images下放jpglabels下放同名txt python - EOF import os, random from pathlib import Path img_dir Path(datasets/microscope/images/all) lbl_dir Path(datasets/microscope/labels/all) files [p.with_suffix() for p in img_dir.glob(*.jpg)] random.shuffle(files) n1 int(len(files) * 0.7) n2 int(len(files) * 0.9) splits {train: files[:n1], val: files[n1:n2], test: files[n2:]} for split, items in splits.items(): for f in items: # 移动图片与同名标签到对应split目录 img_src img_dir / (f.name .jpg) lbl_src lbl_dir / (f.name .txt) img_dst Path(fdatasets/microscope/images/{split}) / img_src.name lbl_dst Path(fdatasets/microscope/labels/{split}) / lbl_src.name img_dst.parent.mkdir(parentsTrue, exist_okTrue) lbl_dst.parent.mkdir(parentsTrue, exist_okTrue) img_src.rename(img_dst) lbl_src.rename(lbl_dst) # 这里应同时复制一份labels代码略 EOF这个脚本的原理是先把所有图像文件和对应的同名TXT统一放好打乱顺序后按比例切割。注意显微图像里如果存在“同一视野连续扫描的相邻图”它们内容高度相似随机划分很可能让训练集和验证集出现同源patch导致mAP虚高。对策是先把属于同一物理样品的patch编一个组按组划分——这一步在实际项目中比调模型参数更影响可信度。数据增强方面YOLOv5默认开启了HSV色域增强和随机平移缩放但显微图像里颜色特征是鉴定依据之一例如黄棕色分泌道、紫红色的细胞壁过强的色调变化会让模型学到错误的颜色关联。我通常在hyp.scratch-low.yaml里将hsv_h: 0.01、hsv_s: 0.4、hsv_v: 0.4调低同时把degrees: 0设为0因为中药材显微图像不存在旋转不变量——粉末制片里“方向”本身是特征如果用了90度旋转增强会把上下颠倒的导管纹孔学成颠倒模式反而降低识别精度。3. 搭建YOLOv5训练环境与配置药材显微数据参数3.1 环境安装CUDA、PyTorch与yolov5仓库这个标题带“项目源码”最常见做法是直接拉取YOLOv5官方仓库再把自己的数据和配置放进去。我建议用conda单独建一个虚拟环境Python版本选3.8或3.10都行PyTorch要根据显卡驱动装对应版本不要无脑装最新。安装好CUDA驱动后先用nvidia-smi看驱动支持的CUDA版本再决定pip install torch torchvision的版本组合。conda create -n yolo python3.10 -y conda activate yolo pip install torch2.1.2 torchvision0.16.2 --index-url https://download.pytorch.org/whl/cu118 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt这段命令先创建干净的Python环境避免和系统Python冲突。--index-url是PyTorch官方指定的CUDA 11.8版本源如果你显卡驱动只支持CUDA 12就把cu118换成cu121。装完后用python -c import torch;print(torch.cuda.is_available())验证CUDA到底通没通。这一步是报错重灾区很多时候不是代码问题而是torch版本跟显卡驱动不匹配报错显示找不到CUDA driver时就要回去查nvidia-smi。3.2 修改data.yaml与模型配置文件YOLOv5的训练入口是train.py它需要两个关键配置一个是数据集的data.yaml一个是模型结构的yolov5s.yaml。数据集的配置长这样# datasets/microscope/data.yaml path: datasets/microscope # 数据集根目录 train: images/train # 训练图像相对路径 val: images/val # 验证图像相对路径 test: images/test # 测试图像相对路径 nc: 4 # 类别数量 names: [starch_grain, stone_cell, vessel, fiber]这里path是相对yolov5项目根的路径train和val都指向images而不是labelsYOLOv5会自行在同级目录下找labels。有个高频问题Windows下路径分隔符容易写反建议统一用Linux风格的斜杠。再打开models/yolov5s.yaml改nc为4其余不动。显微图像目标密集但单个目标小yolov5s比yolov5l更合适因为深层特征图对80像素以下的目标会丢掉太多细节。3.3 训练命令与显微图像超参数设置训练命令本身不复杂复杂的是理解每个参数对显微场景的影响。我自己在类似项目中训练中药材时常用这个命令python train.py \ --img 640 \ --batch 16 \ --epochs 200 \ --data datasets/microscope/data.yaml \ --weights yolov5s.pt \ --cache \ --hyp hyp.scratch-low.yaml \ --patience 40命令中的--img 640代表把输入图像resize到640×640但你的原图是4000×3000时必须先切成patch再喂给训练否则模型看到的都是缩小后的模糊小点。--batch 16以单卡12GB显存为例如果显存不够会报OOM此时优先降batch而不是降图片尺寸。--cache把图像预加载进内存可以显著缩短训练时间前提是机器内存足够。--hyp指定超参数文件显微图像建议在默认基础上改这几项超参数默认值显微场景建议原因hsv_h0.0150.01弱化色相变化保留药材颜色特征degrees0.00.0禁止旋转保持方向特征translate0.10.2允许平移防止边缘目标被切mosaic1.00.8降低mosaic概率密集小目标易被遮蔽copy_paste0.00.3复制粘贴增强适合小目标但需谨慎--patience 40表示验证集指标连续40轮不提升就早停。显微图像训练200轮通常在第120到160轮之间收敛如果到第200轮还没稳定多数是学习率没降下去可自行在hyp.scratch-low.yaml里把lr0从默认0.01改为0.005。这里提醒一句超参数调优最好用YOLOv5自带的utils/evolve.sh思路一次跑多组对比但先保证第一版能跑通再谈最优。4. 显微图像推理、评估与常见错误排查4.1 用best.pt做批量推理训练结束后runs/train/exp/weights/best.pt就是验证集上mAP最高的权重。对一批显微图像做推理最直接的是调用detect.pypython detect.py \ --weights runs/train/exp/weights/best.pt \ --source datasets/microscope/images/test \ --img 640 \ --conf 0.25 \ --iou 0.45 \ --save-txt \ --save-conf \ --project runs/detect \ --name microscope_test这段命令对test目录下所有图像执行检测--conf 0.25表示置信度低于25%的预测框直接丢弃--iou 0.45是NMS时的IoU阈值两个值都直接影响显微图像里密集目标的检出量。实际效果中如果看到一句话里检测框互相重叠可把--iou调到0.6如果看到很多高置信度重复框说明某个类别特征太相似需要从数据端补充难例而不是只调这两个参数。--save-txt会把每个框的class x_center y_center width height存到txt里后续要做面积统计或数量统计时直接读这个文件。4.2 用val.py看mAP和混淆矩阵光看检测效果图不靠谱还要用验证集跑一次数值评估python val.py \ --weights runs/train/exp/weights/best.pt \ --data datasets/microscope/data.yaml \ --img 640 \ --conf 0.001 \ --iou 0.6 \ --save-json \ --save-hybrid--conf 0.001是为了在评估时把所有可能框都计入这样mAP计算会更接近真实上限。--iou 0.6是评价时判定真正例的IoU阈值YOLOv5默认报告的是0.5和0.5:0.95两个mAP。看结果先看runs/val/exp/confusion_matrix.png中药材显微图像里石细胞和纤维经常被互相认错因为两者在单张切片里都呈长条形如果混淆矩阵里这两类的cross值偏高说明标注时类别边界没定清楚需要回标注阶段按“细胞壁厚度”和“胞腔大小”重新划分类别。表一次实际显微识别评估中常见的mAP参考模型mAP0.5mAP0.5:0.95推理速度(ms)yolov5s0.870.528yolov5m0.890.5512yolov5l0.900.5718以上速度是在单张T4显卡上对640×640输入耗时实际显微大图切块后要乘上patch数。若mAP0.5已经很高但mAP0.5:0.95偏低基本可以断定是目标框回归不稳定多半是标注框本身边界画得不齐。显微特征里淀粉粒是圆的还好导管壁那种不规则多边形用水平框表达天然有误差这个损失需要接受不必追求过高的IoU指标。4.3 显微场景下三类典型失败与对策第一类漏检小淀粉粒。原因是640输入下目标不足20像素对策是切patch时用768甚至1024分辨率并把--img同步调大代价是显存占用翻倍。第二类密集区域框合并。两个紧挨的淀粉粒被NMS合并成一个框这常在--iou 0.45默认设置下出现可把NMS的IoU阈值调高到0.6并且检查标注里是否真的把重叠目标都标了。第三类背景误检为结晶。显微制片里气泡、杂质和草酸钙结晶很像优化方向是给背景负样本单独建一个数据集目录YOLOv5不会自动采负样本需要手动加入不包含目标的图像并配上空TXT。5. 让显微识别结果能用的几个工程细节5.1 大图切块推理后合并坐标显微原图通常超过4000×3000直接整图推理显存放不下常见做法是滑窗推理加重叠合并。把每个patch的检测框坐标加上该patch在原图上的偏移量就能还原到全图坐标系。重叠区域里同一个目标可能被检测多次可对重叠框再做一次NMS。这里有一个边界陷阱patch之间重叠率太低时目标正好被切开两边各检测到一半置信度都不高最终漏检。重叠率至少要20%并且两个patch里若都出现高置信框应保留面积更大的那个。相关代码片段里要保证读取TXT时用的坐标系与写入一致。我通常把detect.py的输出TXT还原成原图坐标后再统计每个类别的目标数量和面积分布这一步对中药材显微鉴定的价值比单张可视化更大因为“石细胞是否成群”“导管直径范围”这类化学鉴定报告里的关键结论本质上依赖的是位置和尺寸统计。5.2 导出ONNX并在批处理中保持预处理一致模型训好后如果要给一个离线批处理程序使用导出ONNX比直接调Python推理更稳定python export.py --weights runs/train/exp/weights/best.pt --img 640 --include onnx导出后用ONNX Runtime推理时必须复刻YOLOv5的letterbox处理缩放时长边缩放到640短边按比例缩放后用114灰色填充。实际项目里最容易出的错是导出时用640推理脚本里却把输入resize成了不保持宽高比的640×640导致框位偏移。解决方法是抽一个公共的letterbox函数训练、验证、推理全部调用同一份预处理代码不要各写一版。ONNX推理速度在CPU上通常比PyTorch快20%~30%适合没有GPU的质检工作站。5.3 用多阈值决策替代单一置信度显微鉴定的最终判断很少依赖单张图的单次检测更可靠的做法是固定相机参数在同一批粉末里采5到8个视野每个视野跑一次推理然后按类别汇总检测数量中位数。单一阈值下某个视野漏检几个淀粉粒会让数量统计失真所以我会同时记录置信度大于0.25和大于0.5两个档位的结果当两档数量差异超过30%时就认为这批图像存在较多的边界样本需要人工复核。这一招虽然简单但实际项目中能有效拦住“模型其实没学会只是某一阈值下指标好看”的假阳性风险。本文还有配套的精品资源点击获取
返回列表