Пример #1
0
def get_intersection_volume(roilist, xvoxel=1., yvoxel=1.):
    # There is probably a clever way to compute this by constructing
    # an "intersection contour" for each layer: for each contour, keep only
    # points that are inside all other contours in the list. But is tough to then
    # put those points in the right order.
    # Instead we'll just make a grid of points and get the volume of the combined mask.
    # With xvoxel and yvoxel the caller can tweak the voxel size of the mask in x and y.
    # In z the voxel size is given by the incoming ROIs.
    dz = min([r.dz for r in roilist])
    assert (dz > 0)
    assert (xvoxel > 0)
    assert (yvoxel > 0)
    bb = bounding_box(bb=roilist[0].bb)
    for roi in roilist[1:]:
        bb.intersect(roi.bb)
    if bb.empty:
        # too bad
        return 0.
    spacing = np.array([xvoxel, yvoxel, dz], dtype=float)
    bb.add_margins(2 * spacing)
    dimsize = np.array(np.round((bb.maxcorner - bb.mincorner) / spacing),
                       dtype=int)
    #img = sitk.Image(dimsize,sitk.sitkUInt8)
    img = itk.image_from_array(np.zeros(dimsize[::-2], dtype=np.uint8))
    img.SetOrigin(bb.mincorner)
    img.SetSpacing(spacing)
    itkmask = itk.array_from_image(roilist[0].get_mask(img))
    for roi in roilist[1:]:
        itkmask *= itk.array_from_image(roi.get_mask(img))
    return np.sum(itkmask) * np.prod(spacing)
Пример #2
0
 def test_three_float_3D_images(self):
     logger.info('Test_Product test_three_float_3D_images')
     nx, ny, nz = 2, 3, 4
     minlog, maxlog = -5., 5.
     spacing = (421., 214., 142.)
     origin = (421421., 214214., 142142.)
     thirteen = 13.333
     imglistF = [
         itk.image_from_array(
             np.logspace(minlog, maxlog,
                         nx * ny * nz).reshape(nx, ny,
                                               nz).astype(np.float32)),
         itk.image_from_array(
             np.logspace(minlog, maxlog, nx * ny * nz)[::-1].reshape(
                 nx, ny, nz).astype(np.float32)),
         itk.image_from_array(thirteen * np.ones(
             (nx, ny, nz), dtype=np.float32))
     ]
     for imgF in imglistF:
         imgF.SetSpacing(spacing)
         imgF.SetOrigin(origin)
     imgprodF = image_product(input_list=imglistF)
     self.assertTrue(np.allclose(itk.array_from_image(imgprodF), thirteen))
     self.assertTrue(itk.array_from_image(imgprodF).shape == (nx, ny, nz))
     self.assertTrue(np.allclose(imgprodF.GetSpacing(), spacing))
     self.assertTrue(np.allclose(imgprodF.GetOrigin(), origin))
     self.assertTrue(type(imgprodF) == itk.Image[itk.F, 3])
Пример #3
0
def faf_ACGM_image(gm, acf, factor=4.168696975):

    if gm.GetImageDimension() != 2:
        print("gm image dimension (" + str(gm.GetImageDimension()) +
              ") is not 2")
        sys.exit(1)

    if acf.GetImageDimension() != 2:
        print("acf image dimension (" + str(acf.GetImageDimension()) +
              ") is not 2")
        sys.exit(1)

    resampleACF = gt.applyTransformation(input=acf,
                                         like=gm,
                                         force_resample=True,
                                         pad=-1)

    resampleACFArray = itk.array_from_image(resampleACF)
    gmArray = itk.array_from_image(gm)
    acgmArray = np.zeros(gmArray.shape)
    negativeACFIndex = np.where(resampleACFArray == -1)
    positiveACFIndex = np.where(resampleACFArray != -1)
    acgmArray[negativeACFIndex] = factor * gmArray[negativeACFIndex]
    acgmArray[positiveACFIndex] = resampleACFArray[positiveACFIndex] * gmArray[
        positiveACFIndex]

    acgmImage = itk.image_from_array(acgmArray)
    acgmImage.CopyInformation(gm)
    return acgmImage
Пример #4
0
    def test_itk_registration(self):
        import os
        os.environ["FOOTSTEPS_NAME"] = "test"
        import footsteps

        icon_registration.test_utils.download_test_data()

        model = icon_registration.pretrained_models.OAI_knees_registration_model(
            pretrained=True)

        image_A = itk.imread(
            str(icon_registration.test_utils.TEST_DATA_DIR /
                "knees_diverse_sizes" /
                #"9126260_20060921_SAG_3D_DESS_LEFT_11309302_image.nii.gz")
                "9487462_20081003_SAG_3D_DESS_RIGHT_11495603_image.nii.gz"))

        image_B = itk.imread(
            str(icon_registration.test_utils.TEST_DATA_DIR /
                "knees_diverse_sizes" /
                "9225063_20090413_SAG_3D_DESS_RIGHT_12784112_image.nii.gz"))
        print(image_A.GetLargestPossibleRegion().GetSize())
        print(image_B.GetLargestPossibleRegion().GetSize())
        print(image_A.GetSpacing())
        print(image_B.GetSpacing())

        phi_AB, phi_BA = icon_registration.itk_wrapper.register_pair(
            model, image_A, image_B)

        assert (isinstance(phi_AB, itk.CompositeTransform))
        interpolator = itk.LinearInterpolateImageFunction.New(image_A)

        warped_image_A = itk.resample_image_filter(
            image_A,
            transform=phi_AB,
            interpolator=interpolator,
            size=itk.size(image_B),
            output_spacing=itk.spacing(image_B),
            output_direction=image_B.GetDirection(),
            output_origin=image_B.GetOrigin())

        plt.imshow(
            np.array(itk.checker_board_image_filter(warped_image_A,
                                                    image_B))[40])
        plt.colorbar()
        plt.savefig(footsteps.output_dir + "grid.png")
        plt.clf()
        plt.imshow(np.array(warped_image_A)[40])
        plt.savefig(footsteps.output_dir + "warped.png")
        plt.clf()

        reference = np.load(icon_registration.test_utils.TEST_DATA_DIR /
                            "warped.npy")

        np.save(footsteps.output_dir + "warped.npy",
                itk.array_from_image(warped_image_A)[40])

        self.assertLess(
            np.mean(
                np.abs(reference - itk.array_from_image(warped_image_A)[40])),
            1e-6)
