MonoHair 复现:权重、重建资产与 demo 数据(组织)

这个仓库包含四部分:

  • MonoHair(CVPR 2024)重建所用的 DeepMVSHair 权重;
  • 在作者提供的两个假发样例上,我们自己跑出的发丝重建结果;
  • 在 big_wavy1 上做剪发、物理 demo 时生成的派生数据;
  • 处理真人数据时 MonoHair 需要的 SMPL-X、PIXIE、DELTA 模型文件(仅本人使用,见上面的警告)。

生成这些数据的代码在 Snowflake-Pink/monohair-repro(私有)。

hf download PincoLi/monohair-repro --local-dir monohair-repro-hf
# 只要某一部分,可以加 --include "reconstructions/*"(或 "weights/*"、"derived/*")

文件

personal_licensed/
  assets_data/                  解压好的 14 个文件,直接放进 MonoHair/assets/data/
  original_downloads/           原始下载文件,未改动
weights/
  DeepMVSHair/    infer_inner 推断头发内部用的网络权重(见下文)
  SHA256SUMS
reconstructions/
  big_wavy1/      connected_strands.hair      最终发丝(173,205 根,1,437 万点,173 MB)
                  bust_long_tsfm.obj          头肩网格(与发丝同一坐标系),material_0.* 是它引用的材质
                  scalp_tsfm.obj              头皮网格(发根所在区域)
                  cam_params.json             作者数据里的相机参数,同一坐标系
                  compare_with_authors.json   与作者发布结果的对比指标
                  baseline_authors_full_vs_full1.json   作者两版结果之间的差异(基线)
  short_curly1/   同上(143,516 根,545 万点,66 MB;没有基线文件)
derived/big_wavy1/
  haircut/big_wavy1_haircut.npz               剪发 demo 的全部预计算数据
  physics/big_wavy1_model.npz                 可仿真的发丝模型(5 mm 间距的弹性杆)
  physics/cantilever.json                     弯曲刚度标定结果(物理脚本运行时会读)
  physics/support_scan.json                   发根支撑强度扫描:支撑越强,静置后越接近重建形状
  physics/demo_keyframes/meta.npz             物理 demo 的元数据(剪线、剪断时刻、头部转角、量化范围)
  physics/demo_keyframes/pos_0001.npy         第 1 帧:重力下静置 6 s 之后,即"带物理的重建"
  physics/demo_keyframes/pos_0140.npy         第 140 帧:第一次转头之后、下剪之前
  physics/demo_keyframes/pos_0300.npy         第 300 帧:剪完并再次转头之后
videos/                                       两个 demo 的 1080p 视频和封面

重建质量

case 发丝数 Chamfer(与作者结果) 5 mm 内的点(我们→作者 / 作者→我们) 方向一致性 |cos|
big_wavy1 173,205 1.82 mm 97.5% / 97.9% 0.934
short_curly1 143,516 1.62 mm 98.7% / 99.0% 0.891

作者自己发布的两版 big_wavy1 结果之间相差 2.40 mm,所以我们的结果在"同一方法重跑一次"的正常波动范围之内。

已知问题:约 6% 的发丝没有长在头皮上(是悬空的碎段)。物理模型里,这些碎段挂在最近的有根发丝上。

.hair 格式(MonoHair 原生格式,小端序)

字段 类型 说明
n_strands uint32 发丝数
n_points uint32 总点数
每根发丝的点数 uint16 × n_strands
点坐标 float32 × 3 × n_points 每根发丝从发根到发梢依次排列
import struct
import numpy as np

def load_hair(path):
    with open(path, 'rb') as f:
        n, npts = struct.unpack('<II', f.read(8))
        cnt = np.frombuffer(f.read(2 * n), '<u2').astype(np.int64)
        pts = np.frombuffer(f.read(12 * npts), '<f4').reshape(-1, 3)
    off = np.concatenate([[0], np.cumsum(cnt)])
    return pts, off          # 第 i 根发丝 = pts[off[i]:off[i + 1]]

坐标系

  • 重建坐标系(.hair、.obj、cam_params.json):单位米,y 轴向上,脸朝 +z。头部大约在 y = 1.4–2.0 m 的位置。
  • Blender 坐标系(derived/ 下的所有文件):单位米,z 轴向上,脸朝 −y。由重建坐标系变换得到:先 (x, y, z) → (x, −z, y),再减去平移 shift。平移让水平方向以头发包围盒为中心,地面 z = 0 在头肩网格的最低处。big_wavy1_model.npz 里存了 shift。

派生数据

**big_wavy1_model.npz**(物理模型)

字段 说明
pos、off 重采样到 5 mm 间距的发丝,格式同上
rooted 每根发丝的发根是否在头皮上(距头肩网格 1.5 cm 内)
parent 没有根的发丝挂在哪个点上(全局点索引;有根的为 −1)
bust_v、bust_f 头肩网格(碰撞体)
shift、seg 坐标平移、杆的分段长度

物理 demo 关键帧

