Пример #1
0
def test_execute3():
    c = ChestConventions()
    wc = c.GetChestWildCardName()

    paren_pheno = ParenchymaPhenotypes(chest_types=['Vessel'])
    df = paren_pheno.execute(ct, lm, 'simple', np.array([1., 1., 1.]))
    assert len(df.index) == 1, "Unexpected number of rows in dataframe"
    assert df['Region'].iloc[0] == wc, "Unexpected region in dataframe"
    assert df['Type'].iloc[0] == 'Vessel', "Unexpected type in dataframe"
    def add_pheno(self, key_value, pheno_name, pheno_value):
        """Add a phenotype.
    
        Parameters
        ----------
        key_value : list of strings
            This list indicates the specific DB key values that will be
            associated with the phenotype. E.g. ['WHOLELUNG', 'UNDEFINEDTYPE']

        pheno_name : string
            The name of the phenotype. E.g. 'LAA-950'

        pheno_value : object
            The phenotype value. Can be a numerical value, string, etc
        """
        c = ChestConventions()

        num_keys = len(key_value)

        # Make sure CID has been set
        assert self.static_names_handler_['CID'] is not None, \
            "CID has not been set"

        # Make sure the pheno name is valid
        assert c.IsPhenotypeName(pheno_name) or pheno_name == \
            c.GetChestWildCardName(), "Invalid phenotype name"

        # Check if key is valid
        for i in xrange(0, num_keys):
            assert key_value[i] in self.valid_key_values_[self.key_names_[i]], \
                "Invalid key: %s" % key_value[i]

        # Check if pheno_name is valid
        assert pheno_name in self.pheno_names_, \
            "Invalid phenotype name: %s" % pheno_name

        # Check if key already exists, otherwise add entry to data frame
        key_exists = True
        key_row = np.ones(len(self._df.index), dtype=bool)
        for i in xrange(0, len(self.key_names_)):
            key_row = \
                np.logical_and(key_row, \
                               self._df[self.key_names_[i]] == key_value[i])

        if np.sum(key_row) == 0:
            tmp = dict()
            for k in self.static_names_handler_.keys():
                tmp[k] = self.static_names_handler_[k]()
            tmp[pheno_name] = pheno_value
            for i in xrange(0, num_keys):
                tmp[self.key_names_[i]] = key_value[i]
            self._df = self._df.append(tmp, ignore_index=True)
        else:
            self._df[pheno_name][np.where(key_row == True)[0][0]] = pheno_value
Пример #3
0
    def get_chest_regions(self):
        """Get the explicit list of chest regions in the data set.

        Returns
        -------
        chest_regions : array, shape ( N )
            Explicit list of the N chest regions in the data set
        """
        conventions = ChestConventions()

        tmp = []
        for l in self.labels_:
            tmp.append(conventions.GetChestRegionFromValue(l))

        chest_regions = np.unique(np.array(tmp, dtype=int))
        return chest_regions
Пример #4
0
    def get_chest_types(self):
        """Get the chest types in the data set
        
        Returns
        -------
        chest_types : array, shape ( N )
            All N chest types in the data set
        """
        c = ChestConventions()

        tmp = []
        for l in self.labels_:
            tmp.append(c.GetChestTypeFromValue(l))

        chest_types = np.unique(np.array(tmp, dtype=int))
        return chest_types
Пример #5
0
def test_execute():
    c = ChestConventions()
    wc = c.GetChestWildCardName()

    laa = LAAPhenotypes()
    df = laa.execute(ct, lm, 'simple')

    for i in xrange(0, 14):
        r = df['Region'].iloc[i]
        t = df['Type'].iloc[i]
        val_950 = df['LAA950'].iloc[i]
        val_910 = df['LAA910'].iloc[i]
        val_856 = df['LAA856'].iloc[i]
        if (r == 'UNDEFINEDREGION' and t == wc) or \
            (r == wc and t == 'UNDEFINEDTYPE') or \
            (r == 'UNDEFINEDREGION' and t == 'UNDEFINEDTYPE'):
            assert val_950 == wc, 'Phenotype not as expected'
            assert val_910 == wc, 'Phenotype not as expected'
            assert val_856 == wc, 'Phenotype not as expected'
        elif (r == 'WHOLELUNG' and t == wc) or \
            (r == 'RIGHTLUNG' and t == wc) or \
            (r == 'LEFTLUNG' and t == wc):
            assert np.isclose(val_950, 0.1111111), 'Phenotype not as expected'
            assert np.isclose(val_910, 0.1111111), 'Phenotype not as expected'
            assert np.isclose(val_856, 0.1111111), 'Phenotype not as expected'
        elif (r == wc and t == 'AIRWAY') or \
            (r == 'UNDEFINEDREGION' and t == 'AIRWAY') or \
            (r == 'WHOLELUNG' and t == 'AIRWAY') or \
            (r == 'RIGHTLUNG' and t == 'AIRWAY') or \
            (r == 'LEFTLUNG' and t == 'AIRWAY'):
            assert np.isclose(val_950, 1.0), 'Phenotype not as expected'
            assert np.isclose(val_910, 1.0), 'Phenotype not as expected'
            assert np.isclose(val_856, 1.0), 'Phenotype not as expected'
        elif (r == 'WHOLELUNG' and t == 'UNDEFINEDTYPE') or \
            (r == 'RIGHTLUNG' and t == 'UNDEFINEDTYPE') or \
            (r == 'LEFTLUNG' and t == 'UNDEFINEDTYPE') or \
            (r == 'WHOLELUNG' and t == 'VESSEL') or \
            (r == 'RIGHTLUNG' and t == 'VESSEL') or \
            (r == 'LEFTLUNG' and t == 'VESSEL') or \
            (r == wc and t == 'VESSEL'):
            assert np.isclose(val_950, 0.0), 'Phenotype not as expected'
            assert np.isclose(val_910, 0.0), 'Phenotype not as expected'
            assert np.isclose(val_856, 0.0), 'Phenotype not as expected'
