Beispiel #1
0
def test_compute_energy_ssd_2d():
    sh = (32, 32)

    #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
    grad_F = X - c_f
    grad_G = X - c_g

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

    # Note: this should include the energy corresponding to the
    # regularization term, but it is discarded in ANTS (they just
    # consider the data term, which is not the objective function
    # being optimized). This test case should be updated after
    # further investigation
    expected = ((F - G)**2).sum()
    actual = ssd.compute_energy_ssd_2d(np.array(F-G, dtype = floating))
    assert_almost_equal(expected, actual)
Beispiel #2
0
def v_cycle_2d(n,
               k,
               delta_field,
               sigma_sq_field,
               gradient_field,
               target,
               lambda_param,
               displacement,
               depth=0):
    r"""Multi-resolution Gauss-Seidel solver using V-type cycles

    Multi-resolution Gauss-Seidel solver: solves the Gauss-Newton linear system
    by first filtering (GS-iterate) the current level, then solves for the
    residual at a coarser resolution and finally refines the solution at the
    current resolution. This scheme corresponds to the V-cycle proposed by
    Bruhn and Weickert[Bruhn05].

    Parameters
    ----------
    n : int
        number of levels of the multi-resolution algorithm (it will be called
        recursively until level n == 0)
    k : int
        the number of iterations at each multi-resolution level
    delta_field : array, shape (R, C)
        the difference between the static and moving image (the 'derivative
        w.r.t. time' in the optical flow model)
    sigma_sq_field : array, shape (R, C)
        the variance of the gray level value at each voxel, according to the
        EM model (for SSD, it is 1 for all voxels). Inf and 0 values
        are processed specially to support infinite and zero variance.
    gradient_field : array, shape (R, C, 2)
        the gradient of the moving image
    target : array, shape (R, C, 2)
        right-hand side of the linear system to be solved in the Weickert's
        multi-resolution algorithm
    lambda_param : float
        smoothness parameter, the larger its value the smoother the
        displacement field
    displacement : array, shape (R, C, 2)
        the displacement field to start the optimization from

    Returns
    -------
    energy : the energy of the EM (or SSD if sigmafield[...]==1) metric at this
        iteration

    References
    ----------
    [Bruhn05] Andres Bruhn and Joachim Weickert, "Towards ultimate motion
              estimation: combining highest accuracy with real-time
              performance", 10th IEEE International Conference on Computer
              Vision, 2005. ICCV 2005.
    """
    # pre-smoothing
    for i in range(k):
        ssd.iterate_residual_displacement_field_ssd_2d(delta_field,
                                                       sigma_sq_field,
                                                       gradient_field, target,
                                                       lambda_param,
                                                       displacement)
    if n == 0:
        energy = ssd.compute_energy_ssd_2d(delta_field)
        return energy

    # solve at coarser grid
    residual = None
    residual = ssd.compute_residual_displacement_field_ssd_2d(
        delta_field, sigma_sq_field, gradient_field, target, lambda_param,
        displacement, residual)
    sub_residual = np.array(vfu.downsample_displacement_field_2d(residual))
    del residual
    subsigma_sq_field = None
    if sigma_sq_field is not None:
        subsigma_sq_field = vfu.downsample_scalar_field_2d(sigma_sq_field)
    subdelta_field = vfu.downsample_scalar_field_2d(delta_field)

    subgradient_field = np.array(
        vfu.downsample_displacement_field_2d(gradient_field))

    shape = np.array(displacement.shape).astype(np.int32)
    half_shape = ((shape[0] + 1) // 2, (shape[1] + 1) // 2, 2)
    sub_displacement = np.zeros(shape=half_shape, dtype=floating)
    sublambda_param = lambda_param * 0.25
    v_cycle_2d(n - 1, k, subdelta_field, subsigma_sq_field, subgradient_field,
               sub_residual, sublambda_param, sub_displacement, depth + 1)
    # displacement += np.array(
    #    vfu.upsample_displacement_field(sub_displacement, shape))
    displacement += vfu.resample_displacement_field_2d(sub_displacement,
                                                       np.array([0.5, 0.5]),
                                                       shape)

    # post-smoothing
    for i in range(k):
        ssd.iterate_residual_displacement_field_ssd_2d(delta_field,
                                                       sigma_sq_field,
                                                       gradient_field, target,
                                                       lambda_param,
                                                       displacement)
    energy = ssd.compute_energy_ssd_2d(delta_field)
    return energy
Beispiel #3
0
def v_cycle_2d(n, k, delta_field, sigma_sq_field, gradient_field, target,
               lambda_param, displacement, depth=0):
    r"""Multi-resolution Gauss-Seidel solver using V-type cycles

    Multi-resolution Gauss-Seidel solver: solves the Gauss-Newton linear system
    by first filtering (GS-iterate) the current level, then solves for the
    residual at a coarser resolution and finally refines the solution at the
    current resolution. This scheme corresponds to the V-cycle proposed by
    Bruhn and Weickert[Bruhn05].

    Parameters
    ----------
    n : int
        number of levels of the multi-resolution algorithm (it will be called
        recursively until level n == 0)
    k : int
        the number of iterations at each multi-resolution level
    delta_field : array, shape (R, C)
        the difference between the static and moving image (the 'derivative
        w.r.t. time' in the optical flow model)
    sigma_sq_field : array, shape (R, C)
        the variance of the gray level value at each voxel, according to the
        EM model (for SSD, it is 1 for all voxels). Inf and 0 values
        are processed specially to support infinite and zero variance.
    gradient_field : array, shape (R, C, 2)
        the gradient of the moving image
    target : array, shape (R, C, 2)
        right-hand side of the linear system to be solved in the Weickert's
        multi-resolution algorithm
    lambda_param : float
        smoothness parameter, the larger its value the smoother the
        displacement field
    displacement : array, shape (R, C, 2)
        the displacement field to start the optimization from

    Returns
    -------
    energy : the energy of the EM (or SSD if sigmafield[...]==1) metric at this
        iteration

    References
    ----------
    [Bruhn05] Andres Bruhn and Joachim Weickert, "Towards ultimate motion
              estimation: combining highest accuracy with real-time
              performance", 10th IEEE International Conference on Computer
              Vision, 2005. ICCV 2005.
    """
    # pre-smoothing
    for i in range(k):
        ssd.iterate_residual_displacement_field_ssd_2d(delta_field,
                                                       sigma_sq_field,
                                                       gradient_field,
                                                       target,
                                                       lambda_param,
                                                       displacement)
    if n == 0:
        energy = ssd.compute_energy_ssd_2d(delta_field)
        return energy

    # solve at coarser grid
    residual = None
    residual = ssd.compute_residual_displacement_field_ssd_2d(delta_field,
                                                              sigma_sq_field,
                                                              gradient_field,
                                                              target,
                                                              lambda_param,
                                                              displacement,
                                                              residual)
    sub_residual = np.array(vfu.downsample_displacement_field_2d(residual))
    del residual
    subsigma_sq_field = None
    if sigma_sq_field is not None:
        subsigma_sq_field = vfu.downsample_scalar_field_2d(sigma_sq_field)
    subdelta_field = vfu.downsample_scalar_field_2d(delta_field)

    subgradient_field = np.array(
        vfu.downsample_displacement_field_2d(gradient_field))

    shape = np.array(displacement.shape).astype(np.int32)
    half_shape = ((shape[0] + 1) // 2, (shape[1] + 1) // 2, 2)
    sub_displacement = np.zeros(shape=half_shape,
                                dtype=floating)
    sublambda_param = lambda_param*0.25
    v_cycle_2d(n-1, k, subdelta_field, subsigma_sq_field, subgradient_field,
               sub_residual, sublambda_param, sub_displacement, depth+1)
    # displacement += np.array(
    #    vfu.upsample_displacement_field(sub_displacement, shape))
    displacement += vfu.resample_displacement_field_2d(sub_displacement,
                                                       np.array([0.5, 0.5]),
                                                       shape)

    # post-smoothing
    for i in range(k):
        ssd.iterate_residual_displacement_field_ssd_2d(delta_field,
                                                       sigma_sq_field,
                                                       gradient_field,
                                                       target,
                                                       lambda_param,
                                                       displacement)
    energy = ssd.compute_energy_ssd_2d(delta_field)
    return energy