Beispiel #1
0
def test_plot_2d_diffeomorphic_map():
    # Test the regtools plotting interface (lightly).
    mv_shape = (11, 12)
    moving = np.random.rand(*mv_shape)
    st_shape = (13, 14)
    static = np.random.rand(*st_shape)
    dim = static.ndim
    metric = SSDMetric(dim)
    level_iters = [200, 100, 50, 25]
    sdr = SymmetricDiffeomorphicRegistration(metric,
                                             level_iters,
                                             inv_iter=50)
    mapping = sdr.optimize(static, moving)
    # Smoke testing of plots
    ff = regtools.plot_2d_diffeomorphic_map(mapping, 10)
    # Defualt shape is static shape, moving shape
    npt.assert_equal(ff[0].shape, st_shape)
    npt.assert_equal(ff[1].shape, mv_shape)
    # Can specify shape
    ff = regtools.plot_2d_diffeomorphic_map(mapping,
                                            delta = 10,
                                            direct_grid_shape=(7, 8),
                                            inverse_grid_shape=(9, 10))
    npt.assert_equal(ff[0].shape, (7, 8))
    npt.assert_equal(ff[1].shape, (9, 10))
Beispiel #2
0
 def __init__(self,
              iter_limits=[[64, 32, 8, 2], [128, 64, 32, 8]],
              interpolation='nearest',
              metric='SSD',
              mode='flip',
              always_apply=False,
              p=0.75):
     super(Diffeomorph, self).__init__(always_apply, p)
     self.iter_limits = iter_limits
     self.interpolation = interpolation
     if metric == 'SSD':
         self.metric = SSDMetric(dim=2)
     else:
         raise NotImplementedError
     self.mode = mode
