Skip to content
AImageLab-zipPublic

About

No description, website, or topics provided.

Resources

Contributing

Stars

13 stars

Watchers

1 watching

Forks

Latest commit

 

History

753 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Yggdrasil

A Django platform for medical-imaging research. Clinicians and annotators upload studies, an external compute cluster processes them, and the results are viewed, annotated and exported — all under one authorization model and one durable annotation record.

Five research areas are mounted as their own Django apps:

Area Prefix What it holds
Maxillo /maxillo/ Dental / maxillofacial imaging — CBCT, intraoral scans (IOS), intraoral photos, teleradiography, panoramic
Brain /brain/ Brain-tumour MRI — T1, T1c, T2, FLAIR and segmentation
Laparoscopy /laparoscopy/ Surgical video
Urology /urology/ Multimodal urology — multiparametric prostate MRI, digital pathology Whole Slide Images (WSI), confocal laser endomicroscopy
Cardiology /cardiology/ ECG review — clinical-grid waveform plots and AF / NSR / Other / NI rhythm classification

Live instance: https://yggdrasil.ing.unimore.it

What it does

  • Upload and cataloguing. Volumes are .nii.gz (NIfTI); images, meshes and video use their own modality types. Every uploaded byte lands in S3-compatible object storage and is recorded as a FileRegistry row — the database holds rows, the store holds bytes.
  • Automated processing. An upload creates Job rows, one per enabled processing step of its modality. A dedicated runner worker dispatches them to a SLURM cluster and reports results back over a frozen HTTP API. See docs/runners.md.
  • Imaging viewers. All imaging renders through Cornerstone3D, built from frontend/ into a committed bundle: an orthogonal volume grid with measurements and segmentation, a tooth-segmentation surface, an IOS mesh viewer, a photo viewer with calibrated measurements, a panoramic reconstruction (arch fit → slab → projection), a frame-accurate video editor, and a digital pathology Whole Slide Image (WSI) multi-resolution deep-zoom viewer with synchronized segmentation masks and an in-browser WebAssembly (wasm-vips) gigapixel pyramidal TIFF converter.
  • Durable annotations. Landmarks, segmentations, classifications, panoramic arches, measurements, video-frame segmentation and quadrant markers are all stored in one versioned model in the annotations/ app — snapshots with revision numbers, never deltas, and never carrying viewer-session identifiers.
  • Voice captioning. Live Whisper speech-to-text notes, versioned and editable, in every area.
  • Export. Structured, shareable exports of patient data, derived artifacts and annotation documents, assembled by common/export_catalog.py.
  • Operations. Nightly database backups with retention, a maintenance / read-only / lockdown site mode, presence and activity dashboards, and a health endpoint.

Getting started

Everything runs in Docker.

cp .env.example .env      # then edit; see docs/setup.md
./scripts/dev_bootstrap.sh

That brings up MySQL, Redis and a local single-node Garage, migrates and seeds the database, and serves the app at http://localhost:8000.

Full instructions: docs/setup.md.

API access for scripts

Everything under /api/ can be called from a script with a personal API token instead of a browser session. A token acts as its user, with exactly that user's project permissions. It is not a separate role.

Getting a token. A superuser issues it, either in the admin (Projects & access → API tokens → Add) or from the shell:

python manage.py create_api_token alice --name "nightly upload" --days 90

The token (ygg_…) is shown once. Only a hash is stored, so a lost token can't be recovered: revoke it in the admin and issue a new one. Tokens can expire, are refused once revoked or once their user is deactivated, and record when they were last used.

Using it. Send the token as a bearer header. Token requests need no CSRF token and create no session:

export YGG=https://yggdrasil.example.org
export TOKEN=ygg_...
curl -H "Authorization: Bearer $TOKEN" $YGG/api/projects/

A missing, revoked or expired token gets 401. After 20 bad tokens from one address in 15 minutes, that address gets 429 until the window passes. Tokens work only under /api/. The HTML pages still need a login, and the runner API (/api/runner/) keeps its own RUNNER_API_TOKENS.

Projects

Request Who Returns
GET /api/projects/[?domain=brain&name=Study] any user the projects you can read
GET /api/projects/<slug>/ any user one project. 404 if it doesn't exist or you can't read it
POST /api/projects/ superusers 201 with the new project. 409 with the existing slug if the name (in that domain) or the slug is taken

A project as returned:

{"id": 7, "slug": "new-study", "name": "New Study", "domain": "brain",
 "description": "", "is_active": true, "modalities": ["t1", "t2"],
 "annotation_methods": [], "role": "admin", "created_at": "2026-10-19T15:47:13+00:00"}

Creating one (JSON body). slug is optional and defaults to the slugified name. modalities and annotation_methods take slugs and must belong to the project's domain or to every domain:

curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name": "New Study", "domain": "brain", "modalities": ["t1", "t2"]}' \
  $YGG/api/projects/

Enable the modalities you intend to upload. A new project starts with none, and an upload is refused (400) for any file whose modality the project doesn't enable. The creator gets the admin role on the new project.

The usual pattern for an unattended uploader is: look the project up, create it on 404 (treating 409 as "already there"), then upload.

Folders, patients and uploads (every domain)

These work the same in every domain (maxillo, brain, laparoscopy, urology, cardiology). The project's domain decides where patients are stored.

Request Who Returns
GET /api/<slug>/folders/ readers the project's folders (id, name, full_path)
POST /api/<slug>/folders/ project admins JSON {"name": "..."}. Get-or-create: 201 if created, 200 if it already existed
GET /api/<slug>/patients/[?folder=<id>&name=<name>] readers the project's patients, their folder and modalities
GET /api/<slug>/patients/<id>/files/ readers one patient's stored files
POST /api/<slug>/upload/ annotators and admins creates one patient. See below

Upload takes multipart/form-data: name, folder (a folder id of this project), optional tags (comma-separated), and one part per file. The file field names depend on the domain:

Domain File fields
maxillo cbct, ios_upper + ios_lower (sent together), intraoral-photos (up to 10 files), panoramic, teleradiography, rawzip
brain braintumor-mri-t1, braintumor-mri-t2, braintumor-mri-flair, braintumor-mri-t1c, braintumor-mri-seg
urology urology-mri, urology-wsi, urology-confocal, each with an optional <field>-segmentation
laparoscopy video
cardiology ecg

A project accepts only the fields of the modalities it enables, and GET /api/projects/<slug>/ lists them under upload_fields. Sending any other field gets a 400 naming the rejected and accepted fields, and nothing is created. If storing a file fails, the patient isn't created either, so you can safely retry.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -F name="BraTS-GLI-00002-000" -F folder=12 \
  -F [email protected] \
  -F [email protected] \
  $YGG/api/brain-study/upload/

A typical uploader goes through four steps:

  1. Look the project up, or create it.
  2. Create its folders with POST /folders/.
  3. List GET /patients/?folder=<id> to skip patients already there.
  4. Upload the rest.

Documentation

Each app also carries its own README describing what it owns and where its boundary with common/ runs: common, annotations, maxillo, brain, laparoscopy, urology, cardiology.

Notes:

  • Django accepts either DB_NAME/DB_USER/DB_PASSWORD or the MYSQL_* variables.
  • Object storage is S3-compatible (Garage/MinIO) via OBJECT_STORAGE_*.

Contributing

Contributions are welcome — please open an issue or pull request against the release/3.0 branch. CONTRIBUTING.md covers the quickstart, the test suite, CI, release conventions, and the rules that are easy to break silently.

Contact

For more information or to request an account: [email protected]

About

No description, website, or topics provided.

Resources

Contributing

Stars

13 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages