Skip to content

rdneuro/eigenmorph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧠 EigenMorph

Eigenvalue geometric features for cortical surface morphology analysis

Python 3.9+ License: MIT Tests

EigenMorph bridges 3D point cloud analysis with computational neuroanatomy by treating cortical surface meshes as spatial point clouds and computing eigenvalue-based geometric descriptors from local vertex neighbourhoods at multiple scales.

For each vertex on the cortical surface, EigenMorph finds all neighbours within a given radius, builds a 3Γ—3 spatial covariance matrix, decomposes it into eigenvalues λ₁ β‰₯ Ξ»β‚‚ β‰₯ λ₃, and derives seven complementary geometric features that together form a rich morphological fingerprint.


✨ Features

  • Seven core eigenvalue descriptors β€” linearity, planarity, sphericity, omnivariance, anisotropy, eigenentropy, and surface variation
  • Multi-scale analysis β€” compute features at fine-to-coarse radii (3–20 mm) to capture geometry from individual sulcal branches to lobar shape
  • Weighted neighbourhood schemes β€” uniform, Gaussian, or inverse-distance weighting for the covariance matrix
  • Extended descriptors β€” shape index, curvedness, verticality, normal displacement, surface gradient magnitude, and fractal dimension
  • Parcellation tools β€” aggregate vertex-wise features into brain regions (Schaefer, DK, Brainnetome, etc.) and compute morphological distance matrices
  • Classical comparison β€” quantify how much information eigenvalue features add beyond FreeSurfer thickness / curvature / sulcal depth
  • Group-level statistics β€” vertex-wise t-tests, GLM, permutation testing, FDR/Bonferroni correction, and effect sizes (Cohen's d, Ξ·Β²)
  • Full I/O β€” loaders for FreeSurfer surfaces, morphometry overlays, annotations, GIFTI, and HDF5/NPZ serialisation
  • Publication-quality visualisation β€” surface renders, multi-scale profiles, ternary diagrams, radar fingerprints, hero composite figures, and distance matrices
  • Interactive 3D rendering β€” FURY (VTK) powered RGB identity maps, feature landscapes, scale sweeps, exploded views, and neighbourhood explorers (graceful fallback to matplotlib)
  • Synthetic data β€” generate realistic cortical surfaces for testing and demonstration without external data

πŸ“ Mathematical Foundations

For each vertex v with spatial neighbourhood N(v, r) = { pα΅’ : β€–pα΅’ βˆ’ vβ€– < r }, the 3Γ—3 covariance matrix is:

C = (1/N) Ξ£α΅’ (pα΅’ βˆ’ ΞΌ)(pα΅’ βˆ’ ΞΌ)α΅€

Eigendecomposition yields λ₁ β‰₯ Ξ»β‚‚ β‰₯ λ₃ β‰₯ 0, from which:

Feature Formula Cortical interpretation
Linearity (λ₁ βˆ’ Ξ»β‚‚) / λ₁ Ridge-like geometry β†’ sulcal fundi
Planarity (Ξ»β‚‚ βˆ’ λ₃) / λ₁ Planar geometry β†’ gyral crowns
Sphericity λ₃ / λ₁ Isotropic geometry β†’ sulcal pits
Omnivariance (λ₁ Ξ»β‚‚ λ₃)^(1/3) Overall spatial dispersion
Anisotropy (λ₁ βˆ’ λ₃) / λ₁ Directional bias (β‰ˆ L + P)
Eigenentropy βˆ’Ξ£ Ξ»Μƒα΅’ ln(Ξ»Μƒα΅’) Shape complexity / disorder
Surface variation λ₃ / Σλ Local roughness / change of curvature

where Ξ»Μƒα΅’ = Ξ»α΅’ / Σλ are normalised eigenvalues.

The multi-scale approach computes these at 4 default radii (3, 5, 10, 20 mm), yielding 28 features per vertex that capture cortical geometry from fine sulcal branches to lobar shape.


πŸš€ Installation

# Core (numpy, scipy, matplotlib)
pip install eigenmorph

# With neuroimaging I/O (nibabel)
pip install eigenmorph[neuro]

# With interactive 3D visualization (FURY)
pip install eigenmorph[interactive]

# Everything
pip install eigenmorph[all]

From source:

git clone https://github.com/rdneuro/eigenmorph.git
cd eigenmorph
pip install -e ".[all]"

πŸ’‘ Quick Start

import eigenmorph as em

# Generate a synthetic cortical surface (no data needed)
mesh, classical = em.generate_synthetic_cortex(n_vertices=10_000, seed=42)

# Compute multi-scale eigenvalue features
ms = em.compute_multiscale_eigenfeatures(
    mesh,
    radii=[3.0, 5.0, 10.0, 20.0],
    weighting="uniform",
)
# β†’ 28 features per vertex (7 features Γ— 4 scales)

# Compare with classical FreeSurfer morphometrics
comp = em.compare_with_classical(ms, classical, verbose=True)

# Publication-quality hero figure
em.viz.plot_hero_figure(mesh, ms.scales[1], ms, comparison=comp,
                        save_path="hero.png")

πŸ“– Usage Examples

Single-scale analysis

import eigenmorph as em

mesh = em.io.load_freesurfer_surface("subjects/sub-01/surf/lh.white",
                                      hemisphere="lh")
features = em.compute_eigenfeatures(mesh, radius=5.0, weighting="gaussian")

print(features.summary())
em.viz.plot_feature_overview(mesh, features, save_path="overview.png")

Extended descriptors

# Compute core features with eigenvectors (needed for verticality)
feat = em.compute_eigenfeatures(mesh, radius=5.0, store_eigenvectors=True)
ms = em.compute_multiscale_eigenfeatures(mesh)

# All extended features in one call
extended = em.compute_all_extended_features(mesh, feat, ms)
# β†’ dict with shape_index, curvedness, verticality,
#   normal_displacement, surface_gradient, fractal_dimension

Parcellation and group statistics

# Parcellate into brain regions
labels = em.io.load_freesurfer_annot("subjects/sub-01/label/lh.aparc.annot")
parc = em.parcellate_features(ms, labels, n_parcels=34)

# Morphological distance matrix between regions
dist = em.morphological_distance_matrix(parc, metric="correlation")
em.viz.plot_distance_matrix(dist, save_path="morph_distance.png")

# Group-level vertex-wise comparison
group1 = [...]  # list of MultiScaleFeatures
group2 = [...]
t_stats, p_vals = em.vertex_wise_ttest(group1, group2, feature="linearity")
reject, p_corrected = em.fdr_correction(p_vals, alpha=0.05)

Interactive 3D visualization

# RGB identity map (L→Red, P→Green, S→Blue)
em.viz.plot_rgb_identity(mesh, features, size=(1200, 800),
                          save_path="rgb_identity.png")

# Feature landscape (deformed surface encoding a feature as height)
em.viz.plot_feature_landscape(mesh, features.eigenentropy,
                               title="Eigenentropy Landscape")

# Animated scale sweep (fine β†’ coarse as GIF)
em.viz.render_scale_sweep(mesh, ms, save_path="scale_sweep.gif")

Save and load

# Save computed features (compressed NPZ)
em.io.save_multiscale("sub-01_eigenmorph.npz", ms)

# Reload later
ms_loaded = em.io.load_multiscale("sub-01_eigenmorph.npz")

πŸ“¦ Package Structure

eigenmorph/
β”œβ”€β”€ core.py           # SurfaceMesh, EigenFeatures, compute_eigenfeatures()
β”œβ”€β”€ features.py       # Extended descriptors (shape index, fractal dim, …)
β”œβ”€β”€ parcellation.py   # Region aggregation, classical comparison, distance
β”œβ”€β”€ io.py             # FreeSurfer, GIFTI, NPZ loaders/savers
β”œβ”€β”€ stats.py          # Vertex-wise tests, permutation, FDR correction
β”œβ”€β”€ synthetic.py      # Synthetic cortex generation for demos & testing
β”œβ”€β”€ utils.py          # Adjacency, smoothing, normalization, mesh ops
└── viz/
    β”œβ”€β”€ styles.py     # Colour palettes and publication defaults
    β”œβ”€β”€ static.py     # Matplotlib: overviews, ternary, radar, hero fig
    └── interactive.py  # FURY (VTK): RGB maps, landscapes, scale sweeps

πŸ§ͺ Testing

pip install -e ".[dev]"
pytest tests/ -v

πŸ“š References

The eigenvalue feature framework draws from 3D point cloud analysis in remote sensing and computer vision:

  • Weinmann, M., et al. (2015). Semantic point cloud interpretation based on optimal neighborhoods, relevant features and efficient classifiers. ISPRS J. Photogramm. Remote Sens., 105, 286–304.
  • West, K.H.P., et al. (2018). Revisiting the eigenvalues: features for 3D point cloud segmentation. Int. Arch. Photogramm. Remote Sens., XLII-2, 1179–1184.
  • DemantkΓ©, J., et al. (2011). Dimensionality based scale selection in 3D lidar point clouds. ISPRS XXII, 97–102.

Neuroimaging foundations:

  • Fischl, B. (2012). FreeSurfer. NeuroImage, 62(2), 774–781.
  • Dale, A.M., Fischl, B., & Sereno, M.I. (1999). Cortical surface-based analysis: I. Segmentation and surface reconstruction. NeuroImage, 9, 179–194.

πŸ“„ License

MIT β€” see LICENSE.


🀝 Contributing

Contributions welcome! Please open an issue to discuss your idea before submitting a PR.

git clone https://github.com/rdneuro/eigenmorph.git
cd eigenmorph
pip install -e ".[dev]"
pytest tests/ -v

Developed for research at the Instituto Nacional de NeurociΓͺncia Translacional (INNT-UFRJ).