Beispiel #3
0
    def run(self,
            static_image_files,
            moving_image_files,
            prealign_file='',
            inv_static=False,
            level_iters=[10, 10, 5],
            metric="cc",
            mopt_sigma_diff=2.0,
            mopt_radius=4,
            mopt_smooth=0.0,
            mopt_inner_iter=0.0,
            mopt_q_levels=256,
            mopt_double_gradient=True,
            mopt_step_type='',
            step_length=0.25,
            ss_sigma_factor=0.2,
            opt_tol=1e-5,
            inv_iter=20,
            inv_tol=1e-3,
            out_dir='',
            out_warped='warped_moved.nii.gz',
            out_inv_static='inc_static.nii.gz',
            out_field='displacement_field.nii.gz'):
        """
        Parameters
        ----------
        static_image_files : string
            Path of the static image file.

        moving_image_files : string
            Path to the moving image file.

        prealign_file : string, optional
            The text file containing pre alignment information via an
             affine matrix.

        inv_static : boolean, optional
            Apply the inverse mapping to the static image (default 'False').

        level_iters : variable int, optional
            The number of iterations at each level of the gaussian pyramid.
             By default, a 3-level scale space with iterations
             sequence equal to [10, 10, 5] will be used. The 0-th
             level corresponds to the finest resolution.

        metric : string, optional
            The metric to be used (Default cc, 'Cross Correlation metric').
            metric available: cc (Cross Correlation), ssd (Sum Squared
            Difference), em (Expectation-Maximization).

        mopt_sigma_diff : float, optional
            Metric option applied on Cross correlation (CC).
            The standard deviation of the Gaussian smoothing kernel to be
            applied to the update field at each iteration (default 2.0)

        mopt_radius : int, optional
            Metric option applied on Cross correlation (CC).
            the radius of the squared (cubic) neighborhood at each voxel to
            be considered to compute the cross correlation. (default 4)

        mopt_smooth : float, optional
            Metric option applied on Sum Squared Difference (SSD) and
            Expectation Maximization (EM). Smoothness parameter, the
            larger the value the smoother the deformation field.
            (default 1.0 for EM, 4.0 for SSD)

        mopt_inner_iter : int, optional
            Metric option applied on Sum Squared Difference (SSD) and
            Expectation Maximization (EM). This is number of iterations to be
            performed at each level of the multi-resolution Gauss-Seidel
            optimization algorithm (this is not the number of steps per
            Gaussian Pyramid level, that parameter must be set for the
            optimizer, not the metric). Default 5 for EM, 10 for SSD.

        mopt_q_levels : int, optional
            Metric option applied on Expectation Maximization (EM).
            Number of quantization levels (Default: 256 for EM)

        mopt_double_gradient : bool, optional
            Metric option applied on Expectation Maximization (EM).
            if True, the gradient of the expected static image under the moving
            modality will be added to the gradient of the moving image,
            similarly, the gradient of the expected moving image under the
            static modality will be added to the gradient of the static image.

        mopt_step_type : string, optional
            Metric option applied on Sum Squared Difference (SSD) and
            Expectation Maximization (EM). The optimization schedule to be
            used in the multi-resolution Gauss-Seidel optimization algorithm
            (not used if Demons Step is selected). Possible value:
            ('gauss_newton', 'demons'). default: 'gauss_newton' for EM,
            'demons' for SSD.

        step_length : float, optional
            the length of the maximum displacement vector of the update
             displacement field at each iteration.

        ss_sigma_factor : float, optional
            parameter of the scale-space smoothing kernel. For example, the
             std. dev. of the kernel will be factor*(2^i) in the isotropic case
             where i = 0, 1, ..., n_scales is the scale.

        opt_tol : float, optional
            the optimization will stop when the estimated derivative of the
             energy profile w.r.t. time falls below this threshold.

        inv_iter : int, optional
            the number of iterations to be performed by the displacement field
             inversion algorithm.

        inv_tol : float, optional
            the displacement field inversion algorithm will stop iterating
             when the inversion error falls below this threshold.

        out_dir : string, optional
            Directory to save the transformed files (default '').

        out_warped : string, optional
            Name of the warped file. (default 'warped_moved.nii.gz').

        out_inv_static : string, optional
            Name of the file to save the static image after applying the
             inverse mapping (default 'inv_static.nii.gz').

        out_field : string, optional
            Name of the file to save the diffeomorphic map.
            (default 'displacement_field.nii.gz')

        """
        io_it = self.get_io_iterator()
        metric = metric.lower()
        if metric not in ['ssd', 'cc', 'em']:
            raise ValueError("Invalid similarity metric: Please"
                             " provide a valid metric like 'ssd', 'cc', 'em'")

        logging.info("Starting Diffeomorphic Registration")
        logging.info('Using {0} Metric'.format(metric.upper()))

        # Init parameter if they are not setup
        init_param = {
            'ssd': {
                'mopt_smooth': 4.0,
                'mopt_inner_iter': 10,
                'mopt_step_type': 'demons'
            },
            'em': {
                'mopt_smooth': 1.0,
                'mopt_inner_iter': 5,
                'mopt_step_type': 'gauss_newton'
            }
        }
        mopt_smooth = mopt_smooth or init_param[metric]['mopt_smooth']
        mopt_inner_iter = mopt_inner_iter or  \
            init_param[metric]['mopt_inner_iter']
        mopt_step_type = mopt_step_type or \
            init_param[metric]['mopt_step_type']

        for (static_file, moving_file, owarped_file, oinv_static_file,
             omap_file) in io_it:

            logging.info('Loading static file {0}'.format(static_file))
            logging.info('Loading moving file {0}'.format(moving_file))

            # Loading the image data from the input files into object.
            static_image, static_grid2world = load_nifti(static_file)
            moving_image, moving_grid2world = load_nifti(moving_file)

            # Sanity check for the input image dimensions.
            check_dimensions(static_image, moving_image)

            # Loading the affine matrix.
            prealign = np.loadtxt(prealign_file) if prealign_file else None

            l_metric = {
                "ssd":
                SSDMetric(static_image.ndim,
                          smooth=mopt_smooth,
                          inner_iter=mopt_inner_iter,
                          step_type=mopt_step_type),
                "cc":
                CCMetric(static_image.ndim,
                         sigma_diff=mopt_sigma_diff,
                         radius=mopt_radius),
                "em":
                EMMetric(static_image.ndim,
                         smooth=mopt_smooth,
                         inner_iter=mopt_inner_iter,
                         step_type=mopt_step_type,
                         q_levels=mopt_q_levels,
                         double_gradient=mopt_double_gradient)
            }

            current_metric = l_metric.get(metric.lower())

            sdr = SymmetricDiffeomorphicRegistration(
                metric=current_metric,
                level_iters=level_iters,
                step_length=step_length,
                ss_sigma_factor=ss_sigma_factor,
                opt_tol=opt_tol,
                inv_iter=inv_iter,
                inv_tol=inv_tol)

            mapping = sdr.optimize(static_image, moving_image,
                                   static_grid2world, moving_grid2world,
                                   prealign)

            mapping_data = np.array([mapping.forward.T, mapping.backward.T]).T
            warped_moving = mapping.transform(moving_image)

            # Saving
            logging.info('Saving warped {0}'.format(owarped_file))
            save_nifti(owarped_file, warped_moving, static_grid2world)
            logging.info('Saving Diffeomorphic map {0}'.format(omap_file))
            save_nifti(omap_file, mapping_data, mapping.codomain_world2grid)