Пример #5
0
 def test_eight_3D_images(self):
     logger.info('Test_MinMax test_eight_3D_images')
     nx,ny,nz = 30,40,50
     dmin,dmax = np.float32(-20.5), np.float32(31230.5)
     spacing = (321.,213.,132.)
     origin = (321321.,213213.,132132.)
     alist = [ np.random.uniform(dmin,dmax,nx*ny*nz).astype(np.float32) for i in range(8)]
     indices = np.arange(nx*ny*nz,dtype=np.uint32)
     imglist=list()
     for (j,a) in enumerate(alist):
         a[indices%8 == j] = dmin
         a[indices%8 == (j+4)%8] = dmax
         img=itk.image_from_array(a.reshape(nx,ny,nz).copy())
         img.SetSpacing(spacing)
         img.SetOrigin(origin)
         imglist.append(img)
     imgmin = image_min(imglist)
     imgmax = image_max(imglist)
     self.assertTrue( type(imgmin) == itk.Image[itk.F,3])
     self.assertTrue( type(imgmax) == itk.Image[itk.F,3])
     self.assertTrue( np.allclose(itk.array_from_image(imgmin),dmin))
     self.assertTrue( np.allclose(itk.array_from_image(imgmax),dmax))
     self.assertTrue( np.allclose(imgmin.GetSpacing(),spacing))
     self.assertTrue( np.allclose(imgmax.GetSpacing(),spacing))
     self.assertTrue( np.allclose(imgmin.GetOrigin(),origin))
     self.assertTrue( np.allclose(imgmax.GetOrigin(),origin))
Пример #6
0
def dilat(input, output):
    '''
    Doc todo
    '''

    print(input)
    ctvi = itk.imread(input)

    ImageType = type(ctvi)
    Dimension = ctvi.GetImageDimension()

    radiusValue = 1
    StructuringElementType = itk.FlatStructuringElement[Dimension]
    structuringElement = StructuringElementType.Ball(radiusValue)

    grayscaleFilter = itk.GrayscaleDilateImageFilter[
        ImageType, ImageType, StructuringElementType].New()
    grayscaleFilter.SetInput(ctvi)
    grayscaleFilter.SetKernel(structuringElement)
    grayscaleFilter.Update()

    o = grayscaleFilter.GetOutput()

    o = itk.array_from_image(o)
    c = itk.array_from_image(ctvi)
    o[c > 0.0] = 0
    o = c + o

    o = itk.image_from_array(o)
    o.CopyInformation(ctvi)
    itk.imwrite(o, output)
Пример #7
0
 def test_five_int_3D_images(self):
     logger.info('Test_Product test_five_int_3D_images')
     nx,ny,nz = 30,40,50
     spacing = (321.,213.,132.)
     origin = (321321.,213213.,132132.)
     pval=np.ones(5)/5.0
     p2=np.random.multinomial(1,pval,(nz,nx,ny)).swapaxes(0,3).copy()
     p3=np.random.multinomial(2,pval,(nz,nx,ny)).swapaxes(0,3).copy()
     p7=np.random.multinomial(2,pval,(nz,nx,ny)).swapaxes(0,3).copy()
     p13=np.random.multinomial(1,pval,(nz,nx,ny)).swapaxes(0,3).copy()
     p37=np.random.multinomial(1,pval,(nz,nx,ny)).swapaxes(0,3).copy()
     a0,a1,a2,a3,a4 = 2**p2*3**p3*7**p7*13**p13*37**p37
     imglist = list()
     for a in (a0,a1,a2,a3,a4):
         img = itk.image_from_array(a.astype(ctypes.c_ulong))
         img.SetSpacing( spacing )
         img.SetOrigin( origin )
         imglist.append(img)
     imgprodUS = image_product(input_list=imglist)
     answer = 424242
     self.assertTrue( type(imgprodUS) == itk.Image[itk.UL,3])
     self.assertTrue( (itk.array_from_image(imgprodUS) == answer).all() )
     self.assertTrue( itk.array_from_image(imgprodUS).shape == (nx,ny,nz))
     self.assertTrue( np.allclose(imgprodUS.GetSpacing(),spacing) )
     self.assertTrue( np.allclose(imgprodUS.GetOrigin(),origin) )
