经典人体模型SMPL介绍(一)

SMPL是马普所提出的经典人体模型,目前已成为姿态估计、人体重建等领域必不可少的基础先验。SMPL基于蒙皮和BlendShape实现,从数千个三维人体扫描结果得来,后通过PCA统计学习得来。
论文:SMPL: A Skinned Multi-Person Linear Model
主页:https://smpl.is.tue.mpg.de/index.html
简单来说SMPL是多个人体模型,这些人体模型的形状、姿态都可以被参数化表示


SMPL参数一般分为两组:体型参数 β ⃗ \bold{\vec{\beta}} β 和姿态参数 θ ⃗ \bold{\vec{\theta}} θ 。前者决定人体的高矮胖瘦身材比例等,后者决定人体具体姿态。我们从下图即可看出它们的作用:
SMPL参数
(图片来自链接)
最初始版本(v1.0.0)的SMPL模型有两种性别,对应两个人体模型。每个人体模型有10个体型参数+24x3=72个姿态参数;所以,我们用10+72=82个数就可以表示一个SMPL人体
随便地,我们生成一组参数:

pose = (np.random.rand((24, 3)) - 0.5) * 0.4  # 24x3=72
beta = (np.random.rand((10,)) - 0.5) * 0.06

这里的pose表示姿态参数 θ ⃗ \bold{\vec{\theta}} θ ,beta表示体型参数 β ⃗ \bold{\vec{\beta}} β 。于是,这一smpl人体可以被生成出来——我们可以用obj文件表示,用MeshLab即可打开:
请添加图片描述
什么?你问我怎么得到这个obj文件的?
脚本放在下面,按需自取

import numpy as np
import pickle


class SMPLModel():
  def __init__(self, model_path):
    """
    SMPL model.

    Parameter:
    ---------
    model_path: Path to the SMPL model parameters, pre-processed by
    `preprocess.py`.

    """
    with open(model_path, 'rb') as f:
      params = pickle.load(f)

      self.J_regressor = params['J_regressor']
      self.weights = params['weights']
      self.posedirs = params['posedirs']
      self.v_template = params['v_template']
      self.shapedirs = params['shapedirs']
      self.faces = params['f']
      self.kintree_table = params['kintree_table']

    id_to_col = {
      self.kintree_table[1, i]: i for i in range(self.kintree_table.shape[1])
    }
    self.parent = {
      i: id_to_col[self.kintree_table[0, i]]
      for i in range(1, self.kintree_table.shape[1])
    }

    self.pose_shape = [24, 3]
    self.beta_shape = [10]
    self.trans_shape = [3]

    self.pose = np.zeros(self.pose_shape)
    self.beta = np.zeros(self.beta_shape)
    self.trans = np.zeros(self.trans_shape)

    self.verts = None
    self.J = None
    self.R = None

    self.update()

  def set_params(self, pose=None, beta=None, trans=None):
    """
    Set pose, shape, and/or translation parameters of SMPL model. Verices of the
    model will be updated and returned.

    Parameters:
    ---------
    pose: Also known as 'theta', a [24,3] matrix indicating child joint rotation
    relative to parent joint. For root joint it's global orientation.
    Represented in a axis-angle format.

    beta: Parameter for model shape. A vector of shape [10]. Coefficients for
    PCA component. Only 10 components were released by MPI.

    trans: Global translation of shape [3].

    Return:
    ------
    Updated vertices.

    """
    if pose is not None:
      self.pose = pose
    if beta is not None:
      self.beta = beta
    if trans is not None:
      self.trans = trans
    self.update()
    return self.verts

  def update(self):
    """
    Called automatically when parameters are updated.

    """
    # how beta affect body shape
    v_shaped = self.shapedirs.dot(self.beta) + self.v_template
    # joints location
    self.J = self.J_regressor.dot(v_shaped)
    pose_cube = self.pose.reshape((-1, 1, 3))
    # rotation matrix for each joint
    self.R = self.rodrigues(pose_cube)
    I_cube = np.broadcast_to(
      np.expand_dims(np.eye(3), axis=0),
      (self.R.shape[0]-1, 3, 3)
    )
    lrotmin = (self.R[1:] - I_cube).ravel()
    # how pose affect body shape in zero pose
    v_posed = v_shaped + self.posedirs.dot(lrotmin)
    # world transformation of each joint
    G = np.empty((self.kintree_table.shape[1], 4, 4))
    G[0] = self.with_zeros(np.hstack((self.R[0], self.J[0, :].reshape([3, 1]))))
    for i in range(1, self.kintree_table.shape[1]):
      G[i] = G[self.parent[i]].dot(
        self.with_zeros(
          np.hstack(
            [self.R[i],((self.J[i, :]-self.J[self.parent[i],:]).reshape([3,1]))]
          )
        )
      )
    G = G - self.pack(
      np.matmul(
        G,
        np.hstack([self.J, np.zeros([24, 1])]).reshape([24, 4, 1])
        )
      )
    # transformation of each vertex
    T = np.tensordot(self.weights, G, axes=[[1], [0]])
    rest_shape_h = np.hstack((v_posed, np.ones([v_posed.shape[0], 1])))
    v = np.matmul(T, rest_shape_h.reshape([-1, 4, 1])).reshape([-1, 4])[:, :3]
    self.verts = v + self.trans.reshape([1, 3])

  def rodrigues(self, r):
    """
    Rodrigues' rotation formula that turns axis-angle vector into rotation
    matrix in a batch-ed manner.

    Parameter:
    ----------
    r: Axis-angle rotation vector of shape [batch_size, 1, 3].

    Return:
    -------
    Rotation matrix of shape [batch_size, 3, 3].

    """
    theta = np.linalg.norm(r, axis=(1, 2), keepdims=True)
    # avoid zero divide
    theta = np.maximum(theta, np.finfo(r.dtype).eps)
    r_hat = r / theta
    cos = np.cos(theta)
    z_stick = np.zeros(theta.shape[0])
    m = np.dstack([
      z_stick, -r_hat[:, 0, 2], r_hat[:, 0, 1],
      r_hat[:, 0, 2], z_stick, -r_hat[:, 0, 0],
      -r_hat[:, 0, 1], r_hat[:, 0, 0], z_stick]
    ).reshape([-1, 3, 3])
    i_cube = np.broadcast_to(
      np.expand_dims(np.eye(3), axis=0),
      [theta.shape[0], 3, 3]
    )
    A = np.transpose(r_hat, axes=[0, 2, 1])
    B = r_hat
    dot = np.matmul(A, B)
    R = cos * i_cube + (1 - cos) * dot + np.sin(theta) * m
    return R

  def with_zeros(self, x):
    """
    Append a [0, 0, 0, 1] vector to a [3, 4] matrix.

    Parameter:
    ---------
    x: Matrix to be appended.

    Return:
    ------
    Matrix after appending of shape [4,4]

    """
    return np.vstack((x, np.array([[0.0, 0.0, 0.0, 1.0]])))

  def pack(self, x):
    """
    Append zero matrices of shape [4, 3] to vectors of [4, 1] shape in a batched
    manner.

    Parameter:
    ----------
    x: Matrices to be appended of shape [batch_size, 4, 1]

    Return:
    ------
    Matrix of shape [batch_size, 4, 4] after appending.

    """
    return np.dstack((np.zeros((x.shape[0], 4, 3)), x))

  def save_to_obj(self, path):
    """
    Save the SMPL model into .obj file.

    Parameter:
    ---------
    path: Path to save.

    """
    with open(path, 'w') as fp:
      for v in self.verts:
        fp.write('v %f %f %f\n' % (v[0], v[1], v[2]))
      for f in self.faces + 1:
        fp.write('f %d %d %d\n' % (f[0], f[1], f[2]))



