Skip to content

Commit

Permalink
Merge pull request #293 from GSTT-CSC/release/1.0.5
Browse files Browse the repository at this point in the history
Merge GSTT-CSC/release/1.0.5 into main
  • Loading branch information
tomaroberts authored Dec 30, 2022
2 parents e4f4e32 + f90b263 commit 01046cb
Show file tree
Hide file tree
Showing 46 changed files with 281 additions and 204 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test_cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ jobs:
- name: test acr_uniformity
if: always() # will always run regardless of whether previous step fails - useful to ensure all CLI functions tested
run: |
hazen task_acr_uniformity tests/data/acr/Siemens/Test --report
hazen acr_uniformity tests/data/acr/Siemens --report
- name: test acr_ghosting
if: always() # will always run regardless of whether previous step fails - useful to ensure all CLI functions tested
run: |
hazen task_acr_ghosting tests/data/acr/Siemens/Test --report
hazen acr_ghosting tests/data/acr/Siemens --report
- name: test slice_position
if: always() # will always run regardless of whether previous step fails - useful to ensure all CLI functions tested
Expand Down
52 changes: 32 additions & 20 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,34 +1,46 @@
# virtual environments
hazen-venv
.scannerwork
/venv/

# tests
.coverage
coverage.xml
pytest-coverage.txt
pytest.xml

# cache
**/__pycache__
.idea
.DS_Store
/.cache/
/.bash_history
.pytest_cache

# logs
logs
*.log
Hazen_logger.log
hazen.egg-info
dist

# data
uploads
*.png
report
# TODO: Remove the following if no longer needed
tests/data/slicepos/results
tests/data/uniformity/results
rods.png
tra_slicewidth5_Bottom_Profile.png
tra_slicewidth5_Slice_Width_and_Distortion_Results.txt
tra_slicewidth5_Slice_Width_and_Distortion_ROIs.png
tra_slicewidth5_Top_Profile.png
nodeids
htmlcov
build
dist
hazen.egg-info
hazenlib/data

# docs
docs/_build
docs/build
build

# mischellaneous
# TODO: Remove the following if no longer needed
hazen_getting_started.pdf
.DS_Store
/.cache/
/.bash_history
/junit.xml
pytest-coverage.txt
pytest.xml
Hazen_logger.log
*.png
newdocs/_build
/venv/
.scannerwork
nodeids
htmlcov
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ date-released: 2022-02-24
message: "If you use hazen in your work, please cite it using these metadata."
repository-code: "https://github.com/GSTT-CSC/hazen"
title: hazen
version: "0.6.0"
version: "1.0.5"
...
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,10 @@ We have used hazen with MRI data from a handful of different MRI scanners, inclu
The Release Manager should ensure:
- All outstanding issues for the current release have been closed, or, transferred to future release.
- All tests are passing on Github Actions.
- All tests are passing on GitHub Actions.
- All documentation has been updated with correct version numbers:
- Version number in `docs/conf.py`
- Version number in `hazenlib/__init__.py`
- Version number in `CITATION.cff`
- Update version number `hazenlib/_version.py`, i.e. imported into `docs/conf.py`, `hazenlib/__init__.py` and `setup.py`
- Update version number in `CITATION.cff`
- The `release` branch has been merged into `main` branch
- A new release has been created with a new version tag (tag = version number)
Expand Down
4 changes: 3 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#
import os
import sys
from hazenlib import __version__

sys.path.insert(0, os.path.abspath("../.."))


Expand All @@ -22,7 +24,7 @@
author = 'Haris Shuaib'

# The full version, including alpha/beta/rc tags
release = '0.6.0'
release = __version__


# -- General configuration ---------------------------------------------------
Expand Down
7 changes: 5 additions & 2 deletions hazenlib/HazenTask.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@

class HazenTask:

def __init__(self, data_paths: list, report: bool = False, report_dir: str = os.path.join(os.getcwd(), 'hazen_reports')):
def __init__(self, data_paths: list, report: bool = False, report_dir: str = os.path.join(os.getcwd(), 'report')):
self.data_paths = sorted(data_paths)
self.report: bool = report
self.report_path = os.path.join(report_dir, type(self).__name__)
pathlib.Path(self.report_path).mkdir(parents=True, exist_ok=True)
if report:
pathlib.Path(self.report_path).mkdir(parents=True, exist_ok=True)
else:
pass
self.report_files = []

