|
|
@ -20,6 +20,10 @@ def create_grid(depth, box_size): |
|
|
|
z = np.linspace(start, end, grid_size) |
|
|
|
xx, yy, zz = np.meshgrid(x, y, z, indexing='ij') |
|
|
|
points = np.stack([xx.ravel(), yy.ravel(), zz.ravel()], axis=1) |
|
|
|
|
|
|
|
# 新增归一化处理 |
|
|
|
max_coord = np.max(np.abs(points)) |
|
|
|
points = points / max_coord # 归一化到[-1,1] |
|
|
|
return points, xx, yy, zz |
|
|
|
|
|
|
|
def predict_sdf(model, points, device): |
|
|
@ -36,7 +40,7 @@ def predict_sdf(model, points, device): |
|
|
|
sdf = model(points_t).cpu().numpy().flatten() |
|
|
|
return sdf |
|
|
|
|
|
|
|
def extract_surface(sdf, xx, yy, zz, method='MC'): |
|
|
|
def extract_surface(sdf, xx, yy, zz, method='MC', feature_angle=30.0, voxel_size=0.01): |
|
|
|
""" |
|
|
|
提取零表面 |
|
|
|
:param sdf: SDF值三维数组 |
|
|
@ -46,8 +50,21 @@ def extract_surface(sdf, xx, yy, zz, method='MC'): |
|
|
|
""" |
|
|
|
if method == 'MC': |
|
|
|
verts, faces, _, _ = measure.marching_cubes(sdf, level=0) |
|
|
|
elif method == 'EMC': |
|
|
|
from iso_algorithms import enhanced_marching_cubes |
|
|
|
verts, faces = enhanced_marching_cubes( |
|
|
|
sdf, |
|
|
|
feature_angle=feature_angle, |
|
|
|
gradient_direction='descent' |
|
|
|
) |
|
|
|
elif method == 'DC': |
|
|
|
from iso_algorithms import dual_contouring |
|
|
|
verts, faces = dual_contouring(sdf, voxel_size=voxel_size) |
|
|
|
else: |
|
|
|
raise NotImplementedError("仅支持Marching Cubes方法") |
|
|
|
raise ValueError(f"不支持的算法: {method}") |
|
|
|
|
|
|
|
# 新增顶点后处理 |
|
|
|
verts = (verts - sdf.shape[0]//2) / (sdf.shape[0]//2) # 归一化到[-1,1] |
|
|
|
return verts, faces |
|
|
|
|
|
|
|
def save_ply(vertices, faces, filename): |
|
|
@ -111,9 +128,16 @@ def main(): |
|
|
|
parser = argparse.ArgumentParser(description='IsoSurface Generator') |
|
|
|
parser.add_argument('-i', '--input', type=str, required=True, help='Input model file (.pt)') |
|
|
|
parser.add_argument('-o', '--output', type=str, required=True, help='Output mesh file (.ply)') |
|
|
|
parser.add_argument('--depth', type=int, default=3, help='网格深度(分辨率)') |
|
|
|
parser.add_argument('--box_size', type=float, default=1.0, help='边界框大小') |
|
|
|
parser.add_argument('--method', type=str, default='MC', choices=['MC'], help='表面提取方法') |
|
|
|
parser.add_argument('--depth', type=int, default=7, help='网格深度(分辨率)') |
|
|
|
parser.add_argument('--box_size', type=float, default=2.0, # 从1.0改为2.0 |
|
|
|
help='边界框大小(建议设为2.0以得到[-1,1]范围)') |
|
|
|
parser.add_argument('--method', type=str, default='MC', |
|
|
|
choices=['MC', 'EMC', 'DC'], # 新增算法选项 |
|
|
|
help='表面提取方法: MC-MarchingCubes, EMC-EnhancedMC, DC-DualContouring') |
|
|
|
parser.add_argument('--feature_angle', type=float, default=30.0, |
|
|
|
help='特征角度阈值(EMC算法专用)') |
|
|
|
parser.add_argument('--voxel_size', type=float, default=0.01, |
|
|
|
help='体素尺寸(DC算法专用)') |
|
|
|
parser.add_argument('--use-gpu', action='store_true', help='使用GPU') |
|
|
|
parser.add_argument('--compare', type=str, help='GT网格文件(.ply)') |
|
|
|
parser.add_argument('--compres', type=int, default=32, help='误差计算分辨率') |
|
|
@ -139,6 +163,11 @@ def main(): |
|
|
|
print("Extracting surface...") |
|
|
|
start_time = time.time() |
|
|
|
verts, faces = extract_surface(sdf_grid, xx, yy, zz, args.method) |
|
|
|
|
|
|
|
# 新增顶点归一化校验 |
|
|
|
max_val = np.max(np.abs(verts)) |
|
|
|
if max_val > 1.0 + 1e-6: # 允许微小误差 |
|
|
|
verts = verts / max_val |
|
|
|
print(f"Surface extraction took {time.time() - start_time:.2f} seconds") |
|
|
|
|
|
|
|
# 保存网格 |
|
|
|