An Artificial Intelligence Framework for Universal Landmark Matching and Morphometry in Musculoskeletal Radiography
Dennis Eschweiler · Eneko Cornejo Merodio · Felix Barajas Ordonez · Aleksandar Lichev · Nikol Ignatova · Marc Sebastian von der Stück · Christiane Kuhl · Daniel Truhn · Sven Nebelung
This AI framework enables precise, automated morphometric measurements by transferring landmarks from a single annotated reference radiograph to previously unseen images using dense matching. It performs reliably across diverse anatomies without the need for additional training.
If you find this project useful for your work, please consider citing it:
@article{eschweiler2026RadiographMatching,
title={An Artificial Intelligence Framework for Universal Landmark Matching and Morphometry in Musculoskeletal Radiography},
author={Dennis Eschweiler and Eneko Cornejo Merodio and Felix Barajas Ordonez and Aleksandar Lichev and Nikol Ignatova and Marc Sebastian von der St{\"u}ck and Christiane K. Kuhl and Daniel Truhn and Sven Nebelung},
journal={European Radiology},
pages={1--14},
year={2026},
doi={10.1007/s00330-026-12555-y}
}
This repository builds upon the work "Robust Dense Feature Matching" by Edstedt et al. We gratefully acknowledge their contribution, which forms the core matching algorithm of our medical imaging application. The original RoMa repository is available at: https://github.com/Parskatt/RoMa.
If you use this project, please also consider citing the original RoMa paper:
@article{edstedt2024roma,
title={{RoMa: Robust Dense Feature Matching}},
author={Edstedt, Johan and Sun, Qiyu and Bökman, Georg and Wadenbäck, Mårten and Felsberg, Michael},
journal={IEEE Conference on Computer Vision and Pattern Recognition},
year={2024}
}
- Python environment with required packages (see
requirements.txt) - Reference images with annotated landmarks
- Target images for analysis
Matches landmarks from reference images to target images using RoMa (Robust Matching) algorithm.
Basic Usage:
python do_matching.py \
--reference_path "path/to/reference/images" \
--data_path "path/to/target/images" \
--save_path "path/to/output" \
--config_tag "knee_lateral"Key Parameters:
--reference_path: Directory containing reference images (*_image.jpg) and landmarks (*_landmarks.csv)--data_path: Directory with target images to analyze--save_path: Output directory for matches and results--reference_left_file/--reference_right_file: Optional laterality check references--max_matching_error: Maximum allowed Procrustes error (default: 500)--coarse_res/--upsample_res: Model resolution settings
Output:
- Individual match visualizations (
{ref_id}_to_{target_id}.png) - Landmark coordinates (
{ref_id}_to_{target_id}_matches.csv) - Matching metrics (
{ref_id}_to_{target_id}_metrics.json) - Consensus landmarks (
{target_id}_matches_bulk.csv)
Calculates clinical measurements from matched landmarks using predefined measurement functions.
Basic Usage:
python do_measurements.py \
--data_path "path/to/landmark/files" \
--save_path "path/to/output" \
--config_tag "knee_lateral" \
--config_path "experiment_config_windows.json"Key Parameters:
--data_path: Directory containing*_matches_bulk.csvfiles from matching step--config_tag: Configuration key from experiment config (e.g., "knee_lateral", "feet_lateral")--config_path: Path to experiment configuration file--save_path: Output directory for measurement results
Output:
- Measurement CSV file (
measurements_{config_tag}.csv) with calculated values for each image
The experiment_config_windows.json file contains measurement configurations:
mode: Measurement type (e.g., "knee_lateral", "feet_lateral")mpp: Millimeters per pixel conversion factor- Measurement-specific parameters
# 1. Match landmarks
python do_matching.py \
--reference_path "/path/to/reference/images" \
--data_path "/path/to/target/images" \
--save_path "/path/for/saving/matching" \
--config_tag "knee_lateral"
# 2. Calculate measurements
python do_measurements.py \
--data_path "/path/to/matchings" \
--save_path "/path/for/saving/measurements" \
--config_tag "knee_lateral"The recommended way to run this project is using Docker with the production integration script:
- Tested with Python 3.10
- Docker recommended with NVIDIA support for GPU acceleration
Production Usage:
from docker.run_production import RomaMedicalDocker
# Initialize Docker runner
roma_docker = RomaMedicalDocker("roma_medical:latest")
# Run matching with temporary directories (matches project architecture)
results = roma_docker.run_matching(
data_path="/path/to/target/images", # Folder containing images to analyze
reference_path="/path/to/reference/files", # Folder with reference images & landmarks
reference_left_path="/path/to/left/ref", # Base path for left laterality check
reference_right_path="/path/to/right/ref", # Base path for right laterality check
output_dir="/path/to/save/results", # Where to save results permanently
max_matching_error=500,
image_filetype="jpg"
)Build Instructions (Required First Step):
# From the main project directory (roma_medical/)
docker build -f docker/Dockerfile -t roma_medical:latest .For detailed Docker documentation, see docker/README.md.