Compare commits

..
9 changed files with 1514 additions and 66 deletions
+19
View File
@@ -0,0 +1,19 @@
.PHONY: install install_all install_modules download_flux download_vae
# install everything except WAN‑VACE downloads
install:
./install.sh install
# install everything + WAN‑VACE + HF login
install_all:
./install.sh all
# lower‑level helpers
install_modules:
./install.sh modules
download_flux:
./install.sh flux
download_vae:
./install.sh vae
+17 -4
View File
@@ -80,18 +80,25 @@ A collection of ComfyUI custom nodes to handle diverse camera projections (pinho
* ### Reprojection Nodes
* `ReprojectImage`, `ReprojectDepth`, `OutpaintAnyProjection`
* ### Matrix Nodes
* `TransformToMatrix`, `TransformToMatrixManual`
* ### Depth Nodes
* `DepthEstimatorNode`, `DepthToImageNode`, `ZDepthToRayDepthNode`
* `CombineDepthsNode`, `DepthRenormalizer`
* `CombineDepthsNode`, `DepthRenormalizer`, `FisheyeDepthEstimator`
* ### Point Cloud Nodes
* `DepthToPointCloud`, `TransformPointCloud`, `ProjectPointCloud`
* `PointCloudUnion`, `PointCloudCleaner`, `LoadPointCloud`, `SavePointCloud`
* `DepthToPointCloud`, `TransformPointCloud`, `ProjectPointCloud`, `PointCloudUnion`
* `PointCloudCleaner`, `LoadPointCloud`, `SavePointCloud`, `ProjectAndClean`
* ### Trajectory Nodes
* `CameraMotionNode`, `CameraInterpolationNode`, `CameraTrajectoryNode`
* `SaveTrajectory`, `LoadTrajectory`, `PointcloudTrajectoryEnricher`
---
@@ -201,6 +208,12 @@ Take a wide-angle (fisheye or equirectangular) high-resolution (e.g., 4096×4096
Interactive Open3D-based GUI for walking and setting camera trajectory inside pointcloud.
### 11. `wan-vace_ref_to_video.json`
Integrate the [wan2.1-vace] video generation model to inpaint empty or newly revealed regions during camera movement or view synthesis. This workflow demonstrates how to use the camera-comfyUI nodes to generate camera trajectories and masks, then fill missing areas with the video inpainting model for smooth, high-quality results.
<img src="demo_images/wan-vace-camera.gif" alt="wan2.1-vace Camera Inpainting Demo" width="80%" />
---
## Contributing
@@ -217,4 +230,4 @@ Contributions welcome! Please open issues or PRs to add features, improve docs,
* [x] Add more examples and documentation for each node.
* [x] Add pointcloud union
* [ ] Fix imports for renamed folders (e.g., inpainting_flux)
* [ ] Integrate camera movement pipeline with video models (e.g., wan2.1) for smooth, high-quality inpainting along camera trajectories.
* [x] Integrate camera movement pipeline with video models (e.g., wan2.1) for smooth, high-quality inpainting along camera trajectories.
+2 -2
View File
@@ -64,7 +64,7 @@ class FisheyeDepthEstimator:
RETURN_TYPES = ("TENSOR","MASK")
RETURN_NAMES = ("depthmap","mask")
FUNCTION = "estimate_fisheye_depth"
CATEGORY = "Camera/depth"
CATEGORY = "Camera/Depth"
def estimate_fisheye_depth(
self,
@@ -241,7 +241,7 @@ class PointcloudTrajectoryEnricher:
RETURN_TYPES = ("TENSOR","IMAGE","TENSOR")
RETURN_NAMES = ("enriched_pointcloud","debug_image","debug_depth")
FUNCTION = "enrich_trajectory"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/Trajectory"
def enrich_trajectory(
self,
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB

+113 -37
View File
@@ -1,49 +1,125 @@
#!/usr/bin/env bash
set -euo pipefail
# 1. Install PyTorch with CUDA 12.8 wheels
echo "Installing PyTorch, TorchVision, TorchAudio..."
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
# ----------------------------------------
# Functions
# ----------------------------------------
install_pytorch() {
echo "Installing PyTorch, TorchVision, TorchAudio..."
pip3 install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
pip3 install bitsandbytes
pip3 install accelerate
}
# 2. Update apt repositories and install system dependencies
echo "Updating apt and installing build-essential, ffmpeg, libsm6, libxext6..."
sudo apt-get update
sudo apt-get install -y build-essential ffmpeg libsm6 libxext6
install_system_deps() {
echo "Updating apt and installing system dependencies..."
sudo apt-get update
sudo apt-get install -y build-essential ffmpeg libsm6 libxext6
}
# 3. Clone ComfyUI and install its Python requirements
echo "Cloning ComfyUI..."
git clone https://github.com/comfyanonymous/ComfyUI.git
echo "Installing ComfyUI requirements..."
pip3 install -r ComfyUI/requirements.txt
clone_and_install_comfyui() {
echo "Cloning ComfyUI..."
git clone https://github.com/comfyanonymous/ComfyUI.git
echo "Installing ComfyUI requirements..."
pip3 install -r ComfyUI/requirements.txt
}
# 4. Enter the custom_nodes folder
cd ComfyUI/custom_nodes
install_camera_node() {
echo "Cloning camera‑ComfyUI..."
git clone https://github.com/Alexankharin/camera-comfyUI.git \
ComfyUI/custom_nodes/camera-comfyUI
echo "Installing camera‑ComfyUI requirements..."
pip3 install -r ComfyUI/custom_nodes/camera-comfyUI/requirements.txt
}
# 5. camera-comfyUI
echo "Cloning camera-comfyUI..."
git clone https://github.com/Alexankharin/camera-comfyUI.git
echo "Installing camera-comfyUI requirements..."
pip3 install camera-comfyUI/requirements.txt
install_image_filters() {
echo "Cloning Image‑Filters node..."
git clone https://github.com/spacepxl/ComfyUI-Image-Filters.git \
ComfyUI/custom_nodes/ComfyUI-Image-Filters
echo "Installing Image‑Filters requirements..."
pip3 install -r ComfyUI/custom_nodes/ComfyUI-Image-Filters/requirements.txt
}
# 6. ComfyUI-Flux-Inpainting
echo "Cloning ComfyUI-Flux-Inpainting..."
git clone https://github.com/rubi-du/ComfyUI-Flux-Inpainting.git
echo "Installing ComfyUI-Flux-Inpainting requirements..."
pip3 install ComfyUI-Flux-Inpainting/requirements.txt
clone_flux_inpainting() {
echo "Cloning ComfyUI‑Flux‑Inpainting..."
git clone https://github.com/rubi-du/ComfyUI-Flux-Inpainting.git \
ComfyUI/custom_nodes/Flux-Inpainting
echo "Renaming Flux‑Inpainting folder..."
mv ComfyUI/custom_nodes/Flux-Inpainting \
ComfyUI/custom_nodes/inpainting_flux
}
# 7. ComfyUI-Image-Filters
echo "Cloning ComfyUI-Image-Filters..."
git clone https://github.com/spacepxl/ComfyUI-Image-Filters.git
echo "Installing ComfyUI-Image-Filters requirements..."
pip3 install ComfyUI-Image-Filters/requirements.txt
install_hf_hub() {
echo "Installing huggingface_hub..."
pip3 install huggingface_hub
}
# 8. Tidy up Flux Inpainting folder name
echo "Renaming Flux Inpainting folder..."
cd ..
mv custom_nodes/ComfyUI-Flux-Inpainting-main custom_nodes/inpainting_flux
download_vae_models() {
echo "Downloading WAN‑VACE models via wget..."
wget -O ComfyUI/models/vae/wan_2.1_vae.safetensors \
"https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/vae/wan_2.1_vae.safetensors?download=true"
# 9. Install Hugging Face Hub Python package
echo "Installing huggingface_hub..."
pip3 install huggingface_hub
wget -O ComfyUI/models/text_encoders/umt5_xxl_fp16.safetensors \
"https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/text_encoders/umt5_xxl_fp16.safetensors?download=true"
echo "All done! 🎉"
wget -O ComfyUI/models/diffusion_models/wan2.1_vace_14B_fp16.safetensors \
"https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_vace_14B_fp16.safetensors"
}
login_hf_hub() {
echo "Logging in to Hugging Face Hub..."
huggingface-cli login
}
# ----------------------------------------
# Main CLI
# ----------------------------------------
# default to "install" if no arg given
MODE="${1:-install}"
case "$MODE" in
modules)
install_pytorch
install_system_deps
clone_and_install_comfyui
install_camera_node
install_image_filters
install_hf_hub
;;
flux)
clone_flux_inpainting
;;
vae)
download_vae_models
;;
install)
install_pytorch
install_system_deps
clone_and_install_comfyui
install_camera_node
clone_flux_inpainting
install_image_filters
install_hf_hub
;;
all)
install_pytorch
install_system_deps
clone_and_install_comfyui
install_camera_node
clone_flux_inpainting
install_image_filters
install_hf_hub
download_vae_models
login_hf_hub
echo "All done! 🎉"
;;
*)
echo "Usage: $0 {install|modules|flux|vae|all}"
exit 1
;;
esac
+5 -5
View File
@@ -41,7 +41,7 @@ class DepthEstimatorNode:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("depth tensor",)
FUNCTION = "estimate_depth"
CATEGORY = "Camera/depth"
CATEGORY = "Camera/Depth"
def estimate_depth(
self,
@@ -110,7 +110,7 @@ class DepthToImageNode:
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("depth image",)
FUNCTION = "depth_to_image"
CATEGORY = "Camera/depth"
CATEGORY = "Camera/Depth"
def depth_to_image(
self,
@@ -158,7 +158,7 @@ class ZDepthToRayDepthNode:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("ray depth",)
FUNCTION = "depth_to_ray_depth"
CATEGORY = "Camera/depth"
CATEGORY = "Camera/Depth"
def depth_to_ray_depth(
self,
@@ -229,7 +229,7 @@ class CombineDepthsNode:
RETURN_TYPES = ("TENSOR","MASK")
RETURN_NAMES = ("combined_depth","combined_mask")
FUNCTION = "combine_depths"
CATEGORY = "Camera/depth"
CATEGORY = "Camera/Depth"
def combine_depths(
self,
@@ -358,7 +358,7 @@ class DepthRenormalizer:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("depth tensor",)
FUNCTION = "renormalize_depth"
CATEGORY = "Camera/depth"
CATEGORY = "Camera/Depth"
def renormalize_depth(
self,
+14 -14
View File
@@ -113,7 +113,7 @@ def XYZ_to_equirect(X: torch.Tensor, Y: torch.Tensor, Z: torch.Tensor, fov: floa
Convert XYZ coordinates to normalized UV and depth using equirectangular projection.
"""
# full 360°×180°
fov_rad = math.radians(fov)
fov_rad = math.radians(fov) / 2
depth = torch.sqrt(X**2 + Y**2 + Z**2)
lon = torch.atan2(X, Z) # –π → +π
lat = torch.asin(Y / depth) # –π/2 → +π/2
@@ -167,7 +167,7 @@ class DepthToPointCloud:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("pointcloud",)
FUNCTION = "depth_to_pointcloud"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
def depth_to_pointcloud(
self,
@@ -273,7 +273,7 @@ class TransformPointCloud:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("transformed pointcloud",)
FUNCTION = "transform_pointcloud"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
def transform_pointcloud(
self,
@@ -321,7 +321,7 @@ class ProjectPointCloud:
RETURN_TYPES = ("IMAGE", "MASK", "TENSOR")
RETURN_NAMES = ("image", "mask", "depth")
FUNCTION = "project_pointcloud"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
def project_pointcloud(
self,
@@ -456,7 +456,7 @@ class PointCloudUnion:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES =("merged pointcloud",)
FUNCTION = "union_pointclouds"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
def union_pointclouds(
self,
@@ -492,7 +492,7 @@ class LoadPointCloud:
}
}
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("loaded pointcloud",)
FUNCTION = "load_pointcloud"
@@ -590,7 +590,7 @@ class SavePointCloud:
RETURN_TYPES = ()
FUNCTION = "save_pointcloud"
OUTPUT_NODE = True
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
DESCRIPTION = "Saves the input point cloud to your ComfyUI output directory as .ply or .npy."
def save_pointcloud(self, pointcloud: torch.Tensor, filename_prefix: str, save_as: str = "ply"):
@@ -681,7 +681,7 @@ class CameraMotionNode:
RETURN_TYPES = ("IMAGE", "MASK")
RETURN_NAMES = ("motion_frames", "mask_frames")
FUNCTION = "generate_motion_frames"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/Trajectory"
def generate_motion_frames(
self,
@@ -764,7 +764,7 @@ class CameraInterpolationNode:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("trajectory",)
FUNCTION = "interpolate"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/Trajectory"
def interpolate(
self,
@@ -799,7 +799,7 @@ class CameraTrajectoryNode:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("trajectory",)
FUNCTION = "build_trajectory"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/Trajectory"
def build_trajectory(
self,
@@ -939,7 +939,7 @@ class PointCloudCleaner:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("cleaned_pointcloud",)
FUNCTION = "clean_pointcloud"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
def clean_pointcloud(
self,
@@ -1015,7 +1015,7 @@ class ProjectAndClean:
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("cleaned_pointcloud",)
FUNCTION = "project_and_clean"
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/PointCloud"
def project_and_clean(
self,
@@ -1129,7 +1129,7 @@ class SaveTrajectory:
RETURN_TYPES = ()
FUNCTION = "save_trajectory"
OUTPUT_NODE = True
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/Trajectory"
DESCRIPTION = "Saves the input trajectory tensor (N,4,4) to your ComfyUI output directory as .npy."
def save_trajectory(self, trajectory: torch.Tensor, filename_prefix: str):
@@ -1179,7 +1179,7 @@ class LoadTrajectory:
}
}
CATEGORY = "Camera/pointcloud"
CATEGORY = "Camera/Trajectory"
RETURN_TYPES = ("TENSOR",)
RETURN_NAMES = ("loaded_trajectory",)
FUNCTION = "load_trajectory"
+4 -4
View File
@@ -148,7 +148,7 @@ class ReprojectImage:
RETURN_TYPES: Tuple[str, str] = ("IMAGE", "MASK")
RETURN_NAMES = ("reprojected image", "reprojected mask")
FUNCTION: str = "reproject_image"
CATEGORY: str = "Camera/reproject"
CATEGORY: str = "Camera/Reprojection"
def reproject_image(
self,
@@ -303,7 +303,7 @@ class TransformToMatrix:
RETURN_TYPES: Tuple[str] = ("MAT_4X4",)
RETURN_NAMES = ("transformation matrix",)
FUNCTION: str = "generate_matrix"
CATEGORY: str = "Camera/reproject"
CATEGORY: str = "Camera/Matrix"
def generate_matrix(
self,
@@ -392,7 +392,7 @@ class TransformToMatrixManual:
RETURN_TYPES: Tuple[str] = ("MAT_4X4",)
RETURN_NAMES = ("transformation matrix",)
FUNCTION: str = "generate_matrix"
CATEGORY: str = "Camera/reproject"
CATEGORY: str = "Camera/Matrix"
def generate_matrix(
self,
@@ -444,7 +444,7 @@ class ReprojectDepth:
RETURN_TYPES: Tuple[str, str] = ("TENSOR", "MASK")
RETURN_NAMES = ("reprojected_depth", "reprojected_mask")
FUNCTION: str = "reproject_depth"
CATEGORY: str = "Camera/reproject"
CATEGORY: str = "Camera/Reprojection"
def reproject_depth(
self,
File diff suppressed because it is too large Load Diff