myfirstorder.py 3.81 KB
Newer Older
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
import numpy
from scipy import ndimage

from radiomics.firstorder import RadiomicsFirstOrder
from .mybase import MyRadiomicsFeaturesBase


class MyRadiomicsFirstOrder(MyRadiomicsFeaturesBase):
    def __init__(self, inputImage, inputMask, **kwargs):
        super().__init__(inputImage, inputMask, **kwargs)

        self.pixelSpacing = inputImage.GetSpacing()
        self.voxelArrayShift = kwargs.get('voxelArrayShift', 0)

    def _initCalculation(self):
        return super()._initSegmentBasedCalculation()

        self.targetVoxelArray = self.imageArray[self.labelledVoxelCoordinates].astype(
            'float'
        )
        self.discretizedTargetVoxelArray = None  # Lazy instantiation

        self.logger.debug('First order feature class initialized')

    def _moment(self, a, moment=1, axis=0):
        return RadiomicsFirstOrder._moment(self, a, moment, axis)

    def _getDiscretizedTargetVoxelArray(self):
        return RadiomicsFirstOrder._getDiscretizedTargetVoxelArray(self)

    def getSuvMaxFeatureValue(self):
        r"""
        **20. SUV max**

        Implemented as one of the intensity features extracted by Vallieres et al.
        Maximum SUV of the tumour region. 

        .. note::
        Extracted from PET scans and not used in the CT feature set.
        """
        ROIPet = self.imageArray
        mask = self.maskArray
        ROIPet[~mask] = numpy.nan

        return numpy.max(ROIPet[~numpy.isnan(ROIPet)])

    def getSuvMeanFeatureValue(self):
        r"""
        **21. SUV mean**

        Implemented as one of the intensity features extracted by valieres et al.
        Average SUV of the tumour region. 

        .. note::
        Extracted from PET scans and not used in the CT feature set.
        """
        ROIPet = self.imageArray
        mask = self.maskArray
        ROIPet[~mask] = numpy.nan

        return numpy.mean(ROIPet[~numpy.isnan(ROIPet)])

63
64
    def getTLGFeatureValue(self):
        r"""
65
        **22. TLG**
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

        Total lesion glycolysis. 
        Defined as 
        
        .. math::
        \textit{SUVMean}\times \textit{total volume of the tumour region}
    
        .. note::
        Extracted from PET scans and not used in the CT feature set.
        """
        z, y, x = self.pixelSpacing
        Np = len(self.labelledVoxelCoordinates[0])
        volume = Np * (z * x * y)

        ROIPet = self.imageArray
        mask = self.maskArray
        ROIPet[~mask] = numpy.nan

        return numpy.mean(ROIPet[~numpy.isnan(ROIPet)]) * volume

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
    def getAUCCSHFeatureValue(self):
        r"""
        **23. Inactive volume **

        Area under the curve of the cumulative SUV-volume histogram describing the percentage 
        of total tumour volume above a percentage threshold of maximum SUV, as defined by van Velden et al.

        .. note::
        Extracted from PET scans and not used in the CT feature set.
        """
        nBins = 1000  # By default
        ROIPet = self.imageArray
        mask = self.maskArray

        ROIPet[~mask] = numpy.nan

        outliers = numpy.where(
            ROIPet
            > (
                numpy.mean(ROIPet[~numpy.isnan(ROIPet)])
                + 3 * numpy.std(ROIPet[~numpy.isnan(ROIPet)])
            )
        )[0]

        good_voxels = numpy.where(
            ROIPet
            <= (
                numpy.mean(ROIPet[~numpy.isnan(ROIPet)])
                + 3 * numpy.std(ROIPet[~numpy.isnan(ROIPet)])
            )
        )[0]

        ROIPet[outliers] = numpy.mean(ROIPet[good_voxels])
        ROIPet = ROIPet - numpy.min(ROIPet[~numpy.isnan(ROIPet)])
        ROIPet = ROIPet / numpy.max(ROIPet[~numpy.isnan(ROIPet)])
        volume = ROIPet[~numpy.isnan(ROIPet)]
        nVoxel = len(volume)

        bins, _ = numpy.histogram(volume, nBins)

        csh = numpy.flipud(numpy.cumsum(numpy.flipud(bins)) / nVoxel)
        return numpy.sum(csh / nBins)