计算机视觉实训:基于YOLOv8n-pose的脊柱X光片识别分析系统

计算机视觉实训:基于YOLOv8n-pose的脊柱X光片识别分析系统

本次实训完整记录:从全班55人手工标注1300张数据,到983张有效数据的清洗,再到YOLOv8n-pose模型训练、临床参数自动计算、Gradio可视化界面搭建,以及大模型API生成医学报告的全流程。

一、项目背景与意义

脊柱侧弯(Scoliosis)是一种常见的脊柱三维畸形疾病,好发于青少年群体。据统计,我国中小学生脊柱侧弯发病率约为1%~3%,已成为继近视、肥胖之后的第三大青少年健康问题。传统的脊柱侧弯诊断依赖医生手工测量X光片上的Cobb角等参数,不仅耗时耗力,且不同医生之间的测量结果存在一定主观差异。

本次实训旨在探索基于深度学习的脊柱X光片自动识别与分析系统,通过计算机视觉技术实现:

  • 脊柱关键点的自动检测与定位(18个椎体中心点)
  • 临床参数(Cobb角、C7PL-CSVL、T1倾斜角等)的自动计算
  • 结构化医学报告的自动生成(接入大语言模型)
  • Gradio可交互Web界面,支持拖拽上传、实时分析

这一方向具有重要的临床应用价值,能够辅助医生提高诊断效率,降低主观误差,同时为基层医疗机构提供低成本、高质量的脊柱筛查工具。


二、数据集构建:全班协作的标注工程

2.1 数据来源与标注任务分配

本次实训的数据集来源于全班55位同学的协作标注。每位同学使用 PyCharm 环境下的 LabelMe 工具,对脊柱X光正位片进行关键点标注,每人负责约31张图片,总计采集了1300多张原始标注数据。

标注规范:

  • 每个椎体标注 4个角点(左上、右上、左下、右下),共18个椎体
  • 椎体顺序:C7 → T1 → T2 → … → T12 → L1 → L2 → … → L5
  • 标签文件保存为 .mat 格式,其中 points 字段存储角点坐标 (x, y)

2.2 数据清洗:从1300张到983张

原始数据存在较多质量问题,经过系统清洗后得到有效数据 983张

问题类型 具体情况 处理方式
非18节脊柱 约320多张图片标注的椎体数量不为18 剔除
图名不匹配 部分图片文件名与标签文件名不一致 人工核对后修复或剔除
标注顺序错误 少数同学角点顺序非”左上-右上-左下-右下” 按统一规范重新排序
坐标越界 个别标注点超出图像边界 裁剪至图像范围内

数据清洗流程:

  1. 遍历所有 .mat 标签文件,检查 points 数组维度是否为 [18, 4, 2]
  2. 核对图片文件名与标签文件名是否一一对应
  3. 检查角点顺序是否符合”左上-右上-左下-右下”规范
  4. 验证所有坐标是否在图像有效范围内

最终保留 983张图片-标签完全对应 的数据作为训练集和验证集,另有部分同学保留的原始 JSON 格式标注文件作为独立测试集。


三、技术栈

技术/工具 版本/型号 用途
YOLOv8n-pose Ultralytics 8.x 脊柱18个关键点检测
SiliconFlow API Qwen2.5-72B-Instruct 医学报告文本生成
Gradio 6.x Web可视化交互界面
OpenCV 4.x 图像处理与可视化标注
NumPy / SciPy 数值计算与脊柱曲线拟合
LabelMe 数据集标注
Python 3.10 开发语言

四、数据预处理与格式转换

4.1 从角点到中心点

YOLO-Pose 模型需要输入关键点中心坐标而非角点,因此需要将每个椎体的4个角点转换为1个中心点:

# 角点顺序:左上、右上、左下、右下
center_x = (x1 + x2 + x3 + x4) / 4
center_y = (y1 + y2 + y3 + y4) / 4

4.2 转换为YOLO格式

YOLO-Pose 要求的标签格式为:

<class_id> <x1> <y1> <x2> <y2> ... <x18> <y18>

其中坐标需归一化到 [0, 1] 范围。编写转换脚本批量处理983张数据:

import scipy.io as sio
from pathlib import Path

def convert_mat_to_yolo(mat_path, img_w, img_h):
    data = sio.loadmat(mat_path)
    points = data['points']  # [18, 4, 2]

    # 计算中心点
    centers = points.mean(axis=1)  # [18, 2]

    # 归一化
    centers[:, 0] /= img_w
    centers[:, 1] /= img_h

    # 构建YOLO格式行
    yolo_line = "0 " + " ".join([f"{x:.6f} {y:.6f}" for x, y in centers])
    return yolo_line

4.3 数据集划分

按照 8:2 的比例划分训练集与验证集:

子集 数量 比例 用途
训练集 786张 80% 模型训练
验证集 197张 20% 超参数调优与训练监控

此外,另有部分同学保留的原始 JSON 格式标注文件作为独立测试集,用于最终效果验证。

五、模型训练

5.1 模型选择:YOLOv8n-pose

选用 YOLOv8n-pose(nano版本),原因如下:

  • 参数量小(约3.2M),推理速度快,适合部署
  • 单阶段检测:端到端训练,无需复杂后处理
  • 医学影像适配:对X光片这类灰度图像的关键点检测效果良好

5.2 训练配置

创建 data.yaml 配置文件:

path: C:\python_ws\计算机视觉实训\SpineVLM\dataset
train: train_yolo/images
val: val_yolo/images
test: test_yolo/images

kpt_shape: [18, 2]  # 18个关键点,2D坐标
flip_idx: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]

names:
  0: spine

关键训练参数:

  • 输入尺寸:640×640
  • 批次大小:16
  • 训练轮数:300 epoch
  • 优化器:SGD,初始学习率 0.01
  • 数据增强:Mosaic、MixUp、随机水平翻转

5.3 训练结果

指标 数值
mAP@0.5 0.92
mAP@0.5:0.95 0.78
关键点mAP 0.85
推理速度 ~45ms/张(GPU)

模型能够稳定检测18个脊柱关键点,定位精度满足后续临床参数计算需求。

 


六、临床参数计算:从关键点到诊断指标

模型输出的是18个椎体的中心点坐标,需要进一步计算临床参数。以下是核心参数的计算方法:

6.1 Cobb角(脊柱侧弯金标准)

胸Cobb角 = T5上终板与T12下终板的夹角 腰Cobb角 = T12上终板与L4下终板的夹角

实现中,终板方向通过相邻椎体中心点连线的垂线确定:

def vector(p1, p2):
    return np.array([p2[0] - p1[0], p2[1] - p1[1]])

def perpendicular(v):
    """向量旋转90度得到终板线方向"""
    return np.array([-v[1], v[0]])

# T5上终板方向(垂直于T4-T5连线)
t5_long = vector(kp[T4], kp[T5])
t5_upper = perpendicular(t5_long)

# T12下终板方向(垂直于T12-L1连线)
t12_long = vector(kp[T12], kp[L1])
t12_lower = perpendicular(t12_long)

thoracic_cobb = angle_between(t5_upper, t12_lower)

临床参考值:<10° 正常,10-25° 轻度,25-40° 中度,>40° 重度

6.2 C7PL-CSVL(冠状面平衡)

C7铅垂线与骶骨中垂线(CSVL)的水平偏移距离:

c7pl_csvl_px = abs(c7_center[0] - l5_center[0])
c7pl_csvl_mm = c7pl_csvl_px * 0.3  # 像素到毫米转换

临床参考值:<20mm 正常,20-40mm 轻度失衡,>40mm 明显失衡

6.3 T1倾斜角

T1上终板与水平线的夹角,反映上胸椎段倾斜程度:

t1_long = vector(kp[C7], kp[T1])
t1_upper = perpendicular(t1_long)
t1_tilt = line_angle_with_horizontal(t1_upper)

6.4 脊柱曲线拟合

使用 UnivariateSpline 对18个关键点进行三次样条拟合,计算曲率分布,识别最大弯曲位置:

from scipy.interpolate import UnivariateSpline
from scipy.signal import find_peaks

spline = UnivariateSpline(y_sorted, x_sorted, k=3, s=10)
curvature = np.abs(d2x_dy2) / (1 + dx_dy**2)**1.5
peaks, _ = find_peaks(curvature, distance=50)

七、可视化系统:多轮迭代打磨细节

可视化部分经历了多轮迭代优化,每一轮都是基于实际使用反馈进行调整:

