Skip to content
Snippets Groups Projects
Commit 0b1f8aa0 authored by Tamino Huxohl's avatar Tamino Huxohl
Browse files
parents 9e82c595 7d8f08a4
No related branches found
No related tags found
No related merge requests found
LICENSE 0 → 100644
MIT License
Copyright (c) 2023 Tamino Huxohl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Mu Map
Repository for the code to replicate the paper of Shi et al. with our SPECT/CT Scanner.
## Differences
| | Authors | Ours |
| :-------------------- | :----------------------------: | :-------------------------------: |
| SPECT/CT Scanner | GE NM/CT 850 SPECT/CT | Siemens Symbia Intevo 16 SPECT/CT |
| Scan Arc | 180° | 208° |
| Angles | 60 | 34 |
| Energy Window Lower | 114-126 keV | 110-131 keV |
| Energy Window Upper | 126-155 keV | 131-152 keV |
| Dose | 15 mCi | ? |
| Reconstruction | OSEM (5 iterations, 4 subsets) | Siemens Conjugate Gradient |
| CT Energy | 120 kVp | ? |
| Attenuation Map Shape | (25-35)x64x64 | ? |
| Reconstruction Shape | 64x64x64 | 51x128x128 |
| Voxel Size | 6.8x6.8x6.8 mm³| 4.8x4.8x4.8 mm³ |
## Open Questions
Repository containing the code of the paper `Deep Learning Approximation of Attenuation Maps for Myocardial Perfusion SPECT with an IQ·SPECT Collimator`.
Using this code, it is possible to train a deep neural network to predict attenuation maps from non-attenuation-corrected reconstructions.
The training is inspired by the description in [1] and is implemented with [PyTorch](https://pytorch.org/).
A random search procedure [2] is implemented for the optimization of hyperparameters.
To compute attenuation-corrected reconstructions, the [script](/mu_map/scripts/compute_recons.py) implements the post-reconstruction attenuation correction (PRAC) algorithm [3].
It uses the open-source tomographic reconstruction software [STIR](https://stir.sourceforge.net/).
Reconstructions can be evaluated using the mean squared error or the normalized mean absolute error.
Polar maps cannot be generated with this code, but they can be evaluated.
For the purposes of this paper, grayscale polar maps were generated using the Cedars-Sinai Cardiac Suite [4].
## Results
### Comparison of Polar Maps
![Comparison of Polar Maps](res/polar_maps.png)
## Release ToDo's
* Update dependency versions in pyproject.toml an requirements.txt
* Test installation instructions
* Add illustrations:
* Gif of the comparison between a predicted and an actual attenuation map
* polar maps
## Installation
Installation was tested with Ubuntu 20.04 and 22.04.
1. Create and load a virtual environment `python -m venv .venv && source .venv/bin/activate`
2. Install python requirements `pip install -r requirements.txt`
### STIR
STIR is required to project and reconstruct scans (using the PRAC algorithm).
For its installation, this repository contains STIR as a submodule as well as an installation script.
To install STIR run:
1. `git submodule init && git submodule update`
2. `cd libs && ./install.sh && cd ..`
### Tesseract OCR
Because we could not export perfusion scores from polar maps generated with the Cedars-Sinai Cardiac Suite, but only RGB images with scores written in a green font, we added a [script](/mu_map/polar_map/get_perfusion.py) to help extract these scores.
This script uses [Tesseract](https://tesseract-ocr.github.io/) to automatically parse these numbers from the image.
To install tesseract, run:
`sudo apt install tesseract-ocr`
## Usage
This code is not intended for direct usage as data structures likely differ.
## Features
* cGAN training
* Random search [2] for hyperparameter optimization
* PRAC [3] algorithm
* Evaluation of polar maps
## References
* `Shi et al. "Deep learning-based attenuation map generation for myocardial perfusion SPECT". 2020 In: European Journal of Nuclear Medicine and Molecular Imaging 47.10`
* [DOI: 10.1007/s00259-020-04746-6](www.doi.org/10.1007/s00259-020-04746-6)
## Install
Install libraries for tomographic reconstruction:
### NiftyRec
* `mkdir libs`
* `cd libs`
* `git clone https://github.com/TomographyLab/NiftyRec`
* `cd NiftyRec`
* `git checkout 5329496`
* `cp README.md README.txt` - this file is needed by cmake
* `mkdir build`
* `cd build`
* `ccmake ..` - turn of the volume renderer
* `make -j 8`
* `make package`
* `sudo dpkg -i NiftyRec-3.1.0-Linux-x86_64.deb`
### TomoLab
Make sure your python virtual environment is active for this.
* `mkdir libs`
* `cd libs`
* `git clone https://github.com/TomographyLab/TomoLab`
* `git checkout 86b9a58`
1. L. Shi et al. “Deep learning-based attenuation map generation for myocardial perfusion SPECT”. In: European Journal of Nuclear Medicine and Molecular Imaging 47 (2020). doi: [10.1007/s00259-020-04746-6](https://doi.org/10.1007/s00259-020-04746-6).
2. J. Bergstra and Y. Bengio. “Random Search for Hyper-Parameter Optimization”. In: Journal of Machine Learning Research 13 (2012).
3. H. Liu et al. “Post-reconstruction attenuation correction for SPECT myocardium perfusion imaging facilitated by deep learning-based attenuation map generation”. In: Journal of Nuclear Cardiology 29 (2021). doi: [10.1007/s12350-021-02817-1](http://doi.org/10.1007/s12350-021-02817-1).
4. G. Germano et al. “Quantitation in gated perfusion SPECT imaging: The Cedars-Sinai approach”. In: Journal of Nuclear Cardiology 14 (2007). doi: [10.1016/j.nuclcard.2007.06.008](https://doi.org/10.1016/j.nuclcard.2007.06.008).
import os
import cv2 as cv
import numpy as np
import torch
from mu_map.dataset.default import MuMapDataset
from mu_map.dataset.transform import PadCropTranform, SequenceTransform
from mu_map.models.unet import UNet
from mu_map.util import to_grayscale, COLOR_WHITE
from mu_map.random_search.cgan import load_params
from mu_map.vis.slices import join_images
torch.set_grad_enabled(False)
random_search_iter_dir = "cgan_random_search/001"
params = load_params(os.path.join(random_search_iter_dir, "params.json"))
print(params["normalization"])
print(params["generator_features"])
dataset = MuMapDataset(
"data/second/",
transform_normalization=SequenceTransform(
[params["normalization"], PadCropTranform(dim=3, size=32)]
),
split_name="test",
scatter_correction=False,
)
recon, mu_map_ct = dataset[1]
mu_map_ct = mu_map_ct.squeeze().numpy()
device = torch.device("cpu")
model = UNet(features=params["generator_features"])
model.load_state_dict(
torch.load(
os.path.join(random_search_iter_dir, "snapshots/val_min_generator.pth"), map_location=device
)
)
mu_map_dl = model(recon.unsqueeze(dim=0)).squeeze().numpy()
mu_map_dl = np.clip(mu_map_dl, 0, mu_map_ct.max())
volumes = [mu_map_ct, mu_map_dl, np.abs(mu_map_dl - mu_map_ct)]
min_val = 0
max_val = max(mu_map_ct.max(), mu_map_dl.max())
print(mu_map_ct.max(), mu_map_dl.max())
fourcc = cv.VideoWriter_fourcc(*"mp4v")
frame_size = (512, 3 * 512 + 2 * 10)
print(f"Frame size {frame_size}")
# video_writer = cv.VideoWriter("mu_map_comparison.mp4", fourcc, 25, frame_size, isColor=False)
video_writer = cv.VideoWriter("mu_map_comparison.mp4", cv.VideoWriter_fourcc(*"mp4v"), 25, frame_size[::-1], isColor=False)
for i in range(mu_map_ct.shape[0]):
images = map(lambda volume: volume[i], volumes)
images = map(
lambda img: to_grayscale(img, min_val=min_val, max_val=max_val), images
)
images = map(lambda img: cv.resize(img, (512, 512)), images)
images = list(images)
txt = f"{str(i):{len(str(mu_map_ct.shape[0]))}}/{mu_map_ct.shape[0]}"
cv.putText(images[0], txt, (0, 30), cv.FONT_HERSHEY_SIMPLEX, 1, 255, 3)
image = join_images(images)
for i in range(5):
video_writer.write(image)
video_writer.release()
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "mu_map"
version = "0.0.1"
authors = [
{ name="Tamino Huxohl", email="thuxohl@hdz-nrw.de" },
]
description = "Deep learning approximation of Attenuation Maps from SPECT reconstructions"
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
"Environment :: GPU :: NVIDIA CUDA",
"License :: OSI Approved :: MIT License",
"Operating System :: Unix",
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering :: Artificial Life",
]
dependencies = [
"matplotlib>=3.5.3",
"numpy>=1.23.1",
"opencv-python>=4.6.0.66",
"pandas>=1.4.3",
"pydicom>=2.3.0",
"pytesseract",
"scipy",
"stir>=5.0.0",
"termcolor",
"torch>=1.12.1",
"torchvision>=0.13.1",
]
[project.urls]
"Homepage" = "https://gitlab.ub.uni-bielefeld.de/thuxohl/mu-map"
res/polar_maps.png

1.13 MiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment