Thank you for your interest in contributing to CORE (Coarse-to-fine Registration of whole-slide images)!
This document covers how to set up your environment, coding standards, how to add tests, and how to propose a new registration method.
- Getting Started
- Project Layout
- Coding Standards
- Running Tests
- Adding a New Registration Method
- Pull Request Process
# 1. Fork the repository and clone your fork
git clone https://github.com/<your-username>/WSI_mIF_Reg.git
cd WSI_mIF_Reg
# 2. Create and activate the conda environment
conda env create -f environment.yml
conda activate core
# 3. Set the VisionAgent API key (needed for tissue-mask extraction)
export VISION_AGENT_API_KEY="<your-key>"
# 4. Install the package in editable mode (optional but recommended)
pip install -e .WSI_mIF_Reg/
├── core/
│ ├── config.py # Global configuration and parameter classes
│ ├── preprocessing/
│ │ ├── preprocessing.py # WSI loading, padding, stain normalisation
│ │ ├── tissuemask.py # Tissue mask extraction (Florence-2, UNet, Otsu)
│ │ ├── stainnorm.py # Macenko stain normaliser
│ │ ├── nuclei_analysis.py # Nuclei detection and patch processing
│ │ └── padding.py # Image and landmark padding helpers
│ ├── registration/
│ │ ├── registration.py # Rigid, ICP, CPD, shape-aware registration
│ │ ├── rigid.py # Trimorph + XFeat coarse rigid registration
│ │ ├── nonrigid.py # Elastic / non-rigid registration (VoxelMorph-style)
│ │ └── cpd.py # Coherent Point Drift implementation
│ ├── evaluation/
│ │ └── evaluation.py # TRE, rTRE, NGF metrics
│ ├── utils/
│ │ ├── util.py # General utilities (deformation field ops, maths)
│ │ └── mha_wsi.py # MHA deformation field ↔ WSI application
│ └── visualization/
│ └── visualization.py # Matplotlib and Bokeh plotting helpers
├── tests/ # pytest unit tests
├── notebooks/ # Jupyter walkthrough notebooks
├── example.py # End-to-end usage script
└── apply_deformation_wsi.py # CLI: apply MHA field to full-res WSI
-
Python ≥ 3.10 is required.
-
Follow PEP 8 style; maximum line length is 100 characters.
-
Use type annotations for all new public functions and methods.
-
Use the
loggingmodule rather thanprint()for diagnostic output:import logging logger = logging.getLogger(__name__) logger.info("Processing %d patches", n_patches)
-
Prefer numpy vectorised operations over Python loops when working on large arrays.
-
Do not commit large binary data (model weights, full-res WSIs) to the repository.
Tests live in the tests/ directory and use pytest.
# Run all tests
pytest tests/ -v
# Run a specific test file
pytest tests/test_evaluation.py -v
# Run with coverage report
pytest tests/ --cov=core --cov-report=term-missingTests are also run automatically on every pull request via the CI workflow (.github/workflows/tests.yml).
-
Create a new function or class in the appropriate module under
core/registration/.
If the method is substantial, create a dedicated file (e.g.,core/registration/my_method.py). -
Follow the expected interface — registration functions typically accept:
fixed_points/moving_points(numpyndarray, shape(N, 2)) for point-based methods, orsource_image/target_image(numpyuint8 RGB, shape(H, W, 3)) for image-based methods.
-
Export it from
core/registration/registration.py(or add it tocore/__init__.pyif it is a primary public API). -
Write unit tests in
tests/test_registration.pycovering:- Correctness on a synthetic case (e.g., a known translation).
- Edge cases (empty point sets, single points, etc.).
-
Document it in the docstring using the existing format (NumPy-style), and add a short usage example to
example.pyor a new notebook.
- Branch off
mainwith a descriptive name, e.g.feature/my-methodorfix/bgr-rgb-conversion. - Keep each PR focused on a single concern.
- Ensure all tests pass locally (
pytest tests/). - Ensure your changes do not introduce new linting errors.
- Update the relevant documentation (docstrings,
README.md,CONTRIBUTING.mdif needed). - Open a pull request against
mainand fill in the PR template.
Thank you for helping make CORE better!