Пример #8
0
def _mwr_with_loops(dose, mass, newgrid):
    """
    Reference implementation, only for testing.

    This function computes a dose distribution using the geometry (origin,
    size, spacing) of the `newgrid` image, using the energy deposition and mass
    with some different geometry. A typical use case is that a Gate simulation first
    computes the dose w.r.t. a patient CT (exporting also the mass image),
    and then we want to resample this dose distribution to the geometry of the
    new grid, e.g. from the dose distribution computed by a TPS.
    """
    assert (equal_geometry(dose, mass))
    if equal_geometry(dose, newgrid):
        # If input and output geometry are equal, then we don't need to do anything, just copy the input dose.
        newdose = itk.image_from_array(itk.array_from_image(dose))
        newdose.CopyInformation(dose)
        return newdose
    if not enclosing_geometry(dose, newgrid):
        # In a later release we may provide some smart code to deal with dose resampling outside of the input geometry.
        raise RuntimeError("new grid must be inside the old one")
    t0 = datetime.now()
    xol, yol, zol = [
        _overlaps(*xyz)
        for xyz in zip(dose.GetOrigin(), dose.GetSpacing(),
                       dose.GetLargestPossibleRegion().GetSize(),
                       newgrid.GetOrigin(), newgrid.GetSpacing(),
                       newgrid.GetLargestPossibleRegion().GetSize())
    ]
    nxyz = np.array(dose.GetLargestPossibleRegion().GetSize())
    mxyz = np.array(newgrid.GetLargestPossibleRegion().GetSize())
    mzyx = mxyz[::-1].tolist()
    adose = itk.array_from_image(dose)
    amass = itk.array_from_image(mass)
    anew = np.zeros(mzyx, dtype=float)
    wsum = np.zeros(mzyx, dtype=float)
    N_ops = 0
    # loop over nonzero overlaps of x-internvals
    for (ixs, ixd) in zip(*np.nonzero(xol)):
        dx = xol[ixs, ixd]
        # loop over nonzero overlaps of y-internvals
        for (iys, iyd) in zip(*np.nonzero(yol)):
            dy = yol[iys, iyd]
            # loop over nonzero overlaps of z-internvals
            for (izs, izd) in zip(*np.nonzero(zol)):
                dz = zol[izs, izd]
                w = dx * dy * dz * amass[izs, iys, ixs]
                anew[izd, iyd, ixd] += adose[izs, iys, ixs] * w
                wsum[izd, iyd, ixd] += w
                N_ops += 1
    mask = (wsum > 0)
    anew[mask] /= wsum[mask]
    newdose = itk.image_from_array(anew)
    newdose.CopyInformation(newgrid)
    t1 = datetime.now()
    dt = (t1 - t0).total_seconds()
    logger.debug(
        f"resampling using explicit loops over nonzero voxel overlaps took {dt:.3f} seconds"
    )
    return newdose
Пример #9
0
 def test_big(self):
     resampled_loops = _mwr_with_loops(self.dose, self.mass, self.newdose)
     resampled = mass_weighted_resampling(self.dose, self.mass,
                                          self.newdose)
     self.assertTrue(equal_geometry(resampled_loops, self.newdose))
     self.assertTrue(equal_geometry(resampled, self.newdose))
     ar0 = itk.array_from_image(resampled_loops)
     ar1 = itk.array_from_image(resampled)
     self.assertTrue(np.allclose(ar0, ar1))
Пример #10
0
def faf_ACF_image(image, ctCoeff, spectCoeff, weight=None):

    if image.GetImageDimension() != 3:
        print("Image dimension (" + str(image.GetImageDimension()) +
              ") is not 3")
        sys.exit(1)
    if ctCoeff is None:
        print("ctCoeff is mandatory")
        sys.exit(1)
    elif len(ctCoeff) != 2:
        print("ctCoeff size (" + str(len(ctCoeff)) + ") is not 2")
        sys.exit(1)
    if weight is None:
        weight = [1]
    nbPeak = len(weight)
    if spectCoeff is None:
        print("spectCoeff is mandatory")
        sys.exit(1)
    elif len(spectCoeff) != 3 * nbPeak:
        print("ctCoeff size (" + str(len(spectCoeff)) + ") is not 3*nbPeak (" +
              str(3 * nbPeak) + ")")
        sys.exit(1)

    ctArray = itk.array_from_image(image)
    ctPositiveValueIndex = np.where(ctArray > 0)
    ctNegativeValueIndex = np.where(ctArray < 0)
    attenuation = np.zeros(ctArray.shape)
    for i in range(nbPeak):
        attenuationTemp = np.zeros(ctArray.shape)
        attenuationTemp[ctNegativeValueIndex] = spectCoeff[3 * i + 1] + (
            spectCoeff[3 * i + 1] -
            spectCoeff[3 * i]) / 1000.0 * ctArray[ctNegativeValueIndex]
        attenuationTemp[ctPositiveValueIndex] = spectCoeff[
            3 * i + 1] + ctCoeff[0] / (ctCoeff[1] - ctCoeff[0]) * (
                spectCoeff[3 * i + 2] -
                spectCoeff[3 * i + 1]) / 1000.0 * ctArray[ctPositiveValueIndex]
        attenuation = attenuation + weight[i] * attenuationTemp
    attenuation[attenuation < 0] = 0
    attenuationImage = itk.image_from_array(attenuation)
    attenuationImage.CopyInformation(image)

    projectionAxis = 1
    projection = image_projection.image_projection(attenuationImage,
                                                   projectionAxis)
    acfArray = np.exp(image.GetSpacing()[projectionAxis] / (2.0 * 10.0) *
                      itk.array_from_image(projection))
    acfImage = itk.image_from_array(acfArray)
    acfImage.CopyInformation(projection)
    flipFilter = itk.FlipImageFilter.New(Input=acfImage)
    flipFilter.SetFlipAxes((False, True))
    flipFilter.Update()
    acfImage = flipFilter.GetOutput()

    return acfImage
Пример #11
0
def read_images(folder, scale):
    print(folder)
    f = os.path.join(folder, 'dose-Edep.mhd')
    img = itk.imread(f)
    data = itk.array_from_image(img)
    data = data * scale

    f = os.path.join(folder, 'dose-Edep-Uncertainty.mhd')
    img_s = itk.imread(f)
    data_s = itk.array_from_image(img_s)

    return img, data, data_s
Пример #12
0
    def image_filter_wrapper(*args, **kwargs):
        have_array_input = False
        have_xarray_input = False

        args_list = list(args)
        for index, arg in enumerate(args):
            if _HAVE_XARRAY and isinstance(arg, xr.DataArray):
                have_xarray_input = True
                image = itk.image_from_xarray(arg)
                args_list[index] = image
            elif is_arraylike(arg):
                have_array_input = True
                array = np.asarray(arg)
                image = itk.image_view_from_array(array)
                args_list[index] = image

        potential_image_input_kwargs = ('input', 'input1', 'input2', 'input3')
        for key, value in kwargs.items():
            if (key.lower() in potential_image_input_kwargs
                    or "image" in key.lower()):
                if _HAVE_XARRAY and isinstance(value, xr.DataArray):
                    have_xarray_input = True
                    image = itk.image_from_xarray(value)
                    kwargs[key] = image
                elif is_arraylike(value):
                    have_array_input = True
                    array = np.asarray(value)
                    image = itk.image_view_from_array(array)
                    kwargs[key] = image

        if have_xarray_input or have_array_input:
            # Convert output itk.Image's to numpy.ndarray's
            output = image_filter(*tuple(args_list), **kwargs)
            if isinstance(output, tuple):
                output_list = list(output)
                for index, value in output_list:
                    if isinstance(value, itk.Image):
                        if have_xarray_input:
                            data_array = itk.xarray_from_image(value)
                            output_list[index] = data_array
                        else:
                            array = itk.array_from_image(value)
                            output_list[index] = array
                return tuple(output_list)
            else:
                if isinstance(output, itk.Image):
                    if have_xarray_input:
                        output = itk.xarray_from_image(output)
                    else:
                        output = itk.array_from_image(output)
                return output
        else:
            return image_filter(*args, **kwargs)
