Esempio n. 1
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])
Esempio n. 2
0
def verify_same_geometry(img_1: sitk.Image, img_2: sitk.Image):
    ori1, spacing1, direction1, size1 = img_1.GetOrigin(), img_1.GetSpacing(
    ), img_1.GetDirection(), img_1.GetSize()
    ori2, spacing2, direction2, size2 = img_2.GetOrigin(), img_2.GetSpacing(
    ), img_2.GetDirection(), img_2.GetSize()

    same_ori = np.all(np.isclose(ori1, ori2))
    if not same_ori:
        print("the origin does not match between the images:")
        print(ori1)
        print(ori2)

    same_spac = np.all(np.isclose(spacing1, spacing2))
    if not same_spac:
        print("the spacing does not match between the images")
        print(spacing1)
        print(spacing2)

    same_dir = np.all(np.isclose(direction1, direction2))
    if not same_dir:
        print("the direction does not match between the images")
        print(direction1)
        print(direction2)

    same_size = np.all(np.isclose(size1, size2))
    if not same_size:
        print("the size does not match between the images")
        print(size1)
        print(size2)

    if same_ori and same_spac and same_dir and same_size:
        return True
    else:
        return False
Esempio n. 3
0
def assert_sitk_img_equivalence(img: SimpleITK.Image,
                                img_ref: SimpleITK.Image):
    assert img.GetDimension() == img_ref.GetDimension()
    assert img.GetSize() == img_ref.GetSize()
    assert img.GetOrigin() == img_ref.GetOrigin()
    assert img.GetSpacing() == img_ref.GetSpacing()
    assert (img.GetNumberOfComponentsPerPixel() ==
            img_ref.GetNumberOfComponentsPerPixel())
    assert img.GetPixelIDValue() == img_ref.GetPixelIDValue()
    assert img.GetPixelIDTypeAsString() == img_ref.GetPixelIDTypeAsString()
Esempio n. 4
0
def sitk_to_itk(image: sitk.Image) -> Any:
    r""" Function to convert an image object from SimpleITK to ITK.

    .. note::
        Data is copied to the new object (deep copy).

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

    Returns
    -------
    any
        Image in ITK format.
    """

    if 'itk' not in sys.modules:
        raise Exception(
            'sitk_to_itk: itk module is required to use this feature.')

    a = sitk.GetArrayViewFromImage(image)

    if len(a.shape) < 4:
        result = itk.GetImageFromArray(a)

    else:
        # NOTE: This workaround is implemented this way since it
        # seems that itk.GetImageFromArray() is not working properly
        # with vector images.

        region = itk.ImageRegion[3]()
        region.SetSize(image.GetSize())
        region.SetIndex((0, 0, 0))

        PixelType = itk.Vector[itk_float_type, 3]
        ImageType = itk.Image[PixelType, 3]

        # Create new image
        result = ImageType.New()
        result.SetRegions(region)
        result.Allocate()
        result.SetSpacing(image.GetSpacing())

        # Copy image data
        b = itk.GetArrayViewFromImage(result)
        b[:] = a[:]

    result.SetSpacing(image.GetSpacing())
    result.SetOrigin(image.GetOrigin())

    return result
Esempio n. 5
0
def compatible_metadata(image1: sitk.Image,
                        image2: sitk.Image,
                        check_size: bool = True,
                        check_spacing: bool = True,
                        check_origin: bool = True) -> bool:
    """ Compares the metadata of two images and determines if all checks are successful or not.
    Comparisons are carried out with a small tolerance (0.0001).

    @param image1: first image
    @param image2: second image
    @param check_size: if true, check if the sizes of the images are equal
    @param check_spacing: if true, check if the spacing of the images are equal
    @param check_origin: if true, check if the origin of the images are equal
    @return: true, if images are equal in all given checks, false if one of them failed
    """
    all_parameters_equal = True
    tolerance = 1e-4

    if check_size:
        size1 = image1.GetSize()
        size2 = image2.GetSize()
        if size1 != size2:
            all_parameters_equal = False
            print(f'Images do not have the same size ({size1} != {size2})')

    if check_spacing:
        spacing1 = image1.GetSpacing()
        spacing2 = image2.GetSpacing()
        if any(
                list(
                    abs(s1 - s2) > tolerance
                    for s1, s2 in zip(spacing1, spacing2))):
            all_parameters_equal = False
            print(
                f'Images do not have the same spacing ({spacing1} != {spacing2})'
            )

    if check_origin:
        origin1 = image1.GetOrigin()
        origin2 = image2.GetOrigin()
        if any(
                list(
                    abs(o1 - o2) > tolerance
                    for o1, o2 in zip(origin1, origin2))):
            all_parameters_equal = False
            print(
                f'Images do not have the same origin ({origin1} != {origin2})')

    return all_parameters_equal
Esempio n. 6
0
    def _calculate_area(image: sitk.Image, slice_number: int=-1) -> float:
        """Calculates the area of a slice in a label image.

        Args:
            image (sitk.Image): The 3-D label image.
            slice_number (int): The slice number to calculate the area.
                Defaults to -1, which will calculate the area on the intermediate slice.
        """

        img_arr = sitk.GetArrayFromImage(image)

        if slice_number == -1:
            slice_number = int(img_arr.shape[0] / 2)  # use the intermediate slice

        return img_arr[slice_number, ...].sum() * image.GetSpacing()[0] * image.GetSpacing()[1]
Esempio n. 7
0
def sitk_to_nib(
    image: sitk.Image,
    keepdim: bool = False,
) -> Tuple[np.ndarray, np.ndarray]:
    data = sitk.GetArrayFromImage(image).transpose()
    num_components = image.GetNumberOfComponentsPerPixel()
    if num_components == 1:
        data = data[np.newaxis]  # add channels dimension
    input_spatial_dims = image.GetDimension()
    if not keepdim:
        data = ensure_4d(data, False, num_spatial_dims=input_spatial_dims)
    assert data.shape[0] == num_components
    assert data.shape[-input_spatial_dims:] == image.GetSize()
    spacing = np.array(image.GetSpacing())
    direction = np.array(image.GetDirection())
    origin = image.GetOrigin()
    if len(direction) == 9:
        rotation = direction.reshape(3, 3)
    elif len(direction) == 4:  # ignore first dimension if 2D (1, 1, H, W)
        rotation_2d = direction.reshape(2, 2)
        rotation = np.eye(3)
        rotation[1:3, 1:3] = rotation_2d
        spacing = 1, *spacing
        origin = 0, *origin
    rotation = np.dot(FLIP_XY, rotation)
    rotation_zoom = rotation * spacing
    translation = np.dot(FLIP_XY, origin)
    affine = np.eye(4)
    affine[:3, :3] = rotation_zoom
    affine[:3, 3] = translation
    return data, affine
Esempio n. 8
0
def query_extract_region(fixed_image: sitk.Image, moving_image: sitk.Image,
                         transform: sitk.Transform,
                         registration_method: sitk.ImageRegistrationMethod):
    do_extract = util.query_yes_no(
        'Do you wish to extract a sub-region to register based on? [y/n] >> ')

    if do_extract:
        itkplt.plot_overlay(fixed_image, moving_image, transform=transform)

        size = util.query_int('Enter the region size >> ')

        origin = []
        for dim in range(len(fixed_image.GetSpacing())):
            origin_in_dim = util.query_float(
                'Enter the origin in dimension {0} >> '.format(dim))
            origin.append(origin_in_dim)
        origin = np.array(origin)

        fixed_region = extract_region(fixed_image, size, origin)
        moving_region = extract_region(moving_image, size * 1.1,
                                       origin - 0.05 * size, transform)

        query_registration_sampling_change(registration_method)

        return fixed_region, moving_region, do_extract

    else:
        return fixed_image, moving_image, do_extract
Esempio n. 9
0
def _calculate_volume(image: sitk.Image):
    """Calculates the volume of a label image."""

    voxel_volume = np.prod(image.GetSpacing())
    number_of_voxels = sitk.GetArrayFromImage(image).sum()

    return number_of_voxels * voxel_volume
Esempio n. 10
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()
Esempio n. 11
0
def label_stat_results(labelled_img:sitk.Image, pet_img:sitk.Image) -> dict :
    """a function to gather stats about each ROI

    Args:
        labelled_img (sitk.Image): [3D segmentation sitk.Image with label]
        pet_img (sitk.Image): [3D pet sitk.Image]

    Returns:
        [type]: [description]
    """
    results = {} 
    stats = sitk.LabelIntensityStatisticsImageFilter()
    stats.Execute(labelled_img, pet_img)
    pet_spacing = pet_img.GetSpacing()
    number_of_label = stats.GetNumberOfLabels()
    results['number_of_label'] =  number_of_label
    volume = 0
    for i in range(1, number_of_label + 1) :
        subresult = {}
        subresult['max'] = stats.GetMaximum(i)
        subresult['mean'] = stats.GetMean(i)
        subresult['median'] = stats.GetMedian(i)
        subresult['variance'] = stats.GetVariance(i)
        subresult['sd'] = stats.GetStandardDeviation(i)
        subresult['number_of_pixel'] = stats.GetNumberOfPixels(i)
        volume_voxel = pet_spacing[0] * pet_spacing[1] * pet_spacing[2] * 10**(-3) #ml
        subresult['volume'] = stats.GetNumberOfPixels(i) * volume_voxel
        subresult['centroid'] = stats.GetCentroid(i)
        volume += stats.GetNumberOfPixels(i) * volume_voxel
        results[i] = subresult
    results['total_vol'] = volume
    return results
Esempio n. 12
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)
Esempio n. 13
0
def sitk_to_nib(
    image: sitk.Image,
    keepdim: bool = False,
) -> Tuple[np.ndarray, np.ndarray]:
    data = sitk.GetArrayFromImage(image).transpose()
    num_components = image.GetNumberOfComponentsPerPixel()
    if num_components == 1:
        data = data[np.newaxis]  # add channels dimension
    input_spatial_dims = image.GetDimension()
    if input_spatial_dims == 2:
        data = data[..., np.newaxis]
    if not keepdim:
        data = ensure_4d(data, num_spatial_dims=input_spatial_dims)
    assert data.shape[0] == num_components
    assert data.shape[1:1 + input_spatial_dims] == image.GetSize()
    spacing = np.array(image.GetSpacing())
    direction = np.array(image.GetDirection())
    origin = image.GetOrigin()
    if len(direction) == 9:
        rotation = direction.reshape(3, 3)
    elif len(direction) == 4:  # ignore first dimension if 2D (1, W, H, 1)
        rotation_2d = direction.reshape(2, 2)
        rotation = np.eye(3)
        rotation[:2, :2] = rotation_2d
        spacing = *spacing, 1
        origin = *origin, 0
    else:
        raise RuntimeError(f'Direction not understood: {direction}')
    rotation = np.dot(FLIP_XY, rotation)
    rotation_zoom = rotation * spacing
    translation = np.dot(FLIP_XY, origin)
    affine = np.eye(4)
    affine[:3, :3] = rotation_zoom
    affine[:3, 3] = translation
    return data, affine
