深度学习关键点检测的坐姿识别项目源码解析 📅 发布时间:2026/9/16 16:18:24 👁 浏览次数: 简介这套基于深度学习的智能坐姿检测系统完整源码包面向毕业设计、Python开发者及AI入门人群涵盖数据采集与预处理、模型训练与推理、界面展示及语音提醒等完整流程可解决学习场景下久坐姿势不规范的实时监测问题。压缩包共15个文件包含11个Python脚本、2个data数据集、1个pth模型权重和1个mp3提醒音频整体大小仅46KB结构精简易上手。核心模块划分清晰涵盖姿态估计、数据加载、模型训练、界面展示等功能提供训练好的模型权重与语音提醒音频入口脚本和简易示例可快速启动并完整体验流程。资源已有222人学习下载适合需要快速搭建智能坐姿检测原型的读者也便于在此基础上进行算法改进或界面扩展是完成课程设计或毕业设计的高性价比参考方案。1. 坐姿检测这件事为什么必须用到深度学习和关键点坐姿检测这类任务最直观的做法是找张椅子用压力传感器或者红外测距判断“腰有没有弯”。但这套源码走的完全是另一条路用普通摄像头采集画面靠深度学习模型把人体关键点肩、颈、眼、髋从图像里捞出来再按关键点之间的几何关系判断坐姿。这意味着你不需要买任何额外硬件一台笔记本摄像头就能当监测器。正因为模型是在数据集上训练出来的换一个人、换一个背景它依然能自适应而不是死板地看“画面中有没有一条直线”。这套代码我拆过之后印象最深的是它把“训练”“推理”“提醒”串成一条完整链路。数据集、已训练好的net.pth、语音提醒文件全部带齐运行起来并不需要你去重新训练适合做毕业设计、课程实践也适合作为理解姿态估计落地的入门案例。但它不是那种黑盒 demo训练脚本和模型结构都摆在那里能改能查这一点很关键。2. 源码结构与数据流从摄像头帧到坐姿打分2.1 工程目录拆解每个.py文件到底在干什么拿到压缩包后第一件事不是急着跑而是把文件职责理清楚。这套源码的根目录是AISIT-main核心逻辑在Core子目录下训练和数据入口则在根目录。文件职责Core/module.py定义深度学习网络结构包括卷积层、全连接层以及模型前向传播逻辑Core/process.py负责图像预处理和后处理例如归一化、关键点坐标到角度值的转换Core/pose.py姿态估计相关的封装调用网络输出关键点并计算肩颈角度Core/dataSet.py数据集的读取、标签解析、数据增强返回可供模型训练的 batchCore/view.py辅助可视化把关键点和坐姿状态画到画面上方便看效果train.py训练入口设置超参数、加载数据集、训练并保存模型Model/net.pthdataSet_test.py单独测试数据加载逻辑常用于排查数据路径或标签错误main.py主程序通常负责初始化摄像头和调用处理流程simple_demo.py简化版推理演示不依赖摄像头用图片或视频文件验证模型是否可运行run.py一键启动脚本比较适合作为实际入口这个结构里Core和根目录是分离的。也就是说核心模型和工具函数都被封装成了模块训练脚本和运行脚本只是调用方。后续如果要换模型或改逻辑不需要动入口文件只需把Core里的对应模块替换掉。2.2 数据流水线dataSet.py 与 process.py 的分工我习惯把一条推理流水线分成“数据进来”和“数据出去”两部分。dataSet.py负责的是训练阶段的数据进入它会读取Data/Train目录下的图片和标签做随机翻转、亮度调整、缩放等增强然后转成张量。# Core/dataSet.py 的核心逻辑流程简化 from torch.utils.data import Dataset from PIL import Image import torchvision.transforms as transforms class PoseDataSet(Dataset): def __init__(self, img_dir, label_file): self.img_paths, self.labels load_label(label_file) self.transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(p0.5), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) def __len__(self): return len(self.img_paths) def __getitem__(self, idx): image Image.open(self.img_paths[idx]).convert(RGB) label self.labels[idx] return self.transform(image), torch.tensor(label, dtypetorch.float32)这里Resize((224, 224))不只是一个尺寸它决定网络输入固定为 224×224和module.py里第一个卷积层的输入尺寸必须一致。RandomHorizontalFlip对坐姿检测这种左右对称任务非常有效能让模型不会只记住某个方向的样本。最后Normalize用的均值方差是 ImageNet 标准参数因为预训练权重大多是按这个标准训练的。推理阶段走的是process.py它不关心 label只负责把一副画面喂给网络再把网络输出解析成“当前坐姿是否正常”。常见做法是先把图像转成与训练时相同的格式然后交给pose.py计算关键点。2.3 为什么不直接做图像分类而要用关键点距离这套源码没有走“把整张图分类成好姿势/坏姿势”的路线而是先输出人体关键点再根据关键点计算角度差。这个选择很聪明。图像分类网络对背景、人衣服颜色、体型胖瘦都极其敏感稍微换个环境分类准确率就跳水。而关键点坐标是相对稳定的语义信息只要模型能把关节定位准后续几何计算几乎不被外观影响。另外关键点方案还方便做解释。如果模型判断坐姿错误你可以把关键点和角度画出来直接看到是“脖子前倾”还是“左肩倾斜”。这对于答辩演示、查 bug 都非常有价值。相比之下一个纯分类网络只能给你一个概率值到底哪里错了无从下手。3. 模型训练与权重加载net.pth 是怎么来的3.1 数据标注与增强关键点比框更费人力但收益值得训练坐姿检测模型数据标注不是画矩形框而是标关键点坐标。常见格式是每个样本保存一张图片以及对应的左眼、右眼、左肩、右肩、左髋、右髋等点的 x、y 坐标外加一个坐姿状态标签。比如 0 表示正常1 表示驼背前倾2 表示左倾3 表示右倾。由于手标关键点成本高源码自带的Data/Train数据集必须充分利用。我一般会在训练时多做两种增强先做小范围的随机旋转让模型适应摄像头安装角度偏差再做随机遮挡模拟手部或书本挡住身体局部的情况。这种增强配合dataSet.py里的水平翻转能把小数据集的泛化能力拉高不少。训练过程中dataSet_test.py的作用是先单独检查数据和标签是否对得上。很多毕业设计跑不出效果不是模型问题而是标签文件索引错位图片和坐标没对应上。先跑这个脚本能省一晚上的排查时间。3.2 train.py 里的网络结构与损失函数Core/module.py中的网络结构是典型的卷积加全连接组合。输入是 224×224×3 的图像经过几组卷积和池化后展平送到全连接层输出两种东西关键点的坐标回归值以及坐姿类别概率。所以损失函数往往是两部分相加。# train.py 中的损失计算简化示例 import torch.nn as nn criterion_pose nn.MSELoss() # 关键点坐标回归损失 criterion_cls nn.CrossEntropyLoss() # 坐姿分类损失 for images, keypoints, labels in train_loader: pred_pose, pred_cls net(images) loss_pose criterion_pose(pred_pose, keypoints) loss_cls criterion_cls(pred_cls, labels) loss loss_pose * 0.5 loss_cls * 0.5 optimizer.zero_grad() loss.backward() optimizer.step()这里MSELoss负责让预测的关键点坐标尽量贴近标注值CrossEntropyLoss负责让坐姿分类正确。权重系数0.5和0.5表示两项任务同等重要实际训练时可以根据观察调整如果坐标收敛慢就把坐标权重调大。优化器一般用 Adam学习率从1e-3起步。3.3 加载训练好的模型读取 net.pth 的完整流程训练完成后net.pth被保存到Model目录。这个文件可能是完整模型对象也可能只是state_dict字典。为了两边都兼容我建议写通用加载代码。# 加载训练好的模型权重 import torch from Core.module import PoseEstimationNet net PoseEstimationNet() checkpoint torch.load(Model/net.pth, map_locationcpu) if state_dict in checkpoint: net.load_state_dict(checkpoint[state_dict]) else: net.load_state_dict(checkpoint) net.eval() print(模型加载完成参数数量:, sum(p.numel() for p in net.parameters()))map_locationcpu是这里的关键参数。如果训练时用了 GPU而你现在只有 CPU没有这个参数会直接报 CUDA 错误。加上它之后权重会被映射到 CPU 张量推理时就不需要独显。net.eval()会关闭 dropout 和 batch norm 的训练状态这一点经常有人忘掉导致每次前向传播结果都不一样。4. 实时检测与语音提醒把模型跑起来并让它“开口说话”4.1 run.py / main.py 的启动逻辑run.py是实际入口它的生命周期可以拆成三步初始化摄像头、循环读取帧、退出释放资源。主循环里每一帧都要经过process.py或pose.py做姿态估计然后把结果传给view.py画框同时根据状态决定是否播放语音。# run.py 主循环逻辑简化 import cv2 from Core.process import preprocess_frame from Core.pose import estimate_pose from Core.view import draw_result cap cv2.VideoCapture(0) # 0 代表默认摄像头 while True: ret, frame cap.read() if not ret: break input_tensor preprocess_frame(frame) # 预处理返回 1x3x224x224 keypoints, cls_idx estimate_pose(input_tensor) draw_result(frame, keypoints, cls_idx) cv2.imshow(Smart Sitting Posture, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()VideoCapture(0)里的0是摄像头索引。笔记本一般用0外接摄像头可能是1或2这需要你自己确认。主循环里的waitKey(1)控制画面刷新频率数值越小刷新越快但也不能为 0否则按下按键不会触发退出判断。4.2 坐姿判断规则与阈值设定关键点出来后怎么判断“坐姿不好”源码里最常用的规则是计算三个角度肩膀连线与水平线的夹角、脖子与肩膀的角度、眼睛到屏幕中心线的偏移量。比如左右肩关键点的 y 坐标差超过一定像素就认为身体向一侧倾斜。# pose.py 中计算肩膀水平角度 import math def compute_shoulder_angle(left_shoulder, right_shoulder): dx right_shoulder[0] - left_shoulder[0] dy right_shoulder[1] - left_shoulder[1] angle math.degrees(math.atan2(abs(dy), abs(dx))) return angle # 判定逻辑 angle compute_shoulder_angle(kp[left_shoulder], kp[right_shoulder]) if angle 75: posture_state slouching这里的阈值75对应人体站立时肩膀通常接近水平。如果你把摄像头装在侧面角度值可能整体偏移需要重新标定。我一般会在代码里加一个校准模式先让人坐直记录基准角度再让偏差量作为阈值依据这样比死绝对值更鲁棒。math.atan2之所以用abs(dy)是为了避免左右肩谁高谁低带来的符号干扰。4.3 语音提醒用 audio.mp3 做超时和冷却控制语音提醒是整个系统最直观的点。Audio/audio.mp3就是用来播放“请注意坐姿”的音频文件。播放方式上源码常见的做法是调用playsound库但那个库在某些 Windows 环境下会卡主线程。我更推荐用pygame.mixer初始化它可以异步播放不阻塞画面刷新。# 语音提醒模块带冷却时间 import time import pygame pygame.mixer.init() last_alert_time 0 alert_cooldown 8 def alert_if_needed(posture_state): global last_alert_time if posture_state ! normal: now time.time() if now - last_alert_time alert_cooldown: pygame.mixer.music.load(Audio/audio.mp3) pygame.mixer.music.play() last_alert_time now这里的alert_cooldown是防止系统每帧都播放语音。坐姿异常可能持续几十秒没有冷却时间的话语音会原地爆炸。通常 5 到 8 秒播放一次比较合适。如果你想让提醒更温和可以在pygame.mixer.music.set_volume(0.6)降低音量。另一个细节是pygame.mixer.init()只调用一次别放在循环里否则会反复重新初始化声卡。5. 复现与排错让这个项目在自己电脑上跑通并快速验证5.1 环境配置这个项目对算力要求不高CPU 也能跑但需要装对依赖包。我的建议是用 conda 单独建一个 Python 3.8 环境避免和其他项目冲突。关键依赖是PyTorch、OpenCV、numpy、Pillow、pygame。其中 PyTorch 的 CPU 版本大约 200MB安装命令如下conda create -n posture python3.8 conda activate posture pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install opencv-python numpy Pillow pygame不要在这里追新版本PyTorch 1.x 到 2.x 都能运行关键是和Core/module.py里调用的 API 兼容。如果加载权重时报Missing key(s) in state_dict说明网络定义层名和保存的权重层名不一致先检查module.py类名和顺序。5.2 常见报错与解决办法我自己跑这类项目时遇到过三类高频问题。第一类是路径问题压缩包解压后如果是AISIT-main/AISIT-main两层嵌套直接运行python run.py会找不到Model和Audio目录检查当前工作目录是否正确。第二类是摄像头初始化失败。cv2.VideoCapture(0)返回False通常是因为摄像头被浏览器或微信占用。关闭占用程序或者把索引改成1再试。第三类是模型加载报size mismatch。出现这个多半是训练时改了网络输出维度但net.pth是旧权重。这种情况没有捷径只能重新训练或者去下载和源码匹配的权重版本。5.3 用 simple_demo.py 做快速验证不需要摄像头也能验证整个链路是否通畅。simple_demo.py存在的意义就是作为模型、数据加载、逻辑判断的“冒烟测试”。把一张坐姿图片放到指定目录然后运行它只要不报错模型基本没问题。python simple_demo.py --image test_sit.jpg我建议在跑实时摄像头前先跑通这个命令。它能帮你确认三件事net.pth能加载、图像预处理能运行、坐姿判断逻辑能输出结果。如果这个 demo 都卡住那问题一定在模型或数据层而不是摄像头。实时检测再慢也只是在逐帧调用相同的推理逻辑所以调试时千万不要一上来就纠缠视频流。等 demo 通了再打开run.py加上cv2.imshow查看可视化结果。本文还有配套的精品资源点击获取