Пример #1
0
def cmscr1d_img_pb(img: np.array,
                   alpha0: float, alpha1: float,
                   alpha2: float, alpha3: float,
                   beta: float, deriv='mesh') \
                   -> (np.array, np.array, float, float, bool):
    """Computes the L2-H1 mass conserving flow with source for a 1D image
    sequence with spatio-temporal and convective regularisation with periodic
    spatial boundary.

    Args:
        img (np.array): 1D image sequence of shape (m, n), where m is the
                        number of time steps and n is the number of pixels.
        alpha0 (float): The spatial regularisation parameter for v.
        alpha1 (float): The temporal regularisation parameter for v.
        alpha2 (float): The spatial regularisation parameter for k.
        alpha3 (float): The temporal regularisation parameter for k.
        beta (float): The convective regularisation parameter.
        deriv (str): Specifies how to approximate pertial derivatives.
                     When set to 'mesh' it uses FEniCS built in function.

    Returns:
        v (np.array): A velocity array of shape (m, n).
        k (np.array): A source array of shape (m, n).
        res (float): The residual.
        fun (float): The function value.
        converged (bool): True if Newton's method converged.

    """
    # Check for valid arguments.
    valid = {'mesh'}
    if deriv not in valid:
        raise ValueError("Argument 'deriv' must be one of %r." % valid)

    # Create mesh.
    m, n = img.shape
    mesh = UnitSquareMesh(m - 1, n - 1)

    # Define function space.
    V = dh.create_function_space(mesh, 'periodic')
    W = dh.create_vector_function_space(mesh, 'periodic')

    # Convert array to function.
    f = Function(V)
    f.vector()[:] = dh.img2funvec_pb(img)

    # Compute partial derivatives.
    ft, fx = f.dx(0), f.dx(1)

    # Compute velocity.
    v, k, res, fun, converged = cmscr1d_weak_solution(W, f, ft, fx, alpha0,
                                                      alpha1, alpha2, alpha3,
                                                      beta)

    # Convert back to array and return.
    v = dh.funvec2img(v.vector().get_local(), m, n)
    k = dh.funvec2img(k.vector().get_local(), m, n)
    return v, k, res, fun, converged
Пример #2
0
def cm1d_exp(m: int, n: int, f: Expression, ft: Expression, fx: Expression,
             alpha0: float, alpha1: float) -> np.array:
    """Computes the L2-H1 mass conserving flow for a 1D image sequence.

    Args:
        m (int): Number of temporal sampling points.
        n (int): Number of spatial sampling points.
        f (Expression): 1D image sequence.
        ft (Expression): Partial derivative of f wrt. time.
        fx (Expression): Partial derivative of f wrt. space.
        alpha0 (float): Spatial regularisation parameter.
        alpha1 (float): Temporal regularisation parameter.

    Returns:
        v (np.array): A velocity array of shape (m, n).
        res (float): The residual.
        func (float): The value of the functional.

    """
    # Define mesh and function space.
    mesh = UnitSquareMesh(m - 1, n - 1)
    V = dh.create_function_space(mesh, 'default')

    # Compute velocity.
    v, res, fun = cm1d_weak_solution(V, f, ft, fx, alpha0, alpha1)

    # Convert to array and return.
    return dh.funvec2img(v.vector().get_local(), m, n), res, fun