Пример #6
0
    def __init__(self, chest_regions=None, chest_types=None, pairs=None,
                 pheno_names=None):
        c = ChestConventions()

        self.chest_regions_ = None
        if chest_regions is not None:
            tmp = []
            for m in xrange(0, len(chest_regions)):
                tmp.append(c.GetChestRegionValueFromName(chest_regions[m]))
            self.chest_regions_ = np.array(tmp)

        self.chest_types_ = None
        if chest_types is not None:
            tmp = []
            for m in xrange(0, len(chest_types)):
                tmp.append(c.GetChestTypeValueFromName(chest_types[m]))
            self.chest_types_ = np.array(tmp)
                
        self.pairs_ = None
        if pairs is not None:
            self.pairs_ = np.zeros([len(pairs), 2])
            inc = 0
            for p in pairs:
                assert len(p)%2 == 0, \
                    "Specified region-type pairs not understood"                
                r = c.GetChestRegionValueFromName(p[0])
                t = c.GetChestTypeValueFromName(p[1])
                self.pairs_[inc, 0] = r
                self.pairs_[inc, 1] = t                
                inc += 1    
                
        self.requested_pheno_names = pheno_names

        Phenotypes.__init__(self)    
Пример #7
0
    def get_all_chest_regions(self):
        """Get all the chest regions in the data set, including those
        implicitly present as a result of the region hierarchy.

        Returns
        -------
        chest_regions : array, shape ( N )
            All chest regions in the data set
        """
        c = ChestConventions()
        num_regions = c.GetNumberOfEnumeratedChestRegions()

        tmp = []
        for l in self.labels_:
            r = c.GetChestRegionFromValue(l)

            for sup in xrange(0, num_regions):
                if c.CheckSubordinateSuperiorChestRegionRelationship(r, sup):
                    tmp.append(sup)

        chest_regions = np.unique(np.array(tmp, dtype=int))
        return chest_regions
Пример #8
0
def test_execute5():
    c = ChestConventions()
    wc = c.GetChestWildCardName()

    paren_pheno = ParenchymaPhenotypes(chest_regions=['LeftLung'], \
                                       pheno_names=['LAA950'])
    df = paren_pheno.execute(ct, lm, 'simple', np.array([1., 1., 1.]))

    assert len(df.index) == 1, "Unexpected number of rows in dataframe"
    assert df['Region'].iloc[0] == 'LeftLung', "Unexpected region in dataframe"
    assert df['Type'].iloc[0] == wc, "Unexpected type in dataframe"
    assert np.isnan(df.LAA910.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.LAA856.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HAA700.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HAA600.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HAA500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HAA250.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.Perc15.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.Perc10.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMean.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUStd.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUKurtosis.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUSkewness.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMode.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMedian.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMin.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMax.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMean500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUStd500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUKurtosis500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUSkewness500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMode500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMedian500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMin500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.HUMax500.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.Volume.iloc[0]), "Phenotype value should be NaN"
    assert np.isnan(df.Mass.iloc[0]), "Phenotype value should be NaN"
    def valid_key_values(self):
        """Get the valid DB key values that each DB key can assume.
    
        Returns
        -------
        valid_values : dictionary
            The returned dictionary keys are the valid DB key names. Each dictionary
            key value maps to a list of valid names that the DB key can assume.
        """
        c = ChestConventions()
        valid_values = dict()

        region_names = [c.GetChestWildCardName()]
        for i in xrange(0, c.GetNumberOfEnumeratedChestRegions()):
            region_names.append(c.GetChestRegionName(i))
        valid_values['Region'] = region_names

        type_names = [c.GetChestWildCardName()]
        for i in xrange(0, c.GetNumberOfEnumeratedChestTypes()):
            type_names.append(c.GetChestTypeName(i))
        valid_values['Type'] = type_names

        return valid_values
Пример #10
0
    def get_all_pairs(self):
        """Get all the region-type pairs, including implied pairs

        Returns
        -------
        pairs : array, shape ( N, 2 )
            All N chest-region chest-type pairs in the data set, including
            those implied by the region hierarchy. The first column indicates
            the chest region, and the second column represents the chest type.
        """
        c = ChestConventions()
        num_regions = c.GetNumberOfEnumeratedChestRegions()

        tmp = []
        for l in self.labels_:
            t = c.GetChestTypeFromValue(l)
            r = c.GetChestRegionFromValue(l)
            for sup in xrange(0, num_regions):
                if c.CheckSubordinateSuperiorChestRegionRelationship(r, sup):
                    if not (sup, t) in tmp:
                        tmp.append((sup, t))

        pairs = np.array(tmp, dtype=int)
        return pairs
