def execute(self,
                image: sitk.Image,
                params: ImageRegistrationParameters = None) -> sitk.Image:
        """Registers an image.

        Args:
            image (sitk.Image): The image.
            params (ImageRegistrationParameters): The registration parameters.

        Returns:
            sitk.Image: The registered image.
        """

        # todo: replace this filter by a registration. Registration can be costly, therefore, we provide you the
        # transformation, which you only need to apply to the image!
        # warnings.warn('No registration implemented. Returning unregistered image')

        atlas = params.atlas
        transform = params.transformation
        is_ground_truth = params.is_ground_truth  # the ground truth will be handled slightly different
        if is_ground_truth:
            # apply transformation to ground truth and brain mask using nearest neighbor interpolation
            image = sitk.Resample(image, atlas, transform,
                                  sitk.sitkNearestNeighbor, 0,
                                  image.GetPixelIDValue())
        else:
            # apply transformation to T1w and T2w images using linear interpolation
            image = sitk.Resample(image, atlas, transform, sitk.sitkLinear,
                                  0.0, image.GetPixelIDValue())

        # note: if you are interested in registration, and want to test it, have a look at
        # pymia.filtering.registration.MultiModalRegistration. Think about the type of registration, i.e.
        # do you want to register to an atlas or inter-subject? Or just ask us, we can guide you ;-)

        return image
    def __call__(self, x: sitk.Image) -> sitk.Image:
        """Apply the transform.

        Parameters
        ----------
        image
            Image to transform.

        Returns
        -------
        sitk.Image
            The transformed image.
        """
        angle = -self.max_angle + 2 * self.max_angle * torch.rand(1).item()
        rotation_centre = np.array(x.GetSize()) / 2
        rotation_centre = x.TransformContinuousIndexToPhysicalPoint(
            rotation_centre)

        rotation = sitk.Euler3DTransform(
            rotation_centre,
            0,  # the angle of rotation around the x-axis, in radians -> coronal rotation
            0,  # the angle of rotation around the y-axis, in radians -> saggittal rotation
            angle,  # the angle of rotation around the z-axis, in radians -> axial rotation
            (0., 0., 0.)  # no translation
        )
        return sitk.Resample(x, x, rotation, sitk.sitkLinear, self.fill_value)
Exemple #3
0
def apply_transform_pandas(fixed_image: sitk.Image,
                           moving_image: sitk.Image,
                           reference_path,
                           index=None):

    transform_path = os.path.join(reference_path.parent, 'Transforms.csv')

    if index is None:
        transform_params = blk.read_pandas_row(transform_path,
                                               reference_path.name, 'Image')
    else:
        transform_params = blk.read_pandas_row(transform_path, index, 'Image')

    transform = sitk.AffineTransform(2)

    transform.Rotate(0, 1, transform_params['Rotation'], pre=True)

    matrix = [
        transform_params['Matrix Top Left'],
        transform_params['Matrix Top Right'],
        transform_params['Matrix Bottom Left'],
        transform_params['Matrix Bottom Right']
    ]

    transform.SetMatrix(matrix)
    transform.SetTranslation(
        [transform_params['X Translation'], transform_params['Y Translation']])

    origin = (int(transform_params['X Origin']),
              int(transform_params['Y Origin']))
    moving_image.SetOrigin(origin)

    return sitk.Resample(moving_image, fixed_image, transform, sitk.sitkLinear,
                         0.0, moving_image.GetPixelID())
Exemple #4
0
    def _image_as_numpy_array(image: sitk.Image, mask: np.ndarray = None):
        """Gets an image as numpy array where each row is a voxel and each column is a feature.

        Args:
            image (sitk.Image): The image.
            mask (np.ndarray): A mask defining which voxels to return. True is background, False is a masked voxel.

        Returns:
            np.ndarray: An array where each row is a voxel and each column is a feature.
        """

        number_of_components = image.GetNumberOfComponentsPerPixel(
        )  # the number of features for this image
        no_voxels = np.prod(image.GetSize())
        image = sitk.GetArrayFromImage(image)

        if mask is not None:
            no_voxels = np.size(mask) - np.count_nonzero(mask)

            if number_of_components == 1:
                masked_image = np.ma.masked_array(image, mask=mask)
            else:
                # image is a vector image, make a vector mask
                vector_mask = np.expand_dims(
                    mask, axis=3)  # shape is now (z, x, y, 1)
                vector_mask = np.repeat(
                    vector_mask, number_of_components,
                    axis=3)  # shape is now (z, x, y, number_of_components)
                masked_image = np.ma.masked_array(image, mask=vector_mask)

            image = masked_image[~masked_image.mask]

        return image.reshape((no_voxels, number_of_components))
Exemple #5
0
    def assert_img_properties(img: SimpleITK.Image,
                              internal_image: SimpleITKImage):
        color_space = {
            1: ColorSpace.GRAY,
            3: ColorSpace.RGB,
            4: ColorSpace.RGBA,
        }

        assert internal_image.color_space == color_space.get(
            img.GetNumberOfComponentsPerPixel())
        if img.GetDimension() == 4:
            assert internal_image.timepoints == img.GetSize()[-1]
        else:
            assert internal_image.timepoints is None
        if img.GetDepth():
            assert internal_image.depth == img.GetDepth()
            assert internal_image.voxel_depth_mm == img.GetSpacing()[2]
        else:
            assert internal_image.depth is None
            assert internal_image.voxel_depth_mm is None

        assert internal_image.width == img.GetWidth()
        assert internal_image.height == img.GetHeight()
        assert internal_image.voxel_width_mm == approx(img.GetSpacing()[0])
        assert internal_image.voxel_height_mm == approx(img.GetSpacing()[1])
Exemple #6
0
    def _map_source_images_to_segmentation(
            self, segmentation: sitk.Image,
            source_images: List[pydicom.Dataset]
    ) -> List[List[pydicom.Dataset]]:
        """Maps an list of source image datasets to the slices of a
        SimpleITK image.

        Args:
            segmentation: A `SimpleITK.Image` with integer labels and a single
                component per spatial location.
            source_images: A list of `pydicom.Dataset` which are the
                source images for the segmentation image.

        Returns:
            A `list` with a `list` for each slice, which contains the mapped
            `pydicom.Dataset` instances for that slice location. Slices can
            have zero or more matched datasets.
        """
        result: List[List[pydicom.Dataset]] = [
            list() for _ in range(segmentation.GetDepth())
        ]
        for source_image in source_images:
            position = [float(x) for x in source_image.ImagePositionPatient]
            index = segmentation.TransformPhysicalPointToIndex(position)
            if index[2] < 0 or index[2] >= segmentation.GetDepth():
                continue
            # TODO Add reverse check if segmentation is contained in image
            result[index[2]].append(source_image)
        slices_mapped = sum(len(x) > 0 for x in result)
        logger.info(f"{slices_mapped} of {segmentation.GetDepth()} slices"
                    "mapped to source DICOM images")
        return result
Exemple #7
0
def resample_image_to_voxel_size(image: sitk.Image,
                                 new_spacing,
                                 interpolator,
                                 fill_value=0) -> sitk.Image:
    """
        resample a 3d image to a given voxel size (dx, dy, dz)
    :param image: 3D sitk image
    :param new_spacing: voxel size (dx, dy, dz)
    :param interpolator:
    :param fill_value: pixel value when a transformed pixel is outside of the image.
    :return:
    """

    # computing image shape based on the desired voxel size
    orig_size = np.array(image.GetSize())
    orig_spacing = np.array(image.GetSpacing())
    new_spacing = np.array(new_spacing)
    new_size = orig_size * (orig_spacing / new_spacing)

    #  Image dimensions are in integers
    new_size = np.ceil(new_size).astype(np.int)

    #  SimpleITK expects lists, not ndarrays
    new_size = [int(s) for s in new_size]

    return resample_sitk_image(image, new_size, interpolator, fill_value)
 def __init__(self, data: sitk.Image, segmentation: sitk.Image, bb_size):
     self.segmentation = segmentation
     # place bb so that the segmentation is centered
     self.offset = (
         (np.array(bb_size) - np.array(self.segmentation.GetSize())) /
         2).astype(int)
     # adjust offset if resulting bb is out of bounds
     segmentation_origin_in_data = data.TransformPhysicalPointToIndex(
         segmentation.GetOrigin())
     self.offset = [
         seg_or if seg_or - off < 0 else off
         for seg_or, off in zip(segmentation_origin_in_data, self.offset)
     ]
     self.offset = [
         off + ((seg_or - off + bb_sz) - data_sz)
         if seg_or - off + bb_sz > data_sz else off for seg_or, off, bb_sz,
         data_sz in zip(segmentation_origin_in_data, self.offset, bb_size,
                        data.GetSize())
     ]
     cropped_origin = np.array(segmentation_origin_in_data) - self.offset
     assert all(cr_or >= 0 for cr_or in cropped_origin), \
         f"Data size: {data.GetSize()}, BB size: {bb_size}, BB origin: {cropped_origin}"
     assert all(cr_or + bb_s <= data_s for cr_or, bb_s, data_s in zip(cropped_origin, bb_size, data.GetSize())), \
         f"Data size: {data.GetSize()}, BB size: {bb_size}, BB origin: {cropped_origin}"
     self.data = data[cropped_origin[0]:cropped_origin[0] + bb_size[0],
                      cropped_origin[1]:cropped_origin[1] + bb_size[1],
                      cropped_origin[2]:cropped_origin[2] + bb_size[2]]
Exemple #9
0
def split_4d_itk(img_itk: sitk.Image) -> List[sitk.Image]:
    """
    Helper function to split 4d itk images into multiple 3 images

    Args:
        img_itk: 4D input image

    Returns:
        List[sitk.Image]: 3d output images
    """
    img_npy = sitk.GetArrayFromImage(img_itk)
    spacing = img_itk.GetSpacing()
    origin = img_itk.GetOrigin()
    direction = np.array(img_itk.GetDirection()).reshape(4, 4)

    spacing = tuple(list(spacing[:-1]))
    assert len(spacing) == 3
    origin = tuple(list(origin[:-1]))
    assert len(origin) == 3
    direction = tuple(direction[:-1, :-1].reshape(-1))
    assert len(direction) == 9

    images_new = []
    for i, t in enumerate(range(img_npy.shape[0])):
            img = img_npy[t]
            images_new.append(
                create_itk_image_spatial_props(img, spacing, origin, direction))
    return images_new
Exemple #10
0
    def preprocess_image(self, reg_image: sitk.Image) -> None:
        """
        Run full intensity and spatial preprocessing. Creates the `reg_image` attribute

        Parameters
        ----------
        reg_image: sitk.Image
            Raw form of image to be preprocessed

        """

        reg_image = self.preprocess_reg_image_intensity(
            reg_image, self.preprocessing)

        if reg_image.GetDepth() >= 1:
            raise ValueError(
                "preprocessing did not result in a single image plane\n"
                "multi-channel or 3D image return")

        if reg_image.GetNumberOfComponentsPerPixel() > 1:
            raise ValueError(
                "preprocessing did not result in a single image plane\n"
                "multi-component / RGB(A) image returned")

        reg_image, pre_reg_transforms = self.preprocess_reg_image_spatial(
            reg_image, self.preprocessing, self.pre_reg_transforms)

        if len(pre_reg_transforms) > 0:
            self.pre_reg_transforms = pre_reg_transforms

        self._reg_image = reg_image
Exemple #11
0
    def execute(self,
                image: sitk.Image,
                params: ImageRegistrationParameters = None) -> sitk.Image:
        """Registers an image.

        Args:
            image (sitk.Image): The image.
            params (ImageRegistrationParameters): The registration parameters.

        Returns:
            sitk.Image: The registered image.
        """
        atlas = params.atlas
        transform = params.transformation
        is_ground_truth = params.is_ground_truth  # the ground truth will be handled slightly different
        if is_ground_truth:
            # apply transformation to ground truth and brain mask using nearest neighbor interpolation
            image = sitk.Resample(image, atlas, transform,
                                  sitk.sitkNearestNeighbor, 0,
                                  image.GetPixelIDValue())
        else:
            # apply transformation to T1w and T2w images using linear interpolation
            image = sitk.Resample(image, atlas, transform, sitk.sitkLinear,
                                  0.0, image.GetPixelIDValue())

        return image
def get_largest_segment(image: sitk.Image,
                        extract_background=False) -> sitk.Image:

    # get number of labels
    img_statistic = sitk.StatisticsImageFilter()
    img_statistic.Execute(image)
    min_val = int(img_statistic.GetMinimum())
    max_val = int(img_statistic.GetMaximum())

    # create empty output image
    img_out = sitk.Image(image.GetSize(), image.GetPixelIDValue())
    img_out.CopyInformation(image)

    # setup connected components filter
    connected_comp_filter = sitk.ConnectedComponentImageFilter()
    connected_comp_filter.FullyConnectedOn()

    # extract largest segment
    for label in range(min_val, max_val + 1):
        img_label = image == label
        seg = connected_comp_filter.Execute(img_label != 0)

        if label == 0:
            # create temporary a new label for largest connected comp of the background
            seg = (sitk.RelabelComponent(seg)
                   == 1) * (max_val + 1) * extract_background
        else:
            seg = (sitk.RelabelComponent(seg) == 1) * label
        img_out = img_out + seg

    # arr_image = sitk.GetArrayFromImage(img_out)
    # plt.imshow(arr_image[60,:,:], cmap='jet')
    # plt.show()

    return img_out
Exemple #13
0
def centre_of_mass(image: sitk.Image) -> np.ndarray:
    r""" Compute the centre of mass of the image.

    A real-valued image represents the distribution of mass, and its
    centre of mass is defined as :math:`\frac{1}{\sum_p I(p)} \sum_p p I(p)`.

    Parameters
    ----------
    image : sitk.Image
        Input image.

    Returns
    -------
    np.ndarray
        World coordinates (x, y, z) of the centre of mass.
    """
    data = sitk.GetArrayViewFromImage(image)

    grid = np.meshgrid(*[range(i) for i in data.shape], indexing='ij')
    grid = np.vstack([a.flatten() for a in grid]).T

    cm = np.average(grid, axis=0, weights=data.flatten())

    return np.multiply(np.flip(cm, axis=0),
                       image.GetSpacing()) - image.GetOrigin()
Exemple #14
0
    def execute(self, image: sitk.Image, params: ImageRegistrationParameters = None) -> sitk.Image:
        """Registers an image.

        Args:
            image (sitk.Image): The image.
            params (ImageRegistrationParameters): The registration parameters.

        Returns:
            sitk.Image: The registered image.
        """

        # todo: replace this filter by a registration. Registration can be costly, therefore, we provide you the
        # transformation, which you only need to apply to the image!
        atlas = params.atlas
        transform = params.transformation
        is_ground_truth = params.is_ground_truth  # the ground truth will be handled slightly different

        # note: if you are interested in registration, and want to test it, have a look at
        # pymia.filtering.registration.MultiModalRegistration. Think about the type of registration, i.e.
        # do you want to register to an atlas or inter-subject? Or just ask us, we can guide you ;-)

        # interpolator = sitk.sitkCosineWindowedSinc or sitk.sitkAffine
        if is_ground_truth:
            image = sitk.Resample(image, atlas, transform, sitk.sitkLinear, 0.0, image.GetPixelID())
        else:
            image = sitk.Resample(image, atlas, transform, sitk.sitkLinear, 0.0, image.GetPixelID())

        return image