Пример #3
0
def of1d_exp(m: int, n: int,
             f: Expression, ft: Expression, fx: Expression,
             alpha0: float, alpha1) -> (np.array, float, float):
    """Computes the L2-H1 optical flow for a 1D image sequence.

    Takes a one-dimensional image sequence and partial derivatives, and returns
    a minimiser of the Horn-Schunck functional with spatio-temporal
    regularisation.

    Args:
        m (int): Number of temporal sampling points.
        n (int): Number of spatial sampling points.
        f (Expression): 1D image sequence.
        ft (Expression): Partial derivative of f wrt. time.
        fx (Expression): Partial derivative of f wrt. space.
        alpha0 (float): Spatial regularisation parameter.
        alpha1 (float): Temporal regularisation parameter.

    Returns:
        v (np.array): A velocity array of shape (m, n).
        res (float): The residual.
        fun (float): The function value.
    """
    # Define mesh and function space.
    mesh = UnitSquareMesh(m - 1, n - 1)
    V = dh.create_function_space(mesh, 'default')

    # Compute velocity.
    v, res, fun = of1d_weak_solution(V, f, ft, fx, alpha0, alpha1)

    # Convert to array and return.
    return dh.funvec2img(v.vector().get_local(), m, n), res, fun
Пример #4
0
    def test_characteristic(self):
        m, n = 100, 100

        # Compute characteristic.
        c = vel.characteristic(m, n, c0, v0, tau0, tau1, 0.6)

        # Compute velocity field.
        v = vel.velocity(m, n, c0, v0, tau0, tau1)

        # Convert to matrix.
        v = dh.funvec2img(v.vector().get_local(), m, n)

        # Plot velocity.
        fig = plt.figure()
        plt.imshow(v, cmap=cm.coolwarm)

        # Plot characteristic.
        y = np.linspace(0, m, m + 1).reshape(m + 1, 1)

        points = np.array([n * c, y]).T.reshape(-1, 1, 2)
        segments = np.concatenate([points[:-1], points[1:]], axis=1)

        lc = LineCollection(segments[:-1])
        lc.set_linewidth(2)
        plt.gca().add_collection(lc)
        plt.show()

        plt.close(fig)
Пример #5
0
def cm1dvelocity(img: np.array, vel: np.array, alpha0: float,
                 alpha1: float) -> np.array:
    """Computes the source for a L2-H1 mass conserving flow for a 1D image
    sequence and a given velocity.

    Takes a one-dimensional image sequence and a velocity, and returns a
    minimiser of the L2-H1 mass conservation functional with spatio-temporal
    regularisation.

    Args:
        img (np.array): A 1D image sequence of shape (m, n), where m is the
                        number of time steps and n is the number of pixels.
        vel (np.array): A 1D image sequence of shape (m, n).
        alpha0 (float): The spatial regularisation parameter.
        alpha1 (float): The temporal regularisation parameter.

    Returns:
        k: A source array of shape (m, n).

    """
    # Create mesh.
    [m, n] = img.shape
    mesh = UnitSquareMesh(m - 1, n - 1)

    # Define function space and functions.
    V = FunctionSpace(mesh, 'CG', 1)
    k = TrialFunction(V)
    w = TestFunction(V)

    # Convert image to function.
    f = Function(V)
    f.vector()[:] = dh.img2funvec(img)

    # Convert velocity to function.
    v = Function(V)
    v.vector()[:] = dh.img2funvec(vel)

    # Define derivatives of data.
    ft = Function(V)
    ftv = np.diff(img, axis=0) * (m - 1)
    ftv = np.concatenate((ftv, ftv[-1, :].reshape(1, n)), axis=0)
    ft.vector()[:] = dh.img2funvec(ftv)

    fx = Function(V)
    fxv = np.gradient(img, 1 / (n - 1), axis=1)
    fx.vector()[:] = dh.img2funvec(fxv)

    # Define weak formulation.
    A = k * w * dx + alpha0 * k.dx(1) * w.dx(1) * dx + alpha1 * k.dx(0) * w.dx(
        0) * dx
    b = (ft + v.dx(1) * f + v * fx) * w * dx

    # Compute solution.
    k = Function(V)
    solve(A == b, k)

    # Convert back to array.
    k = dh.funvec2img(k.vector().get_local(), m, n)
    return k
