-
Notifications
You must be signed in to change notification settings - Fork 0
/
generalinfo.py
154 lines (121 loc) · 7.17 KB
/
generalinfo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import collections
import logging
import sys
import numpy
import pywt
import SimpleITK as sitk
import radiomics
class GeneralInfo:
def __init__(self):
self.logger = logging.getLogger(self.__module__)
self.generalInfo_prefix = 'diagnostics_'
self.generalInfo = collections.OrderedDict()
self.addStaticElements()
def getGeneralInfo(self):
"""
Return a dictionary containing all general info items. Format is <info_item>:<value>, where the type
of the value is preserved. For CSV format, this will result in conversion to string and quotes where necessary, for
JSON, the values will be interpreted and stored as JSON strings.
"""
return self.generalInfo
def addStaticElements(self):
"""
Adds the following elements to the general info:
- Version: current version of PyRadiomics
- NumpyVersion: version of numpy used
- SimpleITKVersion: version SimpleITK used
- PyWaveletVersion: version of PyWavelet used
- PythonVersion: version of the python interpreter running PyRadiomics
"""
self.generalInfo[self.generalInfo_prefix + 'Versions_PyRadiomics'] = radiomics.__version__
self.generalInfo[self.generalInfo_prefix + 'Versions_Numpy'] = numpy.__version__
self.generalInfo[self.generalInfo_prefix + 'Versions_SimpleITK'] = sitk.Version().VersionString()
self.generalInfo[self.generalInfo_prefix + 'Versions_PyWavelet'] = pywt.__version__
self.generalInfo[self.generalInfo_prefix + 'Versions_Python'] = '%i.%i.%i' % sys.version_info[:3]
def addImageElements(self, image, prefix='original'):
"""
Calculates provenance info for the image
Adds the following:
- Hash: sha1 hash of the mask, which can be used to check if the same mask was used during reproducibility
tests. (Only added when prefix is "original")
- Dimensionality: Number of dimensions (e.g. 2D, 3D) in the image. (Only added when prefix is "original")
- Spacing: Pixel spacing (x, y, z) in mm.
- Size: Dimensions (x, y, z) of the image in number of voxels.
- Mean: Mean intensity value over all voxels in the image.
- Minimum: Minimum intensity value among all voxels in the image.
- Maximum: Maximum intensity value among all voxels in the image.
A prefix is added to indicate what type of image is described:
- original: Image as loaded, without pre-processing.
- interpolated: Image after it has been resampled to a new spacing (includes cropping).
"""
if prefix == 'original':
self.generalInfo[self.generalInfo_prefix + 'Image-original_Hash'] = sitk.Hash(image)
self.generalInfo[self.generalInfo_prefix + 'Image-original_Dimensionality'] = '%iD' % image.GetDimension()
self.generalInfo[self.generalInfo_prefix + 'Image-' + prefix + '_Spacing'] = image.GetSpacing()
self.generalInfo[self.generalInfo_prefix + 'Image-' + prefix + '_Size'] = image.GetSize()
im_arr = sitk.GetArrayFromImage(image).astype('float')
self.generalInfo[self.generalInfo_prefix + 'Image-' + prefix + '_Mean'] = numpy.mean(im_arr)
self.generalInfo[self.generalInfo_prefix + 'Image-' + prefix + '_Minimum'] = numpy.min(im_arr)
self.generalInfo[self.generalInfo_prefix + 'Image-' + prefix + '_Maximum'] = numpy.max(im_arr)
def addMaskElements(self, image, mask, label, prefix='original'):
"""
Calculates provenance info for the mask
Adds the following:
- MaskHash: sha1 hash of the mask, which can be used to check if the same mask was used during reproducibility
tests. (Only added when prefix is "original")
- BoundingBox: bounding box of the ROI defined by the specified label:
Elements 0, 1 and 2 are the x, y and z coordinates of the lower bound, respectively.
Elements 3, 4 and 5 are the size of the bounding box in x, y and z direction, respectively.
- VoxelNum: Number of voxels included in the ROI defined by the specified label.
- VolumeNum: Number of fully connected (26-connectivity) volumes in the ROI defined by the specified label.
- CenterOfMassIndex: x, y and z coordinates of the center of mass of the ROI in terms of the image coordinate space
(continuous index).
- CenterOfMass: the real-world x, y and z coordinates of the center of mass of the ROI
- ROIMean: Mean intensity value over all voxels in the ROI defined by the specified label.
- ROIMinimum: Minimum intensity value among all voxels in the ROI defined by the specified label.
- ROIMaximum: Maximum intensity value among all voxels in the ROI defined by the specified label.
A prefix is added to indicate what type of mask is described:
- original: Mask as loaded, without pre-processing.
- corrected: Mask after it has been corrected by :py:func:`imageoperations.checkMask`.
- interpolated: Mask after it has been resampled to a new spacing (includes cropping).
- resegmented: Mask after resegmentation has been applied.
"""
if mask is None:
return
if prefix == 'original':
self.generalInfo[self.generalInfo_prefix + 'Mask-original_Hash'] = sitk.Hash(mask)
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_Spacing'] = mask.GetSpacing()
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_Size'] = mask.GetSize()
lssif = sitk.LabelShapeStatisticsImageFilter()
lssif.Execute(mask)
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_BoundingBox'] = lssif.GetBoundingBox(label)
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_VoxelNum'] = lssif.GetNumberOfPixels(label)
labelMap = (mask == label)
ccif = sitk.ConnectedComponentImageFilter()
ccif.FullyConnectedOn()
ccif.Execute(labelMap)
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_VolumeNum'] = ccif.GetObjectCount()
ma_arr = sitk.GetArrayFromImage(labelMap) == 1
maskCoordinates = numpy.array(numpy.where(ma_arr))
center_index = tuple(numpy.mean(maskCoordinates, axis=1)[::-1]) # also convert z, y, x to x, y, z order
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_CenterOfMassIndex'] = center_index
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_CenterOfMass'] = mask.TransformContinuousIndexToPhysicalPoint(center_index)
if image is None:
return
im_arr = sitk.GetArrayFromImage(image)
targetvoxels = im_arr[ma_arr].astype('float')
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_Mean'] = numpy.mean(targetvoxels)
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_Minimum'] = numpy.min(targetvoxels)
self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_Maximum'] = numpy.max(targetvoxels)
def addGeneralSettings(self, settings):
"""
Add a string representation of the general settings.
Format is {<settings_name>:<value>, ...}.
"""
self.generalInfo[self.generalInfo_prefix + 'Configuration_Settings'] = settings
def addEnabledImageTypes(self, enabledImageTypes):
"""
Add a string representation of the enabled image types and any custom settings for each image type.
Format is {<imageType_name>:{<setting_name>:<value>, ...}, ...}.
"""
self.generalInfo[self.generalInfo_prefix + 'Configuration_EnabledImageTypes'] = enabledImageTypes