Пример #13
0
def faf_lutetium_calibration(spect, ct, planar, injected_activity, delta_time):

    if spect.GetImageDimension() != 3:
        print("spect image dimension (" + str(spect.GetImageDimension()) + ") is not 3")
        sys.exit(1)
    
    if ct.GetImageDimension() != 3:
        print("ct image dimension (" + str(ct.GetImageDimension()) + ") is not 3")
        sys.exit(1)

    if planar.GetImageDimension() != 3:
        print("planar image dimension (" + str(planar.GetImageDimension()) + ") is not 3")
        sys.exit(1)
    if planar.GetLargestPossibleRegion().GetSize()[2] != 8:
        print("planar image dimension (" + str(planar.GetLargestPossibleRegion().GetSize()[2]) + ") is not 8")
        sys.exit(1)

    planarArray = itk.array_from_image(planar)
    tempArray1 = planarArray[2:4,:,:]
    tempArray2 = planarArray[6:8,:,:]
    planar208Array = np.concatenate([tempArray1, tempArray2], axis=0)
    planar208Image = itk.image_from_array(planar208Array)
    planar208Image.SetSpacing(planar.GetSpacing())
    planar208Image.SetOrigin(planar.GetOrigin())
    
    gmImage = faf_create_planar_geometrical_mean.faf_create_planar_geometrical_mean(planar208Image)
    registeredGmImage = faf_register_planar_image.faf_register_planar_image(gmImage, spect)
    acfImage = faf_ACF_image.faf_ACF_image(ct, [0.2068007, 0.57384408],  [0.00014657, 0.13597229, 0.24070651])
    acgmImage = faf_ACGM_image.faf_ACGM_image(registeredGmImage, acfImage)
    calibratedSpectImage, fafFactor = faf_calibration.faf_calibration(spect, acgmImage, injected_activity, 6.647*24,delta_time, 900, True)
    print("Calibration factor with FAF (Bq/count): " + str(fafFactor))
    return calibratedSpectImage
    def read_file(self, path):
        image = itk.imread(path, itk.F)
        data = itk.array_from_image(image)  # type: np.ndarray
        data = data.astype(np.int)
        dim_x, dim_y, dim_z = data.shape

        return dim_x, dim_y, dim_z, data
Пример #15
0
    def test_faf_calibration(self):
        gm = np.ones((32, 12)) * 11.2
        spect = np.ones((16, 16, 6)) * 0.33
        gmImage = itk.image_from_array(gm)
        gmImage.SetOrigin(np.array([-6.0, -16.0]))
        spectImage = itk.image_from_array(spect)
        spectImage.SetOrigin(np.array([-3.0, -8.0, -8.0]))
        calibratedSpectImage, calibrationFactor = faf_calibration(spectImage,
                                                                  gmImage,
                                                                  1.0,
                                                                  half_life=4,
                                                                  delta_time=4,
                                                                  verbose=True)
        calibratedSpectArray = itk.array_from_image(calibratedSpectImage)

        self.assertTrue(
            calibratedSpectImage.GetLargestPossibleRegion().GetSize()[0] == 6)
        self.assertTrue(
            calibratedSpectImage.GetLargestPossibleRegion().GetSize()[1] == 16)
        self.assertTrue(
            calibratedSpectImage.GetLargestPossibleRegion().GetSize()[2] == 16)
        theoreticalcalibrationFactor = 1 / (6 * 16 * 16 * 0.33 /
                                            (0.5 * 0.25)) * 1000000
        self.assertTrue(
            np.allclose(calibrationFactor, theoreticalcalibrationFactor))
        self.assertTrue(
            np.allclose(calibratedSpectArray[4, 12],
                        0.33 * theoreticalcalibrationFactor / 1000000))
def Import_data(frames_path, masks_path):
    
    print("Import raw frames ...")
    
    # Read input image
    itk_image = itk.imread(frames_path)
    raw_frames = itk.array_from_image(itk_image).astype(np_.uint8)
    
    
    print("Import masks ...")
    
    with h5py.File(masks_path, 'r') as f:
        # List all groups
        print("Keys: %s" % f.keys())
        a_group_key = list(f.keys())[0]
    
        # Get the data
        data_ = list(f[a_group_key])
    
    masks=[]
    
    for mask in data_:
    
        masks.append(np_.reshape(mask-1,(mask.shape)))
        
    return raw_frames, masks
Пример #17
0
def label_ROI(roiDir, ROI_exp, allRoisView, roiBaseImage, label):
    #for ROI in fnmatch.filter(os.listdir(roiDir), ROI_exp):
    #print(f'{ROI_exp}    {label}')
    found = False
    for ROI in os.listdir(roiDir):
        #print('here ' + ROI + '  ' + ROI_exp)
        if fnmatch.fnmatch(ROI.lower(), ROI_exp):
            #print('yes ' + ROI)
            print(os.path.join(roiDir, ROI))
            roisImage = itk.imread(os.path.join(roiDir, ROI))
            # resize
            roisImage = gt.applyTransformation(input=roisImage,
                                               like=roiBaseImage,
                                               force_resample=True,
                                               interpolation_mode='NN')
            #itk.imwrite(roisImage, f'resized_{ROI}')

            roisView = itk.array_from_image(roisImage)

            allRoisView += roisView * label
            if np.any(allRoisView > label):
                f = open(f'{taskfolder_3D}/errorlog.txt', 'a')
                f.write("Overlapping structures: " +
                        str(int(allRoisView[allRoisView > label][0] - label)) +
                        " and " + str(label) + "\n")
                f.close()
                print("Overlapping structures: " +
                      str(int(allRoisView[allRoisView > label][0] - label)) +
                      " and " + str(label))
                allRoisView = np.where(allRoisView > label, label, allRoisView)
                #return allRoisView, False

            found = True  #return allRoisView, True

    return allRoisView, found