if __name__ == '__main__':
    smpl = SMPLModel('./model.pkl') # python SMPL model
    np.random.seed(9608)
    pose = (np.random.rand(*smpl.pose_shape) - 0.5) * 0.4 # (24, 3)
    beta = (np.random.rand(*smpl.beta_shape) - 0.5) * 0.06 # (10, )
    trans = np.zeros(smpl.trans_shape)
    smpl.set_params(beta=beta, pose=pose, trans=trans)
    smpl.save_to_obj('./smpl_np.obj')

代码来源:https://github.com/CalciferZh/SMPL

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/76502.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenStack监控工具

OpenStack是一个开源的云计算管理平台项目,是一系列软件开源项目的组合。由NASA和Rackspace合作研发并发起,以Apache许可证(Apache软件基金会发布的一个自由软件许可证)授权。 OpenStack为私有云和公有云提供可扩展的弹性的云计算…

二.net core 自动化发布到docker (Jenkins安装之后向导)

目录 ​​​​​​​​​​​​​​ 参考资料:https://www.jenkins.io/doc/book/installing/docker/#setup-wizard Post-installation setup wizard.(安装后安装向导) 基于上一篇文章安装,在安装并运行Jenkins(不包括使用Jenkins Opera…

学习pytorch 3 tensorboard的使用

tensorboard的使用 1. 安装2. add_scalar 查看函数图形3. 查看结果4. add_image() 查看训练步骤中间结果的图片 1. 安装 pytorch conda环境 pip install tensorboard pip install opencv-python2. add_scalar 查看函数图形 常用来查看 train val loss等函数图形 from torch…

TCP 协议十大相关特性总结

目录 一、TCP特性 二、报文格式 TCP十大核心特性 1. 确认应答 2. 超时重传 3. 连接管理(三次握手,四次挥手) 三次握手 四次挥手 4. 滑动窗口 情况一:接收方的ACK丢失 情况二:发送方的数据包丢失 5. 流量控制 6. 拥塞控制 7. 延迟应答 8. 捎带应答 9. 字节流粘包问题 10. TCP的…

