Skip to content
caitlin-leonardPublic

About

Lightweight ITK-SNAP-style medical volume viewer tested on flare22 dataset— synced MPR views + Marching-Cubes 3D rendering.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MedViewer — Modular Medical Volume Viewer

A lightweight, ITK-SNAP-style desktop application for inspecting 3D medical volumes (CT / MRI / PET) alongside their segmentation label maps. Three synchronised multi-planar (Axial / Coronal / Sagittal) views, a rotatable Marching-Cubes 3D surface panel, an editable label table, and a live coordinate/intensity readout — in under 1000 lines of Python across 7 files.

Built on PyQt6, VTK, SimpleITK, and scikit-image. Any integer label map is auto-detected and auto-coloured on load — no hard-coded organ list.

Screenshots below use the public FLARE22 abdominal CT dataset. No patient or clinical data is included in this repository.


Screenshots

Full application — three synchronised MPR views + auto-built 3D surfaces

MedViewer full view with FLARE22 CT and 13-label segmentation

A FLARE22 CT volume with a 13-label segmentation: synchronised Axial/Coronal/Sagittal reslices, the auto-built 3D surface scene, and the per-label control table on the right.

3D surface scene — one Marching-Cubes mesh per label

3D multi-organ surface rendering

Each segmentation label is extracted with Marching Cubes and Laplacian-smoothed into an individually coloured, semi-transparent mesh — rotatable and zoomable for at-a-glance anatomical inspection.


Features

  • Three synchronised 2D MPR views — Axial, Coronal, Sagittal, sharing one crosshair. A click in any panel repositions all others instantly.
  • Rotatable 3D surface panel — one Marching-Cubes mesh per label, with Laplacian smoothing and per-label colour/opacity/visibility.
  • Editable segmentation label table — rename, recolour, toggle visibility, and set opacity per label; changes apply live to both the 2D overlays and the 3D meshes.
  • Live coordinate/intensity bar — voxel index, world-space (mm) coordinate, raw intensity (HU for CT), and the label under the cursor.
  • Auto modality + label detection — CT/MRI inferred from intensity range; any integer label map supported with zero configuration.
  • Radiological interaction conventions — left-click to navigate, right-drag for window/level, wheel to scroll slices.

Install

pip install PyQt6 vtk SimpleITK scikit-image nibabel numpy

Run

# Open the viewer, then load data via the File menu
python main.py

# Pre-load an image
python main.py image.nii.gz

# Pre-load an image + segmentation (auto-builds the 3D scene)
python main.py image.nii.gz segmentation.nii.gz

Controls

Action Effect
Mouse wheel (Axial / Coronal / Sagittal) Scroll Z / Y / X slices
Left click (2D panel) Move crosshair — syncs all views
Right drag (2D panel) Window / Level (L–R width, U–D center)
Left drag (3D panel) Rotate
Right drag (3D panel) Zoom
↑ ↓ / ← → Scroll axial / sagittal slices
V Toggle segmentation overlay
B Build / rebuild 3D surfaces
R Reset all cameras
J Jump to voxel coordinate
Ctrl+O / Ctrl+Shift+O Open image / segmentation
Ctrl+S Save screenshot
Ctrl+Q Quit

Architecture

Strict model–view separation. All volumetric data and per-label metadata live in a single data-model module with no Qt/VTK UI dependency; every other module is a view/controller that reads from it and re-renders on change.

medviewer_app/
├── main.py           ← Entry point
├── main_window.py    ← Window layout, menus, crosshair-sync hub
├── slice_widget.py   ← 2D MPR slice viewer (×3: Axial/Coronal/Sagittal)
├── view3d_widget.py  ← Rotatable 3D surface panel (Marching Cubes)
├── seg_panel.py      ← Segmentation label table (colour/opacity/visibility)
├── info_bar.py       ← Coordinate / intensity status bar
└── data.py           ← Data model: ImageVolume, SegmentationVolume

All views are kept consistent through a single hub: any widget that moves the current voxel emits a crosshairMoved(i, j, k) signal, and one subscriber in main_window.py pushes the new position out to every panel — a hub-and-spoke pattern that makes adding further synchronised views straightforward.


Supported Formats

  • NIfTI (.nii, .nii.gz)
  • CT / MRI / PET — auto-detected from intensity range
  • Any integer label map — labels auto-detected, no hard-coding

Technical Report

A detailed technical report documenting the architecture, the core algorithms (image reslicing, window/level mapping, Marching Cubes, Laplacian mesh smoothing, voxel-to-world mapping), and an annotated walkthrough is available here:

📄 MedViewer — Technical Report (PDF)


Citation

If you use MedViewer, please cite it. A CITATION.cff file is included, so you can use the "Cite this repository" button in the GitHub sidebar, or:

Leonard, C. S. (2026). MedViewer: A Modular, ITK-SNAP-Style Medical Volume Viewer. GitHub repository.


License

Released under the MIT License — free to use, modify, and distribute with attribution.


Notes & Limitations

  • Uses voxel spacing only; does not yet apply the full NIfTI direction/origin affine, so obliquely acquired scans may be displayed in an approximate frame.
  • One image volume + one segmentation at a time (no side-by-side comparison yet).
  • NIfTI only — DICOM series need converting upstream (e.g. dcm2niix).
  • The tool reads label maps produced upstream (MOOSE / TotalSegmentator / VoxTell / etc.); it performs no segmentation or reconstruction itself.

Acknowledgements

Screenshots use the public FLARE22 dataset. The viewer is built on the open-source PyQt6, VTK, SimpleITK, and scikit-image projects.

About

Lightweight ITK-SNAP-style medical volume viewer tested on flare22 dataset— synced MPR views + Marching-Cubes 3D rendering.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages