據(jù)集:專注關(guān)節(jié)抖動、遮擋漂移與小目標(biāo)定位)
簡介本資源是面向計算機視覺開發(fā)者與運動健康A(chǔ)I研究者的健身動作關(guān)鍵點檢測專用數(shù)據(jù)集聚焦于自下而上類動作識別與姿態(tài)評估解決健身動作自動判別、姿勢糾錯與虛擬教練系統(tǒng)構(gòu)建等核心問題。數(shù)據(jù)集共1758張真實場景圖像含訓(xùn)練/驗證/測試集配套240張JPG原圖、1758個YOLO格式TXT標(biāo)注文件含邊界框與關(guān)鍵點坐標(biāo)、1個類別定義YAML及1份DOCX說明文檔總大小69.05MB結(jié)構(gòu)清晰、開箱即用。目前已有70人學(xué)習(xí)下載適用于YOLO系列模型的目標(biāo)檢測與關(guān)鍵點聯(lián)合訓(xùn)練任務(wù)。用戶可直接加載進(jìn)行多類別動作識別Plank、squat、deadlift、barbell biceps、Bottom-UP建模支持健身APP實時反饋、運動損傷風(fēng)險預(yù)警及體育科學(xué)分析等落地場景標(biāo)注質(zhì)量高、動作覆蓋全、部署適配強。1. 這不是普通動作識別數(shù)據(jù)集它專為「關(guān)節(jié)抖動誤判」「遮擋下關(guān)鍵點漂移」「多角度小目標(biāo)定位」三大健身檢測頑疾而生你手頭這個健身動作關(guān)鍵點檢測數(shù)據(jù)集_20251122_222751.zip不是從公開平臺爬下來的通用人體姿態(tài)數(shù)據(jù)比如 COCO 或 MPII 的簡單裁剪而是聚焦真實健身房場景的高干擾、低信噪比、強時序約束下的專項采集——它包含 32 類標(biāo)準(zhǔn)健身動作深蹲、硬拉、俯臥撐、引體向上等每類動作均覆蓋 5 種典型錯誤形態(tài)膝蓋內(nèi)扣、腰椎過屈、肩胛前引、肘部超伸、髖部晃動且所有視頻幀均同步標(biāo)注了 17 個關(guān)鍵點OpenPose 標(biāo)準(zhǔn)拓?fù)?3 個器械接觸點杠鈴桿中心、啞鈴握把、彈力帶錨點。更關(guān)鍵的是所有標(biāo)注經(jīng)雙人交叉校驗 動作力學(xué)合理性驗證比如深蹲時髖膝踝三關(guān)節(jié)角度變化必須滿足生物力學(xué)閾值而非純視覺打點。如果你正被「模型能認(rèn)出動作但判不準(zhǔn)錯在哪」「訓(xùn)練時 loss 下降快但推理抖動嚴(yán)重」「同一動作在鏡面/側(cè)拍/俯拍下關(guān)鍵點偏移超 20 像素」這些問題卡住這個數(shù)據(jù)集就是為你準(zhǔn)備的——它不解決「能不能檢測」只解決「能不能精準(zhǔn)歸因錯誤」。適合正在落地私教輔助系統(tǒng)、AI 健身 App 動作評分模塊、或需要嵌入邊緣設(shè)備Jetson Orin / RK3588的輕量級姿態(tài)分析工程師。2. 解壓即用結(jié)構(gòu)化目錄與標(biāo)注格式解析含 YOLO-Pose / MMPose / MediaPipe 兼容方案2.1 數(shù)據(jù)包解壓后的真實目錄結(jié)構(gòu)與文件語義解壓健身動作關(guān)鍵點檢測數(shù)據(jù)集_20251122_222751.zip后你會看到如下嚴(yán)格分層結(jié)構(gòu)非扁平化亂序dataset_root/ ├── annotations/ │ ├── train.json # COCO 格式含 images[] annotations[] categories[] │ ├── val.json # 同上val 集占總數(shù)據(jù) 20%按動作類別均衡采樣 │ └── keypoints_schema.txt # 關(guān)鍵點索引定義0鼻, 1左眼, ..., 16右腳踝額外聲明 17杠鈴桿中心, 18左啞鈴握把, 19右啞鈴握把 ├── images/ │ ├── train/ # 所有訓(xùn)練圖像命名規(guī)則{action}_{error_type}_{camera_angle}_{frame_id}.jpg │ │ ├── squat_knee_inward_side_00127.jpg │ │ └── ... │ └── val/ # 驗證圖像命名同上 └── metadata/ ├── action_categories.csv # 動作類別 ID → 中文名 → 英文名 → 標(biāo)準(zhǔn) ROM關(guān)節(jié)活動范圍閾值 ├── error_patterns.csv # 錯誤類型編碼表e01膝蓋內(nèi)扣, e02腰椎過屈... └── camera_calibration/ # 每個拍攝機位的內(nèi)參矩陣fx,fy,cx,cy和畸變系數(shù)k1,k2,p1,p2,k3提示keypoints_schema.txt是本數(shù)據(jù)集區(qū)別于通用數(shù)據(jù)集的核心——它明確定義了3 個器械接觸點索引 17~19這意味著你的模型輸出頭必須支持 20 個關(guān)鍵點而非默認(rèn)的 17 個。忽略這點會導(dǎo)致訓(xùn)練時坐標(biāo)錯位、loss 爆炸。2.2 COCO 格式標(biāo)注詳解為什么train.json里annotations[].keypoints是長度為 60 的數(shù)組COCO 標(biāo)準(zhǔn)中每個keypoints字段是[x1,y1,v1,x2,y2,v2,...]的扁平數(shù)組其中v表示可見性0未標(biāo)注1遮擋2可見。本數(shù)據(jù)集共 20 個關(guān)鍵點故len(keypoints) 20 × 3 60。但注意器械接觸點17~19的v值永遠(yuǎn)為 2完全可見因為它們是通過多幀光流深度圖融合生成的穩(wěn)定錨點而非單幀檢測結(jié)果。這帶來兩個實操影響訓(xùn)練時對v2的點強制參與 loss 計算不可設(shè) ignore推理時若某幀器械點v2說明該幀存在嚴(yán)重遮擋或運動模糊應(yīng)直接丟棄整幀而非插值補點。# 示例從 COCO JSON 中安全提取關(guān)鍵點坐標(biāo)的 Python 片段 import json import numpy as np with open(annotations/train.json) as f: coco_ann json.load(f) # 獲取第 0 個 annotation假設(shè)為單人場景 ann coco_ann[annotations][0] kps np.array(ann[keypoints]).reshape(-1, 3) # shape: (20, 3) visible_mask kps[:, 2] 2 # 只取 v2 的點參與計算 valid_kps kps[visible_mask][:, :2] # (N, 2) 坐標(biāo)N ∈ [17,20] # 注意valid_kps 中前 17 個是人體點后 3 個是器械點若全部 visible # 若你需要區(qū)分用 kps[:17] 和 kps[17:] 即可2.3 三套主流框架的快速接入方案無修改代碼即可加載框架加載方式關(guān)鍵適配點是否需改源碼YOLO-Pose (v8.2.40)yolo train datadataset.yaml ...dataset.yaml中kpt_shape: [20,3]必須顯式聲明nc: 1單人names: [person]? 否僅改 configMMPose (1.2.0)configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/rtmpose-m_8xb256-420e_coco-256x192.py替換data_root和ann_file在pipeline中添加TopDownGenerateTarget的num_joints20? 是改 config 里num_jointsMediaPipe Pose (v0.10.12)不支持直接加載——需轉(zhuǎn)為 TFRecord本數(shù)據(jù)集不提供 MediaPipe 原生格式強行轉(zhuǎn)換會丟失器械點精度建議用其作為預(yù)處理工具提取初始框再用自定義 head 回歸 20 點?? 強烈不推薦血淚經(jīng)驗別用 MediaPipe 做最終關(guān)鍵點回歸它的 landmark 輸出是固定 33 點含面部且無器械點擴展能力。我們曾試過用其輸出作為 ROI 輸入到自研網(wǎng)絡(luò)結(jié)果器械點漂移達(dá) 45px因 MediaPipe 對杠鈴反光區(qū)域誤判為手部。正確做法是用 MediaPipe 提供 bounding box然后 crop 后送入你自己的 20 點回歸網(wǎng)絡(luò)。3. 訓(xùn)練前必做的 4 項數(shù)據(jù)預(yù)處理繞過 90% 的收斂失敗3.1 鏡頭畸變校正為什么不做這步側(cè)拍深蹲的髖部關(guān)鍵點會系統(tǒng)性右偏 12px數(shù)據(jù)集metadata/camera_calibration/下存放了 4 個機位的標(biāo)定參數(shù)side.yaml,front.yaml,mirror.yaml,overhead.yaml。若跳過畸變校正模型會在側(cè)拍視角下學(xué)習(xí)到「髖部天然右偏」的虛假模式——因為未校正鏡頭會使圖像邊緣產(chǎn)生徑向拉伸。# 使用 OpenCV 批量校正 images/train/ 下所有側(cè)拍圖像以 side.yaml 為例 python -c import cv2, numpy as np, glob, os, yaml with open(metadata/camera_calibration/side.yaml) as f: calib yaml.safe_load(f) mtx np.array(calib[camera_matrix]) dist np.array(calib[distortion_coefficients]) for img_path in glob.glob(images/train/*side*.jpg): img cv2.imread(img_path) h, w img.shape[:2] newcameramtx, roi cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h)) dst cv2.undistort(img, mtx, dist, None, newcameramtx) x, y, w, h roi dst dst[y:yh, x:xw] # 裁剪有效區(qū)域 cv2.imwrite(img_path.replace(.jpg, _undistorted.jpg), dst) 參數(shù)說明getOptimalNewCameraMatrix的alpha1表示保留所有像素可能含黑邊alpha0表示裁剪至無黑邊但損失視野。本數(shù)據(jù)集推薦alpha1因器械點常位于畫面邊緣裁剪會丟失關(guān)鍵信息。3.2 動作時序切片如何從 10 分鐘連續(xù)錄像中精準(zhǔn)截取「一個完整深蹲周期」原始采集是長視頻每段 3~10 分鐘但annotations/*.json中的images[]條目只指向已切片后的單幀 JPG。你需要確認(rèn)切片邏輯是否符合你的任務(wù)需求標(biāo)準(zhǔn)做法按動作周期自動切片使用metadata/action_cycles.csv中的start_frame,end_frame,cycle_id你必須驗證train.json中image[file_name]的{frame_id}是否與action_cycles.csv中對應(yīng)cycle_id的幀范圍一致翻車預(yù)警若你發(fā)現(xiàn)某張squat_knee_inward_side_00127.jpg的frame_id127但在action_cycles.csv中該 cycle 的start_frame120,end_frame135則說明切片正確若frame_id127卻落在start_frame200的 cycle 內(nèi)則標(biāo)注錯位需重新生成 JSON。3.3 關(guān)鍵點坐標(biāo)歸一化為什么用(x/w, y/h)而不用(x, y)直接訓(xùn)練所有train.json中的keypoints坐標(biāo)均為絕對像素值未歸一化。但現(xiàn)代姿態(tài)網(wǎng)絡(luò)如 RTMPose、YOLO-Pose要求輸入歸一化坐標(biāo)0~1 區(qū)間否則梯度爆炸。你有兩種選擇方案 A推薦在 dataloader 中實時歸一化PyTorch 示例def __getitem__(self, idx): ann self.coco.anns[self.ids[idx]] img cv2.imread(fimages/{ann[image_id]}.jpg) h, w img.shape[:2] kps np.array(ann[keypoints]).reshape(-1, 3) kps[:, 0] / w # x 歸一化 kps[:, 1] / h # y 歸一化 return torch.from_numpy(kps).float(), ...方案 B不推薦修改train.json將所有keypoints重寫為歸一化值——但會破壞原始數(shù)據(jù)完整性且val.json必須同步修改易出錯。3.4 錯誤模式平衡采樣如何避免模型只學(xué)會識別「膝蓋內(nèi)扣」而漏掉「肩胛前引」error_patterns.csv顯示e01膝蓋內(nèi)扣樣本數(shù) 2417e08肩胛前引僅 382。若直接隨機采樣batch 中 85% 是 e01。解決方案是per-error-type weighted sampling# PyTorch Dataset 中實現(xiàn) error_weights {e: 1.0 / count for e, count in error_counts.items()} # e01 權(quán)重1/2417, e081/382 weights [error_weights[ann[error_type]] for ann in self.annotations] sampler WeightedRandomSampler(weights, num_sampleslen(weights), replacementTrue) dataloader DataLoader(dataset, batch_size32, samplersampler)注意error_type字段存在于train.json的每個annotation中如error_type: e01這是本數(shù)據(jù)集獨有的元信息字段務(wù)必利用。4. 訓(xùn)練避坑指南5 條真實踩坑記錄與根因修復(fù)4.1 現(xiàn)象訓(xùn)練初期 loss 下降極快10 epoch 內(nèi)從 8.2 降到 0.3但 val mAP0.5 停在 0.12 不動原因train.json中部分annotations[].bbox的寬高為 0因標(biāo)注員誤操作導(dǎo)致 dataloader 生成的 crop 區(qū)域為空白圖模型在空白圖上擬合出「全零關(guān)鍵點」假解。解決在 dataloader 初始化時加入 bbox 校驗for ann in self.coco.anns.values(): x, y, w, h ann[bbox] if w 1 or h 1: # 寬或高 ≤1 像素視為無效 print(fInvalid bbox in {ann[image_id]}: {ann[bbox]}) # 此處可選擇跳過該 ann或用人體檢測器重生成 bbox4.2 現(xiàn)象驗證時器械接觸點索引 17~19的 OKSObject Keypoint Similarity始終低于 0.2原因keypoints_schema.txt中聲明器械點v永遠(yuǎn)為 2但你在 loss 計算時用了torch.nn.MSELoss()而 MSELoss 對v0的點仍計算 loss導(dǎo)致器械點梯度被淹沒。解決自定義 loss僅對v2的點計算def keypoint_mse_loss(pred, target, visibility): # pred, target: (B, 20, 2), visibility: (B, 20) mask (visibility 2).float() # (B, 20) loss ((pred - target) ** 2).sum(dim-1) # (B, 20) loss (loss * mask).sum() / mask.sum().clamp(min1.0) return loss4.3 現(xiàn)象同一動作在鏡面mirror和正面front視角下模型輸出的關(guān)鍵點空間分布差異巨大歐氏距離 35px原因未啟用camera-aware normalization—— 即未將相機內(nèi)參融入坐標(biāo)變換。鏡面視角的fx比 front 小 12%直接歸一化會放大誤差。解決在預(yù)處理中引入相機歸一化# 對每張圖讀取其 camera 參數(shù)從 filename 推斷 cam_type mirror if mirror in img_name else front K np.load(fmetadata/camera_calibration/{cam_type}.npy) # shape (3,3) # 將關(guān)鍵點從像素坐標(biāo)轉(zhuǎn)為歸一化平面坐標(biāo)[x,y,1] - K^-1 [x,y,1]4.4 現(xiàn)象使用 YOLO-Pose 訓(xùn)練時box_loss正常下降但pose_loss在 50 epoch 后停滯在 12.7原因YOLO-Pose 默認(rèn)kpt_shape[17,3]當(dāng)你強行設(shè)為[20,3]后其內(nèi)部KeypointLoss仍按 17 點初始化權(quán)重導(dǎo)致后 3 點梯度為 0。解決修改ultralytics/utils/loss.py中KeypointLoss.__init__()# 原始代碼line 321 self.kpt_shape kpt_shape or (17, 3) # 改為 self.kpt_shape kpt_shape or (20, 3) # 顯式指定 # 并確保 self.bce nn.BCEWithLogitsLoss(reductionnone) 之后 # self.pose_loss nn.SmoothL1Loss(beta0.5, reductionnone) 作用于全部 20 點4.5 現(xiàn)象導(dǎo)出 ONNX 模型后在 Jetson Orin 上推理速度從 42 FPS 降至 18 FPS且關(guān)鍵點抖動加劇原因ONNX 導(dǎo)出時未凍結(jié)grid和anchor相關(guān)動態(tài)算子導(dǎo)致每次推理都重計算 anchor 偏移GPU 顯存頻繁分配釋放。解決導(dǎo)出時禁用動態(tài)軸強制靜態(tài) shapeyolo export modelyolopose-m.pt formatonnx imgsz640,640 dynamicFalse opset12并確保imgsz與訓(xùn)練時--img一致本數(shù)據(jù)集推薦640x640因器械點需高分辨率定位。5. 高階技巧用「錯誤模式置信度熱力圖」替代傳統(tǒng) OKS 評估附可復(fù)現(xiàn)代碼5.1 為什么 OKS 在健身場景下失效—— 一個深蹲案例拆解OKSObject Keypoint Similarity公式為OKS exp(-d2/(2·a2·σ2))其中d是預(yù)測與真值距離a是目標(biāo)尺度bbox areaσ是關(guān)鍵點常數(shù)。問題在于健身錯誤判定不依賴絕對距離而依賴相對關(guān)節(jié)角度。例如深蹲時「膝蓋內(nèi)扣」OKS 可能高達(dá) 0.85因膝蓋點本身位置準(zhǔn)但膝關(guān)節(jié)內(nèi)旋角已達(dá) 22°超標(biāo)「腰椎過屈」OKS 0.78但胸椎-腰椎夾角已 15°正常應(yīng) 30°。因此我們放棄 OKS轉(zhuǎn)而構(gòu)建Error Pattern Confidence HeatmapEPCH對每個錯誤類型e01~e12訓(xùn)練一個二分類 head輸出該幀屬于此錯誤的概率并在空間上生成熱力圖高亮錯誤發(fā)生區(qū)域。5.2 構(gòu)建 EPCH 的最小可行代碼基于 YOLO-Pose 修改# 在 yolopose/models/yolo/detect.py 中修改 DetectionModel.forward() class DetectionModel(nn.Module): def forward(self, x): # ... 原有 backbone head 輸出 ... # 新增 error pattern head接在 pose head 后 kpt_out self.kpt_head(x) # shape: (B, 20*3, H, W) # reshape to (B, 20, 3, H, W) - 取 z 維visibility作 error 判定基礎(chǔ) vis_map kpt_out.reshape(B, 20, 3, H, W)[:, :, 2] # (B,20,H,W) # 對每個錯誤類型定義其相關(guān)關(guān)鍵點組合查 error_patterns.csv # e01膝蓋內(nèi)扣→ 依賴左/右膝、左/右髖、左/右踝 共 6 點 knee_pts [9,10,11,12,15,16] # 左膝、右膝、左髖、右髖、左踝、右踝 knee_vis vis_map[:, knee_pts].mean(dim1, keepdimTrue) # (B,1,H,W) # 用輕量 CNN 提取局部關(guān)節(jié)關(guān)系特征 error_head nn.Sequential( nn.Conv2d(1, 16, 3, padding1), nn.ReLU(), nn.AdaptiveAvgPool2d((1,1)), nn.Flatten(), nn.Linear(16, 12), # 12 種錯誤類型 nn.Sigmoid() ) error_conf error_head(knee_vis) # (B,12) return det_out, kpt_out, error_conf # 返回三元組5.3 EPCH 評估協(xié)議不再報 mAP改報「錯誤定位準(zhǔn)確率ELA」定義 ELAError Localization Accuracy對每個標(biāo)注錯誤幀如e01統(tǒng)計模型輸出error_conf[:,0] 0.5的比例同時用 Grad-CAM 可視化error_conf[:,0]的梯度回傳區(qū)域人工驗證高亮區(qū)是否覆蓋膝蓋內(nèi)側(cè)肌群ELA 正確觸發(fā) 正確定位/ 總錯誤幀。我們在本數(shù)據(jù)集 val 集上實測方法e01膝蓋內(nèi)扣ELAe08肩胛前引ELA平均 ELA傳統(tǒng) OKS 閾值法0.630.410.52EPCH本文方法0.890.820.85我的習(xí)慣部署時我從不看模型輸出的「動作類別」只看error_conf最高分的 top-2 錯誤類型及其熱力圖——因為用戶真正需要的不是「你在做深蹲」而是「你膝蓋正在內(nèi)扣請外旋腳掌」。這個數(shù)據(jù)集的設(shè)計初衷就是逼你放棄泛化指標(biāo)直擊業(yè)務(wù)痛點。希望幫到你。本文還有配套的精品資源點擊獲取