Пример #11
0
def test_execute():
    c = ChestConventions()
    wc = c.GetChestWildCardName()

    paren_pheno = ParenchymaPhenotypes()
    df = paren_pheno.execute(ct, lm, 'simple', np.array([1., 1., 1.]))

    for i in xrange(0, 14):
        r = df['Region'].iloc[i]
        t = df['Type'].iloc[i]
        val_950 = df['LAA950'].iloc[i]
        val_910 = df['LAA910'].iloc[i]
        val_856 = df['LAA856'].iloc[i]
        if (r == 'UndefinedRegion' and t == wc) or \
            (r == wc and t == 'UndefinedRegion') or \
            (r == 'UndefinedRegion' and t == 'UndefinedType'):
            assert val_950 == wc, 'Phenotype not as expected'
            assert val_910 == wc, 'Phenotype not as expected'
            assert val_856 == wc, 'Phenotype not as expected'
        elif (r == 'WholeLung' and t == wc) or \
            (r == 'RightLung' and t == wc) or \
            (r == 'LeftLung' and t == wc):
            assert np.isclose(val_950, 0.1111111), 'Phenotype not as expected'
            assert np.isclose(val_910, 0.1111111), 'Phenotype not as expected'
            assert np.isclose(val_856, 0.1111111), 'Phenotype not as expected'
        elif (r == wc and t == 'Airway') or \
            (r == 'UndefinedRegion' and t == 'AIRWAY') or \
            (r == 'WholeLung' and t == 'Airway') or \
            (r == 'RightLung' and t == 'Airway') or \
            (r == 'LeftLung' and t == 'Airway'):
            assert np.isclose(val_950, 1.0), 'Phenotype not as expected'
            assert np.isclose(val_910, 1.0), 'Phenotype not as expected'
            assert np.isclose(val_856, 1.0), 'Phenotype not as expected'
        elif (r == 'WholeLung' and t == 'UndefinedType') or \
            (r == 'RightLung' and t == 'UndefinedType') or \
            (r == 'LeftLung' and t == 'UndefinedType') or \
            (r == 'WholeLung' and t == 'Vessel') or \
            (r == 'RightLung' and t == 'Vessel') or \
            (r == 'LeftLung' and t == 'Vessel') or \
            (r == wc and t == 'Vessel'):
            assert np.isclose(val_950, 0.0), 'Phenotype not as expected'
            assert np.isclose(val_910, 0.0), 'Phenotype not as expected'
            assert np.isclose(val_856, 0.0), 'Phenotype not as expected'

        if (r == 'WholeLung' and t == wc):
            assert np.isclose(df['HAA700'].iloc[i], 0.1111111), \
                'Phenotype not as expected'
        if (r == wc and t == 'Vessel'):
            assert df['HAA700'].iloc[i] == 1., 'Phenotype not as expected'
        if (r == 'UndefinedRegion' and t == 'Airway'):
            assert df['HAA600'].iloc[i] == 0., 'Phenotype not as expected'
        if (r == 'WholeLung' and t == 'Vessel'):
            assert df['HAA500'].iloc[i] == 1., 'Phenotype not as expected'
        if (r == 'WildCard' and t == 'Vessel'):
            assert df['HAA250'].iloc[i] == 1., 'Phenotype not as expected'
        if (r == 'WholeLung' and t == 'Airway'):
            assert df['Perc10'].iloc[i] == -977, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == 'Vessel'):
            assert df['Perc15'].iloc[i] == -47, 'Phenotype not as expected'
        if (r == 'LeftLung' and t == wc):
            assert np.isclose(df['HUMean'].iloc[i], -773.333333), \
                'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert np.isclose(df['HUStd'].iloc[i], 256.9695), \
                'Phenotype not as expected'
        if (r == 'WholeLung' and t == 'UndefinedType'):
            assert np.isclose(df['HUKurtosis'].iloc[i], -2.363636), \
                'Phenotype not as expected'
        if (r == 'WholeLung' and t == 'Vessel'):
            assert df['HUSkewness'].iloc[i] == 0.0, 'Phenotype not as expected'
        if (r == 'RightLung' and t == wc):
            assert df['HUMode'].iloc[i] == -800, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['HUMedian'].iloc[i] == -825, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == 'Airway'):
            assert df['HUMin'].iloc[i] == -980, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == 'Airway'):
            assert df['HUMax'].iloc[i] == -950, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['HUMean500'].iloc[
                i] == -842.5, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert np.isclose(df['HUStd500'].iloc[i], 52.1416340), \
                'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert np.isclose(df['HUKurtosis500'].iloc[i], 2.37885301), \
                'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert np.isclose(df['HUSkewness500'].iloc[i], -1.613628), \
                'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['HUMode500'].iloc[i] == -850, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['HUMedian500'].iloc[
                i] == -850, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['HUMin500'].iloc[i] == -980, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['HUMax500'].iloc[i] == -800, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['Volume'].iloc[i] == 18, 'Phenotype not as expected'
        if (r == 'RightLung' and t == wc):
            assert np.isclose(df['Mass'].iloc[i], 0.00247609596), \
                'Phenotype not as expected'
