From ef68b58d053d3fe4bf7a7565bcc1f1802a3f1952 Mon Sep 17 00:00:00 2001 From: Albertgary Date: Mon, 26 Jan 2026 22:04:59 +0800 Subject: [PATCH] fix pycolmap API incompatibility and gsplat spherical_harmonics mask shape --- hsplat/load_data.py | 14 +++++++++++--- hsplat/viz_utils/parser.py | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/hsplat/load_data.py b/hsplat/load_data.py index e976e2f..014fd3f 100644 --- a/hsplat/load_data.py +++ b/hsplat/load_data.py @@ -183,6 +183,12 @@ def load_2dgs_ckpt(pt_path, ch, viewmat, K, width, height, num_points=None, dev= far_plane=200, ) + # fully_fused_projection_2dgs returns radii with shape [C, N, 2]. + # gsplat.spherical_harmonics expects masks to match the batch dimensions + # of dirs, i.e. [C, N]. Collapse the last dimension of radii into a + # single boolean visibility mask. + valid_mask = (radii[..., 0] > 0) & (radii[..., 1] > 0) + camtoworlds = torch.inverse(viewmat[None]) dirs = samples["means"][None, :, :] - camtoworlds[:, None, :3, 3] # Gaussian ray directions @@ -194,7 +200,7 @@ def load_2dgs_ckpt(pt_path, ch, viewmat, K, width, height, num_points=None, dev= sh_opacity_degree = int(math.sqrt(sh_opacities.shape[-2]) - 1) opacities = spherical_harmonics( - sh_opacity_degree, dirs, sh_opacities, masks=radii > 0 + sh_opacity_degree, dirs, sh_opacities, masks=valid_mask ) opacities = opacities[..., 0] # [C, N] @@ -214,7 +220,7 @@ def load_2dgs_ckpt(pt_path, ch, viewmat, K, width, height, num_points=None, dev= sh = sh[..., None].expand(-1, -1, 3) # [N, K, 3] colors = spherical_harmonics( - 0, dirs, sh.unsqueeze(0), masks=radii > 0 + 0, dirs, sh.unsqueeze(0), masks=valid_mask )[..., 0].squeeze() # [N] colors = torch.clamp_min(colors + 0.5, 0.0) @@ -336,7 +342,9 @@ def load_gaussians( sampled_idx = gaussian_primitives.sample_points(num_points) # --- Culling --- - gaussian_primitives.cull_elements("gsplat_culling", radii.squeeze()[sampled_idx]) + # radii has shape [C, N, 2]; derive a per-Gaussian visibility mask [N] + visibility_mask = ((radii[..., 0] > 0) & (radii[..., 1] > 0)).squeeze(0) + gaussian_primitives.cull_elements("gsplat_culling", visibility_mask[sampled_idx]) logger.info(f"Number of Gaussians after culling: {len(gaussian_primitives)}") # Prune Gaussians with Small Scales diff --git a/hsplat/viz_utils/parser.py b/hsplat/viz_utils/parser.py index 4bde40e..899caa2 100644 --- a/hsplat/viz_utils/parser.py +++ b/hsplat/viz_utils/parser.py @@ -7,7 +7,7 @@ import imageio.v2 as imageio import numpy as np import torch -from pycolmap import SceneManager +from pycolmap import Reconstruction from .normalize import ( align_principle_axes, @@ -48,7 +48,7 @@ def __init__( colmap_dir ), f"COLMAP directory {colmap_dir} does not exist." - manager = SceneManager(colmap_dir) + manager = Reconstruction(colmap_dir) manager.load_cameras() manager.load_images() manager.load_points3D()