def _calculateCMatrix(self):
        angles = imageoperations.generateAngles(self.boundingBoxSize,
                                                **self.kwargs)
        Ng = self.coefficients['Ng']

        P_gldm = cMatrices.calculate_gldm(self.matrix, self.maskArray, angles,
                                          Ng, self.gldm_a)

        jvector = numpy.arange(1, P_gldm.shape[1] + 1, dtype='float64')

        # Delete rows and columns that specify gray levels not present in the ROI
        sumP_gldm = numpy.sum(P_gldm)
        pd = numpy.sum(P_gldm, 0)
        pg = numpy.sum(P_gldm, 1)

        P_gldm = numpy.delete(P_gldm, numpy.where(pg == 0), 0)
        P_gldm = numpy.delete(P_gldm, numpy.where(pd == 0), 1)

        jvector = numpy.delete(jvector, numpy.where(pd == 0))

        pg = numpy.delete(pg, numpy.where(pg == 0))
        pd = numpy.delete(pd, numpy.where(pd == 0))

        self.coefficients['sumP_gldm'] = sumP_gldm
        self.coefficients['pd'] = pd
        self.coefficients['pg'] = pg

        self.coefficients['ivector'] = self.coefficients['grayLevels']
        self.coefficients['jvector'] = jvector

        return P_gldm
Exemple #2
0
    def _calculateCMatrix(self):
        self.logger.debug('Calculating GLSZM matrix in C')

        # Do not pass kwargs directly, as distances may be specified, which must be forced to [1] for this class
        angles = imageoperations.generateAngles(
            self.boundingBoxSize,
            force2D=self.kwargs.get('force2D', False),
            force2Ddimension=self.kwargs.get('force2Ddimension', 0))
        Ng = self.coefficients['Ng']
        Ns = self.coefficients['Np']

        P_glszm = cMatrices.calculate_glszm(self.matrix, self.maskArray,
                                            angles, Ng, Ns)

        # Delete rows that specify gray levels not present in the ROI
        NgVector = range(1, Ng + 1)  # All possible gray values
        GrayLevels = self.coefficients[
            'grayLevels']  # Gray values present in ROI
        emptyGrayLevels = numpy.array(
            list(set(NgVector) -
                 set(GrayLevels)))  # Gray values NOT present in ROI

        P_glszm = numpy.delete(P_glszm, emptyGrayLevels - 1, 0)

        return P_glszm
Exemple #3
0
    def _calculateCMatrix(self):
        self.logger.debug('Calculating GLCM matrix in C')

        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size, **self.kwargs)
        Ng = self.coefficients['Ng']

        P_glcm = cMatrices.calculate_glcm(self.matrix, self.maskArray, angles,
                                          Ng)
        P_glcm = self._applyMatrixOptions(P_glcm, angles)

        # Delete rows and columns that specify gray levels not present in the ROI
        Ng = self.coefficients['Ng']
        NgVector = range(1, Ng + 1)  # All possible gray values
        GrayLevels = self.coefficients[
            'grayLevels']  # Gray values present in ROI
        emptyGrayLevels = numpy.array(
            list(set(NgVector) -
                 set(GrayLevels)))  # Gray values NOT present in ROI

        P_glcm = numpy.delete(P_glcm, emptyGrayLevels - 1, 0)
        P_glcm = numpy.delete(P_glcm, emptyGrayLevels - 1, 1)

        return P_glcm
Exemple #4
0
  def _calculateMatrix(self):

    self.matrix = self.matrix.astype('float')

    # Set voxels outside delineation to padding value
    padVal = numpy.nan
    self.matrix[~self.maskArray] = padVal

    angles = imageoperations.generateAngles(self.boundingBoxSize, **self.kwargs)
    angles = numpy.concatenate((angles, angles * -1))

    depMat = numpy.zeros(self.matrix.shape, dtype='int')

    with self.progressReporter(angles, desc='Calculate shifted matrices (GLDM)') as bar:
      for a in bar:
        # create shifted array (by angle), so that for an index idx, angMat[idx] is the neigbour of self.matrix[idx]
        # for the current angle.
        angMat = numpy.roll(numpy.roll(numpy.roll(self.matrix, -a[0], 0), -a[1], 1), -a[2], 2) - self.matrix
        if a[0] > 0:
          angMat[-a[0]:, :, :] = padVal
        elif a[0] < 0:
          angMat[:-a[0], :, :] = padVal

        if a[1] > 0:
          angMat[:, -a[1]:, :] = padVal
        elif a[1] < 0:
          angMat[:, :-a[1], :] = padVal

        if a[2] > 0:
          angMat[:, :, -a[2]:] = padVal
        elif a[2] < 0:
          angMat[:, :, :-a[2]] = padVal

        nanMask = numpy.isnan(angMat)
        depMat[~nanMask] += (numpy.abs(angMat[~nanMask]) <= self.gldm_a)

    grayLevels = self.coefficients['grayLevels']
    dependenceSizes = numpy.unique(depMat[self.maskArray])
    P_gldm = numpy.zeros((len(grayLevels), len(dependenceSizes)))

    with self.progressReporter(grayLevels, desc='calculate GLDM') as bar:
      for i_idx, i in enumerate(bar):
        i_mat = (self.matrix == i)
        for d_idx, d in enumerate(dependenceSizes):
          # By multiplying i_mat and depMat == d, a boolean area is obtained,
          # where the number of elements that are true (1) is equal to the number of voxels
          # with gray level i and dependence d.
          P_gldm[i_idx, d_idx] = numpy.sum(i_mat * (depMat == d))

    pd = numpy.sum(P_gldm, 0)
    pg = numpy.sum(P_gldm, 1)

    self.coefficients['ivector'] = grayLevels
    self.coefficients['jvector'] = dependenceSizes
    self.coefficients['pd'] = pd
    self.coefficients['pg'] = pg
    return P_gldm
Exemple #5
0
    def _calculateCMatrix(self):
        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size)
        Ng = self.coefficients['Ng']

        P_glcm = cMatrices.calculate_glcm(self.matrix, self.maskArray, angles,
                                          Ng)
        P_glcm = self._applyMatrixOptions(P_glcm, angles)

        return P_glcm
Exemple #6
0
  def _calculateCMatrix(self):
    self.logger.debug('Calculating GLCM matrix in C')

    size = numpy.max(self.matrixCoordinates, 1) - numpy.min(self.matrixCoordinates, 1) + 1
    angles = imageoperations.generateAngles(size, **self.kwargs)
    Ng = self.coefficients['Ng']

    P_glcm = cMatrices.calculate_glcm(self.matrix, self.maskArray, angles, Ng)
    P_glcm = self._applyMatrixOptions(P_glcm, angles)

    return P_glcm
Exemple #7
0
    def _calculateCMatrix(self):
        self.logger.debug('Calculating GLSZM matrix in C')

        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size, **self.kwargs)
        Ng = self.coefficients['Ng']
        Ns = self.coefficients['Np']

        return cMatrices.calculate_glszm(self.matrix, self.maskArray, angles,
                                         Ng, Ns)
Exemple #8
0
  def _calculateCMatrix(self):
    angles = imageoperations.generateAngles(self.boundingBoxSize, **self.kwargs)
    Ng = self.coefficients['Ng']

    P_ngtdm = cMatrices.calculate_ngtdm(self.matrix, self.maskArray, angles, Ng)

    # Delete empty grey levels
    P_ngtdm = numpy.delete(P_ngtdm, numpy.where(P_ngtdm[:, 0] == 0), 0)

    # Normalize P_ngtdm[:, 0] (= p_i)
    P_ngtdm[:, 0] = P_ngtdm[:, 0] / self.coefficients['Np']

    return P_ngtdm