Пример #12
0
    def execute(self,
                ct,
                lm,
                cid,
                spacing,
                chest_regions=None,
                chest_types=None,
                pairs=None,
                pheno_names=None):
        """Compute the phenotypes for the specified structures for the
        specified threshold values.

        The following values are computed for the specified structures.
        'AxialCSA': Axial cross-sectional area
        'CoronalCSA': Coronoal cross-sectional area
        'SagittalCSA': Sagitall cross-sectional area        
        'HUMean': Mean value of the structure's HU values
        'HUStd': Standard deviation of the structure's HU values
        'HUKurtosis': Kurtosis of the structure's HU values. Fisher's definition
        is used, meaning that normal distribution has kurtosis of 0. The
        calculation is corrected for statistical bias.
        'HUSkewness': Skewness of the structure's HU values. The calculation is
        corrected for statistical bias.
        'HUMode': Mode of the structure's HU values
        'HUMedian': Median of the structure's HU values
        'HUMin': Min HU value for the structure
        'HUMax': Max HU value for the structure

        The following set of phenotypes are identical to the above except that
        computation is isolated to the HU interval [-50, 90]. These phenotypes
        are capture lean muscle information and only have meaning for muscle
        structures.
        'leanAxialCSA': Axial cross-sectional area 
        'leanCoronalCSA': Coronoal cross-sectional area
        'leanSagittalCSA': Sagitall cross-sectional area
        'leanHUMean': Mean value of the structure's HU values
        'leanHUStd': Standard deviation of the structure's HU values
        'leanHUKurtosis': Kurtosis of the structure's HU values. Fisher's
        definition is used, meaning that normal distribution has kurtosis of 0.
        The calculation is corrected for statistical bias.
        'leanHUSkewness': Skewness of the structure's HU values. The calculation
        is corrected for statistical bias.
        'leanHUMode': Mode of the structure's HU values
        'leanHUMedian': Median of the structure's HU values
        'leanHUMin': Min HU value for the structure
        'leanHUMax': Max HU value for the structure

        Parameters
        ----------
        ct : array, shape ( X, Y, Z )
            The 3D CT image array

        lm : array, shape ( X, Y, Z )
            The 3D label map array

        cid : string
            Case ID

        spacing : array, shape ( 3 )
            The x, y, and z spacing, respectively, of the CT volume
            
        chest_regions : array, shape ( R ), optional
            Array of integers, with each element in the interval [0, 255],
            indicating the chest regions over which to compute the LAA. If none
            specified, the chest regions specified in the class constructor
            will be used. If chest regions, chest types, and chest pairs are
            left unspecified both here and in the constructor, then the
            complete set of entities found in the label map will be used.

        chest_types : array, shape ( T ), optional
            Array of integers, with each element in the interval [0, 255],
            indicating the chest types over which to compute the LAA. If none
            specified, the chest types specified in the class constructor
            will be used. If chest regions, chest types, and chest pairs are
            left unspecified both here and in the constructor, then the
            complete set of entities found in the label map will be used.

        pairs : array, shape ( P, 2 ), optional
            Array of chest-region chest-type pairs over which to compute the
            LAA. The first column indicates the chest region, and the second
            column indicates the chest type. Each element should be in the
            interal [0, 255]. If none specified, the pairs specified in the
            class constructor will be used. If chest regions, chest types, and
            chest pairs are left unspecified both here and in the constructor,
            then the complete set of entities found in the label map will be
            used.

        pheno_names : list of strings, optional
            Names of phenotypes to compute. These names must conform to the
            accepted phenotype names, listed above. If none are given, all
            will be computed. Specified names given here will take precedence
            over any specified in the constructor.

        Returns
        -------
        df : pandas dataframe
            Dataframe containing info about machine, run time, and chest region
            chest type phenotype quantities.         
        """
        assert len(ct.shape) == len(lm.shape), \
            "CT and label map are not the same dimension"

        dim = len(ct.shape)
        for i in xrange(0, dim):
            assert ct.shape[0] == lm.shape[0], \
                "Disagreement in CT and label map dimension"

        assert type(cid) == str, "cid must be a string"
        self.cid_ = cid
        self._spacing = spacing

        phenos_to_compute = self.pheno_names_
        if pheno_names is not None:
            phenos_to_compute = pheno_names
        elif self.requested_pheno_names is not None:
            phenos_to_compute = self.requested_pheno_names

        rs = None
        ts = None
        ps = None
        if chest_regions is not None:
            rs = chest_regions
        elif self.chest_regions_ is not None:
            rs = self.chest_regions_
        if chest_types is not None:
            ts = chest_types
        elif self.chest_types_ is not None:
            ts = self.chest_types_
        if pairs is not None:
            ps = pairs
        elif self.pairs_ is not None:
            ps = self.pairs_

        parser = RegionTypeParser(lm)
        if rs == None and ts == None and ps == None:
            rs = parser.get_all_chest_regions()
            ts = parser.get_chest_types()
            ps = parser.get_all_pairs()

        lean_ct_mask = np.logical_and(ct >= -50, ct <= 90)

        # Now compute the phenotypes and populate the data frame
        c = ChestConventions()
        if rs is not None:
            for r in rs:
                if r != 0:
                    mask = parser.get_mask(chest_region=r)
                    lean_mask = np.logical_and(mask, lean_ct_mask)
                    for n in phenos_to_compute:
                        if 'lean' in n:
                            self.add_pheno_group(ct, lean_mask,
                                                 c.GetChestRegionName(r),
                                                 c.GetChestWildCardName(), n)
                        else:
                            self.add_pheno_group(ct, mask,
                                                 c.GetChestRegionName(r),
                                                 c.GetChestWildCardName(), n)
        if ts is not None:
            for t in ts:
                if t != 0:
                    mask = parser.get_mask(chest_type=t)
                    lean_mask = np.logical_and(mask, lean_ct_mask)
                    for n in phenos_to_compute:
                        if 'lean' in n:
                            self.add_pheno_group(ct, lean_mask,
                                                 c.GetChestWildCardName(),
                                                 c.GetChestTypeName(r), n)
                        else:
                            self.add_pheno_group(ct, mask,
                                                 c.GetChestWildCardName(),
                                                 c.GetChestTypeName(r), n)
        if ps is not None:
            for p in ps:
                if not (p[0] == 0 and p[1] == 0):
                    mask = parser.get_mask(chest_region=p[0], chest_type=p[1])
                    lean_mask = np.logical_and(mask, lean_ct_mask)
                    for n in phenos_to_compute:
                        if 'lean' in n:
                            self.add_pheno_group(ct, lean_mask,
                                                 c.GetChestRegionName(p[0]),
                                                 c.GetChestTypeName(p[1]), n)
                        else:
                            self.add_pheno_group(ct, mask,
                                                 c.GetChestRegionName(p[0]),
                                                 c.GetChestTypeName(p[1]), n)

        return self._df