def faf_create_planar_geometrical_mean(image):

    if image.GetImageDimension() != 3:
        print("Image dimension (" + str(image.image.GetImageDimension()) + ") is not 3")
        sys.exit(1)
    if image.GetLargestPossibleRegion().GetSize()[2] != 4:
        print("Image size (" + str(image.GetLargestPossibleRegion().GetSize()[2]) + ") is not 4")
        sys.exit(1)
    
    array = (itk.array_from_image(image)).astype(float)
    arrayAnt = array[0, :, :] - 1.1*array[2, :, :]
    arrayPost = array[1, :, :] - 1.1*array[3, :, :]
    arrayPost = np.flip(arrayPost, 1)
    
    arrayAnt[arrayAnt < 0] = 0
    arrayPost[arrayPost < 0] = 0
    
    outputArray = np.sqrt(arrayAnt*arrayPost)
    outputImage = itk.image_from_array(outputArray)
    spacing =  np.array(image.GetSpacing())
    spacing = np.delete(spacing, 2)
    outputImage.SetSpacing(spacing)
    origin =  np.array(image.GetOrigin())
    origin = np.delete(origin, 2)
    outputImage.SetOrigin(origin)
    return outputImage
Пример #19
0
def median_filter_with_mask(img, mask, radius_dilatation, radius_median):

    # debug
    debug = False
    if debug:
        input = img
        itk.imwrite(img, 'ctvi_before.mhd')
        ctvim = itk.median_image_filter(img, radius=radius_median)
        itk.imwrite(ctvim, 'ctvi_median.mhd')

    dimg = dilate_at_boundaries(img, radius_dilatation)

    if debug:
        itk.imwrite(dimg, 'ctvi_before_dilated.mhd')

    imgm = itk.median_image_filter(dimg, radius=radius_median)

    if debug:
        itk.imwrite(imgm, 'ctvi_median_after_dilated.mhd')

    # reapply mask after median
    imgm = itk.array_from_image(imgm)
    imgm = imgm.astype('float')
    imgm[mask == 0] = 0

    if debug:
        imgm = imgm.astype(np.float32)
        a = itk.image_from_array(imgm)
        a.CopyInformation(input)
        itk.imwrite(a, 'ctvi_median_final.mhd')

    return imgm
Пример #20
0
def get_stats_struct(uncertpath, dicom_struct, struct_name):
    """Generate stats from a dose image and uncertainty image;
    but only for pixels inside specified structure
    """
    uncertimg = itk.imread(uncertpath)
    uncert_flat = itk.array_from_image(uncertimg).flatten()
    ds = pydicom.dcmread(dicom_struct)

    aroi = roiutils.region_of_interest(ds, struct_name)
    mask = aroi.get_mask(uncertimg, corrected=False)
    mask_voxels_flat = itk.array_view_from_image(mask).flatten()

    relevant_uncerts = []
    for i, val in enumerate(mask_voxels_flat):
        if val == 1:
            relevant_uncerts.append(uncert_flat[i])

    relevant_uncerts = np.array(relevant_uncerts)

    print()
    print("Number of voxels in {} = {}".format(struct_name,
                                               len(relevant_uncerts)))
    print("Mean uncertainty = {}".format(relevant_uncerts.mean()))
    print("Median = {}".format(np.median(relevant_uncerts)))
    print("Max = {}".format(relevant_uncerts.max()))
    print("Min = {}".format(relevant_uncerts.min()))
    print("Std dev = {}".format(relevant_uncerts.std()))

    # Make histogram
    ymax = int(relevant_uncerts.max() * 100 + 2)
    binsize = 0.01
    bins = [i * binsize for i in range(int(ymax / binsize))]
    plt.hist(100 * relevant_uncerts, bins=bins)
    plt.xlabel("Dose uncertainty (%)")
    plt.show()
Пример #21
0
 def add(self, dose_file):
     lockfile = dose_file + ".lock"
     dose = None
     n_primaries = 0
     t0 = datetime.now()
     logger.debug("lockfile exists" if os.path.
                  exists(lockfile) else "lockfile does not exist")
     lock = SoftFileLock(lockfile)
     try:
         # TODO: the length of the timeout should maybe be configured in the system configuration
         with lock.acquire(timeout=3):
             t1 = datetime.now()
             logger.debug("acquiring lock file took {} seconds".format(
                 (t1 - t0).total_seconds()))
             ##########################
             n_primaries = self.get_nprimaries(dose_file)
             if n_primaries < 1:
                 logger.warn(
                     f"dose file seems to be based on too few primaries ({n_primaries})"
                 )
             elif bool(self.mass) and bool(self.mask):
                 simdose = itk.imread(dose_file)
                 logger.debug(
                     "resampling dose with size {} using mass file of size {} to target size {}"
                     .format(itk.size(simdose), itk.size(self.mass),
                             itk.size(self.mask)))
                 dose = mass_weighted_resampling(simdose, self.mass,
                                                 self.mask)
                 del simdose
             else:
                 dose = itk.imread(dose_file)
                 logger.debug("read dose with size {}".format(
                     itk.size(dose)))
             t2 = datetime.now()
             logger.debug(
                 "acquiring dose data {} file took {} seconds".format(
                     os.path.basename(dose_file),
                     (t2 - t1).total_seconds()))
             if self.wmin > n_primaries:
                 self.wmin = n_primaries
             if self.wmax < n_primaries:
                 self.wmax = n_primaries
     except Timeout:
         logger.warn(
             "failed to acquire lock for {} for 3 seconds, giving up for now"
             .format(dose_file))
         return
     if not bool(dose):
         logger.warn("skipping {}".format(dose_file))
         return
     adose = itk.array_from_image(dose)
     if adose.shape != self.dosesum.shape:
         raise RuntimeError(
             "PROGRAMMING ERROR: dose shape {} differs from expected shape {}"
             .format(adose.shape, self.dosesum.shape))
     self.dosesum += adose  # n_primaries * (adose / n_primaries)
     self.dose2sum += adose**2 / n_primaries  # n_primaries * (adose / n_primaries)**2
     self.weightsum += n_primaries
     self.n += 1