Пример #6
0
def of1d_img(img: np.array, alpha0: float, alpha1: float, deriv) \
             -> (np.array, float, float):
    """Computes the L2-H1 optical flow for a 1D image sequence.

    Takes a one-dimensional image sequence and returns a minimiser of the
    Horn-Schunck functional with spatio-temporal regularisation.

    Allows to specify how to approximate partial derivatives of f numerically.

    Args:
        img (np.array): 1D image sequence of shape (m, n), where m is the
                        number of time steps and n is the number of pixels.
        alpha0 (float): Spatial regularisation parameter.
        alpha1 (float): Temporal regularisation parameter.
        deriv (str): Specifies how to approximate pertial derivatives.
                     When set to 'mesh' it uses FEniCS built in function.
                     When set to 'fd' it uses finite differences.

    Returns:
        v (np.array): A velocity array of shape (m, n).
        res (float): The residual.
        fun (float): The function value.
    """
    # Check for valid arguments.
    valid = {'mesh', 'fd'}
    if deriv not in valid:
        raise ValueError("Argument 'deriv' must be one of %r." % valid)

    # Create mesh.
    m, n = img.shape
    mesh = UnitSquareMesh(m - 1, n - 1)

    # Define function space.
    V = dh.create_function_space(mesh, 'default')

    # Convert array to function.
    f = Function(V)
    f.vector()[:] = dh.img2funvec(img)

    # Compute partial derivatives.
    if deriv is 'mesh':
        ft, fx = f.dx(0), f.dx(1)
    if deriv is 'fd':
        imgt, imgx = nh.partial_derivatives(img)
        ft, fx = Function(V), Function(V)
        ft.vector()[:] = dh.img2funvec(imgt)
        fx.vector()[:] = dh.img2funvec(imgx)

    # Compute velocity.
    v, res, fun = of1d_weak_solution(V, f, ft, fx, alpha0, alpha1)

    # Convert to array and return.
    return dh.funvec2img(v.vector().get_local(), m, n), res, fun
Пример #7
0
    def test_funvec2img(self):
        m, n = 30, 100

        # Define mesh.
        mesh = UnitSquareMesh(m - 1, n - 1)

        # Define function spaces
        V = FunctionSpace(mesh, 'CG', 1)
        f = project(Constant(1.0), V)

        v = dh.funvec2img(f.vector().get_local(), m, n)
        np.testing.assert_allclose(v, np.ones((m, n)))
Пример #8
0
def cmscr1d_exp_pb(m: int, n: int, f: Expression, ft: Expression,
                   fx: Expression, alpha0: float, alpha1: float, alpha2: float,
                   alpha3: float, beta: float) -> (np.array, np.array, bool):
    """Computes the L2-H1 mass conserving flow with source for a 1D image
    sequence with spatio-temporal and convective regularisation with periodic
    spatial boundary.

    Args:
        m (int): Number of temporal sampling points.
        n (int): Number of spatial sampling points.
        f (Expression): 1D image sequence.
        ft (Expression): Partial derivative of f wrt. time.
        fx (Expression): Partial derivative of f wrt. space.
        alpha0 (float): The spatial regularisation parameter for v.
        alpha1 (float): The temporal regularisation parameter for v.
        alpha2 (float): The spatial regularisation parameter for k.
        alpha3 (float): The temporal regularisation parameter for k.
        beta (float): The convective regularisation parameter.

    Returns:
        v (np.array): A velocity array of shape (m, n).
        k (np.array): A source array of shape (m, n).
        res (float): The residual.
        fun (float): The function value.
        converged (bool): True if Newton's method converged.

    """
    # Define mesh and function space.
    mesh = UnitSquareMesh(m - 1, n - 1)
    V = dh.create_vector_function_space(mesh, 'periodic')

    # Compute velocity.
    v, k, res, fun, converged = cmscr1d_weak_solution(V, f, ft, fx, alpha0,
                                                      alpha1, alpha2, alpha3,
                                                      beta)

    # Convert back to array and return.
    v = dh.funvec2img(v.vector().get_local(), m, n)
    k = dh.funvec2img(k.vector().get_local(), m, n)
    return v, k, res, fun, converged
Пример #9
0
    def test_velocity(self):
        m, n = 100, 100
        v = vel.velocity(m, n, c0, v0, tau0, tau1)

        # Plot velocity.
        plt.figure()
        p = plot(v)
        p.set_cmap("coolwarm")
        plt.colorbar(p)
        plt.show()
        plt.close()

        # Convert to matrix.
        v = dh.funvec2img(v.vector().get_local(), m, n)

        plt.figure()
        plt.imshow(v, cmap=cm.coolwarm)
        plt.show()
        plt.close()
Пример #10
0
def cm1dsource(img: np.array, k: np.array, alpha0: float,
               alpha1: float) -> np.array:
    """Computes the L2-H1 mass conserving flow for a 1D image sequence and a
    given source.

    Takes a one-dimensional image sequence and a source, and returns a
    minimiser of the L2-H1 mass conservation functional with spatio-temporal
    regularisation.

    Args:
        img (np.array): A 1D image sequence of shape (m, n), where m is the
                        number of time steps and n is the number of pixels.
        k (np.array):   A 1D image sequence of shape (m, n).
        alpha0 (float): The spatial regularisation parameter.
        alpha1 (float): The temporal regularisation parameter.

    Returns:
        v: A velocity array of shape (m, n).

    """
    # Create mesh.
    [m, n] = img.shape
    mesh = UnitSquareMesh(m - 1, n - 1)

    # Define function space and functions.
    V = FunctionSpace(mesh, 'CG', 1)
    v = TrialFunction(V)
    w = TestFunction(V)

    # Convert image to function.
    f = Function(V)
    f.vector()[:] = dh.img2funvec(img)

    # Convert source to function.
    g = Function(V)
    g.vector()[:] = dh.img2funvec(k)

    # Define derivatives of data.
    ft = Function(V)
    ftv = np.diff(img, axis=0) * (m - 1)
    ftv = np.concatenate((ftv, ftv[-1, :].reshape(1, n)), axis=0)
    ft.vector()[:] = dh.img2funvec(ftv)

    fx = Function(V)
    fxv = np.gradient(img, 1 / (n - 1), axis=1)
    fx.vector()[:] = dh.img2funvec(fxv)

    ft = f.dx(0)
    fx = f.dx(1)

    # Define weak formulation.
    A = - (fx*v + f*v.dx(1)) * (fx*w + f*w.dx(1))*dx \
        - alpha0*v.dx(1)*w.dx(1)*dx - alpha1*v.dx(0)*w.dx(0)*dx
    b = ft * (fx * w + f * w.dx(1)) * dx - g * (fx * w + f * w.dx(1)) * dx

    # Compute solution.
    v = Function(V)
    solve(A == b, v)

    # Convert back to array.
    vel = dh.funvec2img(v.vector().get_local(), m, n)
    return vel
Пример #11
0
name = 'artificial'

# Define temporal and spacial number of cells.
m, n = 40, 200

# Define parameters of artificial velocity field.
c0 = 0.05
v0 = 0.5
tau0 = 0.5
tau1 = 0.5

# Create artificial velocity.
v = velocity(m, n, c0, v0, tau0, tau1)

# Convert to array.
v = funvec2img(v.vector().get_local(), m, n)

# Define mesh.
mesh = UnitIntervalMesh(n - 1)

# Define function spaces
V = FunctionSpace(mesh, 'CG', 1)


class DoubleHat(UserExpression):
    def eval(self, value, x):
        value[0] = max(0, 0.1 - abs(x[0] - 0.4)) \
            + max(0, 0.1 - abs(x[0] - 0.6))

    def value_shape(self):
        return ()
Пример #12
0
# Create mesh and function spaces.
m, n = 40, 100
mesh = UnitSquareMesh(m - 1, n - 1)
V = dh.create_function_space(mesh, 'default')
W = dh.create_function_space(mesh, 'periodic')