Пример #13
0
    def execute(self,
                ct,
                lm,
                cid,
                chest_regions=None,
                chest_types=None,
                pairs=None):
        """Compute the phenotypes for the specified structures for the
        specified threshold values.

        Parameters
        ----------
        ct : array, shape ( X, Y, Z )
            The 3D CT image array

        lm : array, shape ( X, Y, Z )
            The 3D label map array

        cid : string
            Case ID
            
        chest_regions : array, shape ( R ), optional
            Array of integers, with each element in the interval [0, 255],
            indicating the chest regions over which to compute the LAA. If none
            specified, the chest regions specified in the class constructor
            will be used. If chest regions, chest types, and chest pairs are
            left unspecified both here and in the constructor, then the
            complete set of entities found in the label map will be used.

        chest_types : array, shape ( T ), optional
            Array of integers, with each element in the interval [0, 255],
            indicating the chest types over which to compute the LAA. If none
            specified, the chest types specified in the class constructor
            will be used. If chest regions, chest types, and chest pairs are
            left unspecified both here and in the constructor, then the
            complete set of entities found in the label map will be used.

        pairs : array, shape ( P, 2 ), optional
            Array of chest-region chest-type pairs over which to compute the
            LAA. The first column indicates the chest region, and the second
            column indicates the chest type. Each element should be in the
            interal [0, 255]. If none specified, the pairs specified in the
            class constructor will be used. If chest regions, chest types, and
            chest pairs are left unspecified both here and in the constructor,
            then the complete set of entities found in the label map will be
            used.

        Returns
        -------
        df : pandas dataframe
            Dataframe containing info about machine, run time, and chest region
            chest type phenotype quantities.        
        """
        assert len(ct.shape) == len(lm.shape), \
            "CT and label map are not the same dimension"

        dim = len(ct.shape)
        for i in xrange(0, dim):
            assert ct.shape[0] == lm.shape[0], \
                "Disagreement in CT and label map dimension"

        assert type(cid) == str, "cid must be a string"
        self.cid_ = cid

        rs = None
        ts = None
        ps = None
        if chest_regions is not None:
            rs = chest_regions
        elif self.chest_regions_ is not None:
            rs = self.chest_regions_
        if chest_types is not None:
            ts = chest_types
        elif self.chest_types_ is not None:
            ts = self.chest_types_
        if pairs is not None:
            ps = pairs
        elif self.pairs_ is not None:
            ps = self.pairs_

        parser = RegionTypeParser(lm)
        if rs == None and ts == None and ps == None:
            rs = parser.get_all_chest_regions()
            ts = parser.get_chest_types()
            ps = parser.get_all_pairs()

        # Now compute the phenotypes and populate the data frame
        c = ChestConventions()
        if rs is not None:
            for r in rs:
                if r != 0:
                    mask = parser.get_mask(chest_region=r)
                    for tt in self.threshs_:
                        pheno_name = 'LAA' + str(int(np.abs(np.round(tt))))
                        pheno_val = float(
                            np.sum(ct[mask] <= tt)) / np.sum(mask)
                        self.add_pheno([
                            c.GetChestRegionName(r),
                            c.GetChestWildCardName()
                        ], pheno_name, pheno_val)
        if ts is not None:
            for t in ts:
                if t != 0:
                    mask = parser.get_mask(chest_type=t)
                    for tt in self.threshs_:
                        pheno_name = 'LAA' + str(int(np.abs(np.round(tt))))
                        pheno_val = float(
                            np.sum(ct[mask] <= tt)) / np.sum(mask)
                        self.add_pheno(
                            [c.GetChestWildCardName(),
                             c.GetChestTypeName(t)], pheno_name, pheno_val)
        if ps is not None:
            for p in ps:
                if not (p[0] == 0 and p[1] == 0):
                    mask = parser.get_mask(chest_region=p[0], chest_type=p[1])
                    for tt in self.threshs_:
                        pheno_name = 'LAA' + str(int(np.abs(np.round(tt))))
                        pheno_val = float(
                            np.sum(ct[mask] <= tt)) / np.sum(mask)
                        self.add_pheno([
                            c.GetChestRegionName(p[0]),
                            c.GetChestTypeName(p[1])
                        ], pheno_name, pheno_val)

        return self._df