def image_resample(image: sitk.Image):
    '''
    image = sitk.ReadImage(image_path)
    使用 SimpleITK 自带函数重新缩放图像
    '''
    origin_spacing = image.GetSpacing()  #  获取源分辨率
    origin_size = image.GetSize()

    new_spacing = [1, 1, 1]  #  设置新分辨率

    resample = sitk.ResampleImageFilter()
    resample.SetInterpolator(sitk.sitkLinear)
    resample.SetDefaultPixelValue(0)

    resample.SetOutputSpacing(new_spacing)
    resample.SetOutputOrigin(image.GetOrigin())
    resample.SetOutputDirection(image.GetDirection())

    #  计算新图像的大小
    new_size = [
        int(np.round(origin_size[0] * (origin_spacing[0] / new_spacing[0]))),
        int(np.round(origin_size[1] * (origin_spacing[1] / new_spacing[1]))),
        int(np.round(origin_size[2] * (origin_spacing[2] / new_spacing[2])))
    ]
    resample.SetSize(new_size)

    new_image = resample.Execute(image)
    return new_image
    def execute(self,
                image: sitk.Image,
                params: fltr.IFilterParams = None) -> sitk.Image:
        """Executes a neighborhood feature extractor on an image.

        Args:
            image (sitk.Image): The image.
            params (fltr.IFilterParams): The parameters (unused).

        Returns:
            sitk.Image: The normalized image.

        Raises:
            ValueError: If image is not 3-D.
        """

        if image.GetDimension() != 3:
            raise ValueError('image needs to be 3-D')

        # test the function and get the output dimension for later reshaping
        function_output = self.function(np.array([1, 2, 3]))
        if np.isscalar(function_output):
            img_out = sitk.Image(image.GetSize(), sitk.sitkFloat32)
        elif not isinstance(function_output, np.ndarray):
            raise ValueError(
                'function must return a scalar or a 1-D np.ndarray')
        elif function_output.ndim > 1:
            raise ValueError(
                'function must return a scalar or a 1-D np.ndarray')
        elif function_output.shape[0] <= 1:
            raise ValueError(
                'function must return a scalar or a 1-D np.ndarray with at least two elements'
            )
        else:
            img_out = sitk.Image(image.GetSize(), sitk.sitkVectorFloat32,
                                 function_output.shape[0])

        img_out_arr = sitk.GetArrayFromImage(img_out)
        img_arr = sitk.GetArrayFromImage(image)
        z, y, x = img_arr.shape

        z_offset = self.kernel[2]
        y_offset = self.kernel[1]
        x_offset = self.kernel[0]
        pad = ((0, z_offset), (0, y_offset), (0, x_offset))
        img_arr_padded = np.pad(img_arr, pad, 'symmetric')

        for xx in range(x):
            for yy in range(y):
                for zz in range(z):

                    val = self.function(img_arr_padded[zz:zz + z_offset,
                                                       yy:yy + y_offset,
                                                       xx:xx + x_offset])
                    img_out_arr[zz, yy, xx] = val

        img_out = sitk.GetImageFromArray(img_out_arr)
        img_out.CopyInformation(image)

        return img_out
Exemple #17
0
def _img_convert_type(img: sitk.Image, output_type) -> sitk.Image:
    """
    Convert the img into the desired pixel type. The method safely ( without overflow/underflow ) converts from one pixel range to another.

    :param img: a SimpleITK Image object
    :param output_type: a SimpleITK PixelID such as sitkUInt8, sitkFloat32 for the pixel type of the returned image
    """

    # the sub_volume_execute

    if img.GetPixelID() == sitk.sitkInt8 and output_type == sitk.sitkUInt8:
        img = sitk.Cast(img, sitk.sitkInt16)
        img += 128
        return sitk.Cast(img, output_type)
    elif img.GetPixelID() == sitk.sitkInt16 and output_type == sitk.sitkUInt8:
        img = sitk.Cast(img, sitk.sitkInt32)
        img += 32768
        img /= 256
        return sitk.Cast(img, output_type)
    elif img.GetPixelID() == sitk.sitkInt16 and output_type == sitk.sitkUInt16:
        img = sitk.Cast(img, sitk.sitkInt32)
        img += 32768
        return sitk.Cast(img, output_type)
    else:
        raise Exception(
            f"Converting from {img.GetPixelIDTypeAsString()} to "
            f"{sitk.GetPixelIDValueAsString(output_type)} is not implemented.")
Exemple #18
0
def downsample_image(image: sitk.Image, input_pixel_size, output_pixel_size):
    image.SetSpacing([input_pixel_size for i in range(3)])
    size = [
        int(math.ceil(i / output_pixel_size * input_pixel_size))
        for i in image.GetSize()
    ]
    return sitk.Resample(image, size, sitk.Transform(), sitk.sitkLinear,
                         [0, 0, 0], [output_pixel_size for i in range(3)])
Exemple #19
0
def write_metadata(image_path: Path, image: sitk.Image):
    """Write down the metadata keys to a txt file"""
    metadata = {}
    for key in image.GetMetaDataKeys():
        metadata[key] = image.GetMetaData(key)

    metadata_path = Path(image_path.parent, image_path.stem + '_metadata.txt')
    util.write_json(metadata, metadata_path)