WebStorm修改默认打开的浏览器

有两种方式第一种修改系统默认浏览器 我采用的是下面这种,在webstorm中修改 将浏览器设置为默认的浏览器即可

【学会动态规划】乘积为正数的最长子数组长度(21)

目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 动态规划怎么学? 学习一个算法没有捷径,更何况是学习动态规划, 跟我…

实现文件的拖放功能

文章目录 实现文件的拖放功能1 拖放文件至QT窗口1.1 实现方法1.2 效果演示 2 拖放文件至python脚本2.1 实现方法2.2 效果演示 实现文件的拖放功能 试想一下,我们希望将一个python项目文件夹或者脚本在IDE中打开,无论是去IDE中选择文件夹路径,…

vuex学习总结

一、vuex工作原理 工作流程:需求:改变组件count的sun变量的值,先调用dispatch函数传入jia函数和要改变的值给actions(这个actions里面必须有jia这个函数);actions收到后调用commit函数将jia方法和值传给mut…

【Visual Studio Code】--- Win11 C盘爆满 修改 Code 插件数据和缓存的保存路径

Win11 C盘爆满 修改 Code 插件数据和缓存的保存路径 一、概述二、修改 Code 插件数据和缓存的保存路径 一、概述 一个好的文章能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径,学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成…

28 | Boss直聘数据分析

针对boss直聘网的招聘信息,然后分析互联网发展排名前十的城市在互联网方面职位的薪水,学历要求,经验要求,等等信息。 准备从以下几个方面进行分析: (1)各个城市的平均工资 (2)各个学历的平均工资 (3)各个岗位的平均工资 (4)不同工作经验要求的工资 (5)各个经验…

冉冉升起的星火,再度升级迎来2.0时代!

文章目录 前言权威性评测结果 星火大模型多模态功能插件功能简历生成文档问答PPT生成 代码能力 福利 前言 前几天从技术群里看到大家都在谈论《人工智能大模型体验报告2.0》里边的内容,抱着好奇和学习的态度把报告看了一遍。看完之后瞬间被里边提到的科大讯飞的星火…

(leecode)错误的集合

最近听到的,还可以,试试吧~ 题目: 示例: 提示: 题解: 思路: 将数字大小的位置,然后遍历每个位置,大小为0的是缺失数字,大小为2的是重复数字 int* findErro…

Gitlab-第四天-CD到k8s集群的坑

一、.gitlab-ci.yml #CD到k8s集群的 stages: - deploy-test build-image-deploy-test: stage: deploy-test image: bitnami/kubectl:latest # 使用一个包含 kubectl 工具的镜像 tags: - k8s script: - ls -al - kubectl apply -f deployment.yaml # 根据实际情况替换…

Linux学习之firewallD

systemctl status firewalld.service查看一下firewalld服务的状态,发现状态是inactive (dead)。 systemctl start firewalld.service启动firewalld,systemctl status firewalld.service查看一下firewalld服务的状态,发现状态是active (runni…

【Apollo】阿波罗自动驾驶:塑造自动驾驶技术的未来

前言 Apollo (阿波罗)是一个开放的、完整的、安全的平台,将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统,快速搭建一套属于自己的自动驾驶系统。 开放能力、共享资源、加速创新、持续共赢是 Apollo 开放平台的口号。百度把自己所拥有的强大、…

【Unity每日一记】方位辨别—向量的叉乘点乘结合

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:uni…

Go 语言并发编程 及 进阶与依赖管理

1.0 从并发编程本质了解Go高性能的本质 1.1 Goroutine 协程可以理解为轻量级线程; Go更适合高并发场景原因之一:Go语言一次可以创建上万协成; “快速”:开多个协成 打印。 go func(): 在函数前加 go 代表 创建协程; time.Sleep():…

阿里云OSS对象存储的核心概念与购买应用

文章目录 1.OSS对象存储基本介绍1.1.OSS对象存储概念1.2.NAS与OSS存储的不同1.3.OSS的应用场景1.4.OSS术语对应表 2.购买OSS存储资源包3.KodCloud云盘接入OSS对象存储3.1.创建Bucket存储空间3.2.创建子用户用于管理Bucket3.3.获取用户的AccessKey3.3.为用户设置权限3.4.将Bucke…

PHP实践:分布式场景下的Session共享解决方案实现

🏆作者简介,黑夜开发者,全栈领域新星创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责…

PHP实现在线年龄计算器

1. 输入日期查询年龄 2. php laravel框架实现 代码 /*** 在线年龄计算器*/public function ageDateCal(){// 输入的生日时间$birthday $this->request(birthday);// 当前时间$currentDate date(Y-m-d);// 计算周岁$age date_diff(date_create($birthday), date_create($…
最新文章