经典人体模型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 pickleclass 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 = Noneself.J = Noneself.R = Noneself.update()def set_params(self, pose=None, beta=None, trans=None):"""Set pose, shape, and/or translation parameters of SMPL model. Verices of themodel will be updated and returned.Parameters:---------pose: Also known as 'theta', a [24,3] matrix indicating child joint rotationrelative 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 forPCA component. Only 10 components were released by MPI.trans: Global translation of shape [3].Return:------Updated vertices."""if pose is not None:self.pose = poseif beta is not None:self.beta = betaif trans is not None:self.trans = transself.update()return self.vertsdef update(self):"""Called automatically when parameters are updated."""# how beta affect body shapev_shaped = self.shapedirs.dot(self.beta) + self.v_template# joints locationself.J = self.J_regressor.dot(v_shaped)pose_cube = self.pose.reshape((-1, 1, 3))# rotation matrix for each jointself.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 posev_posed = v_shaped + self.posedirs.dot(lrotmin)# world transformation of each jointG = 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 vertexT = 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 rotationmatrix 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 dividetheta = np.maximum(theta, np.finfo(r.dtype).eps)r_hat = r / thetacos = 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_hatdot = np.matmul(A, B)R = cos * i_cube + (1 - cos) * dot + np.sin(theta) * mreturn Rdef 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 batchedmanner.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 modelnp.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.mzph.cn/news/39612.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023连锁收银系统该如何选?值得推荐的5款连锁收银系统

现在不管是连锁店还是零售店,只要是开店做生意赚钱的,都少不了要和钱打交道,尤其是对连锁店来说,收银工作更是重中之重。 连锁店涉及的门店较多,必须要有一套足够优秀的连锁收银系统,才能做好每个门店的收银…

使用 `tailwindcss-patch@2` 来提取你的类名吧

使用 tailwindcss-patch2 来提取你的类名吧 使用 tailwindcss-patch2 来提取你的类名吧 安装使用方式 命令行 Cli 开始提取吧 Nodejs API 的方式来使用 配置 初始化 What’s next? tailwindcss-patch 是一个 tailwindcss 生态的扩展项目。也是 tailwindcss-mangle 项目重要…

2023年上半年网络工程师上午真题及答案解析

1.固态硬盘的存储介质是( )。 A.光盘 B.闪存 C.软盘 D.磁盘 2.虚拟存储技术把( )有机地结合起来使用,从而得到一个更大容量的“内存”。 A.内存与外存 B.Cache与内存 C.寄存器与Cache D.Cache与外存 3.下列接口协议中&…

找不到msvcp140.dll无法继续执行代码怎么解决?分享三个解决方法

当你在运行某个程序或游戏时遇到msvcp140.dll缺失的错误提示,你可能会感到困惑和烦恼。在修复msvcp140.dll的过程中,我遇到了一些挑战,但最终成功解决了这个问题。以下是我总结的三个解决方法,希望能帮助你解决这个问题。 找不到m…

Mongodb (四十一)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、概述 1.1 相关概念 1.2 特性 二、应用场景 三、安装 四、目录结构 五、默认数据库 六、 数据库操作 6.1 库操作 6.2 文档操作 七、MongoDB数据库备份 7.1 备…

小游戏扫雷实现教学(详解)

目录 【前言】 一、模块化程序设计(多文件编程)介绍 1.概述 2.传统编程的方式 3.模块化程序设计的方法 二、扫雷代码设计思路 三、扫雷代码设计 1.创建菜单函数 2.实现9x9扫雷 3.初始化棋盘 4.打印棋盘 5.随机布置雷的位置 6.排查雷的信息 7.回…

TEC2083BS-PD码转换器(解决博世矩阵控制PELCO派尔高球机的问题)

TEC2083BS-PD码转换器 使用说明 1.设备概述 控制码转换器在安防工程中起着非常重要的角色,随着高速球型摄像机在安防工程中大范围的使用,而高速球厂家都因为某些原因很少使用博世、飞利浦的协议。为此,工程商经常会遇到博世协议和PELCO协议之…

RabbitMQ工作流程详解

