-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add hazenlib init tests coverage #144
Changes from 18 commits
9c66202
fd1bea4
98241ce
d3a3217
bf4f53e
507526c
0ee77f6
6b5491b
bc42917
d6137d8
d2d224e
008df9e
39353b7
4afff59
1ee8679
54e6fb1
858c2f2
238be87
f9cc8c4
44c2ddc
2510d13
aef3f7a
51fa679
658eab3
ada0244
0c05753
fdbecc9
28f4690
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
2021-11-15 21:19:24 I [spatial_resolution.py:main:514] 'FileDataset' object has no attribute 'SeriesDescription' | ||
2021-11-15 21:20:56 I [spatial_resolution.py:main:514] 'FileDataset' object has no attribute 'SeriesDescription' | ||
2021-11-15 21:28:24 I [spatial_resolution.py:main:514] 'FileDataset' object has no attribute 'SeriesDescription' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add all *.log files to the .gitignore so we don't track them? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, can you also delete this log from the repo? |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,10 +93,13 @@ | |
import pydicom | ||
from docopt import docopt | ||
import numpy as np | ||
import cv2 | ||
from hazenlib.tools import is_dicom_file | ||
|
||
|
||
__version__ = '0.4.0' | ||
|
||
|
||
import hazenlib.exceptions | ||
|
||
EXCLUDED_FILES = ['.DS_Store'] | ||
|
@@ -106,12 +109,10 @@ def rescale_to_byte(array): | |
image_histogram, bins = np.histogram(array.flatten(), 255) | ||
cdf = image_histogram.cumsum() # cumulative distribution function | ||
cdf = 255 * cdf / cdf[-1] # normalize | ||
|
||
# use linear interpolation of cdf to find new pixel values | ||
image_equalized = np.interp(array.flatten(), bins[:-1], cdf) | ||
|
||
return image_equalized.reshape(array.shape).astype('uint8') | ||
|
||
# | ||
|
||
def is_enhanced_dicom(dcm: pydicom.Dataset) -> bool: | ||
""" | ||
|
@@ -310,9 +311,29 @@ def get_field_of_view(dcm: pydicom.Dataset): | |
|
||
|
||
|
||
def parse_relaxometry_data(task, arguments, dicom_objects, report): #def parse_relaxometry_data(arguments, dicom_objects, report): # | ||
|
||
# Relaxometry arguments | ||
relaxometry_cli_args = {'--calc_t1', '--calc_t2', '--plate_number', | ||
'--show_template_fit', '--show_relax_fits', | ||
'--show_rois', '--verbose'} | ||
|
||
# Pass arguments with dictionary, stripping initial double dash ('--') | ||
relaxometry_args = {} | ||
|
||
for key in relaxometry_cli_args: | ||
relaxometry_args[key[2:]] = arguments[key] | ||
|
||
return task.main(dicom_objects, report_path = report, | ||
**relaxometry_args) | ||
|
||
|
||
|
||
|
||
|
||
|
||
def main(): | ||
arguments = docopt(__doc__, version=__version__) | ||
|
||
task = importlib.import_module(f"hazenlib.{arguments['<task>']}") | ||
folder = arguments['<folder>'] | ||
files = [os.path.join(folder, x) for x in os.listdir(folder) if x not in EXCLUDED_FILES] | ||
|
@@ -332,34 +353,24 @@ def main(): | |
|
||
} | ||
|
||
|
||
if arguments['--log'] in log_levels.keys(): | ||
level = log_levels[arguments['--log']] | ||
logging.getLogger().setLevel(level) | ||
else: | ||
# logging.basicConfig() | ||
logging.getLogger().setLevel(logging.INFO) | ||
|
||
# logging.basicConfig() | ||
logging.getLogger().setLevel(logging.INFO) | ||
|
||
|
||
if not arguments['<task>'] == 'snr' and arguments['--measured_slice_width']: | ||
raise Exception("the (--measured_slice_width) option can only be used with snr") | ||
elif arguments['<task>'] == 'snr' and arguments['--measured_slice_width']: | ||
measured_slice_width = float(arguments['--measured_slice_width']) | ||
return pp.pprint(task.main(dicom_objects, measured_slice_width, report_path=report)) | ||
return task.main(dicom_objects, measured_slice_width, report_path=report) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why have you chosen to return the output outside of a pprint object? How does this effect the output the user sees? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not done to change the output the user sees, rather for me to be able to test the function because print returns NONE There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean print returns none or pp.pprint returns none? Could you add some screenshots to example outputs to explain what you mean? I don't think we want to change this if we can. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Lucrezia-Cester, would that mean that the user does not see the result printed to the command line when they run the SNR task? Could you try something like the below so we print the result and we also return a value? if not arguments['<task>'] == 'snr' and arguments['--measured_slice_width']:
raise Exception("the (--measured_slice_width) option can only be used with snr")
elif arguments['<task>'] == 'snr' and arguments['--measured_slice_width']:
measured_slice_width = float(arguments['--measured_slice_width'])
result = task.main(dicom_objects, measured_slice_width, report_path=report)
elif arguments['<task>'] == 'relaxometry':
result = parse_relaxometry_data(task, arguments, dicom_objects, report)
else:
result = task.main(dicom_objects, report_path=report)
pp.pprint(result)
return result |
||
|
||
if arguments['<task>'] == 'relaxometry': | ||
# Relaxometry arguments | ||
relaxometry_cli_args = {'--calc_t1', '--calc_t2', '--plate_number', | ||
'--show_template_fit', '--show_relax_fits', | ||
'--show_rois', '--verbose'} | ||
|
||
# Pass arguments with dictionary, stripping initial double dash ('--') | ||
relaxometry_args = {} | ||
return parse_relaxometry_data(task, arguments, dicom_objects, report) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above we need to re-add this relaxometry code due to the earlier branching from develop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still there, I have put this relaxometry code in a function outside the main function. |
||
|
||
for key in relaxometry_cli_args: | ||
relaxometry_args[key[2:]] = arguments[key] | ||
return pp.pprint(task.main(dicom_objects, report_path=report)) | ||
|
||
return pp.pprint(task.main(dicom_objects, report_path=report, | ||
**relaxometry_args)) | ||
|
||
return pp.pprint(task.main(dicom_objects, report_path=report)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,207 @@ | ||
""" | ||
Tests functions in the hazenlib.__init__.py file | ||
""" | ||
import unittest | ||
import pydicom | ||
from tests import TEST_DATA_DIR | ||
import hazenlib | ||
import unittest | ||
import numpy as np | ||
from docopt import docopt | ||
from hazenlib.logger import logger | ||
from pprint import pprint | ||
import sys | ||
import os | ||
import hazenlib.tools as hazen_tools | ||
|
||
from tests import TEST_DATA_DIR | ||
TEST_DICOM = str(TEST_DATA_DIR / 'toshiba' / 'TOSHIBA_TM_MR_DCM_V3_0.dcm') | ||
TEST_DICOM = pydicom.read_file(TEST_DICOM) | ||
print(TEST_DICOM.Columns * TEST_DICOM.PixelSpacing[0]) | ||
|
||
class TestHazenlib(unittest.TestCase): | ||
# Data by ImplementationVersionName | ||
# all test values are taken from DICOM headers | ||
|
||
ROWS = 512 | ||
COLUMNS = 512 | ||
TR_CHECK = 500 | ||
BW = 205.0 | ||
|
||
def test_intit(self): | ||
test_dicoms = {'philips': {'file': str(TEST_DATA_DIR / 'resolution' / 'philips' / 'IM-0004-0002.dcm'), | ||
'MANUFACTURER': 'philips', | ||
'ROWS': 512, | ||
'COLUMNS': 512, | ||
'TR_CHECK': 500, | ||
'BW': 205.0, | ||
'ENHANCED': False, | ||
'PIX_ARRAY': 1, | ||
'SLICE_THICKNESS':5, | ||
'PIX_SIZE': [0.48828125, 0.48828125], | ||
'AVERAGE': 1}, | ||
'siemens': {'file': str(TEST_DATA_DIR / 'resolution' / 'eastkent' / '256_sag.IMA'), | ||
'MANUFACTURER': 'siemens', | ||
'ROWS' : 256, | ||
'COLUMNS' : 256, | ||
'TR_CHECK' : 500, | ||
'BW' : 130.0, | ||
'ENHANCED': False, | ||
'PIX_ARRAY': 1, | ||
'SLICE_THICKNESS': 5, | ||
'PIX_SIZE': [0.9765625, 0.9765625], | ||
'AVERAGE': 1}, | ||
'toshiba': {'file': str(TEST_DATA_DIR / 'toshiba' / 'TOSHIBA_TM_MR_DCM_V3_0.dcm'), | ||
'MANUFACTURER': 'toshiba', | ||
'ROWS': 256, | ||
'COLUMNS': 256, | ||
'TR_CHECK': 45.0, | ||
'BW': 244.0, | ||
'ENHANCED': False, | ||
'PIX_ARRAY': 1, | ||
'SLICE_THICKNESS': 6, | ||
'PIX_SIZE': [1.0, 1.0], | ||
'AVERAGE': 1}, | ||
'ge': {'file': str(TEST_DATA_DIR / 'ge' / 'ge_eFilm.dcm'), | ||
'MANUFACTURER': 'ge', | ||
'ROWS': 256, | ||
'COLUMNS': 256, | ||
'TR_CHECK': 1000.0, | ||
'BW': 156.25, | ||
'ENHANCED': False, | ||
'PIX_ARRAY': 1, | ||
'SLICE_THICKNESS': 5, | ||
'PIX_SIZE': [0.625, 0.625], | ||
'AVERAGE': 1}} | ||
|
||
|
||
for manufacturer in test_dicoms.keys(): | ||
laurencejackson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
with pydicom.read_file(test_dicoms[manufacturer]['file']) as dcm: | ||
#first test function | ||
assert hazenlib.get_manufacturer(dcm) == test_dicoms[manufacturer]['MANUFACTURER'] | ||
#second test function | ||
rows = hazenlib.get_rows(dcm) | ||
assert rows == test_dicoms[manufacturer]['ROWS'] | ||
#third test function | ||
columns = hazenlib.get_columns(dcm) | ||
assert columns == test_dicoms[manufacturer]['COLUMNS'] | ||
#fourth test function | ||
TR = hazenlib.get_TR(dcm) | ||
assert TR == test_dicoms[manufacturer]['TR_CHECK'] | ||
#fifth test_function | ||
bw = hazenlib.get_bandwidth(dcm) | ||
assert bw == test_dicoms[manufacturer]['BW'] | ||
#sixth test function | ||
enhanced = hazenlib.is_enhanced_dicom(dcm) | ||
assert enhanced == test_dicoms[manufacturer]['ENHANCED'] | ||
#seventh test funvtion | ||
pix_arr = hazenlib.get_num_of_frames(dcm) | ||
assert pix_arr == test_dicoms[manufacturer]['PIX_ARRAY'] | ||
#eigth test funciton | ||
slice_thick = hazenlib.get_slice_thickness(dcm) | ||
assert slice_thick == test_dicoms[manufacturer]['SLICE_THICKNESS'] | ||
#nineth test function | ||
avg = hazenlib.get_average(dcm) | ||
assert avg == test_dicoms[manufacturer]['AVERAGE'] | ||
#tenth test function | ||
pix_size = hazenlib.get_pixel_size(dcm) | ||
pix_size = list(pix_size) | ||
self.assertEqual(pix_size,test_dicoms[manufacturer]['PIX_SIZE']) | ||
|
||
def test_fov(self): | ||
test_dicoms = {'philips': {'file': str(TEST_DATA_DIR / 'resolution' / 'philips' / 'IM-0004-0002.dcm'), | ||
'MANUFACTURER': 'philips', | ||
'FOV': 250.0}, | ||
'siemens': {'file': str(TEST_DATA_DIR / 'resolution' / 'eastkent' / '256_sag.IMA'), | ||
'MANUFACTURER': 'siemens', | ||
'FOV': 250.0}, | ||
'toshiba': {'file': str(TEST_DATA_DIR / 'toshiba' / 'TOSHIBA_TM_MR_DCM_V3_0.dcm'), | ||
'MANUFACTURER': 'toshiba', | ||
'FOV': 256.0}} | ||
|
||
for manufacturer in test_dicoms.keys(): | ||
with pydicom.read_file(test_dicoms[manufacturer]['file']) as dcm: | ||
# first test function | ||
fov = hazenlib.get_field_of_view(dcm) | ||
print(fov) | ||
assert fov == test_dicoms[manufacturer]['FOV'] | ||
|
||
|
||
|
||
class Test(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.file = str(TEST_DATA_DIR / 'resolution' / 'philips' / 'IM-0004-0002.dcm') | ||
self.file = str(TEST_DATA_DIR / 'resolution' / 'eastkent' / '256_sag.IMA') | ||
self.dcm = pydicom.read_file(self.file) | ||
def test_get_bandwidth(self): | ||
bw = hazenlib.get_bandwidth(self.dcm) | ||
assert bw == self.BW | ||
self.dcm = self.dcm.pixel_array | ||
|
||
def test_get_rows(self): | ||
rows = hazenlib.get_rows(self.dcm) | ||
assert rows == self.ROWS | ||
def test_rescale_to_byte(self): | ||
test_array = np.array([[1,2], [3,4]]) | ||
TEST_OUT = np.array([[63,127],[191,255]]) | ||
test_array = hazenlib.rescale_to_byte(test_array) | ||
test_array = test_array.tolist() | ||
TEST_OUT = TEST_OUT.tolist() | ||
self.assertListEqual(test_array, TEST_OUT) | ||
|
||
def test_get_columns(self): | ||
columns = hazenlib.get_columns(self.dcm) | ||
assert columns == self.COLUMNS | ||
|
||
def test_get_TR(self): | ||
TR = hazenlib.get_TR(self.dcm) | ||
assert TR == self.TR_CHECK | ||
|
||
class TestFactorsPhilipsMR531(TestHazenlib): | ||
#PHILIPS_MR_53_1 | ||
|
||
ROWS = 512 | ||
COLUMNS = 512 | ||
TR_CHECK = 500 | ||
BW = 205.0 | ||
class TestCliParser(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.file = str(TEST_DATA_DIR / 'resolution' / 'philips' / 'IM-0004-0002.dcm') | ||
self.dcm = pydicom.read_file(self.file) | ||
|
||
class TestFactorsSiemensMRVE11C(TestHazenlib): | ||
#SIEMENS_MR_VE11C | ||
ROWS = 256 | ||
COLUMNS = 256 | ||
TR_CHECK = 500 | ||
BW = 130.0 | ||
|
||
def setUp(self): | ||
self.file = str(TEST_DATA_DIR / 'resolution' / 'eastkent' / '256_sag.IMA') | ||
self.dcm = pydicom.read_file(self.file) | ||
def test1_logger(self): | ||
sys.argv = ["hazen", "spatial_resolution", ".\\tests\\data\\resolution\\RESOLUTION\\", "--log", "warning"] | ||
|
||
class TestFactorsToshibaTMMRDCMV30(TestHazenlib): | ||
# TOSHIBA_TM_MR_DCM_V3_0 | ||
ROWS = 256 | ||
COLUMNS = 256 | ||
TR_CHECK = 45.0 | ||
BW = 244.0 | ||
sys.argv = [item.replace("\\","/") for item in sys.argv] | ||
|
||
hazenlib.main() | ||
|
||
logging = hazenlib.logging | ||
|
||
self.assertEqual(logging.root.level, logging.WARNING) | ||
|
||
|
||
def test2_logger(self): | ||
sys.argv = ["hazen", "spatial_resolution", ".\\tests\\data\\resolution\\RESOLUTION\\"] | ||
|
||
sys.argv = [item.replace("\\", "/") for item in sys.argv] | ||
|
||
hazenlib.main() | ||
|
||
logging = hazenlib.logging | ||
|
||
self.assertEqual(logging.root.level, logging.INFO) | ||
|
||
|
||
def test_main_snr_exception(self): | ||
sys.argv = ["hazen", "spatial_resolution", ".\\tests\\data\\snr\\Siemens\\", "--measured_slice_width=10"] | ||
|
||
sys.argv = [item.replace("\\", "/") for item in sys.argv] | ||
|
||
self.assertRaises(Exception, hazenlib.main) | ||
|
||
def test_snr_measured_slice_width(self): | ||
sys.argv = ["hazen", "snr", ".\\tests\\data\\snr\\GE", "--measured_slice_width", "1"] | ||
|
||
sys.argv = [item.replace("\\", "/") for item in sys.argv] | ||
|
||
output=hazenlib.main() | ||
|
||
dict1={'snr_subtraction_measured_SNR SAG MEAS1_23_1': 183.97, | ||
'snr_subtraction_normalised_SNR SAG MEAS1_23_1': 7593.04, | ||
'snr_smoothing_measured_SNR SAG MEAS1_23_1': 184.41, | ||
'snr_smoothing_normalised_SNR SAG MEAS1_23_1': 7610.83, | ||
'snr_smoothing_measured_SNR SAG MEAS2_24_1': 189.38, | ||
'snr_smoothing_normalised_SNR SAG MEAS2_24_1': 7816.0} | ||
|
||
self.assertDictEqual(dict1, output) | ||
|
||
|
||
def test_relaxometyr(self): | ||
sys.argv = ["hazen", "relaxometry", ".\\tests\\data\\relaxometry\\T1\\site3_ge\\plate4\\", "--plate_number", "4", "--calc_t1"] | ||
|
||
sys.argv = [item.replace("\\", "/") for item in sys.argv] | ||
|
||
output = hazenlib.main() | ||
|
||
dict1 = {'Spin Echo_32_2_P4_t1': {'rms_frac_time_difference': 0.13499936644959415}} | ||
self.assertDictEqual(dict1, output) | ||
|
||
def setUp(self): | ||
self.file = str(TEST_DATA_DIR / 'toshiba' / 'TOSHIBA_TM_MR_DCM_V3_0.dcm') | ||
self.dcm = pydicom.read_file(self.file) | ||
|
||
class TestFactorsGEeFilm(TestHazenlib): | ||
# GE_eFILM | ||
ROWS = 256 | ||
COLUMNS = 256 | ||
TR_CHECK = 1000.0 | ||
BW = 156.25 | ||
|
||
def setUp(self): | ||
self.file = str(TEST_DATA_DIR / 'ge' / 'ge_eFilm.dcm') | ||
self.dcm = pydicom.read_file(self.file) | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you meant this to be
*.log