SMPL旋转踩坑

使用SMPL的过程中遇到了一个大坑, 在此记录一下.
踩坑过程:
将SMPL在maya中的旋转参数用如下代码导出后保存起来
在这里插入图片描述
数据样例如下所示

{
    "shape": [
        -1.1676373481750488,
        0.0,
        0.7026347517967224,
        -0.6037481427192688,
        0.6046652793884277,
        0.0,
        1.1819937229156494,
        0.8521347641944885,
        1.3137569427490234,
        -0.39927607774734497
    ],
    "trans": [
        -16.9407701057938,
        81.43054041149115,
        -17.379529651080375
    ],
    "pose": [
        [
            -1.2300408964079839,
            60.87467575073242,
            -2.2755821915688337
        ],
        [
            -16.84311440799761,
            5.185341658415617,
            13.773090221263741
        ],
        [
            7.020085591851186,
            -3.0269137334086786,
            -4.544121901545129
        ],
        [
            1.7932181888156469,
            2.717320961726481,
            1.062192563657407
        ],
        [
            14.070326173776268,
            7.3665357519079135,
            -0.3312955681588212
        ],
        [
            0.03709220499904067,
            -6.294331614924962,
            0.9927839188415509
        ],
        [
            1.202923810040509,
            -4.489031857885156,
            0.08547615121912072
        ],
        [
            2.2876832658881385,
            3.837096249615703,
            -4.001307956488775
        ],
        [
            -15.149088259096498,
            -2.1525425346043283,
            1.3961921797858343
        ],
        [
            -1.4177366539284033,
            0.15677062807815287,
            0.5882486590632686
        ],
        [
            0.0,
            0.0,
            0.0
        ],
        [
            0.0,
            0.0,
            0.0
        ],
        [
            5.069978502061632,
            16.906971401638458,
            -3.639994724901513
        ],
        [
            -4.318501507794415,
            -8.755624559190537,
            0.024882670905854963
        ],
        [
            -1.9028504607664005,
            19.229754695185907,
            0.14497061570485434
        ],
        [
            -6.7910243846752,
            5.8034296388979305,
            -5.582838058471679
        ],
        [
            -0.7849124625877097,
            -19.80789608425564,
            -28.250218144169544
        ],
        [
            9.131919013129341,
            33.655449196144374,
            39.719461511682574
        ],
        [
            51.95742006655092,
            -100.60467755353108,
            -24.901278460467307
        ],
        [
            45.06835089789497,
            86.17715341073506,
            24.845804285120078
        ],
        [
            -11.493217144522381,
            -19.804811830873845,
            19.8789047229983
        ],
        [
            -15.749351870115982,
            16.70951701976635,
            -16.144037356644485
        ],
        [
            4.235540319372105,
            2.7374518359148934,
            -17.558513217502167
        ],
        [
            5.200717007672346,
            -0.8718210679513436,
            -32.190611097547745
        ],
        [
            -3.716000804194698,
            -4.215261318065502,
            -7.825357649061411
        ],
        [
            -5.341095394558376,
            0.7620738170765062,
            -22.55488360369647
        ],
        [
            -6.3985393665455,
            0.08861873988752009,
            -29.97952213993779
        ],
        [
            -0.1428171771543997,
            -3.9809873369004993,
            -14.3453711050528
        ],
        [
            -16.092659279152194,
            -13.445568791142215,
            -24.49389704951533
        ],
        [
            -8.060806415699144,
            -4.92116574887876,
            -21.133692706072765
        ],
        [
            -15.60036129421658,
            -3.1178453233506933,
            -2.833860362017596
        ],
        [
            -4.523669348822699,
            -5.2461638274016185,
            -26.75318400065104
        ],
        [
            -11.349463286223234,
            -6.180775253861038,
            -26.174853289568865
        ],
        [
            -6.317445966932508,
            -6.835497396963612,
            -15.398747479474098
        ],
        [
            36.555003413447636,
            11.932007118507666,
            1.343177071324101
        ],
        [
            -21.183915314850985,
            1.6296628669456201,
            1.8769728695904764
        ],
        [
            22.2539958247432,
            4.9019622802734375,
            -10.745315551757809
        ],
        [
            4.235540319372105,
            -2.7374518359148934,
            17.558513217502167
        ],
        [
            5.200717007672346,
            0.8718210679513436,
            32.190611097547745
        ],
        [
            -3.716000804194698,
            4.215261318065502,
            7.825357649061411
        ],
        [
            -5.341095394558376,
            -0.7620738170765062,
            22.55488360369647
        ],
        [
            -6.3985393665455,
            -0.08861873988752009,
            29.97952213993779
        ],
        [
            -0.1428171771543997,
            3.9809873369004993,
            14.3453711050528
        ],
        [
            -16.092659279152194,
            13.445568791142215,
            24.49389704951533
        ],
        [
            -8.060806415699144,
            4.92116574887876,
            21.133692706072765
        ],
        [
            -15.60036129421658,
            3.1178453233506933,
            2.833860362017596
        ],
        [
            -4.523669348822699,
            5.2461638274016185,
            26.75318400065104
        ],
        [
            -11.349463286223234,
            6.180775253861038,
            26.174853289568865
        ],
        [
            -6.317445966932508,
            6.835497396963612,
            15.398747479474098
        ],
        [
            36.555003413447636,
            -11.932007118507666,
            -1.343177071324101
        ],
        [
            -21.183915314850985,
            -1.6296628669456201,
            -1.8769728695904764
        ],
        [
            24.479395407217517,
            -5.392158508300782,
            11.819847106933596
        ]
    ]
}

