經典人體模型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.pswp.cn/news/39612.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39612.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39612.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python讀取svn版本

本文將詳細介紹如何使用Python讀取svn版本。 一、安裝svn庫 首先,我們需要使用Python來連接svn服務器,并獲取版本號。這里我們使用pysvn庫來完成這個工作。 pip install pysvn需要注意的是,如果你需要安裝特定版本的pysvn,你可…

2023連鎖收銀系統該如何選?值得推薦的5款連鎖收銀系統

現在不管是連鎖店還是零售店,只要是開店做生意賺錢的,都少不了要和錢打交道,尤其是對連鎖店來說,收銀工作更是重中之重。 連鎖店涉及的門店較多,必須要有一套足夠優秀的連鎖收銀系統,才能做好每個門店的收銀…

【ARM 嵌入式 編譯系列 5 -- GCC 內建函數 __builtin 詳細介紹】

文章目錄 什么是GCC內建函數?GCC 常見內建函數GCC內建函數使用示例上篇文章:ARM 嵌入式 編譯系列 4.2 – GCC 鏈接規范 extern “C“ 介紹 下篇文章:ARM 嵌入式 編譯系列 6 – GCC objcopy, objdump, readelf, nm 介紹 什么是GCC內建函數? GCC提供了一些專門的功能,用于…

使用 `tailwindcss-patch@2` 來提取你的類名吧

使用 tailwindcss-patch2 來提取你的類名吧 使用 tailwindcss-patch2 來提取你的類名吧 安裝使用方式 命令行 Cli 開始提取吧 Nodejs API 的方式來使用 配置 初始化 What’s next? tailwindcss-patch 是一個 tailwindcss 生態的擴展項目。也是 tailwindcss-mangle 項目重要…

redis的Key的過期策略是如何實現的?

Key的過期策略 一個redis中可能同時存在很多很多key,這些key可能有很大一部分都有過期時間,此時,redis服務器咋知道哪些key已經過期要被刪除,哪些key還沒有過期? 如果直接遍歷所有的key,顯然是行不通的&am…

Abandon_Ubuntu Declaration

鑒于以下幾個原因,持續到明年考研結束,我將不再搗鼓ubuntu和任何linux系統, 原因如下: ubuntu23.04不支持wps編輯pdf這個核心功能,且開機向canonial公司發送遠程遙測,暫時不會用iptables禁用,故…

第幾天(day)

廬陽區2021年信息學競賽試題 題目描述 Description 給定一個日期,求這一天是當年的第幾天。每年的元旦,1月1日,都是每年的第一天,但是每年的最后一天,12月31日,有可能是第365天,也有可能是第3…

2023年上半年網絡工程師上午真題及答案解析

1.固態硬盤的存儲介質是( )。 A.光盤 B.閃存 C.軟盤 D.磁盤 2.虛擬存儲技術把( )有機地結合起來使用,從而得到一個更大容量的“內存”。 A.內存與外存 B.Cache與內存 C.寄存器與Cache D.Cache與外存 3.下列接口協議中&…

關于安卓高版本gradle(7.0+)引入aar包報錯問題

背景 項目開發過程中,接入三方sdk,引入了本地aar包依賴,as rebuild項目的過程中,報錯,提示依賴找不到問題。 報錯:“bundleDebugAar FAILED”等 開發環境 win10 jdk11 gradle 7.5 原因 由于gradle的版…

找不到msvcp140.dll無法繼續執行代碼怎么解決?分享三個解決方法

當你在運行某個程序或游戲時遇到msvcp140.dll缺失的錯誤提示,你可能會感到困惑和煩惱。在修復msvcp140.dll的過程中,我遇到了一些挑戰,但最終成功解決了這個問題。以下是我總結的三個解決方法,希望能幫助你解決這個問題。 找不到m…

Mongodb (四十一)

提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 目錄 前言 一、概述 1.1 相關概念 1.2 特性 二、應用場景 三、安裝 四、目錄結構 五、默認數據庫 六、 數據庫操作 6.1 庫操作 6.2 文檔操作 七、MongoDB數據庫備份 7.1 備…

【golang】類型推斷和變量重聲明

類型推斷是一種編程語言在編譯期自動解釋表達式類型的能力。 1.Go語言的類型推斷可以帶來哪些好處? 在寫代碼時,我們通過使用Go語言的類型推斷會節省敲擊次數,而節省下來的鍵盤敲擊次數幾乎可以忽略不記。但它真正的好處,往往會…

小游戲掃雷實現教學(詳解)

目錄 【前言】 一、模塊化程序設計(多文件編程)介紹 1.概述 2.傳統編程的方式 3.模塊化程序設計的方法 二、掃雷代碼設計思路 三、掃雷代碼設計 1.創建菜單函數 2.實現9x9掃雷 3.初始化棋盤 4.打印棋盤 5.隨機布置雷的位置 6.排查雷的信息 7.回…

網絡安全--利用awk分析Apache日志

一、溯源 你會溯源嗎?怎么溯 拿到日志(ssh登錄日志,Apache日志),通過日志溯到ip,對日志進行每天的拆分,第二通過awk日志分析工具對每天的日志進行拆分,分析某一個ip今天對我訪問多…

如何防止DDOS攻擊與CC攻擊???

防止DDOS(分布式拒絕服務)和CC(網絡層阻斷)攻擊需要綜合采取多種措施,包括以下幾個方面: 1. 增加帶寬和資源:通過增加網絡帶寬和服務器資源,可以擴大系統的吞吐能力,從而…

TEC2083BS-PD碼轉換器(解決博世矩陣控制PELCO派爾高球機的問題)

TEC2083BS-PD碼轉換器 使用說明 1.設備概述 控制碼轉換器在安防工程中起著非常重要的角色,隨著高速球型攝像機在安防工程中大范圍的使用,而高速球廠家都因為某些原因很少使用博世、飛利浦的協議。為此,工程商經常會遇到博世協議和PELCO協議之…

linux命令readelf基本用法

readelf是一個用于顯示ELF (Executable and Linkable Format) 文件信息的工具。它可以用于顯示二進制文件、共享庫以及目標文件的各種詳細信息。 常見用法&#xff1a; 文件頭信息(32位還是64位&#xff0c;入口點的地址等): readelf -h <filename>程序頭表(運行時如何…

RabbitMQ工作流程詳解

1 生產者發送消息的流程 (1)生產者連接RabbitMQ&#xff0c;建立TCP連接(Connection)&#xff0c;開啟信道(Channel) (2)生產者聲明一個Exchange (交換器)&#xff0c;并設置相關屬性&#xff0c;比如交換器類型、是否持久化等 (3)生產者聲明一個隊列井設置相關屬性&#xf…

Spring-Cloud-Loadblancer詳細分析_3

前兩篇文章介紹了加載過程&#xff0c;本文從Feign的入口開始分析執行過程&#xff0c;還是從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 前言 圖片懶加載是一種常見性能優化的方式&#xff0c;它只去加載可視區域圖片&#xff0c;而不是在網頁加載完畢后就立即加載所有圖片…