Convert binary NIfTI segmentation masks to surface meshes (OBJ) with optional GPU Laplacian smoothing.
Project description
xcat-mesh
Fast and efficient conversion of binary NIfTI segmentation masks (.nii / .nii.gz) into high-quality 3D surface meshes.
Features
- 🚀 Fast: Optimized pipeline with progress tracking
- 🎯 Simple: Single command to generate meshes
- 🔧 Configurable: JSON-based configuration for all parameters
- 💻 GPU Accelerated: Optional GPU smoothing with PyTorch
- 📦 Lightweight: Minimal dependencies, clean codebase
- 🔄 Flexible: Supports resampling, reorientation, and multiple smoothing methods
What It Does
xcat-mesh converts 3D medical imaging segmentation masks into polygon surface meshes using:
- Marching Cubes Algorithm: Extracts isosurface at level 0.5
- Optional Resampling: Resample to target voxel spacing
- Mesh Smoothing: Laplacian or Taubin smoothing (CPU/GPU)
- OBJ Export: Standard Wavefront OBJ format
Perfect for visualizing anatomical structures, 3D printing medical models, or preparing meshes for computational simulations.
About XCAT 3.0
This tool was developed as part of research in generating XCAT 3.0 Digital Twins - a comprehensive library of personalized computational phantoms derived from CT scans. XCAT 3.0 enables researchers to create patient-specific anatomical models for:
- Medical imaging simulation and validation
- Radiation dose optimization
- Image reconstruction algorithm development
- AI/ML training with ground truth anatomies
- Virtual clinical trials
The mesh generation pipeline in xcat-mesh is a key component for converting segmented anatomical structures into high-quality surface representations used in the XCAT phantom library.
Installation
Basic Installation (CPU only)
pip install xcat-mesh
GPU-Accelerated Smoothing
pip install "xcat-mesh[gpu]"
This installs PyTorch for GPU-accelerated mesh smoothing.
Development Installation
git clone https://github.com/yourusername/xcat-mesh.git
cd xcat-mesh
pip install -e .
Quick Start
CLI Usage
Step 1: Create a default configuration file
xcat-mesh init-config --out config.json
Step 2: Run the meshing pipeline
xcat-mesh run --input segmentation_mask.nii.gz --config config.json
That's it! Your meshes will be saved to the paths specified in config.json.
One-Liner
xcat-mesh init-config --out config.json && xcat-mesh run --input mask.nii.gz --config config.json
Configuration
The generated config.json looks like this:
{
"target_resolution_mm": [1.0, 1.0, 1.0],
"reorient_canonical": true,
"smooth": {
"enabled": true,
"method": "laplacian",
"num_iter": 10,
"weight": 0.1,
"lambda": 0.5,
"mu": -0.53,
"device": "cpu"
},
"output": {
"mesh_unsmoothed_path": "mesh_raw.obj",
"mesh_smoothed_path": "mesh_smooth.obj"
}
}
Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
target_resolution_mm |
[float, float, float] or null |
[1.0, 1.0, 1.0] |
Target voxel spacing in mm (x,y,z). Set to null to disable resampling. |
reorient_canonical |
bool |
true |
Reorient image to RAS+ canonical orientation before processing. |
| smooth.enabled | bool |
true |
Enable mesh smoothing. |
| smooth.method | str |
"laplacian" |
Smoothing method: "laplacian", "taubin", or "none". |
| smooth.num_iter | int |
10 |
Number of smoothing iterations. |
| smooth.weight | float |
0.1 |
Smoothing weight for Laplacian method (0-1). Higher = more smoothing. |
| smooth.lambda | float |
0.5 |
Shrinkage parameter for Taubin smoothing. |
| smooth.mu | float |
-0.53 |
Inflation parameter for Taubin smoothing (typically negative). |
| smooth.device | str |
"cpu" |
PyTorch device: "cpu", "cuda", or "cuda:0", etc. |
| output.mesh_unsmoothed_path | str or null |
"mesh_raw.obj" |
Output path for raw mesh. |
| output.mesh_smoothed_path | str or null |
"mesh_smooth.obj" |
Output path for smoothed mesh. |
Note: At least one output path must be specified.
Python API
Basic Usage
from xcat_mesh import run
run("segmentation_mask.nii.gz", "config.json")
Advanced Usage
from xcat_mesh import mesh_from_nifti
from xcat_mesh.config import load_config
from xcat_mesh.io import save_obj
# Load configuration
config = load_config("config.json")
# Generate mesh
verts, faces, smoothed_verts = mesh_from_nifti("mask.nii.gz", config)
# Save outputs
save_obj("output_raw.obj", verts, faces)
if smoothed_verts is not None:
save_obj("output_smooth.obj", smoothed_verts, faces)
print(f"Generated {len(verts)} vertices, {len(faces)} faces")
Smoothing Methods
Laplacian Smoothing
Classic mesh smoothing that moves each vertex toward the average of its neighbors.
v_new = v_old + weight × (mean(neighbors) - v_old)
- Pros: Simple, fast, effective
- Cons: Can shrink the mesh over many iterations
- Recommended:
weight=0.1,num_iter=10-50
Taubin Smoothing
Two-step smoothing that reduces shrinkage by alternating between shrinkage and inflation.
Step 1: v = v + lambda × L(v) (shrink)
Step 2: v = v + mu × L(v) (inflate, mu < 0)
- Pros: Minimal volume loss, better shape preservation
- Cons: Slightly slower (2x iterations)
- Recommended:
lambda=0.5,mu=-0.53,num_iter=10-20
Examples
Example 1: High-Quality Mesh with GPU Smoothing
{
"target_resolution_mm": [0.5, 0.5, 0.5],
"reorient_canonical": true,
"smooth": {
"enabled": true,
"method": "taubin",
"num_iter": 20,
"lambda": 0.5,
"mu": -0.53,
"device": "cuda:0"
},
"output": {
"mesh_smoothed_path": "high_quality_mesh.obj"
}
}
Example 2: Raw Mesh Only (No Smoothing)
{
"target_resolution_mm": null,
"reorient_canonical": false,
"smooth": {
"enabled": false
},
"output": {
"mesh_unsmoothed_path": "raw_mesh.obj"
}
}
Example 3: Heavy Smoothing for Visualization
{
"target_resolution_mm": [1.0, 1.0, 1.0],
"smooth": {
"enabled": true,
"method": "laplacian",
"num_iter": 100,
"weight": 0.2,
"device": "cpu"
},
"output": {
"mesh_smoothed_path": "smooth_for_viz.obj"
}
}
Requirements
- Python 3.9+
- NumPy >= 1.22
- NiBabel >= 5.0
- scikit-image >= 0.20
- SciPy >= 1.9
- tqdm >= 4.65
- PyTorch >= 2.0 (optional, for GPU smoothing)
Input Requirements
- Format: NIfTI (
.niior.nii.gz) - Values: Binary mask with values
{0, 1}where:0= background1= foreground (structure to mesh)
- Dimensions: 3D volume (e.g., 256×256×128)
Output Format
Standard Wavefront OBJ format with:
- Vertex coordinates (
v x y z) - Triangle faces (
f v1 v2 v3, 1-indexed)
Compatible with:
- Blender, MeshLab, Rhino
- Unity, Unreal Engine
- MATLAB, Python (trimesh, pyvista)
Performance Tips
- Use GPU for large meshes: Set
"device": "cuda:0"if you have PyTorch with CUDA - Resample before meshing: Lower resolution = faster processing
- Adjust smoothing iterations: Start with 10, increase if needed
- Disable smoothing for speed: Set
"enabled": falsefor instant meshing
Troubleshooting
Issue: "Smoothing requires PyTorch"
Solution: Install PyTorch or disable smoothing:
pip install torch # CPU version
# OR
pip install "xcat-mesh[gpu]" # GPU version
Issue: Mesh looks blocky
Solution: Increase smoothing iterations or weight:
"smooth": {
"num_iter": 50,
"weight": 0.15
}
Issue: Mesh shrinks too much
Solution: Use Taubin smoothing or reduce weight:
"smooth": {
"method": "taubin",
"num_iter": 20
}
Issue: Out of memory
Solution: Resample to lower resolution first:
"target_resolution_mm": [2.0, 2.0, 2.0]
License
Apache 2.0 License - see LICENSE file for details.
Contributing
Contributions welcome! Please open an issue or submit a pull request.
Citation
If you use this tool in your research, please cite the XCAT 3.0 paper:
@article{dahal2025xcat,
title={XCAT 3.0: A comprehensive library of personalized digital twins derived from CT scans},
author={Dahal, Lavsen and Ghojoghnejad, Mobina and Vancoillie, Liesbeth and Ghosh, Dhrubajyoti and Bhandari, Yubraj and Kim, David and Ho, Fong Chi and Tushar, Fakrul Islam and Luo, Sheng and Lafata, Kyle J and others},
journal={Medical Image Analysis},
pages={103636},
year={2025},
publisher={Elsevier}
}
Reference: Dahal, L., et al. (2025). XCAT 3.0: A comprehensive library of personalized digital twins derived from CT scans. Medical Image Analysis, 103636.
Acknowledgments
- Uses scikit-image for marching cubes algorithm
- Uses NiBabel for NIfTI file I/O
- Smoothing algorithms based on classic mesh processing literature
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xcat_mesh-0.1.1.tar.gz.
File metadata
- Download URL: xcat_mesh-0.1.1.tar.gz
- Upload date:
- Size: 18.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4984b0da7940397b8f4dc76ae2d176c56be8cb9ac4107e5d0c338280f68ed508
|
|
| MD5 |
859e8ef071679edec78ebe9a5142c80f
|
|
| BLAKE2b-256 |
ee53b0a573cc92e0714e4d36b5333d8b275500679fb2e31883dd94386f517cdc
|
File details
Details for the file xcat_mesh-0.1.1-py3-none-any.whl.
File metadata
- Download URL: xcat_mesh-0.1.1-py3-none-any.whl
- Upload date:
- Size: 17.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e73f8970ec9b1dafdf92ca5281a0b85ca162d1afffdfe6f99456cbe3aafec4dc
|
|
| MD5 |
82b9369f931fcd0ea5f1ab7e76381064
|
|
| BLAKE2b-256 |
9895be1e1cf1be79ce1690ddc93d592cbe1c9697167d39f3933c5eeb00d5a78d
|