Skip to main content

3-D anatomical surface analysis: symmetry, non-rigid registration, atlas construction and asymmetry mapping

Project description

๐Ÿง  pyclarcs

Python toolkit for the automated analysis of 3-D anatomical surfaces, with a focus on endocranial and bilateral structures.

clarcs is a command-line tool built around two core algorithms:

  • Symmetry-plane estimation โ€” Combรจs et al., CVPR 2008
  • Non-rigid surface registration โ€” EM-ICP with symmetric correspondences, TGD geodesic prior, and RKHS Wu-kernel M-step (Combรจs & Prima, CVIU 2019)

Combined into a full population-analysis pipeline: symmetry โ†’ alignment โ†’ non-rigid registration โ†’ atlas โ†’ asymmetry mapping.


Table of contents


Installation

pip install pyclarcs

Or from source:

git clone https://github.com/rdebroiz/pyclarcs
cd pyclarcs
pip install -e ".[dev]"

Dependencies (installed automatically):

Package Role
numpy โ‰ฅ 1.21 Numerics
scipy โ‰ฅ 1.7 KD-tree, sparse linear algebra, graph shortest paths
vtk โ‰ฅ 9.0 Surface I/O and mesh processing
numba โ‰ฅ 0.57 JIT-compiled kernels (4ร— speedup on EM stages)
click โ‰ฅ 8.0 CLI framework

Supported formats

Format is inferred from the file extension.

Extension Format Read Write
.vtk VTK legacy PolyData (ASCII or binary) โœ“ โœ“
.vtp VTK XML PolyData โœ“ โœ“
.vtu VTK XML UnstructuredGrid (converted to PolyData) โœ“ โ€”
.ply Stanford PLY โœ“ โœ“
.stl STereoLithography โœ“ โœ“
.obj Wavefront OBJ โœ“ โœ“

Note โ€” Asymmetry and deformation fields (VECTORS point data) require .vtk or .vtp.


Commands

Commands are grouped by purpose.

Preprocessing

Command Description
clarcs reorient Permute coordinate axes
clarcs recenter Align symmetry plane to x = 0
clarcs centerofmass Translate to match a reference's centre of mass
clarcs normalize Uniformly scale + translate to match a reference
clarcs downsample Decimate to a target vertex count or ratio

Symmetry analysis

Command Description
clarcs symplane Estimate the bilateral symmetry plane
clarcs mirror Reflect a surface across its symmetry plane
clarcs asymmetry Compute the pointwise asymmetry field

Non-rigid registration

Command Description
clarcs nlregister Non-rigid EM-ICP registration onto a reference

Atlas & population analysis

Command Description
clarcs atlas Build a mean shape atlas from a population
clarcs project-asym Build atlas + project per-subject asymmetries onto it

Typical pipelines

Preprocessing and registration

# 1. Align symmetry plane to x = 0
clarcs recenter target.vtk target-rc.vtk --save-plane

# 2. Match size and centre of mass to the reference
clarcs normalize target-rc.vtk target-rcs.vtk --target reference.vtk

# 3. Non-rigid EM-ICP registration
clarcs nlregister target-rcs.vtk reference.vtk target-registered.vtk \
                  --deformation target-deformation.vtk

Atlas construction

# Build a mean shape atlas from a directory of preprocessed surfaces
clarcs atlas subjects/ atlas.vtk --save-registered

# Lower resolution first (useful for large surfaces)
clarcs downsample subjects/B01.ply subjects/B01-5k.ply --target-n 5000

Asymmetry analysis on an atlas

# All-in-one: build atlas, compute subject asymmetries, project onto atlas
clarcs project-asym subjects/ mean-asym.vtp --save-atlas atlas.vtp \
       --save-stats --save-individual

# Incremental (reuse pre-computed atlas and asymmetry fields)
clarcs asymmetry B01.ply B01-asym.vtk
clarcs project-asym subjects/ mean-asym.vtp \
       --atlas atlas.vtp \
       --registered-dir registered/ \
       --asymmetry-dir  asymmetry/

data/run_pipeline.py automates the preprocessing + registration sequence on the bundled test surfaces:

python data/generate_samples.py   # create test surfaces (once)
python data/run_pipeline.py results/

Python API

Symmetry plane

from pyclarcs.io import load_surface, save_plane_vtk
from pyclarcs.principal_axes import best_principal_axis_plane
from pyclarcs.coarse import coarse_symmetry
from pyclarcs.fine import em_icp_sym, em_icp_sym_corres

points, polygons = load_surface("surface.vtk")

plane = best_principal_axis_plane(points)
plane = coarse_symmetry(points, plane)
plane = em_icp_sym(points, plane)
plane = em_icp_sym_corres(points, plane)

plane.save("plane.pl")

Non-rigid registration

from pyclarcs.io import load_surface, load_surface_with_normals, save_surface
from pyclarcs.nonrigid import register, apply_deformation

mov_pts, mov_poly, mov_normals = load_surface_with_normals("target.vtk")
ref_pts, ref_poly, ref_normals = load_surface_with_normals("reference.vtk")

# Symmetric correspondences + TGD prior + RKHS M-step are all on by default
def_field = register(
    mov_pts, mov_normals,
    ref_pts, ref_normals,
    mov_poly, ref_poly,
)

warped = apply_deformation(mov_pts, def_field)
save_surface("registered.vtk", warped, mov_poly)

Atlas construction

from pyclarcs.io import load_surface_with_normals, save_surface
from pyclarcs.atlas import build_atlas

subjects = [load_surface_with_normals(p) for p in sorted(paths)]

atlas_pts, atlas_poly, registered = build_atlas(subjects, atlas_iter=3)
save_surface("atlas.vtk", atlas_pts, atlas_poly)

Asymmetry projection