这里有一点需要注意, 导出的为角度, 需要先转化为弧度. 转化后在Python中加载, 传入SMPL模型中

class BodyModel(torch.nn.Module):
    def __init__(self, support_dir):
        super().__init__()
        subject_gender = "male"
        bm_fname = os.path.join(
            support_dir, "smplh/{}/model.npz".format(subject_gender)
        )
        dmpl_fname = os.path.join(
            support_dir, "dmpls/{}/model.npz".format(subject_gender)
        )
        num_betas = 16  # number of body parameters
        num_dmpls = 8  # number of DMPL parameters
        self.body_model = BM(
            bm_fname=bm_fname,
            num_betas=num_betas,
            num_dmpls=num_dmpls,
            dmpl_fname=dmpl_fname,
        )

    def forward(self, body_params):  # body_params:{pose_body:(N, 63), root_orient:(N, 3)}
        # with torch.no_grad():
        body_pose = self.body_model(
            **{
                k: v
                for k, v in body_params.items()
                if k in ["pose_body", "trans", "root_orient", "betas"]
            }
        )
        return body_pose

此时得到的SMPL模型姿势大体看着没啥问题, 但是root的旋转对不上! 七扭八歪
在这里插入图片描述
起初以为是坐标系的问题, 但是经过仔细check发现maya也是右手坐标系, 从道理上来讲应该是不需要进行任何坐标系变换, 这就很奇怪.
这里最坑的一点是其他的关节看着都很好, 只有root节点偏了, 这就很不合常理, 要歪应该是一块歪的, 在这个地方卡了很久.
debug了整整1天, 发现问题出在旋转的表示上, maya导出的结果旋转表示为欧拉角表示, 表示绕着xyz轴分别旋转了多少角度, 然而SMPL的输入参数为轴角表示, 类似于一个方向向量!!! 两者并不是同一个东西! 这个问题是从SMPL的内部对输入的处理函数中发现的