@property
Expand Down
15 changes: 10 additions & 5 deletions hazenlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,14 @@
Welcome to the Hazen Command Line Interface
Usage:
hazen <task> <folder> [--measured_slice_width=<mm>] [--report] [--output=<path>] [--calc_t1 | --calc_t2] [--plate_number=<n>] [--show_template_fit]
hazen <task> <folder> [--measured_slice_width=<mm>] [--report] [--output=<path>] [--calc_t1 | --calc_t2]
[--plate_number=<n>] [--show_template_fit]
[--show_relax_fits] [--show_rois] [--log=<lvl>] [--verbose]
hazen -h|--help
hazen -v|--version
hazen --version
Options:
<task> snr | slice_position | slice_width | spatial_resolution | uniformity | ghosting | relaxometry | snr_map
<task> snr | slice_position | slice_width | spatial_resolution | uniformity | ghosting | relaxometry | snr_map |
acr_ghosting | acr_uniformity
<folder>
--report
Expand Down Expand Up @@ -360,6 +362,7 @@ def main():

task = getattr(task_module, class_list[0].__name__)(data_paths=files,
report=arguments['--report'],
# TODO: Is this necessary? See HazenTask __init__()
report_dir=[arguments['--output'] if arguments[
'--output'] else os.path.join(os.getcwd(), 'report')][0])