1 生产者发送消息的流程 (1)生产者连接RabbitMQ,建立TCP连接(Connection),开启信道(Channel) (2)生产者声明一个Exchange (交换器),并设置相关属性,比如交换器类型、是否持久化等 (3)生产者声明一个队列井设置相关属性&#xf…

Spring-Cloud-Loadblancer详细分析_3

前两篇文章介绍了加载过程,本文从Feign的入口开始分析执行过程,还是从FeignBlockingLoadBalancerClient.execute来入手 public class FeignBlockingLoadBalancerClient implements Client {private static final Log LOG LogFactory.getLog(FeignBlock…

Vue3实现图片懒加载及自定义懒加载指令

Vue3实现图片懒加载及自定义懒加载指令 前言1.使用vue3-lazyload插件2.自定义v-lazy懒加载指令2.1 使用VueUse2.2 使用IntersectionObserver 前言 图片懒加载是一种常见性能优化的方式,它只去加载可视区域图片,而不是在网页加载完毕后就立即加载所有图片…

集成DTM实现跨语言分布式事务V1.0

集成DTM实现跨语言分布式事务V1.0 简介 DTM是一款开源的分布式事务管理器,解决跨数据库、跨服务、跨语言栈更新数据的一致性问题。 通俗一点说,DTM提供跨服务事务能力,一组服务要么全部成功,要么全部回滚,避免只更新…

MIMO-NOMA系统MATLAB仿真实现

非正交多址接入(NOMA)技术可以打破传统的正交多址一个基本资源块由单用户独占的限制,通过在时域和频域的基础上开辟新的功率域维度,在相同的时频资源上通过功率复用技术允许同一个时频资源块由多个用户共享,有效提升了…

如何进行无线网络渗透测试?

今天我们将继续深入探讨Kali Linux的应用,这次我们将重点介绍如何使用Kali Linux进行无线网络渗透测试。无线网络渗透测试是评估无线网络安全性的重要步骤,而Kali Linux作为一款专业的渗透测试发行版,提供了丰富的工具来帮助你进行这项任务。…

c++中const修饰成员函数的问题

问题引入&#xff1a; 看下面这一段代码&#xff1a; class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout << "Print()" << endl;cout << "year:" << _year <&…

面试热题(全排列)

给定一个不含重复数字的整数数组 nums &#xff0c;返回其 所有可能的全排列 。可以 按任意顺序 返回答案。 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 先在这里说明一下排列和组合的区别? 组合&#xff1a;是指从一…

开源数据库Mysql_DBA运维实战 (名词解释)

SQL&#xff08;Structured Query Language 即结构化查询语言&#xff09; SQL语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统&#xff0c;SQL语言由IBM开发。 SQL语言分类&#xff1a; DDL语句 数据库定义语言&#xff1a;数据库、表、视图、索引、存储过程…

Steam 灵感的游戏卡悬停效果

先看效果&#xff1a; 再看代码&#xff08;查看更多&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Steam 灵感的游戏卡悬停效果</title><style>* {margin: …

构建高效外卖系统平台:从需求到实现

随着科技的不断进步和人们生活节奏的加快&#xff0c;外卖成为了越来越多人的饮食选择。为了满足这一需求&#xff0c;开发一套高效的外卖系统平台变得尤为重要。本文将从需求分析开始&#xff0c;逐步引导您了解如何开发一套完整的外卖系统平台。 第一步&#xff1a;需求分析…

分类预测 | MATLAB实现EVO-CNN多输入分类预测

分类预测 | MATLAB实现EVO-CNN多输入分类预测 目录 分类预测 | MATLAB实现EVO-CNN多输入分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.MATLAB实现EVO-CNN多输入分类预测 2.代码说明&#xff1a;量谷优化卷积神经网络的数据分类预测&#xff1a;要求于Matlab …

【hadoop】windows上hadoop环境的搭建步骤

文章目录 前言基础环境下载hadoop安装包下载hadoop在windows中的依赖配置环境变量 Hadoop hdfs搭建创建hadfs数据目录修改JAVA依赖修改配置文件初始化hdfs namenode启动hdfs 前言 在大数据开发领域中&#xff0c;不得不说说传统经典的hadoop基础计算框架。一般我们都会将hadoo…