Exemple #9
0
    def _calculateMatrix(self):
        r"""
    Compute GLCMs for the input image for every direction in 3D.
    Calculated GLCMs are placed in array P_glcm with shape (i/j, a)
    i/j = total gray-level bins for image array,
    a = directions in 3D (generated by imageoperations.generateAngles)
    """
        self.logger.debug('Calculating GLCM matrix in Python')

        Ng = self.coefficients['Ng']

        # Exclude voxels outside segmentation, due to binning, no negative values will be encountered inside the mask
        self.matrix[self.maskArray == 0] = -1

        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size, **self.kwargs)

        P_glcm = numpy.zeros((Ng, Ng, int(angles.shape[0])), dtype='float64')

        if self.verbose: bar = trange(Ng, desc='calculate GLCM')

        # iterate over gray levels for center voxel
        for i in range(1, Ng + 1):
            # give some progress
            if self.verbose: bar.update()

            # get the indices to all voxels which have the current gray level i
            i_indices = numpy.where(self.matrix == i)

            # iterate over gray levels for neighbouring voxel
            for j in range(1, Ng + 1):
                # get the indices to all voxels which have the current gray level j
                j_indices = set(zip(*numpy.where(self.matrix == j)))

                for a_idx, a in enumerate(angles):
                    # get the corresponding indices of the neighbours for angle a
                    neighbour_indices = set(zip(*(i_indices + a[:, None])))

                    # The following intersection yields the indices to voxels with gray level j
                    # that are also a neighbour of a voxel with gray level i for angle a.
                    # The number of indices is then equal to the total number of pairs with gray level i and j for angle a
                    count = len(neighbour_indices.intersection(j_indices))
                    P_glcm[i - 1, j - 1, a_idx] = count
        if self.verbose: bar.close()

        P_glcm = self._applyMatrixOptions(P_glcm, angles)

        return P_glcm
Exemple #10
0
    def _calculateCMatrix(self):
        self.logger.debug('Calculating GLSZM matrix in C')

        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        # Do not pass kwargs directly, as distances may be specified, which must be forced to [1] for this class
        angles = imageoperations.generateAngles(
            size,
            force2Dextraction=self.kwargs.get('force2D', False),
            force2Ddimension=self.kwargs.get('force2Ddimension', 0))
        Ng = self.coefficients['Ng']
        Ns = self.coefficients['Np']

        return cMatrices.calculate_glszm(self.matrix, self.maskArray, angles,
                                         Ng, Ns)
Exemple #11
0
    def _calculateMatrix(self):
        r"""
    Compute GLCMs for the input image for every direction in 3D.
    Calculated GLCMs are placed in array P_glcm with shape (i/j, a)
    i/j = total gray-level bins for image array,
    a = directions in 3D (generated by imageoperations.generateAngles)
    """
        self.logger.debug('Calculating GLCM matrix in Python')

        # Exclude voxels outside segmentation, due to binning, no negative values will be encountered inside the mask
        self.matrix[self.maskArray == 0] = -1

        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size, **self.kwargs)

        grayLevels = self.coefficients['grayLevels']

        P_glcm = numpy.zeros(
            (len(grayLevels), len(grayLevels), int(angles.shape[0])),
            dtype='float64')

        # If verbosity > INFO, or no progress reporter is set in radiomics.progressReporter, _dummyProgressReporter is used,
        # which just iterates over the iterator without reporting progress
        with self.progressReporter(grayLevels, desc='calculate GLCM') as bar:
            # iterate over gray levels for center voxel
            for i_idx, i in enumerate(bar):
                # get the indices to all voxels which have the current gray level i
                i_indices = numpy.where(self.matrix == i)

                # iterate over gray levels for neighbouring voxel
                for j_idx, j in enumerate(grayLevels):
                    # get the indices to all voxels which have the current gray level j
                    j_indices = set(zip(*numpy.where(self.matrix == j)))

                    for a_idx, a in enumerate(angles):
                        # get the corresponding indices of the neighbours for angle a
                        neighbour_indices = set(zip(*(i_indices + a[:, None])))

                        # The following intersection yields the indices to voxels with gray level j
                        # that are also a neighbour of a voxel with gray level i for angle a.
                        # The number of indices is then equal to the total number of pairs with gray level i and j for angle a
                        count = len(neighbour_indices.intersection(j_indices))
                        P_glcm[i_idx, j_idx, a_idx] = count

        P_glcm = self._applyMatrixOptions(P_glcm, angles)

        return P_glcm
