feat(pose): 添加姿态估计模型训练和检测脚本- 新增 YOLO 姿态估计模型训练脚本 (14.训练模型-姿态估计.py)

- 新增 YOLO 姿态估计模型检测脚本 (15.模型检测-姿态估计.py)- 添加 LabelMe 标注文件转 YOLO 格式的转换脚本 (labelme_to_yolo.py)
- 添加 LabelMe 姿态标注转 YOLO 姿态格式的转换脚本 (labelme_to_yolo_pose.py)- 新增训练数据集配置文件 (dataset1/train.yaml, dataset1/data.yaml)
- 添加训练样本标签文件 (dataset1/train/labels/5_png.rf.xxx.txt 等)
- 配置手部关键点检测参数,支持11个关键点- 设置图像尺寸为640,批次大小为32,训练轮数为30
- 支持CPU设备训练,预留GPU训练接口
- 实现关键点标签转换,包括归一化坐标处理
- 添加类别名称和关键点顺序定义
- 集成Roboflow数据集配置信息
- 支持模型推理视频和图片文件夹输入-保存检测结果到本地文件
- 提供模型加载和参数配置说明- 支持best.pt和last.pt模型权重加载
- 实现关键点可见性标注 (2 表示可见)- 添加关键点标签映射和排序逻辑
- 创建输出目录自动检查和创建机制- 输出转换完成提示信息
- 定义关键点标签顺序 (f_1_1, f_1_2, ..., f)
This commit is contained in:
mshe 2025-09-27 02:54:06 +08:00
parent e2cbb52dd1
commit 9504085c98
33 changed files with 185 additions and 0 deletions

View File

@ -0,0 +1,15 @@
from ultralytics import YOLO
# 加载预训练模型
yolo = YOLO('models/yolo11n-pose.pt')
# yolo = YOLO('models/yolo11x-pose.pt')
# 训练模型
# data:数据集路径
# epochs:训练轮数
# imgsz: 图片大小
# batch: 批次大小
# device: 使用设备 0:GPU 'cpu':CPU
yolo.train(data='./dataset1/train.yaml', epochs=30, imgsz=640, batch=32, device='cpu')
print("训练完成")

View File

@ -0,0 +1,9 @@
from ultralytics import YOLO
# 加载训练好的模型
# best.pt: 最佳模型,适用于生产
# last.pt: 最后一轮训练的模型,适用于继续训练
yolo = YOLO('runs/pose/train2/weights/best.pt')
# yolo = YOLO('models/yolo11n-pose.pt')
# yolo('resources/input.mp4', show=True, save=True)
yolo('resources/姿态估计-自定义', show=True, save=True)

16
dataset1/data.yaml Normal file
View File

@ -0,0 +1,16 @@
train: ../train/images
val: ../valid/images
test: ../test/images
kpt_shape: [11, 3]
flip_idx: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
nc: 1
names: ['hand']
roboflow:
workspace: crabapples
project: pose-label-qi4gq
version: 4
license: CC BY 4.0
url: https://universe.roboflow.com/crabapples/pose-label-qi4gq/dataset/4

13
dataset1/train.yaml Normal file
View File

@ -0,0 +1,13 @@
path: ./dataset1 # 数据集根目录
train: train/images # 训练集目录名
val: valid/images # 验证集目录名
nc: 1 # 类别数
names: [ 'hand' ] # 类别名称
kpt_shape: [11, 3] # 关键点数量, 维度数量 (2 表示 x,y 或 3 表示 x,y,可见性)
flip_idx: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 关键点
#roboflow:
# workspace: crabapples
# project: pose-label-qi4gq
# version: 1
# license: CC BY 4.0
# url: https://universe.r

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -0,0 +1 @@
0 0.4980106469002696 0.5210340336134454 0.9595187331536388 0.7952501050420168 0.31628382749326145 0.15887090336134455 2 0.49280539083557956 0.3138540966386555 2 0.6320774258760108 0.5677090336134453 2 0.31614238544474393 0.40554527310924365 2 0.1032300539083558 0.31149474789915965 2 0.31880424528301887 0.5359605042016806 2 0.04661044474393531 0.5335344537815127 2 0.34387304582210243 0.6485216386554622 2 0.091125 0.7194095588235294 2 0.40198315363881404 0.7709457983193276 2 0.22757722371967656 0.8904413865546218 2

View File

@ -0,0 +1 @@
0 0.521675468483816 0.5048226765799256 0.8860931856899489 0.9360530669144981 0.13079139693356048 0.6075380111524163 2 0.3619626916524702 0.7667338289962825 2 0.5848917376490631 0.7973117100371747 2 0.4717445485519591 0.45636013011152415 2 0.41038918228279386 0.15159275092936803 2 0.5887324531516185 0.42722407063197027 2 0.5821443781942078 0.08329042750929369 2 0.6753246235782011 0.45754726916000155 2 0.7351526405451448 0.14876626394052045 2 0.7731171209540034 0.5452516728624535 2 0.932955877342419 0.34004916356877324 2