Esempio n. 14
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
Esempio n. 15
0
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
Esempio n. 16
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())
Esempio n. 17
0
def resample_sitk_image(sitk_image: sitk.Image,
                        new_size,
                        interpolator="gaussian",
                        fill_value=0) -> sitk.Image:
    """
        modified version from:
            https://github.com/jonasteuwen/SimpleITK-examples/blob/master/examples/resample_isotropically.py
    """

    # if pass a path to image
    if isinstance(sitk_image, str):
        sitk_image = sitk.ReadImage(sitk_image)

    assert (interpolator in _SITK_INTERPOLATOR_DICT.keys()
            ), "`interpolator` should be one of {}".format(
                _SITK_INTERPOLATOR_DICT.keys())

    if not interpolator:
        interpolator = "linear"
        pixelid = sitk_image.GetPixelIDValue()

        if pixelid not in [1, 2, 4]:
            raise NotImplementedError(
                "Set `interpolator` manually, "
                "can only infer for 8-bit unsigned or 16, 32-bit signed integers"
            )

    #  8-bit unsigned int
    if sitk_image.GetPixelIDValue() == 1:
        # if binary mask interpolate it as nearest
        interpolator = "nearest"

    sitk_interpolator = _SITK_INTERPOLATOR_DICT[interpolator]
    orig_pixelid = sitk_image.GetPixelIDValue()
    orig_origin = sitk_image.GetOrigin()
    orig_direction = sitk_image.GetDirection()

    # new spacing based on the desired output shape
    new_spacing = tuple(
        np.array(sitk_image.GetSpacing()) * np.array(sitk_image.GetSize()) /
        np.array(new_size))

    # setup image resampler - SimpleITK 2.0
    resample_filter = sitk.ResampleImageFilter()
    resample_filter.SetOutputSpacing(new_spacing)
    resample_filter.SetSize(new_size)
    resample_filter.SetOutputDirection(orig_direction)
    resample_filter.SetOutputOrigin(orig_origin)
    resample_filter.SetTransform(sitk.Transform())
    resample_filter.SetDefaultPixelValue(orig_pixelid)
    resample_filter.SetInterpolator(sitk_interpolator)
    resample_filter.SetDefaultPixelValue(fill_value)
    # run it
    resampled_sitk_image = resample_filter.Execute(sitk_image)

    return resampled_sitk_image
Esempio n. 18
0
        def slice_by_slice(image: sitk.Image, *args, **kwargs):

            dim = image.GetDimension()
            iter_dim = 2

            if dim <= iter_dim:
                image = func(image, *args, **kwargs)
                return image

            extract_size = list(image.GetSize())
            extract_size[iter_dim:] = itertools.repeat(0, dim - iter_dim)

            extract_index = [0] * dim
            paste_idx = [slice(None, None)] * dim

            extractor = sitk.ExtractImageFilter()
            extractor.SetSize(extract_size)
            if inplace:
                for high_idx in itertools.product(
                        *[range(s) for s in image.GetSize()[iter_dim:]]):
                    extract_index[iter_dim:] = high_idx
                    extractor.SetIndex(extract_index)

                    paste_idx[iter_dim:] = high_idx
                    image[paste_idx] = func(extractor.Execute(image), *args,
                                            **kwargs)

            else:
                img_list = []
                for high_idx in itertools.product(
                        *[range(s) for s in image.GetSize()[iter_dim:]]):
                    extract_index[iter_dim:] = high_idx
                    extractor.SetIndex(extract_index)

                    paste_idx[iter_dim:] = high_idx

                    img_list.append(
                        func(extractor.Execute(image), *args, **kwargs))

                for d in range(iter_dim, dim):
                    step = reduce((lambda x, y: x * y),
                                  image.GetSize()[d + 1:], 1)

                    join_series_filter = sitk.JoinSeriesImageFilter()
                    join_series_filter.SetSpacing(image.GetSpacing()[d])
                    join_series_filter.SetOrigin(image.GetOrigin()[d])

                    img_list = [
                        join_series_filter.Execute(img_list[i::step])
                        for i in range(step)
                    ]

                assert len(img_list) == 1
                image = img_list[0]

            return image