Exemple #12
0
    def _calculateCDiameters(self):
        """
    Calculate maximum diameters in 2D and 3D using C extension. Function returns a tuple with 4 elements:

    0. Maximum 2D diameter Slice (XY Plane, Axial)
    1. Maximum 2D diameter Column (ZX Plane, Coronal)
    2. Maximum 2D diameter Row (ZY Plane, Sagittal)
    3. Maximum 3D diameter
    """
        self.logger.debug('Calculating Maximum 3D diameter in C')
        Ns = self.targetVoxelArray.size
        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size)
        return cShape.calculate_diameter(self.maskArray, self.pixelSpacing,
                                         angles, Ns)
Exemple #13
0
    def _calculateCMatrix(self):
        self.logger.debug('Calculating GLRLM matrix in C')

        Ng = self.coefficients['Ng']
        Nr = self.coefficients['Nr']

        # Do not pass kwargs directly, as distances may be specified, which must be forced to [1] for this class
        angles = imageoperations.generateAngles(
            self.boundingBoxSize,
            force2D=self.kwargs.get('force2D', False),
            force2Ddimension=self.kwargs.get('force2Ddimension', 0))

        P_glrlm = cMatrices.calculate_glrlm(self.matrix, self.maskArray,
                                            angles, Ng, Nr)
        P_glrlm = self._applyMatrixOptions(P_glrlm, angles)

        return P_glrlm
Exemple #14
0
    def _calculateMatrix(self):
        """
    Number of times a region with a
    gray level and voxel count occurs in an image. P_glszm[level, voxel_count] = # occurrences

    For 3D-images this concerns a 26-connected region, for 2D an 8-connected region
    """
        self.logger.debug('Calculating GLSZM matrix in Python')

        Np = self.coefficients['Np']
        # Do not pass kwargs directly, as distances may be specified, which must be forced to [1] for this class
        angles = imageoperations.generateAngles(
            self.boundingBoxSize,
            force2D=self.kwargs.get('force2D', False),
            force2Ddimension=self.kwargs.get('force2Ddimension', 0))

        grayLevels = self.coefficients['grayLevels']

        # Empty GLSZ matrix
        P_glszm = numpy.zeros((len(grayLevels), Np))
        maxRegion = 0

        # If verbosity > INFO, or no progress reporter is set in radiomics.progressReporter, _dummyProgressReporter is used,
        # which just iterates over the iterator without reporting progress
        with self.progressReporter(grayLevels, desc='calculate GLSZM') as bar:
            # Iterate over all gray levels in the image
            for i_idx, i in enumerate(bar):
                ind = zip(*numpy.where(self.matrix == i))
                ind = list(
                    set(ind).intersection(
                        set(zip(*self.labelledVoxelCoordinates))))

                while ind:  # check if ind is not empty: unprocessed regions for current gray level
                    # Pop first coordinate of an unprocessed zone, start new stack
                    ind_region = [ind.pop()]

                    # Define regionSize
                    regionSize = 0

                    # Grow zone for item popped from stack of region indices, loop until stack of region indices is exhausted
                    # Each loop represents one voxel belonging to current zone. Therefore, count number of loops as regionSize
                    while ind_region:
                        regionSize += 1

                        # Use pop to remove next node for set of unprocessed region indices
                        ind_node = ind_region.pop()

                        # get all coordinates in the 26-connected region, 2 voxels per angle
                        region_full = [
                            tuple(sum(a) for a in zip(ind_node, angle_i))
                            for angle_i in angles
                        ]
                        region_full += [
                            tuple(sum(a) for a in zip(ind_node, angle_i))
                            for angle_i in angles * -1
                        ]

                        # get all unprocessed coordinates in the 26-connected region with same gray level
                        region_level = list(
                            set(ind).intersection(set(region_full)))

                        # Remove already processed indices to prevent reprocessing
                        ind = list(set(ind) - set(region_level))

                        # Add all found neighbours to the total stack of unprocessed neighbours
                        ind_region.extend(region_level)

                    # Update the gray level size zone matrix
                    P_glszm[i_idx, regionSize - 1] += 1
                    if maxRegion < regionSize:
                        maxRegion = regionSize

        return P_glszm[:, 0:maxRegion]
Exemple #15
0
  def _calculateMatrix(self):
    Ng = self.coefficients['Ng']

    self.matrix = self.matrix.astype('float')

    # Set voxels outside delineation to padding value
    padVal = numpy.nan
    self.matrix[(self.maskArray == 0)] = padVal

    angles = imageoperations.generateAngles(self.boundingBoxSize, **self.kwargs)
    angles = numpy.concatenate((angles, angles * -1))

    dataTemp = numpy.zeros(self.matrix.shape, dtype='float')
    countMat = numpy.zeros(self.matrix.shape, dtype='int')

    with self.progressReporter(angles, desc='Calculate shifted matrices (NGTDM)') as bar:
      for a in bar:
        # create shifted array (by angle), so that for an index idx, angMat[idx] is the neigbour of self.matrix[idx]
        # for the current angle.
        angMat = numpy.roll(numpy.roll(numpy.roll(self.matrix, -a[0], 0), -a[1], 1), -a[2], 2)
        if a[0] > 0:
          angMat[-a[0]:, :, :] = padVal
        elif a[0] < 0:
          angMat[:-a[0], :, :] = padVal

        if a[1] > 0:
          angMat[:, -a[1]:, :] = padVal
        elif a[1] < 0:
          angMat[:, :-a[1], :] = padVal

        if a[2] > 0:
          angMat[:, :, -a[2]:] = padVal
        elif a[2] < 0:
          angMat[:, :, :-a[2]] = padVal
        nanmask = numpy.isnan(angMat)
        dataTemp[~nanmask] += angMat[~nanmask]
        countMat[~nanmask] += 1

    # Average neighbourhood is the dataTemp (which is the sum of gray levels of neighbours that are non-NaN) divided by
    # the countMat (which is the number of neighbours that are non-NaN)
    nZeroMask = countMat > 0  # Prevent division by 0
    dataTemp[nZeroMask] = dataTemp[nZeroMask] / countMat[nZeroMask]

    # Only consider voxels that are part of the Mask AND have a neighbourhood
    validMask = nZeroMask * self.maskArray.astype('bool')
    dataTemp[validMask] = numpy.abs(dataTemp[validMask] - self.matrix[validMask])  # Calculate the absolute difference

    P_ngtdm = numpy.zeros((Ng, 3), dtype='float')

    # For each gray level present in self.matrix:
    # element 0 = probability of gray level (p_i),
    # element 1 = sum of the absolute differences (s_i),
    # element 2 = gray level (i)
    grayLevels = self.coefficients['grayLevels']
    with self.progressReporter(grayLevels, desc='Calculate NGTDM') as bar:
      for i in bar:
        if not numpy.isnan(i):
          i_ind = numpy.where(self.matrix == i)
          P_ngtdm[int(i - 1), 0] = len(i_ind[0])
          P_ngtdm[int(i - 1), 1] = numpy.sum(dataTemp[i_ind])

    # Fill in gray levels (needed as empty gray level slices will be deleted)
    P_ngtdm[:, 2] = numpy.arange(1, Ng + 1)

    # Delete empty grey levels
    P_ngtdm = numpy.delete(P_ngtdm, numpy.where(P_ngtdm[:, 0] == 0), 0)

    # Normalize P_ngtdm[:, 0] (= p_i)
    P_ngtdm[:, 0] = P_ngtdm[:, 0] / self.coefficients['Np']

    return P_ngtdm
