ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

人体姿态估计与几何判定:翻越栏杆检测全流程实战

2026/9/13 22:40:56 拓冰建站 浏览量
人体姿态估计与几何判定:翻越栏杆检测全流程实战 简介基于人体姿态估计的翻越栏杆检测赛题项目包来自极市平台竞赛面向计算机视觉学习者、竞赛参与者和人工智能相关专业学生聚焦监控场景下翻越栏杆行为的自动识别与判定。项目融合YOLO目标检测与人体姿态估计算法覆盖目标框选、关键点提取、行为分类到结果后处理的完整流程源码经过严格测试验证可正常运行并配有README说明便于快速上手。资源共49个文件以Python脚本为核心包含训练、推理、后处理及配置模块另有bat/sh运行脚本、yaml参数文件、ipynb交互示例和文档资料压缩包约30.26MB目录结构清晰、易于定位关键代码。读者可获得一套完整的赛题解决方案既可直接运行看效果也能学习姿态估计在真实安防场景中的落地思路还可修改模型参数、阈值和后处理逻辑来适配不同数据。目前已有178人学习下载非常适合作为毕业设计、课程作业或算法研究的项目参考。1. 为什么翻越栏杆检测要用人体姿态估计先理解任务边界一个反复出现的误区是把翻越栏杆检测当成普通的视频分类任务先给目标检测框再用3D CNN判断“翻到底翻了没有”。这种思路天然缺少一个关键中间量——栏杆和身体的空间关系。姿态估计输出的脚踝、膝盖、髋关节坐标能把“跨越”变成一组可计算的几何事件这也是极市平台这类竞赛把人体姿态估计作为解题前置环节的原因。如果你已经有目标检测基础但还没接触过姿态估计这个赛题正好补上从“找得到人”到“理解人的动作”的一步。赛题包通常给出监控视频片段、目标框或关键点标注、评测脚本要求返回翻越栏杆行为发生的时间区间并在对应帧用人体框把行为主体标出来。下面按“赛题包结构、关键点几何判定、模型训练、阈值与评测”的顺序展开讲的是做这一类任务最常见的一线流程拿到任何同类数据都能直接套用。2. 解析翻越栏杆检测赛题包关键点标注与数据组织极市平台常见的姿态估计竞赛赛题包不会只丢给你一段视频压缩包里通常还有数据集说明、标注文件夹、评测脚本和提交样例。先不要急着训练第一步要把数据格式读准尤其是关键点坐标放在什么坐标系、事件标签是逐帧还是片段级。2.1 先解压并用脚本列出目录结构拿到基于人体姿态估计的翻越栏杆检测 极市平台竞赛赛题.zip后我会先列目录不把整个包解出来unzip -l 基于人体姿态估计的翻越栏杆检测 极市平台竞赛赛题.zip | head -50这个命令列出压缩包前50条条目能快速看出train、val、test、annotations的分布。如果包含视频目录名一般是视频ID如果包含抽帧图片目录名一般是帧号。head -50是防止有些打包文件包含几千张小图导致终端输出爆炸如果只想找标注文件可以改成unzip -l xxx.zip | grep json。解压完成后我的习惯是先把标注文件打开看一眼。如果提供的是COCO风格标注通常包含images、annotations、categories三层。但有些翻越栏杆赛题会改成自定义JSON字段名不固定所以先打印键名是最稳妥的import json with open(annotations/train.json, r, encodingutf-8) as f: data json.load(f) print(data.keys()) print(data[annotations][0] if annotations in data else data[samples][0])这段代码的作用是确认三件事标注里有没有关键点关键点的数量是17还是其他值每个样本是按“单帧”还是“视频片段”记录。翻越栏杆检测如果用姿态估计来做通常关键点是COCO 17点但如果赛题把“栏杆上下沿”“脚底触点”也标成关键点索引和数量都会变化后面所有几何判定都要跟着改。先打印第一个样本能避免拿通用模型底座硬套自定义标签。注意如果赛题包只提供视频和事件标签没有关键点标注不要急着放弃。先自己跑一个公开姿态模型生成关键点再走几何判定仍然能得到不错的基线。2.2 整理成统一的关键点时间序列不论原始标注是单帧坐标还是视频片段最好先转成长表视频ID、帧号、目标ID、关键点数组、置信度、翻越标签。我本地一般用CSV或纯文本缓存后面要反复做统计和后处理每次都读JSON太慢。表翻越栏杆检测任务中常用关键点索引索引关键点名称在翻越判定中的作用0nose判断头部是否低于栏杆5/6left/right shoulder区分正身、侧身翻越11/12left/right hip计算重心高度变化13/14left/right knee捕捉腿部抬跨动作15/16left/right ankle越过栏杆线的主要判定点如果赛题包只给了目标框而没有关键点就要先跑一次公开的姿态估计模型生成关键点。这一步的准确率会直接影响到最终事件判定我通常用RTMPose或YOLOv8-pose先跑一遍视频并把置信度一起存下来import cv2 from ultralytics import YOLO model YOLO(yolov8n-pose.pt) cap cv2.VideoCapture(videos/0001.mp4) frame_id 0 with open(keypoints_0001.txt, w) as f: while True: ret, frame cap.read() if not ret: break results model(frame, verboseFalse)[0] # keypoints.data 的形状是 [人数, 17, 3]最后一维为 x, y, confidence for person in results.keypoints.data: kpt person.cpu().numpy() f.write(f{frame_id} {kpt.tolist()}\n) frame_id 1 cap.release()yolov8n-pose.pt是轻量姿态模型适合快速生成伪标签和验证方案frame_id用来对齐视频帧。这段代码把每一帧所有检测到的目标关键点压成一行文本后面做状态机读取时比JSON更省内存。注意results.keypoints.data的维度是[检测人数, 17, 3]如果视频里有多个人每组关键点都来自不同的人后续要根据目标框位置或轻量跟踪器区分。2.3 用统计脚本看正负样本分布生成关键点序列后先按标签做一次分布统计比直接训练更有价值import collections labels [] for line in open(annotations/train.txt): vid, event_start, event_end line.strip().split() labels.append((vid, int(event_start), int(event_end))) print(视频总数:, len(set(v[0] for v in labels))) print(事件样本数:, len(labels))统计结果可以帮助确定后续阈值方向。如果事件样本只有几十条深度学习分类头很容易过拟合应该主要靠姿态关键点加几何规则如果正样本视频很多可以在状态机后面再接一个轻量分类器。另一个常见问题是标注只给了事件起止帧中间可能包含“抬腿但没过去”的负样本这会让单帧分类任务的定义变得模糊所以我在判定逻辑里会区分“跨线”和“完成翻越”后处理阶段再输出事件级结果。3. 从关键点序列到穿越事件翻越行为的几何判定姿态估计输出的只是“脚踝在那个位置”真正决定是否翻越的是脚踝和栏杆参考线的位置关系。很多实现直接用模型最后的分类概率这样不好调试我习惯自己写几何判定因为可以把“A侧到B侧、抬起身体、落地”拆成三个可解释的条件每一个阈值都可以单独对着验证集调。3.1 定义栏杆线并计算相对位置在每个视频里手动标一次栏杆的两个端点以像素坐标保存。比如从画面上读出起点300,240和终点800,240表示一条水平栏杆如果监控角度造成透视栏杆也可能是斜线这不影响后续计算因为用的是向量叉积而不是直接比较y坐标。表状态机中的三种状态状态触发条件含义0双脚在栏杆同一侧正常通行1任一只脚跨过栏杆线但髋部高度未超过阈值跨腿试探/跨越中2状态1后脚踝保持对侧或回到同侧且持续时间足够判定为一次翻越3.2 用叉积判断脚踝相对栏杆在哪一侧判断一个点在线段左侧还是右侧最稳定的是二维叉积代码实现很简单def side_of_line(p, line_start, line_end): 返回点在直线哪一侧正为B侧负为A侧接近0为在线附近 return (line_end[0] - line_start[0]) * (p[1] - line_start[1]) - ( line_end[1] - line_start[1] ) * (p[0] - line_start[0]) def ankle_sides(kpts, line): left_ankle kpts[15][:2] right_ankle kpts[16][:2] return side_of_line(left_ankle, line[0], line[1]), side_of_line(right_ankle, line[0], line[1])代码里line[0]和line[1]分别是栏杆端点kpts是当前帧的17个关键点。叉积的符号等价于点在直线哪一侧数值大小与点到线的距离有关。需要注意的是单次符号变化不能直接当作翻越姿态估计在脚踝快速移动时常出现抖动一个脚踝的符号可能在连续两三帧内来回跳所以下一小节要加“至少连续三帧位于异侧”的约束。3.3 加入髋部高度和持续帧数的事件状态机如果只看脚踝侧别任何一个“迈腿跨过栏杆又收回来”的动作都会被误报。翻越栏杆的特点不仅是位置变化重心也会发生变化最明显的特征是髋关节高度升高并前移。状态机可以写成这样def detect_crossing_event(seq, line, hip_high0.35, need_frames3): state 0 count 0 crossed_frame 0 frame_h max(k[11][1] for k in seq) 1e-6 for i, kpts in enumerate(seq): s_l, s_r ankle_sides(kpts, line) crossed (s_l * s_r 0) or (abs(s_l) 10 and abs(s_r) -10) hip_y (kpts[11][1] kpts[12][1]) / 2 if crossed and hip_y hip_high * frame_h: if state 0: state 1 crossed_frame 0 elif state 1: crossed_frame 1 if crossed_frame need_frames: count 1 state 2 elif state 2: state 0 return count这个状态机从“双脚同侧”进入“越线”并统计连续越线帧数。hip_high是按帧高归一化后的髋部高度阈值通常设到0.35到0.45之间太低会把蹲着系鞋带误判为翻越太高又会漏掉俯身翻越。need_frames一般设为3用来过滤单帧姿态跳变。判断crossed时我用了“双脚符号异号”或“单脚明显在另一侧”两种情况。前者适合检测跨越栏杆中部的位置后者适合检测在栏杆端点绕过去的人。不过绕行在语义上不算翻越是否计数要看赛题定义极市平台多数翻越栏杆检测赛题把“人体躯干越过栏杆后方边界”作为正样本所以几何判定比分类器更容易对齐这个口径。3.4 时间维度的滑窗合并逐帧状态机输出往往是离散片段直接提交会带来大量重复检测。我会先用滑窗把连续“翻越中”的帧合并成一个事件区间并输出事件中心帧和起止帧def merge_ranges(pred, max_gap5, min_len10): ranges [] start None last None for i, flag in enumerate(pred): if flag: if start is None: start i last i elif start is not None and i - last max_gap: if last - start 1 min_len: ranges.append((start, last)) start None if start is not None and last - start 1 min_len: ranges.append((start, last)) return rangesmax_gap5允许事件中间有至多5帧被姿态模型漏掉min_len10表示一个事件至少要连续10帧避免仅凭一两帧的姿态抖动报警。事件判定以后给每条事件算一个分数常用的分数是“跨越期间的脚踝平均距离髋部高度变化比例”这个分数用于后续阈值选择和竞赛提交排序。4. 姿态估计模型选型与训练细节面向翻越栏杆比赛场景前面的几何判定默认你已经有可用的关键点序列如果没有标注模型选型就直接决定了任务上限。4.1 选择带人体框的姿态估计模型而不是直接做视频分类在极市平台这类比赛里最快的起步方式是用COCO预训练的姿态估计模型。三个主流选择RTMPose、HRNet、YOLOv8-pose。YOLOv8-pose把检测和姿态放在同一个网络里适合视频里同时出现多个行人RTMPose在速度和精度上相对均衡适合长视频推理HRNet在遮挡场景下更稳因为高分辨率特征能保留更多细节但显存占用和推理时间明显变大。表翻越栏杆检测常用姿态估计模型模型输入尺寸是否输出检测框推理速度适用情况RTMPose-t256x192否快单目标、实时在线检测HRNet-w32384x288否中目标遮挡较多HigherHRNet512x512否慢目标很小、密集人群YOLOv8-pose640x640是快多目标、需要同时输出人体框如果你用HRNet这类单阶段姿态估计需要额外接入一个人体检测器先框人再送姿态网络。我一般用YOLOv8做人体检测HRNet做关键点两个模型解耦调姿态阈值时不会影响检测结果。4.2 关键数据预处理与增强参数姿态估计训练时输入尺寸常见的是256x192或384x288。翻越栏杆检测有别于通用姿态估计的地方是栏杆经常挡住腿部所以随机遮挡增强不能只做矩形随机遮挡还要能遮住画面下半部分。用MMPose训练时我的基础配置大致长这样train_pipeline [ dict(typeLoadImageFromFile), dict(typeGetBBoxCenterScale), dict(typeRandomFlip, prob0.0), # 翻越方向敏感不开启随机翻转 dict(typeRandomBBoxTransform, scale_factor[0.75, 1.25], rotation_factor30), dict(typeTopdownAffine, input_size(192, 256)), dict(typeGenerateTarget, encoderMSRA, sigma2), ]scale_factor控制随机缩放模拟人从远到近接近栏杆rotation_factor模拟监控视角的轻微倾斜。这里把RandomFlip的概率设为0原因是翻越栏杆有左右方向语义从左边翻和从右边翻在坐标符号上是反的如果水平翻转关键点坐标会换到身体另一侧但事件标签没有变会让脚踝侧别关系学习混乱。如果使用YOLOv8-pose训练内置增强参数较多重点是degrees和translate。degrees控制在±10度因为监控摄像头几乎不会大幅度旋转translate控制在±0.2模拟行人在画面中的位置变化。其他增强按COCO预设置即可不要为了提升mAP而加入过大的旋转角度。4.3 置信度过滤和多人跟踪减少误报源姿态估计模型可能在栏杆遮挡下半身时输出非常差的关键点。如果直接把坏关键点送到状态机只要有一点位置误差就会误报。我每帧都会做一次置信度过滤def filter_by_confidence(kpts, threshold0.4): # kpts shape 是 [17, 3]最后一维为置信度 for i, point in enumerate(kpts): if point[2] threshold: kpts[i][0] np.nan kpts[i][1] np.nan return kpts脚踝置信度低于threshold时把它设为nan这样第3章的几何判定会跳过该脚踝不会把不可信位置当成跨线。阈值太小会让错误脚踝进入判定阈值太大会大量丢失真实跨越帧。我在验证集上会额外统计“脚踝置信度低于0.4的帧数占比”一般要控制在30%以内超过这个值说明模型或输入分辨率不够。多人场景还要做时间上的目标关联。最简单的是基于检测框IoU的匈牙利匹配def match_tracks(prev_boxes, curr_boxes, iou_min0.3): import numpy as np from scipy.optimize import linear_sum_assignment if not prev_boxes or not curr_boxes: return [] iou_matrix np.zeros((len(prev_boxes), len(curr_boxes))) for i, pb in enumerate(prev_boxes): for j, cb in enumerate(curr_boxes): iou_matrix[i, j] compute_iou(pb, cb) rows, cols linear_sum_assignment(-iou_matrix) return [(r, c) for r, c in zip(rows, cols) if iou_matrix[r, c] iou_min]iou_min建议取0.3到0.5。太小会让轨迹频繁跳变太大对快速移动的人会跟丢。翻越栏杆动作发生时人往往从画面一侧接近栏杆再离开目标框位移较大只用IoU不够稳我还会加入关键点距离的加权代价但竞赛初期用IoU匹配已经能跑通不需要一上来就接DeepSORT。4.4 训练损失和事件级验证姿态估计最常用的是基于OKS的损失或MSE热图损失。OKS考虑了关键点相对目标框的尺度适合不同远近的目标MSE对热图误差更均匀。对于翻越栏杆脚踝的细微误差会对侧别判断产生较大影响我会在训练时给脚踝热图加一份额外的损失loss orig_loss 0.5 * mse_loss(ankle_heatmap)这里的0.5是脚踝热图损失的额外权重属于经验值。这样做能缩小脚踝关键点的热图误差让叉积符号在关键帧上更稳定。每训练一个epoch同时计算关键点mAP和事件级F1并只按事件级F1选模型关键点mAP提升不代表翻越检测准确率同步提升。5. 评测指标与阈值标定翻越栏杆检测的调优技巧比赛提交前必须搞清楚评测口径。极市平台这类赛题的常见评测方式有两种一种是事件级检测要求给出事件起止时间和置信度用时间IoU大于0.5算命中另一种是逐帧输出翻越状态再用逐帧精确率、召回率计算F1。前者更接近实际安防需求后者的实现更简单。我一般先按帧级跑通再转成事件级。5.1 先跑通官方评测脚本不要自己写一套评测就提交。先把赛题包里的评估代码跑一遍重点确认输出的时间单位是秒还是帧以及提交结果是否需要减去视频片段内的起始帧偏移。我见过不少提交结果全部事件错位原因就是忘了加片段偏移量。5.2 按顺序调三个阈值调参顺序建议是先调后处理再调关键点置信度最后再换模型。三个必调参数如下参数推荐范围调大/调小的影响need_frames3~10帧调大更稳但会漏掉快速翻越hip_high0.35~0.45调大漏检坐姿翻越调小误报蹲下conf_threshold0.3~0.6调大减少遮挡误检调小保留更多跨越帧我用验证集上的“事件级F1”做选择。候选事件分数定义为跨越期间左右脚踝侧别变化次数与髋部高度均值之和然后对测试集按分数从高到低排序让评测脚本按分数算PR曲线。5.3 一次快速验证事件后处理的命令模型固定以后调后处理参数不需要重新训练。可以把保存好的关键点序列喂给判定脚本快速验证python detect_crossing.py \ --kpts keypoints_val.txt \ --line 300,240,800,240 \ --hip-threshold 0.38 \ --min-frames 5 \ --max-gap 5 pred.json python eval_segments.py \ --gt annotations/val.json \ --pred pred.json \ --iou 0.5第一条命令生成事件格式的预测结果第二条用分割评估脚本计算事件级F1。如果--min-frames从3调到5F1明显上升说明抖动是主要误报源如果F1下降说明真实翻越动作的连续帧数本来就少于5这时应减小--hip-threshold并优先提高姿态模型输入分辨率把腿部关键点做稳。本文还有配套的精品资源点击获取