Пример #22
0
def write_scaled_dose(mhdfile, output, scalefactor):
    """Scale provided dose image and save to output"""
    img = itk.imread(mhdfile)
    dose = itk.array_from_image(img)
    dosescaled = dose * scalefactor
    newimg = itk.image_view_from_array(dosescaled)
    newimg.CopyInformation(img)
    itk.imwrite(newimg, output)
Пример #23
0
def force_positive_directionality( image ):
    """Return altered mhd image with positive axes directionality
    
    Accepts path to mhd image or itk image object
    Returns mhd image
    """
    
    #img = itk.imread(imgpath)
    img = None 
    if type( image )==str:
        #Assume we have file path
        img = itk.imread( image )
    else:
        #Assume we have itk image object
        img = image   

    spacing = img.GetSpacing()
    origin = img.GetOrigin()
    size = img.GetLargestPossibleRegion().GetSize()
    direction = np.array( img.GetDirection()*[1,1,1] )
    
    new_origin=[]
    for d,o,sz,sp in zip( direction, origin, size, spacing ):
        if d==-1:
            orig = o - (sz-1)*sp
            new_origin.append(orig)
        else:
            new_origin.append( o )
        
        arr = itk.array_from_image( img )


    rot_arr = None   
    if np.array_equal( direction, np.array([-1,-1,1]) ):
        #(1,2 for z-axes)  (2,1) opposite sense; take care for 90 degrees.
        rot_arr = np.rot90( arr, k=2, axes=(1,2) )   
    elif np.array_equal( direction, np.array([1,-1,-1]) ):
        rot_arr_1 = np.rot90( arr, k=2, axes=(1,2) )   
        rot_arr = np.rot90( rot_arr_1, k=2, axes=(0,2) )   #(0,2 for y-axis)
    elif np.array_equal( direction, np.array([1,1,1]) ):
        pass
    else:
        print("TransformMatrix (Direction) of image not handled correctly")
        print("Exiting")
        exit(0)


    if rot_arr is not None:
        #Image shape will change for 90 degree rotations (decubitis positions)
        
        new_img = itk.image_from_array( rot_arr )
        new_img.CopyInformation(img)
        new_img.SetOrigin( new_origin )
        new_img.SetDirection( np.array([[1,0,0],[0,1,0],[0,0,1]]) )
        
        return new_img
    else:
        return img
Пример #24
0
def ctvi_slice_nbr_click(input, ct, mask, axis, slice_start, slice_step,
                         slice_stop, output):
    '''
    Doc todo
    '''

    # read images
    ctvi_itk = itk.imread(input)
    ct = itk.imread(ct)
    mask = itk.imread(mask)
    ctvi = itk.array_from_image(ctvi_itk)
    ct = itk.array_from_image(ct)
    mask = itk.array_from_image(mask)
    print(ctvi.shape, ct.shape, mask.shape)

    # images MUST be the same size
    # spacing MUST be isotropic

    # slice
    if slice_start == -1:
        slice_start = int(ctvi.shape[1] / 2)
    if slice_stop == -1:
        slice_stop = slice_start + 1
    elif slice_stop == -2:
        slice_stop = ctvi.shape[axis] - 1
    print(slice_start, slice_step, slice_stop)

    # normalisation ? 90% percentile like in Kipritidis2019 ?
    print('min max', np.min(ctvi), np.max(ctvi))
    t = np.quantile(ctvi[ctvi > 0], 0.9)
    print('Q90%', t)
    ctvi = ctvi / t

    # get colormap
    cmap, cmap_ct, norm = get_colormap1()

    # loop for slice
    s = slice_start
    while s < slice_stop:
        f = f'{output}_{s:03d}.png'
        ctvi_s = get_slice(ctvi, axis, s)
        ct_s = get_slice(ct, axis, s)
        mask_s = get_slice(mask, axis, s)
        save_img(f, ctvi_s, ct_s, mask_s, cmap, cmap_ct, norm)
        s = s + slice_step