迭代版本 问题反馈 解决方案
v1 大方框框住整个脊柱,看不清单个椎体 改为每个椎体独立四边形框
v2 参考线与椎体框重合,参数值看不清 延长终板线(extend_factor=2.5),增加白色描边
v3 参数面板被截断,黑底黑字看不清 改为白底黑字,移至左下角
v4 关键点标记像”黑圈黑十字” 改为黄圈白十字黑细线
v5 原图被覆盖看不清 降低所有叠加元素透明度,仅画细线
v6 参数面板遮挡图像 参数直接标在对应位置,取消独立面板

最终可视化效果包含以下元素:

  • 椎体四边形框:C7红色、T1-T12青色、L1-L5绿色
  • 关键点十字标记:T5、T12、L4、C7、L5、T1 六个计算参数的关键椎体
  • 终板延长线:带参数值标注(如 “Th=31.1°”)
  • C7PL/CSVL虚线:红色/蓝色垂直参考线,直观展示冠状面偏移
  • 脊柱拟合曲线:白色细线,展示脊柱整体走向
  • 弯曲点标注:黄色圆点,标记曲率最大位置


八、医学报告生成:大模型的临床应用

8.1 方案设计

接入 SiliconFlow 平台的 Qwen2.5-72B-Instruct 大模型,通过结构化 Prompt 自动生成医学报告。

Prompt设计要点:

  • 角色设定:资深脊柱外科主任医师
  • 参数输入:6项临床参数及正常参考范围
  • 输出结构:检查信息 → 影像所见 → 参数解读 → 诊断意见 → 建议
  • 温度参数:0.3(保证输出稳定)

8.2 API调用代码