View File

@ -0,0 +1,2 @@
0 0.31119766627771295 0.4018844506517691 0.42091645274212364 0.7651220670391061 0.1250828471411902 0.3437918994413408 2 0.15997456242707117 0.4997692737430168 2 0.2824428821470245 0.6896988826815642 2 0.2559768961493582 0.33362635009310987 2 0.2565303967327888 0.0508830540037244 2 0.3240253792298716 0.3400173184357542 2 0.31313162193698946 0.061950279329608934 2 0.3841848626286199 0.36324192201343036 2 0.4163682030338389 0.08204785847299814 2 0.4366808634772462 0.4498942271880819 2 0.5070864644107351 0.24957290502793295 2
0 0.7588829638273046 0.4356913407821229 0.4290819136522754 0.6692012104283054 0.942162252042007 0.5224180633147114 2 0.8413381563593932 0.6512546554934823 2 0.6957051341890315 0.7228277467411546 2 0.7854238623103851 0.4522063314711359 2 0.8205078179696617 0.1698008379888268 2 0.7087509334889148 0.43044608938547485 2 0.6952493582263711 0.12026340782122906 2 0.6450586931155192 0.4419185288640596 2 0.621041015169195 0.15973640595903166 2 0.5924945740956826 0.4828463687150838 2 0.563469544924154 0.2698160148975791 2

View File

@ -0,0 +1 @@
0 0.5116909190371991 0.5103464203233257 0.9214625820568928 0.9355762124711315 0.7077192560175055 0.7290727482678984 2 0.47908183807439825 0.8937125866050808 2 0.3129327133479213 0.8123004618937644 2 0.47407625820568927 0.6644008083140877 2 0.9567908096280088 0.3453039260969977 2 0.4309589715536105 0.5227428406466512 2 0.8209161925601751 0.1121919168591224 2 0.3286816192560175 0.4369609699769053 2 0.671258533916849 0.08105127020785219 2 0.1860917943107221 0.4227184757505774 2 0.44097035010940916 0.1309676674364896 2

View File

@ -0,0 +1,2 @@
0 0.237708533916849 0.4413739197530864 0.4057931072210066 0.8759524691358025 0.38839091903719913 0.562329012345679 2 0.29891706783369804 0.7599103395061728 2 0.0704477024070022 0.8311961419753087 2 0.27909442013129104 0.5735907407407408 2 0.4108089715536105 0.14452253086419753 2 0.21449015317286654 0.4787239197530864 2 0.3647879649890591 0.06194212962962963 2 0.13330361050328227 0.4352554012345679 2 0.263048249452954 0.05245046296296297 2 0.07826487964989058 0.42285370370370373 2 0.14125284463894966 0.15948333333333334 2
0 0.7253844638949671 0.5215375 0.5492310722100656 0.913316049382716 0.520664989059081 0.6375057098765432 2 0.6906377461706783 0.7938762345679011 2 0.910586761487965 0.8017950617283951 2 0.675085010940919 0.5425566358024692 2 0.4784204595185996 0.23187052469135805 2 0.7411031982848176 0.4784855650122625 2 0.5631542669584244 0.11600925925925927 2 0.8206215016687666 0.4754104267988527 2 0.673181181619256 0.10558055555555557 2 0.907315317286652 0.4800390432098765 2 0.8391327133479213 0.18670864197530865 2

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1 @@
0 0.5 0.5139559633027523 1 0.9717500917431192 0.23999856194690264 0.25721348623853213 2 0.10956393805309735 0.5475046788990825 2 0.22414026548672566 0.8682677064220183 2 0.4551941371681416 0.4291499082568807 2 0.6244196902654867 0.055982752293577985 2 0.5889128318584071 0.47038311926605497 2 0.8739679203539823 0.1098356880733945 2 0.6822233407079646 0.5905195412844036 2 0.9602350663716814 0.22233366972477064 2 0.7657805309734512 0.7057052293577982 2 0.9813836283185841 0.44794908256880733 2

View File

@ -0,0 +1 @@
0 0.5150173850574712 0.38422231947483587 0.7927554597701149 0.6767075492341357 0.1701617816091954 0.39178424507658643 2 0.37381580459770114 0.5174552516411378 2 0.5782625 0.6283656455142231 2 0.4658104885057471 0.3583204595185996 2 0.41665962643678156 0.12851301969365425 2 0.5853130747126437 0.3540252735229759 2 0.5842818965517241 0.08341378555798687 2 0.6711130747126437 0.3756934354485777 2 0.7037633620689655 0.13914945295404813 2 0.7507885057471265 0.4276787746170678 2 0.8816913793103448 0.2640832603938731 2

