136 lines
5.6 KiB
Python
136 lines
5.6 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import os
|
|
from .common import get_default_extrinsics, get_default_intrinsics, get_recommended_resolution
|
|
from .load_gaussian_ply import LoadGaussianPLY
|
|
|
|
|
|
class ProcessGaussianPLY:
|
|
"""Process a Gaussian splat PLY file from upstream nodes (e.g., SHARP Predict)."""
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"ply_path": ("STRING", {
|
|
"forceInput": True,
|
|
"tooltip": "PLY file path from upstream node (e.g., SHARP Predict)",
|
|
}),
|
|
},
|
|
"optional": {
|
|
"input_extrinsics": ("EXTRINSICS", {
|
|
"tooltip": "Extrinsics from upstream node (ignored if override_camera enabled)",
|
|
}),
|
|
"input_intrinsics": ("INTRINSICS", {
|
|
"tooltip": "Intrinsics from upstream node (ignored if override_camera enabled)",
|
|
}),
|
|
"override_camera": (["disabled", "enabled"], {
|
|
"default": "enabled",
|
|
"tooltip": "Override input camera params with custom FOV settings",
|
|
}),
|
|
"fov_degrees": ("FLOAT", {
|
|
"default": 50.0,
|
|
"min": 10.0,
|
|
"max": 180.0,
|
|
"step": 1.0,
|
|
"tooltip": "Horizontal field of view in degrees (used when override_camera enabled)",
|
|
}),
|
|
"auto_resolution": (["disabled", "enabled"], {
|
|
"default": "enabled",
|
|
"tooltip": "Auto-calculate optimal resolution based on FOV and target scale",
|
|
}),
|
|
"target_scale": ("FLOAT", {
|
|
"default": 10.0,
|
|
"min": 1.0,
|
|
"max": 50.0,
|
|
"step": 1.0,
|
|
"tooltip": "Target gaussian scale in viewer (used when auto_resolution enabled)",
|
|
}),
|
|
"image_width": ("INT", {
|
|
"default": 512,
|
|
"min": 64,
|
|
"max": 8192,
|
|
"step": 1,
|
|
"tooltip": "Image width (used when auto_resolution disabled)",
|
|
}),
|
|
"image_height": ("INT", {
|
|
"default": 512,
|
|
"min": 64,
|
|
"max": 8192,
|
|
"step": 1,
|
|
"tooltip": "Image height (used when auto_resolution disabled)",
|
|
}),
|
|
"enable_opacity_filter": (["disabled", "enabled"], {
|
|
"default": "disabled",
|
|
"tooltip": "Filter out low-opacity Gaussians to reduce background noise",
|
|
}),
|
|
"opacity_threshold": ("FLOAT", {
|
|
"default": 0.1,
|
|
"min": 0.0,
|
|
"max": 1.0,
|
|
"step": 0.01,
|
|
"tooltip": "Minimum opacity (0-1). Gaussians below this will be removed",
|
|
}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("STRING", "EXTRINSICS", "INTRINSICS")
|
|
RETURN_NAMES = ("ply_path", "extrinsics", "intrinsics")
|
|
FUNCTION = "process_ply"
|
|
CATEGORY = "PlyPreview"
|
|
|
|
def process_ply(
|
|
self,
|
|
ply_path: str,
|
|
input_extrinsics=None,
|
|
input_intrinsics=None,
|
|
override_camera: str = "enabled",
|
|
fov_degrees: float = 50.0,
|
|
auto_resolution: str = "enabled",
|
|
target_scale: float = 10.0,
|
|
image_width: int = 512,
|
|
image_height: int = 512,
|
|
enable_opacity_filter: str = "disabled",
|
|
opacity_threshold: float = 0.1,
|
|
):
|
|
if not ply_path or ply_path.strip() == "":
|
|
raise ValueError("PLY path cannot be empty")
|
|
|
|
resolved = ply_path.strip().strip('"')
|
|
if not os.path.exists(resolved):
|
|
raise ValueError(f"PLY file not found: {resolved}")
|
|
if not resolved.lower().endswith(".ply"):
|
|
raise ValueError("File must be a .ply Gaussian splat")
|
|
|
|
print(f"[ProcessGaussianPLY] Input PLY: {resolved}")
|
|
|
|
if override_camera == "enabled":
|
|
if auto_resolution == "enabled":
|
|
image_width, image_height = get_recommended_resolution(fov_degrees, target_scale)
|
|
print(f"[ProcessGaussianPLY] Auto-resolution for FOV {fov_degrees}° @ scale {target_scale}: {image_width}x{image_height}")
|
|
extrinsics = get_default_extrinsics()
|
|
intrinsics = get_default_intrinsics(image_width, image_height, fov_degrees)
|
|
print(f"[ProcessGaussianPLY] Override camera: FOV={fov_degrees}°, size={image_width}x{image_height}")
|
|
else:
|
|
if input_extrinsics is not None:
|
|
extrinsics = input_extrinsics
|
|
print("[ProcessGaussianPLY] Using input extrinsics")
|
|
else:
|
|
extrinsics = get_default_extrinsics()
|
|
print("[ProcessGaussianPLY] Using default extrinsics (no input provided)")
|
|
|
|
if input_intrinsics is not None:
|
|
intrinsics = input_intrinsics
|
|
print("[ProcessGaussianPLY] Using input intrinsics")
|
|
else:
|
|
intrinsics = get_default_intrinsics(image_width, image_height, fov_degrees)
|
|
print("[ProcessGaussianPLY] Using default intrinsics (no input provided)")
|
|
|
|
output_path = resolved
|
|
if enable_opacity_filter == "enabled":
|
|
loader = LoadGaussianPLY()
|
|
output_path = loader._filter_by_opacity(resolved, opacity_threshold)
|
|
print(f"[ProcessGaussianPLY] Filtered PLY saved to: {output_path}")
|
|
|
|
return (output_path, extrinsics, intrinsics)
|