pos_XXXX.npy 用 uint16 量化存储,发丝划分用 meta.npz 里的 off(与 big_wavy1_model.npz 相同):

m = np.load('meta.npz')
q = np.load('pos_0001.npy')
P = m['qlo'] + q / 65535.0 * (m['qhi'] - m['qlo'])   # (N, 3),单位米,精度约 21 µm

meta.npz 里的主要字段:

  • cut_abs:每根发丝被剪掉的第一个点的全局索引,这个点及以后的部分是剪下的发尾;−1 表示不剪。
  • tcut:剪刀经过这根发丝的帧号。
  • yaw:每帧头部绕 z 轴的转角。
  • zc、slope:剪线高度为 zc + slope · y。
  • F0–F1:剪刀绕头一圈的帧范围。
  • rise:每根被剪发丝的新发梢在剪后的回弹量(mm)。

仿真参数:

  • 头发:直径 70 µm,密度 1.3 g/cm³,E = 3 GPa;
  • 每帧 40 个子步,24 fps;
  • 发根支撑 3e-3 N/m,5 cm 衰减,发梢处为 0。

静置后与重建形状平均相差 11.7 mm(中位数 2.6 mm,p95 62 mm)。

**big_wavy1_haircut.npz**(剪发 demo,纯几何,不含物理)

字段 说明
pos、off、rad 重采样到 2.5 mm 的发丝,以及渲染用的半径(发根 45 µm,渐细到发梢 20 µm)
ci 每根发丝被剪掉的第一个点(局部索引;等于点数表示不剪)
Pc 剪线与发丝的交点
tcut 剪刀经过的帧号
cut_strands 被剪的发丝
cpos、coff、crad 剪下的发尾
cen、vel、axis、omega、land_dt、lift、spread、land_floor 发尾作为刚体下落、翻转、落地的参数
rmax 每个方位角上剪刀的半径
meta [FPS, 帧数, 开剪帧, 剪完帧, 起始方位角, 剪线高度, 剪线斜率, 重力, 地面高度, 最大翻转角]
bust_v、bust_f 头肩网格

字段的具体用法见代码仓库里的 scripts/haircut_prep.py 和 scripts/haircut_render.py。

权重

weights/DeepMVSHair/ 与上游仓库 commit 38c3bce 下 submodules/DeepMVSHair/trained/ 里的文件完全相同(见 SHA256SUMS),没有重新训练或修改。放在这里,是为了在访问 GitHub 很慢的环境(比如 SenseCore 容器)里也能下载。

目录 说明
wky10-30-undirection/ MonoHair 默认配置实际使用的这组(configs/dense_sample_real/vit_standard.txt),我们的复现也用这组
wky04-19/、wky09-21-depth/、wky10-14-cat_depth/ 上游一起发布的其他版本

每组包括 occ.pth(占据)、ori.pth(方向)和训练统计 stats_*.txt。放回代码目录:

cp -r monohair-repro-hf/weights/DeepMVSHair/* MonoHair/submodules/DeepMVSHair/trained/

MODNet、CDGNet、face-parsing 的预训练模型不在这里;需要时用上游的 fetch_pretrained_model.sh 下载。

需要注册的模型文件(personal_licensed/,仅本人使用)

只有处理真人数据(多视角头部拟合)时才需要;作者的假发样例用的是固定的头模,用不到。

assets_data/ 是 MonoHair 的 configs/Bust_fit/base.yaml 所需的文件,放回代码目录:

cp monohair-repro-hf/personal_licensed/assets_data/* MonoHair/assets/data/
原始文件(original_downloads/) 来源 解压出的文件
smplx/SMPLX_NEUTRAL_2020.npz SMPL-X,SMPL-X 2020 本身
smplx/smplx_mano_flame_correspondences.zip SMPL-X,MANO and FLAME vertex indices MANO_SMPLX_vertex_ids.pkl、SMPL-X__FLAME_vertex_ids.npy
pixie/utilities.zip PIXIE flame2smplx_tex_1024.npy、smplx_tex.*、smplx_hand.obj、SMPLX_to_J14.pkl、uv_face*_mask.png 等 11 个
delta/delta_utilities.zip DELTA(上游 fetch_data.sh) FLAME_masks.pkl(另有 head_template_mesh_mouth.obj、subdiv_level_1/,没有放进 assets_data/)
delta/delta_utilities2.zip DELTA FLAME_albedo_from_BFM.npz(解压后 1.26 GB)

这些文件各自受其官方许可约束(非商业研究用途、禁止再分发),不适用本仓库其余部分的 CC BY-NC 4.0。

许可与出处

输入数据(作者的假发样例)、MonoHair 代码和 DeepMVSHair 权重都是 CC BY-NC 4.0,这里的权重和结果也遵守这一许可:只能非商业使用,并需要注明出处。

Keyu Wu, Lingchen Yang, Zhiyi Kuang, Yao Feng, Xutao Han, Yuefan Shen, Hongbo Fu, Kun Zhou, Youyi Zheng. MonoHair: High-Fidelity Hair Modeling from a Monocular Video. CVPR 2024.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support