Esempio n. 19
0
def match_world_info(source: sitk.Image,
                     target: sitk.Image,
                     spacing: Union[bool, Tuple[int], List[int]] = True,
                     origin: Union[bool, Tuple[int], List[int]] = True,
                     direction: Union[bool, Tuple[int], List[int]] = True):
    """Copy world information (eg spacing, origin, direction) from one
    image object to another.

    This matching is sometimes necessary for slight differences in
    metadata perhaps from founding that may prevent ITK filters from executing.

    Args:
        source (:obj:`sitk.Image`): Source object whose relevant metadata
            will be copied into ``target``.
        target (:obj:`sitk.Image`): Target object whose corresponding
            metadata will be overwritten by that of ``source``.
        spacing: True to copy the spacing from ``source`` to ``target``, or
            the spacing to set in ``target``; defaults to True.
        origin: True to copy the origin from ``source`` to ``target``, or
            the origin to set in ``target``; defaults to True.
        direction: True to copy the direction from ``source`` to ``target``, or
            the direction to set in ``target``; defaults to True.

    """
    # get the world info from the source if not already set
    if spacing is True:
        spacing = source.GetSpacing()
    if origin is True:
        origin = source.GetOrigin()
    if direction is True:
        direction = source.GetDirection()

    # set the values in the target
    _logger.debug(
        "Adjusting spacing from %s to %s, origin from %s to %s, "
        "direction from %s to %s", target.GetSpacing(), spacing,
        target.GetOrigin(), origin, target.GetDirection(), direction)
    if spacing:
        target.SetSpacing(spacing)
    if origin:
        target.SetOrigin(origin)
    if direction:
        target.SetDirection(direction)
Esempio n. 20
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())
Esempio n. 21
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
Esempio n. 22
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)
Esempio n. 23
0
    def transaxis(img: sitk.Image, dtype: np.dtype) -> sitk.Image:
        spacing = img.GetSpacing()

        img_raw = sitk.GetArrayFromImage(img)
        img_raw = np.transpose(img_raw, axes=[2, 1, 0])
        img_raw = img_raw[-1::-1, :, :]
        img_new = sitk.GetImageFromArray(img_raw.astype(dtype))
        img_new.SetSpacing(tuple(reversed(spacing)))
        img_new.SetDirection((1, 0, 0, 0, 1, 0, 0, 0, 1))

        return img_new
Esempio n. 24
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()
Esempio n. 25
0
    def _assert_3d(self, image: sitk.Image, is_vector=False):
        self.assertEqual(self.properties_3d.size, image.GetSize())

        if is_vector:
            self.assertEqual(self.no_vector_components,
                             image.GetNumberOfComponentsPerPixel())
        else:
            self.assertEqual(1, image.GetNumberOfComponentsPerPixel())

        self.assertEqual(self.origin_spacing_3d, image.GetOrigin())
        self.assertEqual(self.origin_spacing_3d, image.GetSpacing())
        self.assertEqual(self.direction_3d, image.GetDirection())
Esempio n. 26
0
    def __init__(self, image: sitk.Image):
        """Initializes a new instance of the ImageInformation class.

        Args:
            image (sitk.Image): The image whose properties to hold.
        """
        self.size = image.GetSize()
        self.origin = image.GetOrigin()
        self.spacing = image.GetSpacing()
        self.direction = image.GetDirection()
        self.dimensions = image.GetDimension()
        self.number_of_components_per_pixel = image.GetNumberOfComponentsPerPixel()
        self.pixel_id = image.GetPixelID()
Esempio n. 27
0
def rgb_to_grayscale_img(image: sitk.Image, white_light_filter_value=0.9):
    """Convert an RGB to grayscale image by extracting the average intensity, filtering out white light >0.9 max"""
    array = sitk.GetArrayFromImage(image)
    dimension = image.GetDimension()

    grayscale_array = np.average(array, 2)
    grayscale_array[grayscale_array > white_light_filter_value *
                    np.max(array)] = 0

    grayscale_image = sitk.GetImageFromArray(grayscale_array)
    grayscale_image.SetSpacing(image.GetSpacing())
    grayscale_image.SetOrigin(image.GetOrigin())

    return grayscale_image
