File size: 4,538 Bytes
c3ec853
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d24edb6
 
c3ec853
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d24edb6
 
 
 
 
 
 
c3ec853
 
 
 
 
 
 
 
d24edb6
 
 
 
 
 
 
c3ec853
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df91e2b
c3ec853
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df91e2b
 
 
 
c3ec853
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import os
import yaml
import smplx
import torch

from .lib.model.cvae import SMPL2PressureCVAE

class PressureGenerator:
    # 静态配置数据
    DATASET_META = {
        'tip': {
            'max_p': 512.0,
            'crop_size': [56, 40], 
            'path': "/workspace/zyk/public_data/wzy_opt_dataset_w_feats"
        }, 
        'pressurepose': {
            'max_p': 100.0, 
            'crop_size': [64, 27], 
            'path': "/workspace/zyk/public_data/pressurepose/synth"
        }, 
        'moyo': {
            'max_p': 64.0, 
            'crop_size': [110, 37], 
            'path': "/workspace/zyk/public_data/moyo"
        }
    }

    def __init__(self, 
                 ckpt_dir="src/generate_utils/lib/ckpt/pressurepose_20251222_180032",
                 smpl_model_dir="src/smpl_models",
                 device="cpu"):
        """
        初始化生成器:加载配置、权重和 SMPL 模型。
        """
        self.device = torch.device(device)
        self.ckpt_dir = ckpt_dir
        self.smpl_model_dir = smpl_model_dir

        # 1. 加载配置
        self.cfg = self._load_config()
        
        # 2. 设置数据集相关参数
        dataset_name = self.cfg['dataset']['name']
        if dataset_name not in self.DATASET_META:
             raise ValueError(f"Unknown dataset name: {dataset_name}")
             
        self.max_pressure = self.DATASET_META[dataset_name]['max_p']
        self.is_normalized = self.cfg['dataset'].get('normal', False)

        # 3. 加载 CVAE 模型
        self.cvae_model = self._load_cvae()

        # 4. 加载 SMPL 模型
        self.smpl_model = self._load_smpl()
        
        print(f"Pressure Generator loaded successfully from {self.ckpt_dir}")

    def _load_config(self):
        config_path = os.path.join(self.ckpt_dir, 'config.yaml')
        if not os.path.exists(config_path):
            from huggingface_hub import snapshot_download
            snapshot_download(
                "yolozyk/PaGe",
                local_dir="src/generate_utils/lib/ckpt/",
                local_dir_use_symlinks=False,
                ignore_patterns=["*.safetensors", ".gitattributes"],
            )
        with open(config_path, 'r') as f:
            return yaml.safe_load(f)

    def _load_cvae(self):
        model = SMPL2PressureCVAE(self.cfg).to(self.device)
        ckpt_path = os.path.join(self.ckpt_dir, 'ckpts', 'best_model.pth')
        
        if not os.path.exists(ckpt_path):
            from huggingface_hub import snapshot_download
            snapshot_download(
                "yolozyk/PaGe",
                local_dir="src/generate_utils/lib/ckpt/",
                local_dir_use_symlinks=False,
                ignore_patterns=["*.safetensors", ".gitattributes"],
            )

        checkpoint = torch.load(ckpt_path, map_location=self.device)
        model.load_state_dict(checkpoint['model_state_dict'])
        model.eval()
        return model

    def _load_smpl(self):
        # 创建 SMPL 模型 (这是一个比较耗时的操作)
        smpl = smplx.create(
            self.smpl_model_dir, 
            model_type='smpl', 
            gender='neutral', 
            ext='pkl'
        ).to(self.device)
        return smpl

    @torch.no_grad()
    def generate(self, betas, transl, poses, transfer=False):
        """
        执行推理。
        输入参数应该是 Tensor, 维度需符合模型要求 (Batch Size, ...)。
        """
        # 确保输入在正确的设备上
        if betas.device != self.device: betas = betas.to(self.device)
        if transl.device != self.device: transl = transl.to(self.device)
        if poses.device != self.device: poses = poses.to(self.device)

        # 1. 获取 SMPL 顶点 (Vertices)
        output = self.smpl_model(
            betas=betas,
            global_orient=poses[:, :3], # 前3位是全局旋转
            body_pose=poses[:, 3:],     # 后69位是身体姿态
            transl=transl,
        )
        vertices = output.vertices

        if transfer:
            vertices[:, :, 1] = 1.80 - vertices[:, :, 1]
            vertices[:, :, 2] = -vertices[:, :, 2]

        # 2. 预测压力图
        pred_pmap = self.cvae_model.inference(vertices)

        # 3. 后处理 (反归一化 & 阈值过滤)
        if self.is_normalized:
            pred_pmap = pred_pmap * self.max_pressure
        
        # 这里的 0.1 是硬编码的阈值,也可以提取为参数
        pred_pmap[pred_pmap < 0.1] = 0

        return pred_pmap