ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于深度学习的骨龄检测识别系统:PyTorch+YOLOv5+PySide6实战解析

基于深度学习的骨龄检测识别系统:PyTorch+YOLOv5+PySide6实战解析 简介基于深度学习的骨龄检测识别系统是一套完整落地项目面向医学影像算法开发者、计算机视觉学习者及儿科辅助诊断场景。系统以PyTorch为训练框架采用Pyside6构建桌面GUI并集成YOLOv5模型完成儿童手腕X光图像中的骨骼特征定位与骨龄推断。压缩包总计205个文件包含71个Python源码、43个编译后pyc、32个YAML配置、11个模型权重pt、3个Jupyter教程以及类型齐全的Dockerfile、MD文档、UI设计文件等压缩后整体约406MB。已有331人学习下载。内容覆盖模型训练、推理、界面展示、项目说明与开源规范目录结构完整清晰适合直接二次开发或作为毕业设计、科研课题参考。通过源码、配置与教程结合可快速掌握从数据处理到界面部署的完整流程并利用预训练权重自行复现骨龄检测效果。 骨龄评估这个事说起来简单做起来全是主观判断。儿科内分泌科的医生拿到一张左手腕X光片要么翻开GP图谱一页页比对骨化中心的发育形态要么按TW法对桡骨、尺骨和指骨的十多个骨化中心逐一打分快则十几分钟慢则半小时同一张片子不同医生读出来的结果能差出一岁上下。这种又耗时又依赖经验的活儿天然适合交给深度学习。这篇文章就把我做的这套基于深度学习的骨龄检测识别系统完整拆开讲一遍PyTorch做算法框架YOLOv5做手部区域检测PySide6搭桌面客户端从数据整理、模型训练到软件集成把值得注意的细节都交代清楚。无论你是准备毕业设计还是想入门一个能真正落地的计算机视觉项目这套流程都可以直接参考。1. 骨龄评估的痛点以及系统为什么采用先检测再回归的两段式方案1.1 GP图谱法和TW计分法的瓶颈在哪骨龄是衡量儿童骨骼成熟度的重要指标临床上用来辅助诊断生长迟缓、性早熟等问题。最常用的读片方法是Greulich-PyleGP图谱法医生把左腕X光片与标准发育图谱逐龄比对通过骨化中心数量、形态和骨骺闭合程度判定骨龄Tanner-WhitehouseTW计分法则把桡骨、尺骨及指骨的骨化中心拆成多个评分部位逐个打分。两种方法都严重依赖读片医生经验骨化中心边缘算开始出现还是已发育不同医生的标准不一样文献里观察者间误差差距很大半年到一年的偏差并不罕见。对需要长期随访生长激素治疗效果的孩子来说读片噪声会直接影响临床判断。1.2 为什么先让YOLOv5定位手部再做年龄回归早期做骨龄深度估计很多论文直接照搬RSNA 2017骨龄挑战赛的思路把整张左手X光片丢给卷积回归网络。挑战赛数据是标准化裁剪过的手在画面中央整图回归没问题但真实系统的X光片五花八门有的带检查床边缘有的有铅字标记有的拍进一整段前臂整图回归会让网络浪费大量感受野去理解背景误差被放大。所以这套系统拆成两段YOLOv5在整张图上检测左手腕区域输出一个边界框把裁剪出的手部图归一化后送进一个回归CNN直接输出月龄。先定位再评估在医学影像辅诊里很常见本质是把一个难任务拆成两个简单任务。检测器只负责框得准回归器只在干净区域里提取骨成熟度特征。这个过程有点像先在地图上定位城市再放大看街道细节——第一步解决在哪第二步解决细不细。至于为什么选YOLOv5而不是YOLOv6或YOLOv8这个项目难在数据整理和系统集成单手部检测的精度YOLOv5s在GPU上几十毫秒搞定绰绰有余加上YOLOv5社区资料最多、训练自定义数据集的坑最少做毕设或中小型系统是最稳的选择。后续想升级检测器回归网络可以原封不动保留。2. 环境搭建实录PyTorch GPU版、YOLOv5与PySide6的版本配合2.1 先建独立环境再解决版本匹配这类项目依赖多千万别在系统Python里直接pip装。我习惯用Anaconda建独立环境conda create -n boneage python3.10 -y conda activate boneage选Python 3.10纯粹是因为PyTorch、PySide6、YOLOv5对它的兼容性最稳3.11、3.12也能跑但部分旧库在它们上面偶尔有编译兼容问题没必要赌。Windows和Ubuntu操作一致唯一区别是装之前先用nvidia-smi确认NVIDIA驱动支持的CUDA版本驱动太老就得选低一档的CUDA组合。2.2 安装GPU版PyTorch与PySide6PyTorch安装最关键的坑是版本要和CUDA匹配。我用的是CUDA 12.1组合pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121装完立刻验证python -c import torch; print(torch.__version__, torch.cuda.is_available())输出2.x和True才算正常。如果显示False多半是驱动版本太低或装成了CPU版趁早返工比后面排查省时间。接着装PySide6pip install pyside6当前6.6、6.7这些稳定版本在Python 3.10下都没问题。装完顺手运行pyside6-designer确认能打开UI设计器后面画界面要用。2.3 拉取YOLOv5仓库依赖安装顺序有讲究git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt这里有个高频坑一定要先装好GPU版PyTorch再执行requirements.txt。因为YOLOv5的requirements里包含torch依赖先装它很容易被pip装成CPU版前面配的GPU环境直接白费。先装GPU版之后requirements检查到torch已满足会自动跳过。提示如果网络访问官方源慢普通依赖可以换国内PyPI镜像pip install -i但PyTorch官方GPU wheel建议还是走官方源避免拿到不完整版本。3. 数据准备把公开骨龄数据集改造成YOLOv5能训练的格式3.1 RSNA 2017骨龄挑战赛数据基础做骨龄深度估计最常用的公开数据是RSNA 2017骨龄挑战赛的左手X光片训练集12595张每张带两个标注boneage骨龄单位是月和male性别。数据集本身面向回归任务图像基本居中但没有手部检测框标注检测器的标签得自己造。使用医学影像数据前先确认来源合规如果是医院合作数据必须走伦理审批并做患者信息脱敏。演示和毕设用公开集完全够不需要碰真实临床数据。3.2 半自动生成手腕检测框给上万张图手动画框不现实。标准做法是先写脚本自动生成初框再人工微调。X光片里骨骼区域明显偏亮先做Otsu阈值拿高亮前景再取最大连通域的边界框import cv2 def auto_bbox(path): img cv2.imread(path, cv2.IMREAD_GRAYSCALE) _, th cv2.threshold(img, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) contours, _ cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) x, y, w, h cv2.boundingRect(max(contours, keycv2.contourArea)) mx, my int(w * 0.05), int(h * 0.05) # 外扩5%防止截到指尖腕骨 return max(0, x - mx), max(0, y - my), x w mx, y h my自动框偶尔会把铅字标记当目标把这些图用LabelImg打开手工改一遍。数据量不用贪多我最后用1200张带框图训练检测器已经很稳。标注时框可以画松一点关键是完整包住手部不要为了贴合把腕骨切掉。3.3 转YOLO格式与按患者划分YOLOv5的标签是每张图一个同名.txt每行格式为class_id x_center y_center width height四个坐标除以图像宽高做归一化。写转换脚本时最容易错的是坐标用成了左上角格式训练时loss会异常震荡建议转换后写个检查函数逐张校验。数据集划分要按患者ID切同一个患者不能同时出现在训练集和验证集否则评估虚高部署到真实场景就露馅。3.4 医学图像的增强要克制YOLOv5自带增强直接可用旋转、平移、缩放对骨骼检测友好但HSV颜色增强一定要调低。X光片的灰度分布本质上就是诊断信息颜色扰动过猛等于把骨骼纹理特征洗掉。我是把hyp里的hsv_h、hsv_s、hsv_v直接调到接近0训练明显更稳。4. 训练实战手部检测器与骨龄回归器分别怎么调4.1 手部检测器一份配置文件加一条命令在YOLOv5仓库下建boneage.yamlpath: ./datasets/boneage train: images/train val: images/val nc: 1 names: [hand]启动训练python train.py --img 640 --batch 16 --epochs 80 \ --data boneage.yaml --weights yolov5s.pt \ --device 0 --patience 15几个参数的解释yolov5s.pt是COCO预训练权重用它做迁移学习目标域虽是医学X光片预训练特征依然能显著加速收敛--img 640保持默认输入--batch 16在8GB显存卡上没问题不够就降到8--patience 15表示验证指标连续15个epoch不涨就早停。实测GTX 3060约45分钟收敛到mAP0.5接近0.98。手部检测对YOLOv5几乎没有挑战难的全在数据标注质量。4.2 骨龄回归网络ResNet主干加性别辅助第二段才是核心。任务定义是输入裁剪后的手部X光图输出0到240个月的月龄本质是回归问题。网络最后一层是单节点输出损失函数用SmoothL1评估指标用MAE月。主干用ResNet34足够。我额外加了性别辅助输入把male标签做embedding后在全局池化层和图像特征拼接再进全连接。原因很直接男女骨成熟节奏差异大同样骨化程度对应不同月龄性别先验能明显降低MAERSNA挑战赛顶尖方案也这么做。预处理上灰度图先做直方图均衡化再resize到224x224。不同设备拍的X光片整体亮度对比度差异很大均衡化能抹平这部分域差异让模型专注学骨骼形态。训练50个epoch大约1到2小时验证集MAE做到8~10个月。跟顶尖团队4~5个月有差距但作为工程演示系统足够说明问题。4.3 先把推理链路跑通再做界面训练完两个模型强烈建议先写脚本把完整推理跑通再动界面import torch device torch.device(cuda:0) det torch.hub.load(./yolov5, custom, pathbest_det.pt, sourcelocal) reg torch.load(best_reg.pth, map_locationdevice) reg.eval() for *xyxy, conf, cls in det(img_path).xyxy[0].cpu().numpy(): x1, y1, x2, y2 [int(v) for v in xyxy] crop img[y1:y2, x1:x2] crop preprocess(crop) # 直方图均衡化、resize、归一化 age_month reg(crop.unsqueeze(0).to(device)).item()torch.hub.load这里用sourcelocal直接从本地仓库加载避免每次联网检查版本。这条链路一旦通了后面做界面就是纯粹的UI拼装。5. PySide6桌面客户端把两段模型串成可交付的软件5.1 界面功能规划桌面端的核心是医生能直接上手。主界面左侧放原图显示区右侧结果面板展示检测框坐标、预测骨龄按月龄和岁数同时显示、性别和推理耗时底部放打开图片、开始检测、批量检测按钮。检测框用不同颜色在原图上画出让用户直观看清YOLOv5框在哪不只是给一个数字。工具型软件界面越简单越好信息层级要一眼看懂。5.2 用QThread异步推理避免界面卡死新手最常见的问题是直接在按钮回调里跑模型推理。单张图推理虽然只有一两百毫秒加上图像解码和预处理界面依然会明显未响应。正确做法是把推理放独立线程用QThread加Worker对象from PySide6.QtCore import QObject, Signal class InferWorker(QObject): result_ready Signal(dict) def __init__(self, det, reg): super().__init__() self.det, self.reg det, reg def run(self, img_path): age_month infer(self.det, self.reg, img_path) self.result_ready.emit({age_month: age_month, path: img_path})注意QThread对象要保存为成员变量否则会被Python垃圾回收线程跑到一半消失这个坑很隐蔽。5.3 模型加载与显示细节模型只在MainWindow初始化时加载一次全局复用别每次点按钮都重新读权重。加载后设置eval模式推理包在torch.no_grad()里能省不少显存和时间。显示X光片建议用QImage的Format_Grayscale8直接渲染灰度图不要转成RGB再显示以免颜色失真。画框可以用cv2.rectangle画好再转QImage如果用QGraphicsView做大图缩放显示记得处理坐标换算否则缩放后框和图像对不上。按钮和Worker之间用signal/slot连接点击开始检测按钮时把图片路径发给Worker线程的run方法Worker跑完通过result_ready信号回到主线程更新界面。这里有个细节如果YOLOv5在图上没有检测到任何目标要给出明确提示而不是抛异常我在系统里会弹出未检测到手部区域请确认图像为正位左手X光片的提示。批量检测时最好加一个进度条遍历文件夹的同时不断emit进度信号用户体验会好很多。到这一步一个打开图片、点击检测、读出骨龄的桌面软件就成型了。6. 实测效果与高频踩坑记录6.1 实测数据整套系统在RTX 3060上的实测结果项目数值手部检测器mAP0.50.98骨龄回归MAE验证集8~10个月单张纯GPU推理耗时40~60ms端到端单张含界面加载约0.8~1.2s作为初筛工具这个精度已经能把明显正常的孩子先筛掉让医生集中精力看异常片。6.2 高频踩坑记录现象原因解决办法torch.hub.load每次联网默认拉取线上最新代码用sourcelocal指定本地仓库pyside6-designer无法识别Scripts目录未进PATH在site-packages/PySide6下找designer.exe直接运行高DPI屏上图像模糊Qt缩放策略不合适程序入口开启Qt.AA_EnableHighDpiScaling批量检测显存暴涨每张图新建tensor未释放复用同一模型实例循环内包torch.no_grad()检测框框住铅字标号阈值分割误判高亮标记自动框脚本过滤最大连通域并人工复核PyInstaller打包后模型路径失效打包后资源路径变成临时目录用sys._MEIPASS拼接路径把权重外置为资源这几个坑里铅字标记那个最典型。X光片上常用铅字标记左右侧灰度值和骨骼一样高Otsu经常把它当目标。我后来在自动标注脚本里只保留面积最大的高亮连通域再人工补漏基本解决了。6.3 还能往哪些方向扩展想做成更完整的作品有三个现成方向一是把YOLOv5从检测整个手升级为检测手腕关键骨化中心区域对每个区域做TW分期分类输出骨龄可解释性更强医生更容易接受二是把模型导出ONNX用NCNN或RKNN部署到树莓派这类边缘设备做成低成本门诊终端三是界面加医生复核流程算法出初稿、医生改终稿并留痕更贴近真实医疗软件规范。最后聊一点做完这个项目的体会。整套系统里花时间最多的不是训练而是数据整理和界面集成。检测器训练半天就收敛但数据转换脚本、标注工具调优、手工校对框加上两段模型联调占掉整个项目一大半时间。模型虽为核心工程才是大头这种体验在垂直领域视觉项目里特别典型。另一个实用建议是无论做毕设还是产品原型先把一条最小推理链路跑通再回头补数据和界面整体节奏会稳很多。本文还有配套的精品资源点击获取
返回列表