Exemple #20
0
    def execute(self, image: sitk.Image, params: MultiModalRegistrationParams=None) -> sitk.Image:
        """Executes a multi-modal rigid registration.

        Args:
            image (sitk.Image): The moving image.
            params (MultiModalRegistrationParams): The parameters, which contain the fixed image.

        Returns:
            sitk.Image: The registered image.
        """

        if params is None:
            raise ValueError("params is not defined")
        dimension = image.GetDimension()
        if dimension not in (2, 3):
            raise ValueError('Image dimension {} is not among the accepted (2, 3)'.format(dimension))

        # set a transform that is applied to the moving image to initialize the registration
        if self.registration_type == RegistrationType.BSPLINE:
            transform_domain_mesh_size = [10] * image.GetDimension()
            initial_transform = sitk.BSplineTransformInitializer(params.fixed_image, transform_domain_mesh_size)
        else:
            if self.registration_type == RegistrationType.RIGID:
                transform_type = sitk.VersorRigid3DTransform() if dimension == 3 else sitk.Euler2DTransform()
            elif self.registration_type == RegistrationType.AFFINE:
                transform_type = sitk.AffineTransform(dimension)
            elif self.registration_type == RegistrationType.SIMILARITY:
                transform_type = sitk.Similarity3DTransform() if dimension == 3 else sitk.Similarity2DTransform()
            else:
                raise ValueError('not supported registration_type')

            initial_transform = sitk.CenteredTransformInitializer(sitk.Cast(params.fixed_image,
                                                                            image.GetPixelIDValue()),
                                                                  image,
                                                                  transform_type,
                                                                  sitk.CenteredTransformInitializerFilter.GEOMETRY)

        self.registration.SetInitialTransform(initial_transform, inPlace=True)

        if params.fixed_image_mask:
            self.registration.SetMetricFixedMask(params.fixed_image_mask)

        if params.callbacks is not None:
            for callback in params.callbacks:
                callback.set_params(self.registration, params.fixed_image, image, initial_transform)

        self.transform = self.registration.Execute(sitk.Cast(params.fixed_image, sitk.sitkFloat32),
                                                   sitk.Cast(image, sitk.sitkFloat32))

        if self.verbose:
            print('MultiModalRegistration:\n Final metric value: {0}'.format(self.registration.GetMetricValue()))
            print(' Optimizer\'s stopping condition, {0}'.format(
                self.registration.GetOptimizerStopConditionDescription()))
        elif self.number_of_iterations == self.registration.GetOptimizerIteration():
            print('MultiModalRegistration: Optimizer terminated at number of iterations and did not converge!')

        return sitk.Resample(image, params.fixed_image, self.transform, self.resampling_interpolator, 0.0,
                             image.GetPixelIDValue())