def call_api(prompt):
    headers = {"Authorization": f"Bearer {API_KEY}"}
    data = {
        "model": "Qwen/Qwen2.5-72B-Instruct",
        "messages": [
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.3,
        "max_tokens": 2000
    }
    response = requests.post(API_URL, headers=headers, json=data, timeout=120)
    return response.json()['choices'][0]['message']['content']

8.3 遇到的问题

最初使用 Qwen/Qwen2-72B-Instruct 模型,API返回 403 Model disabled 错误,排查后发现该模型ID已被平台禁用,更换为 Qwen2.5-72B-Instruct 后正常。

8.4 备用方案

考虑到API可能不可用(网络问题、余额不足等),系统内置了基于规则的本地报告生成作为 fallback。当API调用失败时,自动根据临床参数阈值生成结构化报告,确保系统在任何情况下都能输出可用的诊断建议。

本地报告生成
LLM返回报告

九、Gradio交互界面

9.1 界面布局

使用 Gradio 搭建的 Web 界面采用左右分栏布局,左侧为图像上传与检测结果展示,右侧为临床参数表格与AI医学报告,通过标签页切换:

左侧上方为X光片上传区域(支持拖拽),下方为模型检测后的可视化标注结果;右侧上方通过标签页切换「临床参数」和「医学报告」两个视图,下方提供参数JSON文件的下载按钮。

9.2 交互流程

  1. 上传:用户拖拽或点击上传脊柱X光正位片
  2. 检测:YOLOv8n-pose 自动检测18个关键点
  3. 计算:基于关键点计算6项临床参数
  4. 可视化:在图像上叠加椎体框、终板线、Cobb角标注等
  5. 报告:调用大模型API生成结构化医学报告
  6. 下载:支持导出JSON格式参数文件

9.3 部署运行

cd C:\python_ws\计算机视觉实训\SpineVLM
python app.py

访问 http://127.0.0.1:7860 即可使用。


十、效果展示与案例分析

10.1 典型病例自动测量结果

输入一张全长脊柱正位X光片,系统自动输出以下参数:

参数 数值 参考范围 判定
胸Cobb角 3.1° <10°正常, 10-25°轻度, 25-40°中度, >40°重度 未见明显侧弯
腰Cobb角 15.9° <10°正常, 10-25°轻度, 25-40°中度, >40°重度 未见明显侧弯
C7PL-CSVL 17.8px (5.3mm) <20mm正常, 20-40mm轻度, >40mm明显 冠状面平衡
T1倾斜角 5.7° <5°正常, 5-10°轻度, >10°明显 轻度倾斜
脊柱弯曲角1 13.5°
脊柱弯曲角2 30.0°

10.2 AI生成诊断报告摘要

影像所见
1.胸椎生理曲度存在,未见明显侧弯。胸椎椎体形态、大小及间距正常,椎间隙均匀,未见明显骨质增生或破坏。
2.腰椎生理曲度存在,未见明显侧弯。腰椎椎体形态、大小及间距正常,椎间隙均匀,未见明显骨质增生或破坏。
3.脊柱整体排列基本正常,未见明显结构性异常。脊柱各段的生理曲度均在正常范围内。
诊断意见
1.胸椎未见明显侧弯,Cobb角为3.1°,在正常范围内。
2.腰椎存在轻度侧弯,Cobb角为15.9°。
3.脊柱整体排列基本正常,但存在轻度和中度的局部弯曲,具体为脊柱弯曲角1为13.5°,脊柱弯曲角2为30.0°。
建议
1. 定期复查:建议患者每6个月进行一次脊柱X光检查,以监测脊柱侧弯的变化情况。
2. 物理治疗:建议患者进行物理治疗,包括脊柱矫正操和肌肉强化训练,以改善脊柱的局部弯曲。
3. 姿势矫正:日常生活中注意保持正确的坐姿和站姿,避免长时间保持同一姿势,尤其是弯腰驼背。
4. 随访观察:建议患者定期随访,如有脊柱侧弯加重或出现相关症状(如腰背痛、下肢麻木等),应及时就医。
5. 生活方式调整:建议患者保持良好的生活习惯,避免过度劳累,保持适当的体重,以减轻脊柱的负担。

 


十一、遇到的问题与解决方案汇总

阶段 问题 原因 解决方案
数据清洗 320多张非18节脊柱 标注时漏标或多标椎体 编写脚本自动筛选,人工复核
数据清洗 图片与标签名不匹配 文件管理混乱 建立统一命名规范,批量重命名
模型训练 角点转中心点丢失信息 YOLO-Pose只需中心点 保留原始角点数据用于可视化重建
可视化 大方框遮挡原图 设计问题 改为每个椎体独立小框
可视化 参考线与框重合 线长不足 延长终板线,增加extend_factor
可视化 参数值看不清 颜色对比度低 白底黑字,直接标在对应位置
API调用 403 Model disabled 模型ID已停用 更换为 Qwen2.5-72B-Instruct
Gradio css参数位置报错 版本6.0 API变化 按新版本API调整代码
Gradio show_copy_button参数不存在 Gradio 6.0移除该参数 删除该参数

十二、总结与展望

12.1 项目收获

  • 数据工程能力:从1300张原始标注到983张有效数据,深刻理解了数据清洗在AI项目中的重要性——”垃圾进,垃圾出”
  • 模型训练经验:完整走通了 YOLO-Pose 的训练流程:数据标注 → 格式转换 → 训练调参 → 推理部署
  • 临床知识积累:深入理解了 Cobb角、C7PL-CSVL、T1倾斜角等脊柱外科核心诊断指标的计算原理
  • 工程化思维:通过 Gradio 快速搭建 Demo 验证想法;通过 API 接入大模型降低开发成本;通过 fallback 机制保证系统鲁棒性

12.2 不足与改进方向

  • 数据集规模:983张仍偏小,可扩展至5000+张提升泛化能力
  • 角点信息利用:当前仅用中心点训练,可探索同时预测中心点+角点的多任务模型
  • 三维评估:目前仅做2D分析,可结合三维CT重建评估椎体旋转角(Nash-Moe分级)
  • 本地LLM部署:当前依赖外部API,可本地部署 Qwen2-7B 实现离线可用
  • 移动端适配:Gradio界面可进一步优化为移动端友好的响应式布局

12.3 应用前景

该系统可部署于:

  • 医院PACS系统:辅助放射科医生快速初筛,减少重复劳动
  • 基层筛查场景:为缺乏专业骨科医生的地区提供低成本筛查工具
  • 青少年体检:大规模脊柱侧弯早期筛查,助力”早发现、早干预”

十三、参考资料

  1. Ultralytics YOLOv8 Documentation: https://docs.ultralytics.com
  2. SiliconFlow API Docs: https://docs.siliconflow.cn
  3. Gradio Docs: https://www.gradio.app/docs
  4. Scoliosis Research Society (SRS) Cobb角测量标准
  5. 《脊柱外科学》人民卫生出版社
  6. LabelMe: https://github.com/wkentaro/labelme

项目代码:SpineVLM 实训时间:2026年6月-7月 联系方式wzy5585@foxmail.com

本文首发于个人博客,转载请注明出处。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部