Expand All @@ -369,12 +372,14 @@ def main():
measured_slice_width = float(arguments['--measured_slice_width'])
logger.info(f'Calculating SNR with measured slice width {measured_slice_width}')
result = task.run(measured_slice_width)
# Relaxometry not currently converted to HazenTask object - this task accessible in the CLI using the old syntax until it can be refactored
# TODO: Refactor Relaxometry task into HazenTask object Relaxometry not currently converted to HazenTask object -
# this task accessible in the CLI using the old syntax until it can be refactored
elif arguments['<task>'] == 'relaxometry':
task = importlib.import_module(f"hazenlib.{arguments['<task>']}")
dicom_objects = [pydicom.read_file(x, force=True) for x in files if is_dicom_file(x)]
result = parse_relaxometry_data(task, arguments, dicom_objects, report=True)
# Relaxometry not currently converted to HazenTask object - this task accessible in the CLI using the old syntax until it can be refactored
# TODO: Refactor SNR Map into HazenTask object (if not already) Relaxometry not currently converted to HazenTask
# object - this task accessible in the CLI using the old syntax until it can be refactored
elif arguments['<task>'] == 'snr_map':
task = importlib.import_module(f"hazenlib.{arguments['<task>']}")
dicom_objects = [pydicom.read_file(x, force=True) for x in files if is_dicom_file(x)]
Expand Down
2 changes: 1 addition & 1 deletion hazenlib/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.0.4'
__version__ = '1.0.5'
13 changes: 9 additions & 4 deletions hazenlib/snr_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
method for measurement of signal-to-noise ratio in MRI. Physics in Medicine
& Biology, 58(11), 3775.
"""
import pathlib

import pydicom
import numpy as np
Expand Down Expand Up @@ -361,7 +362,7 @@ def plot_summary(original_image, snr_map, roi_corners, roi_size):


def main(dcm_list, kernel_len=9, roi_size=20, roi_distance=40,
report_path=False):
report_path=False, report_dir=pathlib.Path.joinpath(pathlib.Path.cwd(), 'report', 'SNRMap')):
"""
Returns SNR parametric map on flood phantom DICOM file.
Expand All @@ -384,17 +385,21 @@ def main(dcm_list, kernel_len=9, roi_size=20, roi_distance=40,
roi_distance : int, optional
Distance from centre of image to centre of each ROI along both
dimensions. The default is 40.
report_path:
report_dir:
Returns
-------
results : dict
"""
# TODO
# ----
# * Scale ROI distance to account for different image sizes.
# * Pass kernel_len and roi_size parameters from command line.

results = {}
if report_path:
# Create nested report folder and ignore if already exists
pathlib.Path.mkdir(report_dir, parents=True, exist_ok=True)

for dcm in dcm_list:

Expand Down Expand Up @@ -463,8 +468,8 @@ def main(dcm_list, kernel_len=9, roi_size=20, roi_distance=40,
# Save images
# ===========
if report_path:
detailed_image_path = f'{report_path}_snr_map_detailed.png'
summary_image_path = f'{report_path}_snr_map.png'
detailed_image_path = pathlib.Path.joinpath(report_dir, f'{report_path}_snr_map_detailed.png')
summary_image_path = pathlib.Path.joinpath(report_dir, f'{report_path}_snr_map.png')

fig_detailed.savefig(detailed_image_path, dpi=300)
fig_summary.savefig(summary_image_path, dpi=300)
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import setuptools
import os

__version__ = '1.0.4'
from hazenlib import __version__

install_requires = ['pydicom==2.2.2',
'numpy==1.21.4',
Expand Down
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
import pathlib

TEST_DATA_DIR = pathlib.Path(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data'))
TEST_REPORT_DIR = pathlib.Path(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'report'))
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
14 changes: 8 additions & 6 deletions tests/test_acr_ghosting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import pathlib
import pydicom

from hazenlib.tasks.task_acr_ghosting import ACRGhosting
from tests import TEST_DATA_DIR
from hazenlib.tasks.acr_ghosting import ACRGhosting
from tests import TEST_DATA_DIR, TEST_REPORT_DIR


class TestACRGhostingSiemens(unittest.TestCase):
Expand All @@ -13,8 +13,9 @@ class TestACRGhostingSiemens(unittest.TestCase):
psg = 0.056

def setUp(self):
self.acr_ghosting_task = ACRGhosting(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')])
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'Siemens', 'Test', '6.dcm'))
self.acr_ghosting_task = ACRGhosting(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')],
report_dir=pathlib.PurePath.joinpath(TEST_REPORT_DIR))
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'Siemens', '6.dcm'))

def test_object_centre(self):
assert self.acr_ghosting_task.centroid_com(self.dcm.pixel_array)[1] == self.centre
Expand All @@ -29,8 +30,9 @@ class TestACRGhostingGE(unittest.TestCase):
psg = 0.487

def setUp(self):
self.acr_ghosting_task = ACRGhosting(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')])
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'GE', 'Test', '4.dcm'))
self.acr_ghosting_task = ACRGhosting(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')],
report_dir=pathlib.PurePath.joinpath(TEST_REPORT_DIR))
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'GE', '4.dcm'))

def test_object_centre(self):
assert self.acr_ghosting_task.centroid_com(self.dcm.pixel_array)[1] == self.centre
Expand Down
20 changes: 11 additions & 9 deletions tests/test_acr_uniformity.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@
import pydicom
import numpy as np

from hazenlib.tasks.task_acr_uniformity import ACRUniformity
from tests import TEST_DATA_DIR
from hazenlib.tasks.acr_uniformity import ACRUniformity
from tests import TEST_DATA_DIR, TEST_REPORT_DIR


class TestACRUniformitySiemens(unittest.TestCase):
ACR_UNIFORMITY_DATA = pathlib.Path(TEST_DATA_DIR / 'acr')
centre = [129, 128]
piu = 68.66
array = np.zeros((256,256), dtype=int)
array = np.zeros((256, 256), dtype=int)
array[127][126] = 1
array[126][127] = 1
array[127][127] = 1
array[128][127] = 1
array[127][128] = 1

def setUp(self):
self.acr_uniformity_task = ACRUniformity(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')])
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'Siemens', 'Test', '6.dcm'))
self.acr_uniformity_task = ACRUniformity(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')],
report_dir=pathlib.PurePath.joinpath(TEST_REPORT_DIR))
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'Siemens', '6.dcm'))

def test_object_centre(self):
assert self.acr_uniformity_task.centroid_com(self.dcm.pixel_array) == self.centre
Expand All @@ -32,7 +33,7 @@ def test_circular_mask(self):

def test_uniformity(self):
results = self.acr_uniformity_task.get_integral_uniformity(self.dcm)
assert round(results,2) == self.piu
assert round(results, 2) == self.piu


# class TestACRUniformityPhilips(unittest.TestCase):
Expand All @@ -43,12 +44,13 @@ class TestACRUniformityGE(unittest.TestCase):
piu = 84.76

def setUp(self):
self.acr_uniformity_task = ACRUniformity(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')])
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'GE', 'Test', '4.dcm'))
self.acr_uniformity_task = ACRUniformity(data_paths=[os.path.join(TEST_DATA_DIR, 'acr')],
report_dir=pathlib.PurePath.joinpath(TEST_REPORT_DIR))
self.dcm = pydicom.read_file(os.path.join(TEST_DATA_DIR, 'acr', 'GE', '4.dcm'))

def test_object_centre(self):
assert self.acr_uniformity_task.centroid_com(self.dcm.pixel_array) == self.centre

def test_uniformity(self):
results = self.acr_uniformity_task.get_integral_uniformity(self.dcm)
assert round(results,2) == self.piu
assert round(results, 2) == self.piu
Loading

0 comments on commit 01046cb

Please sign in to comment.