# Run experiments with decaying data.
f = f_decay(degree=2)
ft = f_decay_t(degree=1)
fx = f_decay_x(degree=1)
datastr = DecayingData().string()

# Interpolate function.
fa = interpolate(f, V)
fa = dh.funvec2img(fa.vector().get_local(), m, n)

fa_pb = interpolate(f, W)
fa_pb = dh.funvec2img_pb(fa_pb.vector().get_local(), m, n)

v, res, fun = cm1d_exp_pb(m, n, f, ft, fx, alpha0, alpha1)
saveresults(resultpath, 'decay_cm1d_l2h1_exp_pb', 'l2h1', fa_pb, v)

v, k, res, fun, converged = cmscr1d_exp_pb(m, n, f, ft, fx, alpha0, alpha1,
                                           alpha2, alpha3, beta)
saveresults(resultpath, 'decay_cmscr1d_l2h1h1cr_exp_pb', 'l2h1h1cr', fa_pb, v,
            k, (c0 - fa_pb) / tau)


# The next example shows that for the initial concentration used in the
# mechanical models the algorithm picks up the source well.
Пример #13
0
            'l2h1h1cr', f, v, k, (c0 - f) / tau)

v, k, res, fun, converged = cmscr1d_img_pb(f, alpha0, alpha1, alpha2, alpha3,
                                           beta, 'mesh')
saveresults(resultpath, 'analytic_example_decay_cmscr1d_l2h1h1cr_img_pb',
            'l2h1h1cr', f, v, k, (c0 - f) / tau)

# Run experiments with constant data.
f = f_const(degree=2)
ft = f_const_t(degree=1)
fx = f_const_x(degree=1)
datastr = ConstantData().string()

# Interpolate function.
fa = interpolate(f, V)
fa = dh.funvec2img(fa.vector().get_local(), m, n)

fa_pb = interpolate(f, W)
fa_pb = dh.funvec2img_pb(fa_pb.vector().get_local(), m, n)

v, res, fun = of1d_exp(m, n, f, ft, fx, alpha0, alpha1)
saveresults(resultpath, 'analytic_example_const_of1d_l2h1_exp', 'l2h1', fa, v)

v, res, fun = of1d_exp_pb(m, n, f, ft, fx, alpha0, alpha1)
saveresults(resultpath, 'analytic_example_const_of1d_l2h1_exp_pb', 'l2h1',
            fa_pb, v)

v, res, fun = cm1d_exp(m, n, f, ft, fx, alpha0, alpha1)
saveresults(resultpath, 'analytic_example_const_cm1d_l2h1_exp', 'l2h1', fa, v)

v, res, fun = cm1d_exp_pb(m, n, f, ft, fx, alpha0, alpha1)
Пример #14
0
 def test_img2fun_fun2img(self):
     m, n = 7, 13
     img = np.random.rand(m, n)
     v = dh.img2funvec(img)
     np.testing.assert_allclose(dh.funvec2img(v, m, n), img)
Пример #15
0
def cmscr1dnewton(img: np.array, alpha0: float, alpha1: float, alpha2: float,
                  alpha3: float, beta: float) \
                  -> (np.array, np.array, float, float, bool):
    """Same as cmscr1d but doesn't use FEniCS Newton method.

    Args:
        img (np.array): A 1D image sequence of shape (m, n), where m is the
                        number of time steps and n is the number of pixels.
        alpha0 (float): The spatial regularisation parameter for v.
        alpha1 (float): The temporal regularisation parameter for v.
        alpha2 (float): The spatial regularisation parameter for k.
        alpha3 (float): The temporal regularisation parameter for k.
        beta (float): The parameter for convective regularisation.

    Returns:
        v: A velocity array of shape (m, n).
        k: A source array of shape (m, n).
        res (float): The residual.
        fun (float): The function value.
        converged (bool): True if Newton's method converged.

    """
    # Create mesh.
    [m, n] = img.shape
    mesh = UnitSquareMesh(m - 1, n - 1)

    # Define function space and functions.
    W = VectorFunctionSpace(mesh, 'CG', 1, dim=2)
    w = Function(W)
    v, k = split(w)
    w1, w2 = TestFunctions(W)

    # Convert image to function.
    V = FunctionSpace(mesh, 'CG', 1)
    f = Function(V)
    f.vector()[:] = dh.img2funvec(img)

    # Define derivatives of data.
    ft = Function(V)
    ftv = np.diff(img, axis=0) * (m - 1)
    ftv = np.concatenate((ftv, ftv[-1, :].reshape(1, n)), axis=0)
    ft.vector()[:] = dh.img2funvec(ftv)

    fx = Function(V)
    fxv = np.gradient(img, 1 / (n - 1), axis=1)
    fx.vector()[:] = dh.img2funvec(fxv)

    # Define weak formulation.
    F = - (ft + fx*v + f*v.dx(1) - k) * (fx*w1 + f*w1.dx(1))*dx \
        - alpha0*v.dx(1)*w1.dx(1)*dx - alpha1*v.dx(0)*w1.dx(0)*dx \
        - beta*k.dx(1)*(k.dx(0) + k.dx(1)*v)*w1*dx \
        + (ft + fx*v + f*v.dx(1) - k)*w2*dx \
        - alpha2*k.dx(1)*w2.dx(1)*dx - alpha3*k.dx(0)*w2.dx(0)*dx \
        - beta*(k.dx(0)*w2.dx(0) + k.dx(1)*v*w2.dx(0)
                + k.dx(0)*v*w2.dx(1) + k.dx(1)*v*v*w2.dx(1))*dx

    # Define derivative.
    dv, dk = TrialFunctions(W)
    J = - (fx*dv + f*dv.dx(1) - dk)*(fx*w1 + f*w1.dx(1))*dx \
        - alpha0*dv.dx(1)*w1.dx(1)*dx - alpha1*dv.dx(0)*w1.dx(0)*dx \
        - beta*(k.dx(1)*(dk.dx(0) + dk.dx(1)*v) + k.dx(1)**2*dv
                + dk.dx(1)*(k.dx(0) + k.dx(1)*v))*w1*dx \
        + (fx*dv + f*dv.dx(1) - dk)*w2*dx \
        - alpha2*dk.dx(1)*w2.dx(1)*dx - alpha3*dk.dx(0)*w2.dx(0)*dx \
        - beta*(dv*k.dx(1) + dk.dx(0) + v*dk.dx(1))*w2.dx(0)*dx \
        - beta*(dv*k.dx(0) + 2*v*dv*k.dx(1) + v*dk.dx(0)
                + v*v*dk.dx(1))*w2.dx(1)*dx

    # Alternatively, use automatic differentiation.
    # J = derivative(F, w)

    # Define algorithm parameters.
    tol = 1e-10
    maxiter = 100

    # Define increment.
    dw = Function(W)

    # Run Newton iteration.
    niter = 0
    eps = 1
    res = 1
    while res > tol and niter < maxiter:
        niter += 1

        # Solve for increment.
        solve(J == -F, dw)

        # Update solution.
        w.assign(w + dw)

        # Compute norm of increment.
        eps = dw.vector().norm('l2')

        # Compute norm of residual.
        a = assemble(F)
        res = a.norm('l2')

        # Print statistics.
        print("Iteration {0} eps={1} res={2}".format(niter, eps, res))

    # Split solution.
    v, k = w.split(deepcopy=True)

    # Evaluate and print residual and functional value.
    res = abs(ft + fx * v + f * v.dx(1) - k)
    fun = 0.5 * (res**2 + alpha0 * v.dx(1)**2 + alpha1 * v.dx(0)**2 +
                 alpha2 * k.dx(1)**2 + alpha3 * k.dx(0)**2 + beta *
                 (k.dx(0) + k.dx(1) * v)**2)
    print('Res={0}, Func={1}'.format(assemble(res * dx), assemble(fun * dx)))

    # Convert back to array.
    vel = dh.funvec2img(v.vector().get_local(), m, n)
    k = dh.funvec2img(k.vector().get_local(), m, n)
    return vel, k, assemble(res * dx), assemble(fun * dx), res > tol
Пример #16
0
def cmscr1d_img(img: np.array,
                alpha0: float, alpha1: float,
                alpha2: float, alpha3: float,
                beta: float, deriv, mesh=None, bc='natural') \
                -> (np.array, np.array, float, float, bool):
    """Computes the L2-H1 mass conserving flow with source for a 1D image
    sequence with spatio-temporal and convective regularisation.

    Allows to specify how to approximate partial derivatives of f numerically.

    Args:
        img (np.array): 1D image sequence of shape (m, n), where m is the
                        number of time steps and n is the number of pixels.
        alpha0 (float): The spatial regularisation parameter for v.
        alpha1 (float): The temporal regularisation parameter for v.
        alpha2 (float): The spatial regularisation parameter for k.
        alpha3 (float): The temporal regularisation parameter for k.
        beta (float): The convective regularisation parameter.
        deriv (str): Specifies how to approximate pertial derivatives.
                     When set to 'mesh' it uses FEniCS built in function.
                     When set to 'fd' it uses finite differences.
        mesh: A custom mesh (optional). Must have (m - 1, n - 1) cells.
        bc (str): One of {'natural', 'zero', 'zerospace'} for boundary
                    conditions for the velocity v (optional).

    Returns:
        v (np.array): A velocity array of shape (m, n).
        k (np.array): A source array of shape (m, n).
        res (float): The residual.
        fun (float): The function value.
        converged (bool): True if Newton's method converged.

    """
    # Check for valid arguments.
    valid = {'mesh', 'fd'}
    if deriv not in valid:
        raise ValueError("Argument 'deriv' must be one of %r." % valid)

    # Create mesh.
    m, n = img.shape
    if mesh is None:
        mesh = UnitSquareMesh(m - 1, n - 1)

    # Define function spaces.
    V = dh.create_function_space(mesh, 'default')
    W = dh.create_vector_function_space(mesh, 'default')

    # Convert array to function.
    f = Function(V)
    f.vector()[:] = dh.img2funvec(img)

    # Compute partial derivatives.
    if deriv is 'mesh':
        ft, fx = f.dx(0), f.dx(1)
    if deriv is 'fd':
        imgt, imgx = nh.partial_derivatives(img)
        ft, fx = Function(V), Function(V)
        ft.vector()[:] = dh.img2funvec(imgt)
        fx.vector()[:] = dh.img2funvec(imgx)

    # Check for valid arguments.
    valid = {'natural', 'zero', 'zerospace'}
    if bc not in valid:
        raise ValueError("Argument 'bc' must be one of %r." % valid)

    # Define boundary conditions for velocity.
    if bc is 'natural':
        bc = []
    if bc is 'zero':
        bc = DirichletBC(W.sub(0), Constant(0), dh.DirichletBoundary())
    if bc is 'zerospace':
        bc = DirichletBC(W.sub(0), Constant(0), dh.DirichletBoundarySpace())

    # Compute velocity.
    v, k, res, fun, converged = cmscr1d_weak_solution(W,
                                                      f,
                                                      ft,
                                                      fx,
                                                      alpha0,
                                                      alpha1,
                                                      alpha2,
                                                      alpha3,
                                                      beta,
                                                      bcs=bc)

    # Convert back to array and return.
    v = dh.funvec2img(v.vector().get_local(), m, n)
    k = dh.funvec2img(k.vector().get_local(), m, n)
    return v, k, res, fun, converged