Instructions to use xfcghj/AR with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use xfcghj/AR with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("xfcghj/AR", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
File size: 8,156 Bytes
f0fc238 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | import io
import os
import tarfile
import pickle
import zstandard
import matplotlib.pyplot as plt
import numpy as np
import torch
import trimesh
# 引入刚才写好的 VAE 包装类
from models.vae import TripoSGVaeWrapper
# 引入 TripoSG 官方提供的层次化几何提取工具
from triposg.inference_utils import hierarchical_extract_geometry
# 配置路径
archive_path = "/home/dataset-assist-0/usr/lh/ysh/dw/RL/AR/data/DyMesh_50000v_16f_0001_part_00"
triposg_weights = "/home/dataset-assist-0/usr/lh/ysh/dw/RL/AR/TripoSG/pretrained_weights/TripoSG"
output_image_path = "vae_reconstruction_test.png"
def get_first_mesh_frame(archive_file):
"""从数据集中提取第一个有效物体的第0帧"""
with open(archive_file, 'rb') as fh:
dctx = zstandard.ZstdDecompressor()
with dctx.stream_reader(fh) as reader:
with tarfile.open(fileobj=reader, mode='r|') as tar:
for member in tar:
if member.isfile():
f = tar.extractfile(member)
if f is not None:
data = pickle.load(io.BytesIO(f.read()))
if isinstance(data, dict) and 'vertices' in data and 'faces' in data:
if data['vertices'].shape[0] == 16:
# 提取第0帧 (形状为 [V, 3]) 和 共享的面片
v_f0 = data['vertices'][0]
faces = data['faces']
short_name = os.path.basename(member.name).split('.')[0]
return v_f0, faces, short_name
raise RuntimeError("未在压缩包中找到合法的 16帧 动态 Mesh 数据。")
if __name__ == "__main__":
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16
# 1. 读取原数据并抽取静态帧
print("📦 正在从数据包中读取测试 Mesh...")
raw_vertices, raw_faces, obj_name = get_first_mesh_frame(archive_path)
print(f"成功提取物体 [{obj_name}] 的第一帧. 顶点数: {raw_vertices.shape[0]}, 面数: {raw_faces.shape[0]}")
# 2. 对原网格在内存中做归一化,以便后续做对齐可视化
mesh_raw = trimesh.Trimesh(vertices=raw_vertices, faces=raw_faces, process=False)
max_edge = np.max(mesh_raw.bounding_box.extents)
mesh_raw.vertices = (mesh_raw.vertices - mesh_raw.center_mass) * (2.0 / max_edge)
# 3. 初始化 VAE 包装模型
print("🔮 正在初始化冻结的 TripoSG VAE 模型...")
vae_wrapper = TripoSGVaeWrapper(weights_dir=triposg_weights, device=device, dtype=dtype)
# 4. 编码 (Mesh -> Latent Code)
# 修改 3. 编码部分的调用逻辑:
print("🚀 正在将 Mesh 表面密集点云编码至隐空间...")
# 将 numpy 数组显式转换为 torch.Tensor
v_tensor = torch.from_numpy(raw_vertices)
f_tensor = torch.from_numpy(raw_faces)
latent_code = vae_wrapper.encode_mesh(v_tensor, f_tensor, num_samples=204800)
print(f"编码成功!隐特征张量形状: {latent_code.shape}")
# 5. 解码重建 (Latent Code -> SDF -> Marching Cubes Mesh)
print("📐 正在通过层次化八叉树提取器(Hierarchical Octree)解码并重建 Mesh...")
geometric_func = lambda x: vae_wrapper.decode_latent(latent_code, sampled_points=x)
output_geometry = hierarchical_extract_geometry(
geometric_func,
device=device,
bounds=(-1.005, -1.005, -1.005, 1.005, 1.005, 1.005),
dense_octree_depth=8, # 密度深度
hierarchical_octree_depth=9, # 恢复细节的八叉树总深度
)
# 将提取出的解算数据转换为 trimesh 对象
recon_v, recon_f = output_geometry[0]
mesh_recon = trimesh.Trimesh(vertices=recon_v.astype(np.float32), faces=recon_f, process=False)
print(f"重建成功!重建后 Mesh 顶点数: {mesh_recon.vertices.shape[0]}, 面数: {mesh_recon.faces.shape[0]}")
# 🌟 5.5 进行几何指标定量评估 (Evaluation Metric) - 使用 Scipy KDTree 修复版本
print("📊 正在执行 KDTree 算法,评测重建精度指标...")
from scipy.spatial import KDTree
num_eval_samples = 50000
# 在两个几何表面分别均匀采样 5万 个测试点
pts_raw, _ = trimesh.sample.sample_surface(mesh_raw, num_eval_samples)
pts_recon, _ = trimesh.sample.sample_surface(mesh_recon, num_eval_samples)
# 建立空间平衡二叉树,用于秒级检索最近邻点
tree_raw = KDTree(pts_raw)
tree_recon = KDTree(pts_recon)
# 1. 计算重建点到真值点云的最近距离 (Recon -> Raw) -> 代表重建偏离误差
dists_recon_to_raw, _ = tree_raw.query(pts_recon, k=1)
# 2. 计算真值点到重建点云的最近距离 (Raw -> Recon) -> 代表细节遗漏误差
dists_raw_to_recon, _ = tree_recon.query(pts_raw, k=1)
# 计算均值
mae_recon_to_raw = np.mean(dists_recon_to_raw)
mae_raw_to_recon = np.mean(dists_raw_to_recon)
# 模拟双向倒角距离 (Chamfer Distance)
chamfer_dist_approx = mae_recon_to_raw + mae_raw_to_recon
# 计算在 1% 空间尺度阈值下的 F-Score
obj_scale = np.linalg.norm(mesh_raw.bounding_box.extents)
tau = 0.01 * obj_scale # 阈值设置为物体对角线长度的 1%
precision = np.mean(dists_recon_to_raw < tau)
recall = np.mean(dists_raw_to_recon < tau)
f_score = (2 * precision * recall) / (precision + recall) if (precision + recall) > 0 else 0.0
# 打印评估报告
print("\n" + "="*50)
print("📈 VAE Mesh 自编码重建评测报告 (KDTree 加速版):")
print("="*50)
print(f"1. 重建偏离误差 (Recon -> Raw MAE): {mae_recon_to_raw:.6f} (越小越好)")
print(f"2. 细节遗漏误差 (Raw -> Recon MAE): {mae_raw_to_recon:.6f} (越小越好)")
print(f"3. 倒角距离指标 (Chamfer Distance): {chamfer_dist_approx:.6f} (越小越好)")
print(f"4. 表面对齐分数 (F-Score @ 1%): {f_score * 100:.2f}% (越大越好)")
print("="*50 + "\n")
# 6. 使用 Matplotlib 绘制同视角对比图
print("🎨 正在绘制原网格与 VAE 重建网格的对比效果图...")
fig = plt.figure(figsize=(14, 6))
# 共同视角参数控制,防止发生视差偏离
all_points = np.concatenate([mesh_raw.vertices, mesh_recon.vertices], axis=0)
mid_x, mid_y, mid_z = (all_points.max(axis=0) + all_points.min(axis=0)) / 2.0
max_range = (all_points.max(axis=0) - all_points.min(axis=0)).max() / 2.0
# 子图 1:原始 Mesh(归一化后)
ax1 = fig.add_subplot(1, 2, 1, projection='3d')
ax1.plot_trisurf(mesh_raw.vertices[:, 0], mesh_raw.vertices[:, 1], mesh_raw.vertices[:, 2],
triangles=mesh_raw.faces, cmap='coolwarm', edgecolor='none', alpha=0.7)
ax1.set_title(f"Original Mesh (Normalized)\n({obj_name})", fontsize=12, weight='bold')
ax1.set_xlim(mid_x - max_range, mid_x + max_range)
ax1.set_ylim(mid_y - max_range, mid_y + max_range)
ax1.set_zlim(mid_z - max_range, mid_z + max_range)
ax1.axis('off')
ax1.view_init(elev=20, azim=45) # 设定固定视角
# 子图 2:VAE 解码重建的 Mesh
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
ax2.plot_trisurf(mesh_recon.vertices[:, 0], mesh_recon.vertices[:, 1], mesh_recon.vertices[:, 2],
triangles=mesh_recon.faces, cmap='viridis', edgecolor='none', alpha=0.7)
# 在标题上动态附带上 F-Score 信息,方便肉眼和指标联动对照
ax2.set_title(f"Reconstructed Mesh\n(F-Score: {f_score * 100:.2f}%)", fontsize=12, weight='bold')
ax2.set_xlim(mid_x - max_range, mid_x + max_range)
ax2.set_ylim(mid_y - max_range, mid_y + max_range)
ax2.set_zlim(mid_z - max_range, mid_z + max_range)
ax2.axis('off')
ax2.view_init(elev=20, azim=45) # 设定相同视角
plt.tight_layout()
plt.savefig(output_image_path, dpi=150, bbox_inches='tight')
plt.close()
print(f"💾 对比可视化结果已成功保存至: {output_image_path}") |