Пример #25
0
 def test_five_2D_images(self):
     logger.info('Test_Sum test_five_2D_images')
     nx,ny = 4,5
     hundred = 100
     thousand = 1000
     spacing = (42.,24.)
     origin = (4242.,2424.)
     # float images
     imglistF = [ itk.image_from_array(np.arange(nx*ny,dtype=np.float32).reshape(nx,ny).copy()),
                  itk.image_from_array(np.arange(nx*ny,dtype=np.float32)[::-1].reshape(nx,ny).copy()),
                  itk.image_from_array(np.arange(0,nx*ny*hundred,hundred,dtype=np.float32).reshape(nx,ny).copy()),
                  itk.image_from_array(np.arange(0,nx*ny*hundred,hundred,dtype=np.float32)[::-1].reshape(4,5).copy()),
                  itk.image_from_array(thousand*np.ones((nx,ny),dtype=np.float32)) ]
     for imgF in imglistF:
         imgF.SetSpacing( spacing )
         imgF.SetOrigin( origin )
     imgsumF = image_sum(input_list=imglistF)
     logger.debug("got image with spacing {}".format(imgsumF.GetSpacing()))
     index = imgsumF.GetLargestPossibleRegion().GetSize() -1
     logger.debug("get sum value {} while expecting {}".format(imgsumF.GetPixel(index),4.*5. -1.))
     self.assertTrue( np.allclose(itk.array_view_from_image(imgsumF),nx*ny-1.+(nx*ny-1.)*hundred +thousand) ) # floats: approximate equality
     self.assertTrue( itk.array_from_image(imgsumF).shape == (nx,ny))
     self.assertTrue( np.allclose(imgsumF.GetSpacing(),spacing))
     self.assertTrue( np.allclose(imgsumF.GetOrigin(),origin))
     # unsigned short int images ("US" in itk lingo)
     nx,ny = 40,50
     ten = 10
     thirteen = 13
     spacing = (32.,23.)
     origin = (3232.,2323.)
     imglistUS = [ itk.image_from_array(np.arange(nx*ny,dtype=np.uint16).reshape(nx,ny).copy()),
                   itk.image_from_array(np.arange(nx*ny,dtype=np.uint16)[::-1].reshape(nx,ny).copy()),
                   itk.image_from_array(np.arange(0,ten*nx*ny,ten,dtype=np.uint16).reshape(nx,ny).copy()),
                   itk.image_from_array(np.arange(0,ten*nx*ny,ten,dtype=np.uint16)[::-1].reshape(nx,ny).copy()),
                   itk.image_from_array(thirteen*np.ones((nx,ny),dtype=np.uint16)) ]
     for imgUS in imglistUS:
         imgUS.SetSpacing( spacing )
         imgUS.SetOrigin( origin )
     imgsumUS = image_sum(input_list=imglistUS)
     logger.debug("got image with spacing {}".format(imgsumUS.GetSpacing()))
     logger.debug("get sum value {} while expecting {}".format(imgsumUS.GetPixel(index),40*50-1+10*40*50-10+13))
     self.assertTrue( (itk.array_view_from_image(imgsumUS)==nx*ny-1+ten*nx*ny-ten+thirteen).all() ) # ints: exact equality
     self.assertTrue( itk.array_from_image(imgsumUS).shape == (nx,ny))
     self.assertTrue( np.allclose(imgsumUS.GetSpacing(),spacing))
     self.assertTrue( np.allclose(imgsumUS.GetOrigin(),origin))
Пример #26
0
def update_plan_dose(pdd, label, beam_dose_image):
    # 'pdd' is plan dose dictionary
    # label will be "unresampled", "Physical" or "RBE"
    if label in pdd:
        # add dose image to dose image in the dict
        a_plandose = itk.array_from_image(pdd[label])
        a_beamdose = itk.array_view_from_image(beam_dose_image)
        assert (a_plandose.shape == a_beamdose.shape)
        a_plandose += a_beamdose
        img_plandose = itk.image_from_array(a_plandose)
        img_plandose.CopyInformation(pdd[label])
        pdd[label] = img_plandose
    else:
        # copy dose image into dict
        a_plandose = itk.array_from_image(beam_dose_image)
        img_plandose = itk.image_from_array(a_plandose)
        img_plandose.CopyInformation(beam_dose_image)
        pdd[label] = img_plandose
Пример #27
0
def update_roi_characteristics(db, r, background=0):
    '''
    Update roi volume, density and mass 
    '''
    im_roi = syd.find_one(db['Image'], roi_id=r['id'])
    dicom_struct = syd.find_one(db['DicomStruct'], id=r['dicom_struct_id'])
    if dicom_struct is not None:
        im_ct = syd.find_one(db['Image'],
                             dicom_series_id=dicom_struct['dicom_series_id'])
    else:
        im_ct = syd.find_one(
            db['Image'],
            frame_of_reference_uid=r['frame_of_reference_uid'],
            modality='CT')
    file_img = syd.find_one(db['File'], id=im_roi['file_mhd_id'])
    if im_ct is not None:
        file_img_ct = syd.find_one(db['File'], id=im_ct['file_mhd_id'])
    else:
        print(f'Could not find the CT file image for the roi {r.id}')
        return 0
    filename_im = os.path.join(
        db.absolute_data_folder,
        os.path.join(file_img['folder'], file_img['filename']))
    filename_ct = os.path.join(
        db.absolute_data_folder,
        os.path.join(file_img_ct['folder'], file_img_ct['filename']))
    roi = itk.imread(filename_im)
    ct = itk.imread(filename_ct)
    array_im = itk.array_from_image(roi)
    spacing = roi.GetSpacing()

    ### Volume ###
    e = np.count_nonzero(array_im != background)
    volume_elem = spacing[0] * spacing[1] * spacing[2]  # spacing is in mm
    volume_elem = volume_elem * 0.001  # convert mm3 to cm3 (/1000)
    volume = e * volume_elem
    r['volume'] = volume
    syd.update_one(db['Roi'], r)

    ### Density ###
    mask = gt.applyTransformation(input=roi,
                                  like=ct,
                                  force_resample=True,
                                  interpolation_mode='NN')
    stats = gt.imageStatistics(input=ct, mask=mask)
    HU_mean = stats['mean']
    density = 1 + (HU_mean / 1000)
    r['density'] = density
    syd.update_one(db['Roi'], r)

    ### Mass ###
    mass = np.multiply(volume, density)
    r['mass'] = mass
    syd.update_one(db['Roi'], r)

    return 1