Esempio n. 28
0
def create_circle_mask_itk(
    image_itk: sitk.Image,
    world_centers: Sequence[Sequence[float]],
    world_rads: Sequence[float],
    ndim: int = 3,
) -> sitk.Image:
    """
    Creates an itk image with circles defined by center points and radii

    Args:
        image_itk: original image (used for the coordinate frame)
        world_centers: Sequence of center points in world coordiantes (x, y, z)
        world_rads: Sequence of radii to use
        ndim: number of spatial dimensions

    Returns:
        sitk.Image: mask with circles
    """
    image_np = sitk.GetArrayFromImage(image_itk)
    min_spacing = min(image_itk.GetSpacing())

    if image_np.ndim > ndim:
        image_np = image_np[0]
    mask_np = np.zeros_like(image_np).astype(np.uint8)

    for _id, (world_center,
              world_rad) in enumerate(zip(world_centers, world_rads), start=1):
        check_rad = (world_rad / min_spacing) * 1.5  # add some buffer to it
        bounds = []
        center = image_itk.TransformPhysicalPointToContinuousIndex(
            world_center)[::-1]
        for ax, c in enumerate(center):
            bounds.append((
                max(0, int(c - check_rad)),
                min(mask_np.shape[ax], int(c + check_rad)),
            ))
        coord_box = product(*[list(range(b[0], b[1])) for b in bounds])

        # loop over every pixel position
        for coord in coord_box:
            world_coord = image_itk.TransformIndexToPhysicalPoint(
                tuple(reversed(coord)))  # reverse order to x, y, z for sitk
            dist = np.linalg.norm(
                np.array(world_coord) - np.array(world_center))
            if dist <= world_rad:
                mask_np[tuple(coord)] = _id
        assert mask_np.max() == _id

    mask_itk = sitk.GetImageFromArray(mask_np)
    return copy_meta_data_itk(image_itk, mask_itk)
Esempio n. 29
0
    def get_mask(ground_truth: sitk.Image,
                 ground_truth_labels: list,
                 label_percentages: list,
                 background_mask: sitk.Image = None) -> sitk.Image:
        """Gets a training mask.

        Args:
            ground_truth (sitk.Image): The ground truth image.
            ground_truth_labels (list of int): The ground truth labels,
                where 0=background, 1=label1, 2=label2, ..., e.g. [0, 1]
            label_percentages (list of float): The percentage of voxels of a corresponding label to extract as mask,
                e.g. [0.2, 0.2].
            background_mask (sitk.Image): A mask, where intensity 0 indicates voxels to exclude independent of the label.

        Returns:
            sitk.Image: The training mask.
        """

        # initialize mask
        ground_truth_array = sitk.GetArrayFromImage(ground_truth)
        mask_array = np.zeros(ground_truth_array.shape, dtype=np.uint8)

        # exclude background
        if background_mask is not None:
            background_mask_array = sitk.GetArrayFromImage(background_mask)
            background_mask_array = np.logical_not(background_mask_array)
            ground_truth_array = ground_truth_array.astype(
                float)  # convert to float because of np.nan
            ground_truth_array[background_mask_array] = np.nan

        for label_idx, label in enumerate(ground_truth_labels):
            indices = np.transpose(np.where(ground_truth_array == label))
            np.random.shuffle(indices)

            no_mask_items = int(indices.shape[0] *
                                label_percentages[label_idx])

            for no in range(no_mask_items):
                x = indices[no][0]
                y = indices[no][1]
                z = indices[no][2]
                mask_array[x, y, z] = 1  # this is a masked item

        mask = sitk.GetImageFromArray(mask_array)
        mask.SetOrigin(ground_truth.GetOrigin())
        mask.SetDirection(ground_truth.GetDirection())
        mask.SetSpacing(ground_truth.GetSpacing())

        return mask
Esempio n. 30
0
def get_cuboid_image(radii_world, reference: sitk.Image, center_ras):
    r, a, s = center_ras
    center_lps = -r, -a, s
    center_voxel = reference.TransformPhysicalPointToIndex(center_lps)
    spacing = np.array(reference.GetSpacing())
    radii_voxel = np.array(radii_world) / spacing
    radii_voxel = radii_voxel.round().astype(np.uint16)
    axes_voxel = 2 * radii_voxel
    cuboid = sitk.Image(*axes_voxel.tolist(), sitk.sitkUInt8) + 1
    result = reference * 0
    destination = (center_voxel - radii_voxel).tolist()
    paste = sitk.PasteImageFilter()
    paste.SetDestinationIndex(destination)
    paste.SetSourceSize(cuboid.GetSize())
    result = paste.Execute(result, cuboid)
    return result