Exemple #16
0
    def _calculateMatrix(self):
        """
    Number of times a region with a
    gray level and voxel count occurs in an image. P_glszm[level, voxel_count] = # occurrences

    For 3D-images this concerns a 26-connected region, for 2D an 8-connected region
    """
        self.logger.debug('Calculating GLSZM matrix in Python')

        Ng = self.coefficients['Ng']
        Np = self.coefficients['Np']
        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size, **self.kwargs)

        # Empty GLSZ matrix
        P_glszm = numpy.zeros((Ng, Np))

        # If verbosity > INFO, or no progress reporter is set in radiomics.progressReporter, _dummyProgressReporter is used,
        # which just iterates over the iterator without reporting progress
        with self.progressReporter(range(1, Ng + 1),
                                   desc='calculate GLSZM') as bar:
            # Iterate over all gray levels in the image
            for i in bar:
                ind = zip(*numpy.where(self.matrix == i))
                ind = list(
                    set(ind).intersection(set(zip(*self.matrixCoordinates))))

                while ind:  # check if ind is not empty: unprocessed regions for current gray level
                    # Pop first coordinate of an unprocessed zone, start new stack
                    ind_region = [ind.pop()]

                    # Define regionSize
                    regionSize = 0

                    # Grow zone for item popped from stack of region indices, loop until stack of region indices is exhausted
                    # Each loop represents one voxel belonging to current zone. Therefore, count number of loops as regionSize
                    while ind_region:
                        regionSize += 1

                        # Use pop to remove next node for set of unprocessed region indices
                        ind_node = ind_region.pop()

                        # get all coordinates in the 26-connected region, 2 voxels per angle
                        region_full = [
                            tuple(sum(a) for a in zip(ind_node, angle_i))
                            for angle_i in angles
                        ]
                        region_full += [
                            tuple(sum(a) for a in zip(ind_node, angle_i))
                            for angle_i in angles * -1
                        ]

                        # get all unprocessed coordinates in the 26-connected region with same gray level
                        region_level = list(
                            set(ind).intersection(set(region_full)))

                        # Remove already processed indices to prevent reprocessing
                        ind = list(set(ind) - set(region_level))

                        # Add all found neighbours to the total stack of unprocessed neighbours
                        ind_region.extend(region_level)

                    # Update the gray level size zone matrix
                    P_glszm[i - 1, regionSize - 1] += 1

        # Crop gray-level axis of GLSZM matrix to between minimum and maximum observed gray-levels
        # Crop size-zone area axis of GLSZM matrix up to maximum observed size-zone area
        self.logger.debug(
            'Cropping calculated matrix to observed gray levels and maximum observed zone size'
        )
        P_glszm_bounds = numpy.argwhere(P_glszm)
        (xstart, ystart), (xstop, ystop) = P_glszm_bounds.min(
            0), P_glszm_bounds.max(0) + 1  # noqa: F841
        return P_glszm[xstart:xstop, :ystop]
Exemple #17
0
    def _calculateGLSZM(self):
        """
    Number of times a region with a
    gray level and voxel count occurs in an image. P_glszm[level, voxel_count] = # occurrences

    For 3D-images this concerns a 26-connected region, for 2D an 8-connected region
    """
        size = numpy.max(self.matrixCoordinates, 1) - numpy.min(
            self.matrixCoordinates, 1) + 1
        angles = imageoperations.generateAngles(size)

        # Empty GLSZ matrix
        P_glszm = numpy.zeros(
            (self.coefficients['Ng'], self.coefficients['Np']))

        # Iterate over all gray levels in the image
        numGrayLevels = self.coefficients['Ng'] + 1

        if self.verbose:
            bar = trange(numGrayLevels - 1, desc='calculate GLSZM')

        for i in range(1, numGrayLevels):
            # give some progress
            if self.verbose: bar.update()

            ind = zip(*numpy.where(self.matrix == i))
            ind = list(
                set(ind).intersection(set(zip(*self.matrixCoordinates))))

            while ind:  # check if ind is not empty: unprocessed regions for current gray level
                # Pop first coordinate of an unprocessed zone, start new stack
                ind_region = [ind.pop()]

                # Define regionSize
                regionSize = 0

                # Grow zone for item popped from stack of region indices, loop until stack of region indices is exhausted
                # Each loop represents one voxel belonging to current zone. Therefore, count number of loops as regionSize
                while ind_region:
                    regionSize += 1

                    # Use pop to remove next node for set of unprocessed region indices
                    ind_node = ind_region.pop()

                    # get all coordinates in the 26-connected region, 2 voxels per angle
                    region_full = [
                        tuple(sum(a) for a in zip(ind_node, angle_i))
                        for angle_i in angles
                    ]
                    region_full += [
                        tuple(sum(a) for a in zip(ind_node, angle_i))
                        for angle_i in angles * -1
                    ]

                    # get all unprocessed coordinates in the 26-connected region with same gray level
                    region_level = list(
                        set(ind).intersection(set(region_full)))

                    # Remove already processed indices to prevent reprocessing
                    ind = list(set(ind) - set(region_level))

                    # Add all found neighbours to the total stack of unprocessed neighbours
                    ind_region.extend(region_level)

                # Update the gray level size zone matrix
                P_glszm[i - 1, regionSize - 1] += 1

        if self.verbose: bar.close()

        # Crop gray-level axis of GLSZM matrix to between minimum and maximum observed gray-levels
        # Crop size-zone area axis of GLSZM matrix up to maximum observed size-zone area
        P_glszm_bounds = numpy.argwhere(P_glszm)
        (xstart, ystart), (xstop, ystop) = P_glszm_bounds.min(
            0), P_glszm_bounds.max(0) + 1  # noqa: F841
        self.P_glszm = P_glszm[xstart:xstop, :ystop]