Beispiel #4
0
show_images(img_ref, img_in, 'input')
"""
.. figure:: input.png
   :align: center

   Input images before alignment.
"""
"""
Let's use the general Registration function with some naive parameters,
such as set `step_length` as 1 assuming maximal step 1 pixel and a reasonably
small number of iterations since the deformation with already aligned images
should be minimal.
"""

sdr = SymmetricDiffeomorphicRegistration(metric=SSDMetric(img_ref.ndim),
                                         step_length=1.0,
                                         level_iters=[50, 100],
                                         inv_iter=50,
                                         ss_sigma_factor=0.1,
                                         opt_tol=1.e-3)
"""
Perform the registration with equal images.
"""

mapping = sdr.optimize(img_ref.astype(float), img_ref.astype(float))
img_warp = mapping.transform(img_ref, 'linear')
show_images(img_ref, img_warp, 'output-0')
regtools.plot_2d_diffeomorphic_map(mapping, 5, 'map-0.png')
"""
.. figure:: output-0.png
   :align: center

   Input images.
"""

"""
We want to find an invertible map that transforms the moving image (circle)
into the static image (the C letter).

The first decision we need to make is what similarity metric is appropriate
for our problem. In this example we are using two binary images, so the Sum
of Squared Differences (SSD) is a good choice.
"""

dim = static.ndim
metric = SSDMetric(dim) 

"""
Now we define an instance of the registration class. The SyN algorithm uses
a multi-resolution approach by building a Gaussian Pyramid. We instruct the
registration instance to perform at most $[n_0, n_1, ..., n_k]$ iterations at
each level of the pyramid. The 0-th level corresponds to the finest resolution.
"""

level_iters = [200, 100, 50, 25]

sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, inv_iter = 50)