from pyclarcs.io import load_vector_field
from pyclarcs.atlas import project_asymmetry_to_atlas
import numpy as np

# registered[i]: atlas vertices in subject i's space (from build_atlas)
# asym_fields[i]: asymmetry field at subject i's vertices (from clarcs asymmetry)
projected = project_asymmetry_to_atlas(registered, asym_fields, subject_pts)

mean_asym = np.stack(projected).mean(axis=0)   # (N, 3) mean field on atlas

Data โ€” PaleoBRAIN dataset

75 brain surfaces (B01โ€“B75) and 75 endocasts (E01โ€“E75) from the PaleoBRAIN project (Balzeau A., 2025, doi:10.48579/PRO/KZMMLM).

# Download first 10 subjects (brains + endocasts), resample to 5 000 vertices
python data/download_paleobrain.py --n 10 --target-n 5000

# Brains only, all 75
python data/download_paleobrain.py --type brain

Registration benchmark

MNI pial endocranium (10 k vertices), synthetic deformation of 8 Gaussian bumps ร— 5 mm amplitude. RMS before: 2.28 mm.

Configuration RMS after Improvement
Baseline (Laplacian) 0.333 mm 85.4 %
+ Symmetric correspondences + TGD 0.267 mm 88.3 %
+ RKHS M-step (default) 0.190 mm 91.6 %

See docs/nlregister.md for full details and parameters.


Repository structure

pyclarcs/
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ docs/                           โ† per-command documentation
โ”‚   โ”œโ”€โ”€ reorient.md
โ”‚   โ”œโ”€โ”€ symplane.md
โ”‚   โ”œโ”€โ”€ recenter.md
โ”‚   โ”œโ”€โ”€ centerofmass.md
โ”‚   โ”œโ”€โ”€ normalize.md
โ”‚   โ”œโ”€โ”€ mirror.md
โ”‚   โ”œโ”€โ”€ downsample.md
โ”‚   โ”œโ”€โ”€ nlregister.md
โ”‚   โ”œโ”€โ”€ atlas.md
โ”‚   โ”œโ”€โ”€ asymmetry.md
โ”‚   โ””โ”€โ”€ project-asym.md
โ”œโ”€โ”€ data/
โ”‚   โ”œโ”€โ”€ generate_samples.py         โ† generate synthetic + MNI test surfaces
โ”‚   โ”œโ”€โ”€ download_paleobrain.py      โ† download PaleoBRAIN dataset
โ”‚   โ”œโ”€โ”€ benchmark_compare.py        โ† compare clarcs / CPD / BCPD
โ”‚   โ””โ”€โ”€ run_pipeline.py             โ† run the full pipeline end-to-end
โ””โ”€โ”€ src/pyclarcs/
    โ”œโ”€โ”€ _cli.py                     โ† CLI entry-point (clarcs command)
    โ”œโ”€โ”€ symmetry.py                 โ† SymmetryPlane class
    โ”œโ”€โ”€ principal_axes.py           โ† inertia tensor initialisation
    โ”œโ”€โ”€ io.py                       โ† multi-format surface I/O (VTK 9+)
    โ”œโ”€โ”€ coarse.py                   โ† coarse ICP with trimmed estimator
    โ”œโ”€โ”€ fine.py                     โ† EM-ICP annealing + doubly-stochastic
    โ”œโ”€โ”€ alignment.py                โ† rigid transforms (recenter, rescale, โ€ฆ)
    โ”œโ”€โ”€ mesh.py                     โ† adjacency, TGD, Wu kernel graph
    โ”œโ”€โ”€ nonrigid.py                 โ† register(), _em_icp(), _build_hierarchy()
    โ”œโ”€โ”€ atlas.py                    โ† build_atlas(), project_asymmetry_to_atlas()
    โ””โ”€โ”€ _numba_kernels.py           โ† JIT-compiled inner loops (internal)

Scientific references

Combรจs B., Hennessy R., Waddington J., Roberts N., Prima S. Automatic symmetry plane estimation of bilateral objects in point clouds. IEEE CVPR 2008. Anchorage, United States.

Abadie A., Combรจs B., Haegelen C., Prima S. CLARCS, a C++ Library for Automated Registration and Comparison of Surfaces: Medical Applications. MeshMed @ MICCAI 2011. Toronto, Canada, pp. 117โ€“126.

Combรจs B., Prima S. New algorithms for the deformable registration of brain images. Medical Image Analysis / CVIU 2019.

Balzeau A. (2025). Database of 75 endocasts and 75 brains obtained on the same sample of volunteers. doi:10.48579/PRO/KZMMLM


Licence

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyclarcs-0.4.1.tar.gz (58.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyclarcs-0.4.1-py3-none-any.whl (58.7 kB view details)

Uploaded Python 3

File details

Details for the file pyclarcs-0.4.1.tar.gz.

File metadata

  • Download URL: pyclarcs-0.4.1.tar.gz
  • Upload date:
  • Size: 58.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pyclarcs-0.4.1.tar.gz
Algorithm Hash digest
SHA256 376d39ee09b4e5b31d2adc30dbf4eeace96c430ad60e867661cf79fff9a8a47d
MD5 9da9d525b5c509c134f12d71cb786665
BLAKE2b-256 afbaceb8829021a9088f49b0f18f92dec27952023c4dcf30ad372547a47211a9

See more details on using hashes here.

File details

Details for the file pyclarcs-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: pyclarcs-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 58.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pyclarcs-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 33eabfdf88dd55ebf0f3257c22c5d3812f18c536aa2851813dbc815241fc892f
MD5 ff03015a5ba4c84f08915edcdc1c610c
BLAKE2b-256 8e12a1070da4d523a95407b0f2731eb181c7a55d5f08e01a7b8d33d574d73562

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page