Exemple #18
0
  def _calculateMatrix(self):
    self.logger.debug('Calculating GLRLM matrix in Python')

    Ng = self.coefficients['Ng']
    Nr = self.coefficients['Nr']

    padVal = -2000  # use eps or NaN to pad matrix
    self.matrix[(self.maskArray == 0)] = padVal

    matrixDiagonals = []

    size = numpy.max(self.matrixCoordinates, 1) - numpy.min(self.matrixCoordinates, 1) + 1
    # Do not pass kwargs directly, as distances may be specified, which must be forced to [1] for this class
    angles = imageoperations.generateAngles(size,
                                            force2Dextraction=self.kwargs.get('force2D', False),
                                            force2Ddimension=self.kwargs.get('force2Ddimension', 0))

    self.logger.debug('Calculating diagonals')
    for angle in angles:
      staticDims, = numpy.where(angle == 0)  # indices for static dimensions for current angle (z, y, x)
      movingDims, = numpy.where(angle != 0)  # indices for moving dimensions for current angle (z, y, x)

      if len(movingDims) == 1:  # movement in one dimension, e.g. angle (0, 0, 1)
        T = tuple(numpy.append(staticDims, movingDims))
        diags = chain.from_iterable(numpy.transpose(self.matrix, T))

      elif len(movingDims) == 2:  # movement in two dimension, e.g. angle (0, 1, 1)
        d1 = movingDims[0]
        d2 = movingDims[1]
        direction = numpy.where(angle < 0, -1, 1)
        diags = chain.from_iterable([self.matrix[::direction[0], ::direction[1], ::direction[2]].diagonal(a, d1, d2)
                                     for a in range(-self.matrix.shape[d1] + 1, self.matrix.shape[d2])])

      else:  # movement in 3 dimensions, e.g. angle (1, 1, 1)/
        diags = []
        direction = numpy.where(angle < 0, -1, 1)
        for h in [self.matrix[::direction[0], ::direction[1], ::direction[2]].diagonal(a, 0, 1)
                  for a in range(-self.matrix.shape[0] + 1, self.matrix.shape[1])]:
          diags.extend([h.diagonal(b, 0, 1) for b in range(-h.shape[0] + 1, h.shape[1])])

      matrixDiagonals.append(filter(lambda diag: numpy.any(diag != padVal), diags))

    P_glrlm = numpy.zeros((Ng, Nr, int(len(matrixDiagonals))))

    # Run-Length Encoding (rle) for the list of diagonals
    # (1 list per direction/angle)
    self.logger.debug('Calculating run lengths')
    for angle_idx, angle in enumerate(matrixDiagonals):
      P = P_glrlm[:, :, angle_idx]
      # Check whether delineation is 2D for current angle (all diagonals contain 0 or 1 non-pad value)
      isMultiElement = False
      for diagonal in angle:
        if not isMultiElement and numpy.sum(diagonal != padVal) > 1:
          isMultiElement = True
        pos, = numpy.where(numpy.diff(diagonal) != 0)
        pos = numpy.concatenate(([0], pos + 1, [len(diagonal)]))
        rle = zip([int(n) for n in diagonal[pos[:-1]]], pos[1:] - pos[:-1])
        for level, run_length in rle:
          if level != padVal:
            P[level - 1, run_length - 1] += 1
      if not isMultiElement:
        P[:] = 0

    P_glrlm = self._applyMatrixOptions(P_glrlm, angles)

    return P_glrlm