0

我有一组 4 个 DICOM CT 卷,我正在使用 SimpleITK ImageSeriesReader 阅读它们。其中两张图像代表患者手术前后的 CT。其他两个图像是在前 2 个 CT 图像上分割的二元分割掩模。分割是其源 CT 的 ROI。

所有 4 张 CT 图像,具有不同的大小、间距、原点和方向。我已尝试应用此 GitHub gist https://gist.github.com/zivy/79d7ee0490faee1156c1277a78e4a4c4将我的图像大小调整为 512x512x512 和间距 1x1x1。但是,它不会将图像放置在正确的位置。从图片中可以看出,分割的结构始终位于 CT 图像的中心,而不是正确的位置。

这是我的“原始”DICOM 图像及其肿瘤分割(橙色斑点)。

在此处输入图像描述

这是在“调整大小”算法并写入磁盘之后(与以前的图像相同,只是肿瘤因不一致而被涂成绿色斑点): 在此处输入图像描述

用于将所有 4 个 DICOM 卷重新采样到相同尺寸的代码:

def resize_resample_images(images):
    """ Resize all the images to the same dimensions, spacing and origin.
        Usage: newImage = resize_image(source_img_plan, source_img_validation, ROI(ablation/tumor)_mask)
        1. translate to same origin
        2. largest number of slices and interpolate the others.
        3. same resolution 1x1x1 mm3 - resample
        4. (physical space)
        Slice Thickness (0018,0050)
        ImagePositionPatient (0020,0032)
        ImageOrientationPatient (0020,0037)
        PixelSpacing (0028,0030)
        Frame Of Reference UID (0020,0052)
    """
    # %% Define tuple to store the images
    tuple_resized_imgs = collections.namedtuple('tuple_resized_imgs',
                                                ['img_plan',
                                                 'img_validation',
                                                 'ablation_mask',
                                                 'tumor_mask'])
    # %% Create Reference image with zero origin, identity direction cosine matrix and isotropic dimension
    dimension = images.img_plan.GetDimension()  #
    reference_direction = np.identity(dimension).flatten()
    reference_size = [512] * dimension
    reference_origin = np.zeros(dimension)
    data = [images.img_plan, images.img_validation, images.ablation_mask, images.tumor_mask]

    reference_spacing = np.ones(dimension) # resize to isotropic size
    reference_image = sitk.Image(reference_size, images.img_plan.GetPixelIDValue())
    reference_image.SetOrigin(reference_origin)
    reference_image.SetSpacing(reference_spacing)
    reference_image.SetDirection(reference_direction)
    reference_center = np.array(
        reference_image.TransformContinuousIndexToPhysicalPoint(np.array(reference_image.GetSize()) / 2.0))

    #%% Paste the GT segmentation masks before transformation
    tumor_mask_paste = (paste_roi_image(images.img_plan, images.tumor_mask))
    ablation_mask_paste = (paste_roi_image(images.img_validation, images.ablation_mask))
    images.tumor_mask = tumor_mask_paste
    images.ablation_mask = ablation_mask_paste


    # %%  Apply transforms
    data_resized = []
    for idx,img in enumerate(data):
        transform = sitk.AffineTransform(dimension) # use affine transform with 3 dimensions
        transform.SetMatrix(img.GetDirection()) # set the cosine direction matrix
        # TODO: check translation when computing the segmentations
        transform.SetTranslation(np.array(img.GetOrigin()) - reference_origin) # set the translation.
        # Modify the transformation to align the centers of the original and reference image instead of their origins.
        centering_transform = sitk.TranslationTransform(dimension)
        img_center = np.array(img.TransformContinuousIndexToPhysicalPoint(np.array(img.GetSize()) / 2.0))
        centering_transform.SetOffset(np.array(transform.GetInverse().TransformPoint(img_center) - reference_center))
        centered_transform = sitk.Transform(transform)
        centered_transform.AddTransform(centering_transform)
        # Using the linear interpolator as these are intensity images, if there is a need to resample a ground truth
        # segmentation then the segmentation image should be resampled using the NearestNeighbor interpolator so that
        # no new labels are introduced.

        if (idx==1 or idx==2): # temporary solution to resample the GT image with NearestNeighbour
            resampled_img = sitk.Resample(img, reference_image, centered_transform, sitk.sitkNearestNeighbor, 0.0)

        else:
             resampled_img = sitk.Resample(img, reference_image, centered_transform, sitk.sitkLinear, 0.0)
        # append to list
        data_resized.append(resampled_img)


    # assuming the order stays the same, reassigng back to tuple
    resized_imgs = tuple_resized_imgs(img_plan=data_resized[0],
                                      img_validation=data_resized[1],
                                      ablation_mask=data_resized[2],
                                      tumor_mask=data_resized[3])

用于将 ROI 分段图像“粘贴”为正确大小的代码。可能是多余的。:

def paste_roi_image(image_source, image_roi):
    """ Resize ROI binary mask to size, dimension, origin of its source/original img.
        Usage: newImage = paste_roi_image(source_img_plan, roi_mask)

    """
    newSize = image_source.GetSize()
    newOrigin = image_source.GetOrigin()

    newSpacing = image_roi.GetSpacing()
    newDirection = image_roi.GetDirection()

    if image_source.GetSpacing() != image_roi.GetSpacing():
        print('the spacing of the source and derived mask differ')
    # re-cast the pixel type of the roi mask
    pixelID = image_source.GetPixelID()
    caster = sitk.CastImageFilter()
    caster.SetOutputPixelType(pixelID)
    image_roi = caster.Execute(image_roi)

    # black 3D image
    outputImage = sitk.Image(newSize, image_source.GetPixelIDValue())
    outputImage.SetOrigin(newOrigin)
    outputImage.SetSpacing(newSpacing)
    outputImage.SetDirection(newDirection)
    # transform from physical point to index the origin of the ROI image
    # img_center = np.array(img.TransformContinuousIndexToPhysicalPoint(np.array(img.GetSize()) / 2.0))
    destinationIndex = outputImage.TransformPhysicalPointToIndex(image_roi.GetOrigin())
    # paste the roi mask into the re-sized image
    pasted_img = sitk.Paste(outputImage, image_roi, image_roi.GetSize(), destinationIndex=destinationIndex)
    return pasted_img
4

0 回答 0