Пример #28
0
def combine_let(dosefiles, letfiles, outname):
    """
    Combine LET distributions from multiple simulations in a
    dose-weighted fashion
    
    NOTE: The order of dosefiles and letfiles must match,
    i.e the index corresponds to a specific simulation!
    """
    #Store FLATTENED image arrays
    dosearrays = []
    letarrays = []

    # Get shape and image info
    img1 = itk.imread(dosefiles[0])
    shape = itk.array_from_image(img1).shape

    if len(dosefiles) != len(letfiles):
        print("Unequal number of dose and LET files")
    if len(dosefiles) == 0:
        print("No files given to combine_let method")
    else:
        for f in dosefiles:
            dosearrays.append(itk.array_from_image(itk.imread(f)).flatten())
        for f in letfiles:
            letarrays.append(itk.array_from_image(itk.imread(f)).flatten())

    sumdose = sum(dosearrays)

    #itk.imread(dosefiles[0])
    totlet = np.zeros(len(letarrays[0]))
    for i in range(len(totlet)):
        tot = 0
        for j in range(len(dosearrays)):
            if sumdose[i] != 0:  #TODO this ok for floats?
                tot = tot + letarrays[j][i] * (dosearrays[j][i] / sumdose[i])
        totlet[i] = tot

    combinedlet = totlet.reshape(shape)
    letimg = itk.image_from_array(combinedlet.astype(
        np.float32))  ## ITK CANNOT WRITE DOUBLES, MUST CAST TO FLOAT
    letimg.CopyInformation(img1)

    itk.imwrite(letimg, outname)
Пример #29
0
def combine_uncertainty(dosefiles, dosesquaredfiles, statfiles, output):
    """
    How to combine dose uncertainties from simulations?
    """
    dosearrays = []
    dosesq = []

    #Gate uncertainty calculation uses NUMBER OF PRIMARIES in simulation,
    #not the numberOfHits per voxel
    N = get_tot_primaries(statfiles)

    # Get shape and image info
    img1 = itk.imread(dosefiles[0])
    shape = itk.array_from_image(img1).shape

    if len(dosefiles) != len(dosesquaredfiles):
        print("Unequal number of dose and dosesquared files")
    if len(dosefiles) == 0:
        print("No files given to sum_uncertainty method")
    else:
        for f in dosefiles:
            dosearrays.append(itk.array_from_image(itk.imread(f)).flatten())
        for f in dosesquaredfiles:
            dosesq.append(itk.array_from_image(itk.imread(f)).flatten())

    sumdose = sum(dosearrays)
    sumdosesq = sum(dosesq)

    uncertainty = np.ones(len(dosearrays[0]))
    for i in range(len(uncertainty)):
        #Using Eq(2) from Chetty2006, "Reporting and analyzing statistical uncertainties in MC-based
        #treatment planning" and dividing by dose/N for relative uncertainty...
        if sumdosesq[i] != 0 and sumdose[i] != 0 and N > 1:
            uncertainty[i] = math.sqrt(
                1.0 / (N - 1) * (sumdosesq[i] / N -
                                 (sumdose[i] / N)**2)) / (sumdose[i] / N)

    combinedUncert = uncertainty.reshape(shape)
    uncertimg = itk.image_from_array(combinedUncert.astype(
        np.float32))  ## ITK CANNOT WRITE DOUBLES, MUST CAST TO FLOAT
    uncertimg.CopyInformation(img1)

    itk.imwrite(uncertimg, output)
Пример #30
0
def imageStatistics(input=None, mask=None, resample=False, histogramBins=1000):

    if input is None:
        logger.error("Set an input")
        sys.exit(1)

    inputArray = itk.array_from_image(input)
    outputStats = {}
    outputStats["nbPixel"] = inputArray.size
    if not mask is None:
        if resample:
            mask = gt.applyTransformation(input=mask, like=input, force_resample=True)
        if not np.allclose(mask.GetSpacing(), input.GetSpacing()):
            logger.error("Input and mask do not have the same spacing")
            sys.exit(1)
        if not np.allclose(mask.GetOrigin(), input.GetOrigin()):
            logger.error("Input and mask do not have the same origin")
            sys.exit(1)
        if not np.allclose(itk.array_from_matrix(mask.GetDirection()), itk.array_from_matrix(input.GetDirection())):
            logger.error("Input and mask do not have the same direction")
            sys.exit(1)
        if not np.allclose(mask.GetLargestPossibleRegion().GetSize(),  input.GetLargestPossibleRegion().GetSize()):
            logger.error("Input and mask do not have the same size")
            sys.exit(1)

        maskArray = itk.array_from_image(mask)
        if len(np.where(maskArray > 1)[0]) >0:
            logger.error("The mask seems to be a non-binary image")
        index = np.where(maskArray == 1)
        outputStats["nbPixel"] = len(index[0])
        inputArray = inputArray[index]

    outputStats["minimum"] = np.amin(inputArray)
    outputStats["maximum"] = np.amax(inputArray)
    outputStats["sum"] = np.sum(inputArray)
    outputStats["median"] = np.median(inputArray)
    outputStats["mean"] = np.mean(outputStats["sum"]/outputStats["nbPixel"])
    outputStats["variance"] = np.var(inputArray)
    outputStats["sigma"] = np.sqrt(outputStats["variance"])
    outputStats["hist"] = np.histogram(inputArray, histogramBins)

    return outputStats
Пример #31
0
# test reading image series with `itk.imread()` and check that dimension is
# not increased if last dimension is 1.
image_series = itk.imread([image_series3d_filename, image_series3d_filename])
assert image_series.GetImageDimension() == 3

# pipeline, auto_pipeline and templated class are tested in other files

# BridgeNumPy
try:
    # Images
    import numpy as np
    image = itk.imread(fileName)
    arr = itk.GetArrayFromImage(image)
    arr.fill(1)
    assert np.any(arr != itk.GetArrayFromImage(image))
    arr = itk.array_from_image(image)
    arr.fill(1)
    assert np.any(arr != itk.GetArrayFromImage(image))
    view = itk.GetArrayViewFromImage(image)
    view.fill(1)
    assert np.all(view == itk.GetArrayFromImage(image))
    image = itk.GetImageFromArray(arr)
    image.FillBuffer(2)
    assert np.any(arr != itk.GetArrayFromImage(image))
    image = itk.GetImageViewFromArray(arr)
    image.FillBuffer(2)
    assert np.all(arr == itk.GetArrayFromImage(image))
    image = itk.GetImageFromArray(arr, is_vector=True)
    assert image.GetImageDimension() == 2
    image = itk.GetImageViewFromArray(arr, is_vector=True)
    assert image.GetImageDimension() == 2