"""
Now we execute the optimization, which returns a DiffeomorphicMap object,
that can be used to register images back and forth between the static and moving
Beispiel #6
0
def register_demons_sym_diffeom(img_sense,
                                img_ref,
                                smooth_sigma=1.,
                                params=DIPY_DEAMONS_PARAMS,
                                inverse=False,
                                verbose=False):
    """ Register the image and reconstruction from atlas
    on the end we smooth the final deformation by a gaussian filter

    :param ndarray img_sense:
    :param ndarray img_ref:
    :param float smooth_sigma:
    :param dict params:
    :param bool verbose: whether show debug time measurements
    :return tuple(ndarray,ndarray):

    >>> np.random.seed(0)
    >>> img_ref = np.zeros((10, 10), dtype=int)
    >>> img_ref[2:6, 1:7] = 1
    >>> img_ref[5:9, 4:10] = 1
    >>> img_ref
    array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
           [0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
           [0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
           [0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
    >>> from skimage.morphology import erosion, dilation
    >>> img_ref_fuz = np.zeros((10, 10), dtype=float)
    >>> img_ref_fuz[dilation(img_ref, np.ones((3, 3))) == 1] = 0.1
    >>> img_ref_fuz[img_ref == 1] = 0.5
    >>> img_ref_fuz[erosion(img_ref, np.ones((3, 3))) == 1] = 1.0
    >>> img_ref_fuz
    array([[ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ],
           [ 0.1,  0.1,  0.1,  0.1,  0.1,  0.1,  0.1,  0.1,  0. ,  0. ],
           [ 0.1,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5,  0.1,  0. ,  0. ],
           [ 0.1,  0.5,  1. ,  1. ,  1. ,  1. ,  0.5,  0.1,  0. ,  0. ],
           [ 0.1,  0.5,  1. ,  1. ,  1. ,  1. ,  0.5,  0.1,  0.1,  0.1],
           [ 0.1,  0.5,  0.5,  0.5,  0.5,  1. ,  0.5,  0.5,  0.5,  0.5],
           [ 0.1,  0.1,  0.1,  0.1,  0.5,  1. ,  1. ,  1. ,  1. ,  1. ],
           [ 0. ,  0. ,  0. ,  0.1,  0.5,  1. ,  1. ,  1. ,  1. ,  1. ],
           [ 0. ,  0. ,  0. ,  0.1,  0.5,  0.5,  0.5,  0.5,  0.5,  0.5],
           [ 0. ,  0. ,  0. ,  0.1,  0.1,  0.1,  0.1,  0.1,  0.1,  0.1]])
    >>> d_deform = register_demons_sym_diffeom(img_ref_fuz, img_ref,
    ...                         smooth_sigma=1.5, inverse=True, verbose=True)
    >>> img_warp = warp2d_transform_image(img_ref, d_deform, method='nearest',
    ...                                   inverse=True)
    >>> np.round(img_warp.astype(float), 1)
    array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
           [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
           [ 0.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.],
           [ 0.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.],
           [ 0.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.],
           [ 0.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  1.,  1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  1.,  1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  1.,  1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])
    >>> img_sense = np.zeros(img_ref.shape, dtype=int)
    >>> img_sense[4:9, 3:10] = 1
    >>> img_sense
    array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
    >>> d_deform = register_demons_sym_diffeom(img_sense, img_ref, smooth_sigma=0.)
    >>> img_warp = warp2d_transform_image(img_sense, d_deform)
    >>> np.round(img_warp.astype(float), 1)  # doctest: +SKIP
    array([[ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ],
           [ 0. ,  0.3,  0.5,  0.3,  0.1,  0. ,  0. ,  0. ,  0. ,  0. ],
           [ 0. ,  1. ,  1. ,  1. ,  1. ,  0.8,  0.4,  0.1,  0. ,  0. ],
           [ 0. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ,  0.5,  0. ],
           [ 0. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ],
           [ 0. ,  0.2,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ],
           [ 0. ,  0. ,  0.6,  0.9,  1. ,  1. ,  1. ,  1. ,  1. ,  1. ],
           [ 0. ,  0. ,  0.2,  0.4,  0.5,  0.8,  1. ,  1. ,  1. ,  1. ],
           [ 0. ,  0. ,  0. ,  0.2,  0.2,  0.3,  0.4,  0.6,  0.7,  1. ],
           [ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ]])
    >>> np.round(img_warp - img_sense, 1)  # doctest: +SKIP
    """
    if img_ref.max() == 0 or img_sense.max() == 0:
        logging.debug(
            'skip image registration (demons): max values for '
            'RECONST=%d and SENSE=%d', img_ref.max(), img_sense.max())
        return {'mapping': None, 'mapping-inv': None, 'package': 'dipy'}

    sdr_params = {k: params[k] for k in params if k in LIST_SDR_PARAMS}
    sdr = SmoothSymmetricDiffeomorphicRegistration(metric=SSDMetric(
        img_ref.ndim),
                                                   smooth_sigma=smooth_sigma,
                                                   **sdr_params)
    sdr.verbosity = VerbosityLevels.NONE

    t = time.time()
    mapping = sdr.optimize(img_ref.astype(float), img_sense.astype(float))
    if verbose:
        logging.debug('demons took: %d s', time.time() - t)

    mapping.forward = smooth_deform_field(mapping.forward, sigma=smooth_sigma)
    mapping.backward = smooth_deform_field(mapping.backward,
                                           sigma=smooth_sigma)

    # img_warped = mapping.transform(img_moving, 'linear')

    # mapping_inv = sdr.moving_to_ref
    if inverse:
        mapping_inv = DiffeomorphicMap(img_ref.ndim, img_ref.shape, None,
                                       img_ref.shape, None, img_ref.shape,
                                       None, None)
        mapping_inv.forward = smooth_deform_field(sdr.moving_to_ref.forward,
                                                  sigma=smooth_sigma)
        mapping_inv.backward = smooth_deform_field(sdr.moving_to_ref.backward,
                                                   sigma=smooth_sigma)
    else:
        mapping_inv = None

    if verbose:
        logging.debug('smoothing and warping took: %d s', time.time() - t)

    dict_deform = {
        'mapping': mapping,
        'mapping-inv': mapping_inv,
        'package': 'dipy'
    }

    return dict_deform