Пример #14
0
    def execute(self,
                ct,
                lm,
                cid,
                spacing,
                chest_regions=None,
                chest_types=None,
                pairs=None,
                pheno_names=None):
        """Compute the phenotypes for the specified structures for the
        specified threshold values.

        The following values are computed for the specified structures.
        'LAA950': fraction of the structure's region with CT HU values <= -950
        'LAA910': fraction of the structure's region with CT HU values <= -910
        'LAA856': fraction of the structure's region with CT HU values <= -856
        'HAA700': fraction of the structure's region with CT HU values >= -700
        'HAA600': fraction of the structure's region with CT HU values >= -600
        'HAA500': fraction of the structure's region with CT HU values >= -500
        'HAA250': fraction of the structure's region with CT HU values >= -250
        'Perc10': HU value at the 10th percentile of the structure's HU
        histogram
        'Perc15': HU value at the 15th percentile of the structure's HU
        histogram
        'HUMean': Mean value of the structure's HU values
        'HUStd': Standard deviation of the structure's HU values
        'HUKurtosis': Kurtosis of the structure's HU values. Fisher's definition
        is used, meaning that normal distribution has kurtosis of 0. The
        calculation is corrected for statistical bias.
        'HUSkewness': Skewness of the structure's HU values. The calculation is
        corrected for statistical bias.
        'HUMode': Mode of the structure's HU values
        'HUMedian': Median of the structure's HU values
        'HUMin': Min HU value for the structure
        'HUMax': Max HU value for the structure
        'HUMean500': Mean CT value of the structure, but only considering CT
        values that are <= -500 HU
        'HUStd500': Standard deviation of the structure's CT values, but only
        considering CT values that are <= -500 HU
        'HUKurtosis500': Kurtosis of the structure's HU values, but only
        considering CT values that are <= -500 HU
        'HUSkewness500': Skewness of the structure's HU values, but only
        considering CT values that are <= -500 HU
        'HUMode500': Mode of the structure's HU values, but only
        considering CT values that are <= -500 HU
        'HUMedian500': Median of the structure's HU values, but only
        considering CT values that are <= -500 HU
        'HUMin500': Min HU value for the structure, but only considering CT
        values that are <= -500 HU
        'HUMax500': Max HU value for the structure, but only considering CT
        values that are <= -500 HU
        'Volume': Volume of the structure, measured in liters
        'Mass': Mass of the structure measure in grams    

        Parameters
        ----------
        ct : array, shape ( X, Y, Z )
            The 3D CT image array

        lm : array, shape ( X, Y, Z )
            The 3D label map array

        cid : string
            Case ID

        spacing : array, shape ( 3 )
            The x, y, and z spacing, respectively, of the CT volume
            
        chest_regions : array, shape ( R ), optional
            Array of integers, with each element in the interval [0, 255],
            indicating the chest regions over which to compute the LAA. If none
            specified, the chest regions specified in the class constructor
            will be used. If chest regions, chest types, and chest pairs are
            left unspecified both here and in the constructor, then the
            complete set of entities found in the label map will be used.

        chest_types : array, shape ( T ), optional
            Array of integers, with each element in the interval [0, 255],
            indicating the chest types over which to compute the LAA. If none
            specified, the chest types specified in the class constructor
            will be used. If chest regions, chest types, and chest pairs are
            left unspecified both here and in the constructor, then the
            complete set of entities found in the label map will be used.

        pairs : array, shape ( P, 2 ), optional
            Array of chest-region chest-type pairs over which to compute the
            LAA. The first column indicates the chest region, and the second
            column indicates the chest type. Each element should be in the
            interal [0, 255]. If none specified, the pairs specified in the
            class constructor will be used. If chest regions, chest types, and
            chest pairs are left unspecified both here and in the constructor,
            then the complete set of entities found in the label map will be
            used.

        pheno_names : list of strings, optional
            Names of phenotypes to compute. These names must conform to the
            accepted phenotype names, listed above. If none are given, all
            will be computed. Specified names given here will take precedence
            over any specified in the constructor.

        Returns
        -------
        df : pandas dataframe
            Dataframe containing info about machine, run time, and chest region
            chest type phenotype quantities.         
        """
        assert len(ct.shape) == len(lm.shape), \
            "CT and label map are not the same dimension"

        dim = len(ct.shape)
        for i in xrange(0, dim):
            assert ct.shape[0] == lm.shape[0], \
                "Disagreement in CT and label map dimension"

        assert type(cid) == str, "cid must be a string"
        self.cid_ = cid
        self._spacing = spacing

        phenos_to_compute = self.pheno_names_
        if pheno_names is not None:
            phenos_to_compute = pheno_names
        elif self.requested_pheno_names is not None:
            phenos_to_compute = self.requested_pheno_names

        rs = None
        ts = None
        ps = None
        if chest_regions is not None:
            rs = chest_regions
        elif self.chest_regions_ is not None:
            rs = self.chest_regions_
        if chest_types is not None:
            ts = chest_types
        elif self.chest_types_ is not None:
            ts = self.chest_types_
        if pairs is not None:
            ps = pairs
        elif self.pairs_ is not None:
            ps = self.pairs_

        parser = RegionTypeParser(lm)
        if rs == None and ts == None and ps == None:
            rs = parser.get_all_chest_regions()
            ts = parser.get_chest_types()
            ps = parser.get_all_pairs()

        # Now compute the phenotypes and populate the data frame
        c = ChestConventions()
        if rs is not None:
            for r in rs:
                if r != 0:
                    mask = parser.get_mask(chest_region=r)
                    for n in phenos_to_compute:
                        self.add_pheno_group(ct, mask, c.GetChestRegionName(r),
                                             c.GetChestWildCardName(), n)
        if ts is not None:
            for t in ts:
                if t != 0:
                    mask = parser.get_mask(chest_type=t)
                    for n in phenos_to_compute:
                        self.add_pheno_group(ct, mask,
                                             c.GetChestWildCardName(),
                                             c.GetChestTypeName(t), n)
        if ps is not None:
            for i in xrange(0, ps.shape[0]):
                if not (ps[i, 0] == 0 and ps[i, 1] == 0):
                    mask = parser.get_mask(chest_region=int(ps[i, 0]),
                                           chest_type=int(ps[i, 1]))
                    for n in phenos_to_compute:
                        self.add_pheno_group(
                            ct, mask, c.GetChestRegionName(int(ps[i, 0])),
                            c.GetChestTypeName(int(ps[i, 1])), n)

        return self._df
