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.0.tar.gz (58.6 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.0-py3-none-any.whl (58.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pyclarcs-0.4.0.tar.gz
  • Upload date:
  • Size: 58.6 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.0.tar.gz
Algorithm Hash digest
SHA256 7ab83cf0edc7e921f27e28f44f009bdb682d894cd649c62df027ad75c7d95036
MD5 cc766743924f43d5ee4b5547293b2f32
BLAKE2b-256 fca66ff67951d1d531c4633912a129c6c87ae9f2a8ab535137b82f12b2d9cf6d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pyclarcs-0.4.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8c3d4dac6595917bb6c7a292549056e02fbee604f7d0a70ba78d68a6a41705a6
MD5 fe0911195fbfaf9cef3eb87c44150032
BLAKE2b-256 ed30c9d5d4a507d34c25fcecc450674e65450c2dbde385bfeb130936944b419a

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