View File

@ -0,0 +1 @@
0 0.47921510791366906 0.5048761224489796 0.5155844124700241 0.8138338775510203 0.6748226618705035 0.5235385714285714 2 0.5472028776978417 0.7444142857142857 2 0.3504914868105516 0.7438351020408163 2 0.5531387290167866 0.5306761224489795 2 0.7279676258992805 0.17757755102040818 2 0.4361697841726619 0.4416508163265306 2 0.6429606714628298 0.1937818367346939 2 0.3815884892086331 0.40159448979591833 2 0.5656037170263789 0.1929634693877551 2 0.30450635491606715 0.41855877551020404 2 0.45534508393285367 0.18808469387755103 2

54
labelme_to_yolo.py Normal file
View File

@ -0,0 +1,54 @@
import json
import os
def labelme_to_yolo(json_file, output_dir):
with open(json_file, 'r') as f:
data = json.load(f)
# 自动提取所有类别并建立索引
classes = list(set(shape['label'] for shape in data['shapes']))
classes.sort() # 按字母排序保持一致性
img_width = data['imageWidth']
img_height = data['imageHeight']
yolo_lines = []
for shape in data['shapes']:
class_name = shape['label']
class_id = classes.index(class_name)
points = shape['points']
x_coords = [p[0] for p in points]
y_coords = [p[1] for p in points]
x_min, x_max = min(x_coords), max(x_coords)
y_min, y_max = min(y_coords), max(y_coords)
# 归一化坐标
x_center = (x_min + x_max) / 2 / img_width
y_center = (y_min + y_max) / 2 / img_height
width = (x_max - x_min) / img_width
height = (y_max - y_min) / img_height
yolo_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
# 保存标签文件
txt_filename = os.path.splitext(os.path.basename(json_file))[0] + '.txt'
txt_path = os.path.join(output_dir, txt_filename)
with open(txt_path, 'w') as f:
f.write('\n'.join(yolo_lines))
# 保存类别文件
with open(os.path.join(output_dir, 'classes.txt'), 'w') as f:
f.write('\n'.join(classes))
return classes
# 使用
json_file = "./dataset1/json/1.json"
output_dir = "./dataset1/labels"
classes = labelme_to_yolo(json_file, output_dir)
print("检测到的类别:", classes)

68
labelme_to_yolo_pose.py Normal file
View File

@ -0,0 +1,68 @@
import json
import os
def labelme_to_yolo_pose(json_file, output_dir):
with open(json_file, 'r') as f:
data = json.load(f)
img_width = data['imageWidth']
img_height = data['imageHeight']
# 提取手部边界框和关键点
bbox = None
keypoints = {}
for shape in data['shapes']:
if shape['shape_type'] == 'rectangle' and shape['label'] == 'hand':
points = shape['points']
x_coords = [p[0] for p in points]
y_coords = [p[1] for p in points]
x_min, x_max = min(x_coords), max(x_coords)
y_min, y_max = min(y_coords), max(y_coords)
x_center = (x_min + x_max) / 2 / img_width
y_center = (y_min + y_max) / 2 / img_height
width = (x_max - x_min) / img_width
height = (y_max - y_min) / img_height
bbox = (x_center, y_center, width, height)
elif shape['shape_type'] == 'point':
label = shape['label']
x, y = shape['points'][0]
keypoints[label] = (x / img_width, y / img_height)
# 关键点顺序按JSON中的标签
keypoint_order = ['f_1_1', 'f_1_2', 'f_2_1', 'f_2_2', 'f_3_2', 'f_3_1',
'f_4_1', 'f_4_2', 'f_5_2', 'f_5_1', 'f']
if bbox:
yolo_line = f"0 {bbox[0]:.6f} {bbox[1]:.6f} {bbox[2]:.6f} {bbox[3]:.6f}"
for kp_name in keypoint_order:
if kp_name in keypoints:
kx, ky = keypoints[kp_name]
yolo_line += f" {kx:.6f} {ky:.6f} 2"
else:
yolo_line += " 0 0 0"
# 保存为txt文件
txt_filename = os.path.splitext(os.path.basename(json_file))[0] + '.txt'
txt_path = os.path.join(output_dir, txt_filename)
with open(txt_path, 'w') as f:
f.write(yolo_line)
print(f"转换完成: {txt_filename}")
# 使用
json_file = "./dataset1/json/1.json"
output_dir = "./dataset1/labels"
if not os.path.exists(output_dir):
os.makedirs(output_dir)
labelme_to_yolo_pose(json_file, output_dir)

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 KiB