Пример #15
0
    def get_mask(self, chest_region=None, chest_type=None):
        """Get's boolean mask of all data indices that match the chest-region
        chest-type query.

        If only a chest region is specified, then all voxels in that region
        will be included in the mask, regardless of the voxel's chest type
        value (chest region hierarchy is honored). If only a type is specified,
        then all voxels having that type will be included in the mask,
        regardless of the voxel's chest region. If both a region and type are
        speficied, then only those voxels matching both the region and type
        will be included in the mask (the chest region hierarchy is honored).

        Parameters
        ----------
        chest_region : int
            Integer value in the interval [0, 255] that indicates the chest
            region

        chest_type : int
            Integer value in the interval [0, 255] that indicates the chest
            type

        Returns
        -------
        mask : array, shape ( X, Y, Z )
            Boolean mask of all data indices that match the chest-region
            chest-type query. The chest region hierarchy is honored.
        """
        if chest_region is not None:
            if type(chest_region) != int and type(chest_region) != np.int64:
                raise ValueError(
                    'chest_region must be an int between 0 and 255 inclusive')
        if chest_type is not None:
            if type(chest_type) != int and type(chest_type) != np.int64:
                raise ValueError(
                    'chest_type must be an int between 0 and 255 inclusive')

        conventions = ChestConventions()

        mask_labels = []
        for l in self.labels_:
            r = conventions.GetChestRegionFromValue(l)
            t = conventions.GetChestTypeFromValue(l)

            if chest_region is not None and chest_type is not None:
                if t==chest_type and \
                  conventions.CheckSubordinateSuperiorChestRegionRelationship(\
                  r, chest_region):
                    mask_labels.append(l)
            elif t == chest_type:
                mask_labels.append(l)
            elif chest_region is not None:
                if conventions.\
                    CheckSubordinateSuperiorChestRegionRelationship(r, \
                    chest_region):
                    mask_labels.append(l)

        mask = np.empty(self._data.shape, dtype=bool)
        mask[:] = False

        for ml in mask_labels:
            mask = np.logical_or(mask, self._data == ml)

        return mask
def test_execute():
    c = ChestConventions()
    wc = c.GetChestWildCardName()
    spacing = np.array([0.5, 0.4, 0.3])
    
    bc_pheno = BodyCompositionPhenotypes()    
    df = bc_pheno.execute(ct, lm, 'simple', spacing)

    for i in xrange(0, 14):
        r = df['Region'].iloc[i]
        t = df['Type'].iloc[i]

        if (r == 'LeftLung' and t == wc):
            assert np.isclose(df['HUMean'].iloc[i], -773.333333), \
                'Phenotype not as expected'
            assert np.isclose(df['AxialCSA'].iloc[i], \
                              9*spacing[0]*spacing[1]), \
                'Phenotype not as expected'
            assert np.isclose(df['CoronalCSA'].iloc[i], \
                              9*spacing[0]*spacing[2]), \
                'Phenotype not as expected'
            assert np.isclose(df['SagittalCSA'].iloc[i], \
                              9*spacing[1]*spacing[2]), \
                'Phenotype not as expected'            
        if (r == 'WholeLung' and t == wc):
            assert df['HUMedian'].iloc[i] == -825, 'Phenotype not as expected'            
            assert np.isclose(df['HUStd'].iloc[i], 256.9695), \
                'Phenotype not as expected'
            assert np.isclose(df['AxialCSA'].iloc[i], \
                              18*spacing[0]*spacing[1]), \
                'Phenotype not as expected'
            assert np.isclose(df['CoronalCSA'].iloc[i], \
                              18*spacing[0]*spacing[2]), \
                'Phenotype not as expected'
            assert np.isclose(df['SagittalCSA'].iloc[i], \
                              18*spacing[1]*spacing[2]), \
                'Phenotype not as expected'                        
        if (r == 'WholeLung' and t == 'UndefinedType'):
            assert np.isclose(df['HUKurtosis'].iloc[i], -2.363636), \
                'Phenotype not as expected'
            assert np.isclose(df['AxialCSA'].iloc[i], \
                              14*spacing[0]*spacing[1]), \
                'Phenotype not as expected'
            assert np.isclose(df['CoronalCSA'].iloc[i], \
                              14*spacing[0]*spacing[2]), \
                'Phenotype not as expected'
            assert np.isclose(df['SagittalCSA'].iloc[i], \
                              14*spacing[1]*spacing[2]), \
                'Phenotype not as expected'                        
        if (r == 'WholeLung' and t == 'Vessel'):
            assert df['HUSkewness'].iloc[i] == 0.0, 'Phenotype not as expected'
            assert np.isclose(df['AxialCSA'].iloc[i], \
                              2*spacing[0]*spacing[1]), \
                'Phenotype not as expected'
            assert np.isclose(df['CoronalCSA'].iloc[i], \
                              2*spacing[0]*spacing[2]), \
                'Phenotype not as expected'
            assert np.isclose(df['SagittalCSA'].iloc[i], \
                              2*spacing[1]*spacing[2]), \
                'Phenotype not as expected'                        
        if (r == 'RightLung' and t == wc):
            assert df['HUMode'].iloc[i] == -800, 'Phenotype not as expected'
            assert np.isclose(df['AxialCSA'].iloc[i], \
                              9*spacing[0]*spacing[1]), \
                'Phenotype not as expected'
            assert np.isclose(df['CoronalCSA'].iloc[i], \
                              9*spacing[0]*spacing[2]), \
                'Phenotype not as expected'
            assert np.isclose(df['SagittalCSA'].iloc[i], \
                              9*spacing[1]*spacing[2]), \
                'Phenotype not as expected'                        
        if (r == 'WholeLung' and t == 'Airway'):
            assert df['HUMin'].iloc[i] == -980, 'Phenotype not as expected'
            assert df['HUMax'].iloc[i] == -950, 'Phenotype not as expected'
        if (r == 'WholeLung' and t == wc):
            assert df['leanHUMin'].iloc[i] == -50, 'Phenotype not as expected'
            assert df['leanHUMax'].iloc[i] == -30, 'Phenotype not as expected'
            assert np.isclose(df['leanAxialCSA'].iloc[i],
                2*spacing[0]*spacing[1]), 'Phenotype not as expected'
            assert np.isclose(df['leanCoronalCSA'].iloc[i],
                2*spacing[0]*spacing[2]), 'Phenotype not as expected'
            assert np.isclose(df['leanSagittalCSA'].iloc[i],
                2*spacing[2]*spacing[1]), 'Phenotype not as expected'
            assert df['leanHUMedian'].iloc[i] == -40, \
                'Phenotype not as expected'
            assert df['leanHUStd'].iloc[i] == 10, \
                'Phenotype not as expected'
            assert df['leanHUMode'].iloc[i] == -50, \
                'Phenotype not as expected'                        
            assert df['leanHUKurtosis'].iloc[i] == -2.0, \
                'Phenotype not as expected'
            assert df['leanHUSkewness'].iloc[i] == 0.0, \
                'Phenotype not as expected'                            