def batch_rodrigues(
        rot_vecs: Tensor,
        epsilon: float = 1e-8,
) -> Tensor:
    """Calculates the rotation matrices for a batch of rotation vectors
    Parameters
    ----------
    rot_vecs: torch.tensor Nx3
        array of N axis-angle vectors
    Returns
    -------
    R: torch.tensor Nx3x3
        The rotation matrices for the given axis-angle parameters
    """
    batch_size = rot_vecs.shape[0]
    device, dtype = rot_vecs.device, rot_vecs.dtype
    angle = torch.norm(rot_vecs + 1e-8, dim=1, keepdim=True)
    rot_dir = rot_vecs / angle
    cos = torch.unsqueeze(torch.cos(angle), dim=1)
    sin = torch.unsqueeze(torch.sin(angle), dim=1)
    # Bx1 arrays
    rx, ry, rz = torch.split(rot_dir, 1, dim=1)
    K = torch.zeros((batch_size, 3, 3), dtype=dtype, device=device)
    zeros = torch.zeros((batch_size, 1), dtype=dtype, device=device)
    K = torch.cat([zeros, -rz, ry, rz, zeros, -rx, -ry, rx, zeros], dim=1).view((batch_size, 3, 3))
    ident = torch.eye(3, dtype=dtype, device=device).unsqueeze(dim=0)
    rot_mat = ident + sin * K + (1 - cos) * torch.bmm(K, K)
    return rot_mat

于是乎需要将eular角先转换为轴角表示, 才能作为SMPL的输入参数, 可以先将欧拉角转成旋转矩阵, 然后根据旋转矩阵变成轴角

def euler_to_matrix_batch(euler):
    # euler: (batch_size, 3)
    batch_size = euler.shape[0]
    rx, ry, rz = euler[:, 0], euler[:, 1], euler[:, 2]
    
    # Create rotation matrices for each axis
    R_x = torch.zeros((batch_size, 3, 3), dtype=euler.dtype, device=euler.device)
    R_y = torch.zeros((batch_size, 3, 3), dtype=euler.dtype, device=euler.device)
    R_z = torch.zeros((batch_size, 3, 3), dtype=euler.dtype, device=euler.device)
    
    # Fill in the rotation matrices
    R_x[:, 0, 0] = 1
    R_x[:, 1, 1] = torch.cos(rx)
    R_x[:, 1, 2] = -torch.sin(rx)
    R_x[:, 2, 1] = torch.sin(rx)
    R_x[:, 2, 2] = torch.cos(rx)
    
    R_y[:, 0, 0] = torch.cos(ry)
    R_y[:, 0, 2] = torch.sin(ry)
    R_y[:, 1, 1] = 1
    R_y[:, 2, 0] = -torch.sin(ry)
    R_y[:, 2, 2] = torch.cos(ry)
    
    R_z[:, 0, 0] = torch.cos(rz)
    R_z[:, 0, 1] = -torch.sin(rz)
    R_z[:, 1, 0] = torch.sin(rz)
    R_z[:, 1, 1] = torch.cos(rz)
    R_z[:, 2, 2] = 1
    # Compute the final rotation matrix for each batch
    R = torch.bmm(R_z, torch.bmm(R_y, R_x))
    return R

def rotation_matrix_to_axis_angle_batch(R):
    # R: (batch_size, 3, 3)
    batch_size = R.shape[0]
    # Calculate the angle
    trace = R[:, 0, 0] + R[:, 1, 1] + R[:, 2, 2]
    theta = torch.acos((trace - 1) / 2)
    # Handle the case when theta is very small (to avoid division by zero)
    sin_theta = torch.sin(theta)
    sin_theta[sin_theta == 0] = 1e-6  # Avoid division by zero
    # Calculate the rotation axis
    rx = (R[:, 2, 1] - R[:, 1, 2]) / (2 * sin_theta)
    ry = (R[:, 0, 2] - R[:, 2, 0]) / (2 * sin_theta)
    rz = (R[:, 1, 0] - R[:, 0, 1]) / (2 * sin_theta)
    axis = torch.stack((rx, ry, rz), dim=1)
    # Return the axis-angle representation
    return axis * theta.unsqueeze(1)

def euler_to_axis_angle_batch(euler):
    # Convert Euler angles to rotation matrices
    R = euler_to_matrix_batch(euler)
    # Convert rotation matrices to axis-angle representation
    axis_angle = rotation_matrix_to_axis_angle_batch(R)
    return axis_angle

转换完成后得到了正确结果!
!](https://i-blog.csdnimg.cn/direct/329144ba53214eb0a09fc1ccd2fb66b9.png)

这里有个地方比较奇怪! 不光把root转成了轴角表示, 其他的也转成了轴角表示, 但是貌似对于其他关节来讲好像没差多少?也挺神奇的.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值