Beispiel #1
0
    def compute_demons_step(self, forward_step=True):
        r"""Demons step for SSD metric

        Computes the demons step proposed by Vercauteren et al.[Vercauteren09]
        for the SSD metric.

        Parameters
        ----------
        forward_step : boolean
            if True, computes the Demons step in the forward direction
            (warping the moving towards the static image). If False,
            computes the backward step (warping the static image to the
            moving image)

        Returns
        -------
        displacement : array, shape (R, C, 2) or (S, R, C, 3)
            the Demons step

        References
        ----------
        [Vercauteren09] Tom Vercauteren, Xavier Pennec, Aymeric Perchant,
                        Nicholas Ayache, "Diffeomorphic Demons: Efficient
                        Non-parametric Image Registration", Neuroimage 2009
        """
        sigma_reg_2 = np.sum(self.static_spacing**2)/self.dim

        if forward_step:
            gradient = self.gradient_static
            delta_field = self.static_image - self.moving_image
        else:
            gradient = self.gradient_moving
            delta_field = self.moving_image - self.static_image

        if self.dim == 2:
            step, self.energy = ssd.compute_ssd_demons_step_2d(delta_field,
                                                               gradient,
                                                               sigma_reg_2,
                                                               None)
        else:
            step, self.energy = ssd.compute_ssd_demons_step_3d(delta_field,
                                                               gradient,
                                                               sigma_reg_2,
                                                               None)
        for i in range(self.dim):
            step[..., i] = ndimage.filters.gaussian_filter(step[..., i],
                                                           self.smooth)
        return step
Beispiel #2
0
    def compute_demons_step(self, forward_step=True):
        r"""Demons step for SSD metric

        Computes the demons step proposed by Vercauteren et al.[Vercauteren09]
        for the SSD metric.

        Parameters
        ----------
        forward_step : boolean
            if True, computes the Demons step in the forward direction
            (warping the moving towards the static image). If False,
            computes the backward step (warping the static image to the
            moving image)

        Returns
        -------
        displacement : array, shape (R, C, 2) or (S, R, C, 3)
            the Demons step

        References
        ----------
        [Vercauteren09] Tom Vercauteren, Xavier Pennec, Aymeric Perchant,
                        Nicholas Ayache, "Diffeomorphic Demons: Efficient
                        Non-parametric Image Registration", Neuroimage 2009
        """
        sigma_reg_2 = np.sum(self.static_spacing**2)/self.dim

        if forward_step:
            gradient = self.gradient_static
            delta_field = self.static_image - self.moving_image
        else:
            gradient = self.gradient_moving
            delta_field = self.moving_image - self.static_image

        if self.dim == 2:
            step, self.energy = ssd.compute_ssd_demons_step_2d(delta_field,
                                                               gradient,
                                                               sigma_reg_2,
                                                               None)
        else:
            step, self.energy = ssd.compute_ssd_demons_step_3d(delta_field,
                                                               gradient,
                                                               sigma_reg_2,
                                                               None)
        for i in range(self.dim):
            step[..., i] = ndimage.filters.gaussian_filter(step[..., i],
                                                           self.smooth)
        return step
Beispiel #3
0
def test_compute_ssd_demons_step_2d():
    r"""
    Compares the output of the demons step in 2d against an analytical
    step. The fixed image is given by $F(x) = \frac{1}{2}||x - c_f||^2$, the
    moving image is given by $G(x) = \frac{1}{2}||x - c_g||^2$,
    $x, c_f, c_g \in R^{2}$

    References
    ----------
    [Vercauteren09] Vercauteren, T., Pennec, X., Perchant, A., & Ayache, N.
                    (2009). Diffeomorphic demons: efficient non-parametric
                    image registration. NeuroImage, 45(1 Suppl), S61-72.
                    doi:10.1016/j.neuroimage.2008.10.040
    """
    #Select arbitrary images' shape (same shape for both images)
    sh = (20, 10)

    #Select arbitrary centers
    c_f = np.asarray(sh)/2
    c_g = c_f + 0.5

    #Compute the identity vector field I(x) = x in R^2
    x_0 = np.asarray(range(sh[0]))
    x_1 = np.asarray(range(sh[1]))
    X = np.ndarray(sh + (2,), dtype = np.float64)
    O = np.ones(sh)
    X[...,0]= x_0[:, None] * O
    X[...,1]= x_1[None, :] * O

    #Compute the gradient fields of F and G
    np.random.seed(1137271)

    grad_F = X - c_f
    grad_G = X - c_g

    Fnoise = np.random.ranf(np.size(grad_F)).reshape(grad_F.shape) * grad_F.max() * 0.1
    Fnoise = Fnoise.astype(floating)
    grad_F += Fnoise

    Gnoise = np.random.ranf(np.size(grad_G)).reshape(grad_G.shape) * grad_G.max() * 0.1
    Gnoise = Gnoise.astype(floating)
    grad_G += Gnoise

    #The squared norm of grad_G to be used later
    sq_norm_grad_G = np.sum(grad_G**2,-1)

    #Compute F and G
    F = 0.5*np.sum(grad_F**2,-1)
    G = 0.5*sq_norm_grad_G

    Fnoise = np.random.ranf(np.size(F)).reshape(F.shape) * F.max() * 0.1
    Fnoise = Fnoise.astype(floating)
    F += Fnoise

    Gnoise = np.random.ranf(np.size(G)).reshape(G.shape) * G.max() * 0.1
    Gnoise = Gnoise.astype(floating)
    G += Gnoise

    delta_field =  np.array(G - F, dtype = floating)

    #Select some pixels to force gradient = 0 and F=G
    random_labels = np.random.randint(0, 2, sh[0]*sh[1])
    random_labels = random_labels.reshape(sh)

    F[random_labels == 0] = G[random_labels == 0]
    delta_field[random_labels == 0] = 0
    grad_G[random_labels == 0, ...] = 0
    sq_norm_grad_G[random_labels == 0, ...] = 0

    #Set arbitrary values for $\sigma_i$ (eq. 4 in [Vercauteren09])
    #The original Demons algorithm used simply |F(x) - G(x)| as an
    #estimator, so let's use it as well
    sigma_i_sq = (F - G)**2

    #Now select arbitrary parameters for $\sigma_x$ (eq 4 in [Vercauteren09])
    for sigma_x_sq in [0.01, 1.5, 4.2]:
        #Directly compute the demons step according to eq. 4 in [Vercauteren09]
        num = (sigma_x_sq * (F - G))[random_labels == 1]
        den = (sigma_x_sq * sq_norm_grad_G + sigma_i_sq)[random_labels == 1]
        expected = (-1 * np.array(grad_G)) #This is $J^{P}$ in eq. 4 [Vercauteren09]
        expected[random_labels == 1, 0] *= num / den
        expected[random_labels == 1, 1] *= num / den
        expected[random_labels == 0, ...] = 0

        #Now compute it using the implementation under test
        actual = np.empty_like(expected, dtype=floating)

        ssd.compute_ssd_demons_step_2d(delta_field,
                                       np.array(grad_G, dtype=floating),
                                       sigma_x_sq,
                                       actual)

        assert_array_almost_equal(actual, expected)