Exemple #21
0
def fitting_index(image: sitk.Image,
                  norm: Union[int, str] = 2.0,
                  centre: Tuple[float, float, float] = None,
                  radius: float = None,
                  padding: bool = True) -> float:
    r""" Compute the fitting index of an input object.

    The fitting index of order `p` is defined as the Jaccard coefficient
    computed between the input object and a p-ball centred in the object's
    centre of mass.

    Parameters
    ----------
    image : sitk.Image
        Input binary image of the object.
    norm : Union[int,str]
        Order of the Minkowski norm ('inf' or 'max' to use the Chebyshev norm).
    centre : Tuple[float, float, float]
        Forces the p-ball to be centred in a specific point.
    radius : float
        Force the radius of the p-ball.
    padding : bool
        If `True`, add enough padding to be sure that the ball will entirely
        fit within the volume.

    Returns
    -------
    float
        Value of the fitting index.
    """

    if image.GetPixelID() != sitk.sitkUInt8:
        raise Exception('Unsupported %s pixel type' %
                        image.GetPixelIDTypeAsString())

    if centre is None:
        # Use the centroid as centre
        lssif = sitk.LabelShapeStatisticsImageFilter()
        lssif.Execute(image)
        centre = lssif.GetCentroid(1)

    if padding:
        # Add some padding to be sure that an isovolumetric 1-ball can fit
        # within the same volume of a sphere touching the boundary
        pad = tuple([x // 4 for x in image.GetSize()])
        image = sitk.ConstantPad(image, pad, pad, 0)
        image.SetOrigin((0, 0, 0))
        centre = tuple([x + y for x, y in zip(centre, pad)])

    if radius is None:
        radius = isovolumteric_radius(image, norm)

    size = image.GetSize()

    sphere = drawing.create_sphere(radius, size=size, centre=centre,
                                   norm=norm) > 0

    return jaccard(image, sphere)
Exemple #22
0
def zoom(image: sitk.Image,
         scale_factor: Union[float, Sequence[float]],
         interpolation: str = "linear",
         anti_alias: bool = True,
         anti_alias_sigma: Optional[float] = None) -> sitk.Image:
    """Rescale image, preserving its spatial extent.

    The rescaled image will have the same spatial extent (size) but will be
    rescaled by `scale_factor` in each dimension. Alternatively, a separate
    scale factor for each dimension can be specified by passing a sequence
    of floats.

    Parameters
    ----------
    image
        The image to rescale.

    scale_factor
        If float, each dimension will be scaled by that factor. If tuple, each
        dimension will be scaled by the corresponding element.

    interpolation, optional
        The interpolation method to use. Valid options are:
        - "linear" for bi/trilinear interpolation (default)
        - "nearest" for nearest neighbour interpolation
        - "bspline" for order-3 b-spline interpolation

    anti_alias, optional
        Whether to smooth the image with a Gaussian kernel before resampling.
        Only used when downsampling, i.e. when `size < image.GetSize()`.
        This should be used to avoid aliasing artifacts.

    anti_alias_sigma, optional
        The standard deviation of the Gaussian kernel used for anti-aliasing.

    Returns
    -------
    sitk.Image
        The rescaled image.
    """
    dimension = image.GetDimension()

    if isinstance(scale_factor, float):
        scale_factor = (scale_factor, ) * dimension

    centre_idx = np.array(image.GetSize()) / 2
    centre = image.TransformContinuousIndexToPhysicalPoint(centre_idx)

    transform = sitk.ScaleTransform(dimension, scale_factor)
    transform.SetCenter(centre)

    return resample(image,
                    spacing=image.GetSpacing(),
                    interpolation=interpolation,
                    anti_alias=anti_alias,
                    anti_alias_sigma=anti_alias_sigma,
                    transform=transform,
                    output_size=image.GetSize())
Exemple #23
0
def get_raw_liver_image(raw: sitk.Image, liver: sitk.Image) -> sitk.Image:
    size = raw.GetSize()
    output = sitk.Image(size, sitk.sitkUInt8)
    output.CopyInformation(raw)
    for i in range(0, size[0]):
        for j in range(0, size[1]):
            if liver.GetPixel(i, j) == 1:
                output.SetPixel(i, j, raw.GetPixel(i, j))
    return output
Exemple #24
0
def copy_relevant_metadata(new_image: sitk.Image,
                           old_image: sitk.Image,
                           necessary_keys: list = None):
    if necessary_keys is None:
        necessary_keys = ['Unit']

    for key in necessary_keys:
        try:
            new_image.SetMetaData(key, old_image.GetMetaData(key))
        except:
            warnings.warn('The {0} key does not exist'.format(key))
Exemple #25
0
def check_if_image_is_rgb(image: sitk.Image):
    """Check if an image is RGB by looking for a 3-component 8 bit pixel image"""
    components = image.GetNumberOfComponentsPerPixel()
    pixel_type = image.GetPixelIDTypeAsString()

    if components == 3 and pixel_type == 'vector of 8-bit unsigned integer':
        image_is_rgb = True
    else:
        image_is_rgb = False

    return image_is_rgb
Exemple #26
0
def display_info(img: sitk.Image) -> None:
    """display information about a sitk.Image

    Args:
        img (sitk.Image): [sitk image]
    """
    print('img information :')
    print('\t Origin    :', img.GetOrigin())
    print('\t Size      :', img.GetSize())
    print('\t Spacing   :', img.GetSpacing())
    print('\t Direction :', img.GetDirection())
Exemple #27
0
    def set_origin_image(self, origin_img:sitk.Image) -> None : 
        """method to set the origin sitk.Image on which we want to resample 

        Args:
            origin_img (sitk.Image): []
        """
        self.origin_img = origin_img 
        self.origin_size = origin_img.GetSize()
        self.origin_spacing = origin_img.GetSpacing()
        self.origin_direction = origin_img.GetDirection()
        self.origin_origin = origin_img.GetOrigin()
Exemple #28
0
def resize(image: sitk.Image,
           size: Union[int, Sequence[int], np.ndarray],
           interpolation: str = "linear",
           anti_alias: bool = True,
           anti_alias_sigma: Optional[float] = None) -> sitk.Image:
    """Resize image to a given size by resampling coordinates.

    Parameters
    ----------
    image
        The image to be resize.

    size
        The new image size. If float, assumes the same size in all directions.
        Alternatively, a sequence of floats can be passed to specify size along
        each dimension. Passing 0 at any position will keep the original
        size along that dimension.

    interpolation, optional
        The interpolation method to use. Valid options are:
        - "linear" for bi/trilinear interpolation (default)
        - "nearest" for nearest neighbour interpolation
        - "bspline" for order-3 b-spline interpolation

    anti_alias, optional
        Whether to smooth the image with a Gaussian kernel before resampling.
        Only used when downsampling, i.e. when `size < image.GetSize()`.
        This should be used to avoid aliasing artifacts.

    anti_alias_sigma, optional
        The standard deviation of the Gaussian kernel used for anti-aliasing.

    Returns
    -------
    sitk.Image
        The resized image.
    """

    original_size = np.array(image.GetSize())
    original_spacing = np.array(image.GetSpacing())

    if isinstance(size, (float, int)):
        new_size = np.repeat(size, len(original_size)).astype(np.float64)
    else:
        size = np.asarray(size)
        new_size = np.where(size == 0, original_size, size)

    new_spacing = original_spacing * original_size / new_size

    return resample(image,
                    new_spacing,
                    anti_alias=anti_alias,
                    anti_alias_sigma=anti_alias_sigma,
                    interpolation=interpolation)
Exemple #29
0
def sitk_to_nib(image: sitk.Image) -> Tuple[np.ndarray, np.ndarray]:
    data = sitk.GetArrayFromImage(image).transpose()
    spacing = np.array(image.GetSpacing())
    rotation = np.array(image.GetDirection()).reshape(3, 3)
    rotation = np.dot(FLIP_XY, rotation)
    rotation_zoom = rotation * spacing
    translation = np.dot(FLIP_XY, image.GetOrigin())
    affine = np.eye(4)
    affine[:3, :3] = rotation_zoom
    affine[:3, 3] = translation
    return data, affine
Exemple #30
0
    def execute(self,
                image: sitk.Image,
                params: MultiModalRegistrationParams = None) -> sitk.Image:
        """Executes a multi-modal rigid registration.

        Args:
            image (sitk.Image): The moving image.
            params (MultiModalRegistrationParams): The parameters, which contain the fixed image.

        Returns:
            sitk.Image: The registered image.
        """

        if params is None:
            raise ValueError("params is not defined")

        # set a transform that is applied to the moving image to initialize the registration
        if self.registration_type == RegistrationType.RIGID:
            transform_type = sitk.VersorRigid3DTransform()
        elif self.registration_type == RegistrationType.AFFINE:
            transform_type = sitk.AffineTransform(3)
        else:
            raise ValueError('not supported registration_type')

        initial_transform = sitk.CenteredTransformInitializer(
            sitk.Cast(params.fixed_image, image.GetPixelIDValue()), image,
            transform_type, sitk.CenteredTransformInitializerFilter.GEOMETRY)
        self.registration.SetInitialTransform(initial_transform, inPlace=True)

        if params.fixed_image_mask:
            self.registration.SetMetricFixedMask(params.fixed_image_mask)

        if params.plot_directory_path:
            RegistrationPlotter(self.registration, params.fixed_image, image,
                                initial_transform, params.plot_directory_path)

        self.transform = self.registration.Execute(
            sitk.Cast(params.fixed_image, sitk.sitkFloat32),
            sitk.Cast(image, sitk.sitkFloat32))

        if self.verbose:
            print('MultiModalRegistration:\n Final metric value: {0}'.format(
                self.registration.GetMetricValue()))
            print(' Optimizer\'s stopping condition, {0}'.format(
                self.registration.GetOptimizerStopConditionDescription()))
        elif self.number_of_iterations == self.registration.GetOptimizerIteration(
        ):
            print(
                'MultiModalRegistration: Optimizer terminated at number of iterations and did not converge!'
            )

        return sitk.Resample(image, params.fixed_image, self.transform,
                             sitk.sitkLinear, 0.0, image.GetPixelIDValue())