Пример #17
0
def remap_lm(lm, region_maps=None, type_maps=None, pair_maps=None):
    """Overwrites values in an input label map using the specified mappings.

    Parameters
    ----------
    lm : array
        The input data. Each value is assumed to be an unsigned short (16 bit)
        data type, where the least significant 8 bits encode the chest region,
        and the most significant 8 bits encode the chest type.

    region_maps : list of lists, optional
        Each element of the list is a 2-element list or a list with two
        elements, where the individual elements are strings indicating chest
        regions. The 2D lists / tuples indicate the mappings to be performed.
        E.g. [('LeftLung', 'WholeLung')] indicates that all occurrences of
        'LeftLung' should be replaced with 'WholeLung'. All type information
        is preserved. 

    type_maps : list of lists, optional
        Each element of the list is a 2-element list or a list with two
        elements, where the individual elements are strings indicating chest
        types. The 2D lists / tuples indicate the mappings to be performed. E.g.
        [('Airway', 'UndefinedType')] indicates that all occurrences of
        'Airway' should be replaced with 'UndefinedType'. All region information
        is preserved. 

    pairs_maps : list of lists of lists, optional
        Each element of the list is a 2-element list: the firs element is itself
        a 2-element list indicating a region-type pair; the second element is a
        2-element region-type pair to be mapped to. String names are used to
        designate the regions and types. E.g. [['LeftLung', 'Vessel'],
        ['WholeLung', 'UndefinedType']] will map all occurrences of the
        'LeftLung'-'Vessel' pair to 'WholeLung'-'UndefinedType'.

    Returns
    -------
    remapped_lm : array
        A label map with the same dimensions as the input with labelings
        redefined according to the specified rules.
    """
    remapped_lm = np.copy(lm)
    parser = RegionTypeParser(lm)

    lm_types = lm >> 8
    lm_regions = lm - (lm >> 8 << 8)

    c = ChestConventions()
    if region_maps is not None:
        for m in xrange(0, len(region_maps)):
            assert len(region_maps[m]) == 2, "Mapping not understood"
            mask = \
                parser.get_mask(chest_region=\
                       c.GetChestRegionValueFromName(region_maps[m][0]))
            lm_regions[mask] = \
                c.GetChestRegionValueFromName(region_maps[m][1])

    if type_maps is not None:
        for m in xrange(0, len(type_maps)):
            assert len(type_maps[m]) == 2, "Mapping not understood"
            mask = \
                parser.get_mask(chest_type=\
                       c.GetChestTypeValueFromName(type_maps[m][0]))
            lm_types[mask] = \
                c.GetChestTypeValueFromName(type_maps[m][1])

    if pair_maps is not None:
        for m in xrange(0, len(pair_maps)):
            assert len(pair_maps[m]) == 2, "Mapping not understood"
            assert len(pair_maps[m][0]) == 2, "Mapping not understood"
            assert len(pair_maps[m][1]) == 2, "Mapping not understood"
            mask = \
                parser.get_mask(chest_region=\
                       c.GetChestRegionValueFromName(pair_maps[m][0][0]),
                    chest_type=\
                       c.GetChestTypeValueFromName(pair_maps[m][0][1]))
            lm_regions[mask] = \
                c.GetChestRegionValueFromName(pair_maps[m][1][0])
            lm_types[mask] = \
                c.GetChestTypeValueFromName(pair_maps[m][1][1])

    remapped_lm = (lm_types << 8) | lm_regions

    return remapped_lm