
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "auto_examples/plot_active_contours.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_auto_examples_plot_active_contours.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_auto_examples_plot_active_contours.py:


Active contours
===============

This example shows a basic active contours implementation using splinebox.
The goal is to segments the astronaut's head in the example image.

.. GENERATED FROM PYTHON SOURCE LINES 8-17

.. code-block:: Python


    import matplotlib
    import matplotlib.pyplot as plt
    import numpy as np
    import scipy
    import skimage
    import splinebox.basis_functions
    import splinebox.spline_curves








.. GENERATED FROM PYTHON SOURCE LINES 18-19

Let's load the astronaut example image from skimage

.. GENERATED FROM PYTHON SOURCE LINES 19-21

.. code-block:: Python

    img = skimage.data.astronaut()








.. GENERATED FROM PYTHON SOURCE LINES 22-26

We want our contour to stick to the edges, so we have to
compute an edge map. To do that we first convert the image
to gray scale, smooth it to make the edge map less noisy, and
apply the sobel filter for edge detection.

.. GENERATED FROM PYTHON SOURCE LINES 26-31

.. code-block:: Python

    gray = skimage.color.rgb2gray(img)
    smooth = skimage.filters.gaussian(gray, 3, preserve_range=False)
    edge = skimage.filters.sobel(smooth)









.. GENERATED FROM PYTHON SOURCE LINES 32-36

To make calculating the edge energy at non integer locations easier
we use a surface spline on a regular grid.
This returns a callable object that we can interogate as follows:
`edge_energy(x, y)`

.. GENERATED FROM PYTHON SOURCE LINES 36-41

.. code-block:: Python

    edge_energy = scipy.interpolate.RectBivariateSpline(
        np.arange(edge.shape[1]), np.arange(edge.shape[0]), edge, kx=2, ky=2, s=1
    )









.. GENERATED FROM PYTHON SOURCE LINES 42-44

In order to regularize the curvature of our spline we can define an internal energy function
that scales with the first and second derivative.

.. GENERATED FROM PYTHON SOURCE LINES 44-48

.. code-block:: Python

    def internal_energy(spline, t, alpha, beta):
        return 0.5 * (alpha * spline.eval(t, derivative=1) ** 2 + beta * spline.eval(t, derivative=2) ** 2)









.. GENERATED FROM PYTHON SOURCE LINES 49-51

Let's initialize our spline with 50 knots that form a circle
around the astronouts head.

.. GENERATED FROM PYTHON SOURCE LINES 51-57

.. code-block:: Python

    M = 50
    s = np.linspace(0, 2 * np.pi, M + 1)[:-1]
    y = 100 + 100 * np.sin(s)
    x = 220 + 100 * np.cos(s)
    knots = np.array([y, x]).T








.. GENERATED FROM PYTHON SOURCE LINES 58-59

We keep a copy of the initial knots so we can plot them later.

.. GENERATED FROM PYTHON SOURCE LINES 59-61

.. code-block:: Python

    initial_knots = knots.copy()








.. GENERATED FROM PYTHON SOURCE LINES 62-64

Now, we can construct a B3 spline and adjust its control points (coefficients)
using the knots we generated above.

.. GENERATED FROM PYTHON SOURCE LINES 64-69

.. code-block:: Python

    spline = splinebox.spline_curves.Spline(M=M, basis_function=splinebox.basis_functions.B3(), closed=True)
    print(knots.shape)
    spline.knots = knots






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    (50, 2)




.. GENERATED FROM PYTHON SOURCE LINES 70-74

Here, we set the necessary paramters for active contours:

* :math:`\alpha` controls the contribution of the first derivative to the internal force
* :math:`\beta` controls the contribution of the second derivative to the internal force

.. GENERATED FROM PYTHON SOURCE LINES 74-92

.. code-block:: Python

    alpha = 0
    beta = 0.005

    contours = []
    external_energies = []


    def energy_function(control_points, spline, t, alpha, beta):
        control_points = control_points.reshape((spline.M, -1))
        spline.control_points = control_points
        contour = spline.eval(t)
        contours.append(contour.copy())
        edge_energy_value = np.sum(edge_energy(contour[:, 0], contour[:, 1], grid=False))
        external_energies.append(-edge_energy_value)
        internal_energy_value = np.sum(internal_energy(spline, t, alpha, beta))
        return -edge_energy_value + internal_energy_value









.. GENERATED FROM PYTHON SOURCE LINES 93-95

The active contours approach consists of iteratively updating our control points (coefficients)
to minimize the energy.

.. GENERATED FROM PYTHON SOURCE LINES 95-101

.. code-block:: Python

    initial_control_points = spline.control_points.copy()
    t = np.linspace(0, M, 400)
    result = scipy.optimize.minimize(
        energy_function, initial_control_points.flatten(), method="Powell", args=(spline, t, alpha, beta)
    )








.. GENERATED FROM PYTHON SOURCE LINES 102-104

Inorder to plot the spline as a smooth line, we have to evaluate it
more densly than just at the knots.

.. GENERATED FROM PYTHON SOURCE LINES 104-108

.. code-block:: Python

    samples = spline.eval(np.linspace(0, len(knots), 400))

    final_knots = spline.eval(np.arange(M))








.. GENERATED FROM PYTHON SOURCE LINES 109-110

Finaly, we can plot the result.

.. GENERATED FROM PYTHON SOURCE LINES 110-120

.. code-block:: Python

    plt.imshow(img)
    plt.scatter(initial_knots[:, 1], initial_knots[:, 0], marker="x", color="black", label="initial knots")
    contours = contours[::2000]
    colors = matplotlib.colormaps["viridis"](np.linspace(0, 1, len(contours)))
    for contour, color in zip(contours, colors):
        plt.plot(contour[:, 1], contour[:, 0], color=color, alpha=0.2)
    plt.scatter(final_knots[:, 1], final_knots[:, 0], marker="o", color="red", label="final final_knots")
    plt.plot(samples[:, 1], samples[:, 0], label="spline", color="red")
    plt.legend()
    plt.show()



.. image-sg:: /auto_examples/images/sphx_glr_plot_active_contours_001.png
   :alt: plot active contours
   :srcset: /auto_examples/images/sphx_glr_plot_active_contours_001.png
   :class: sphx-glr-single-img






.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 40.036 seconds)


.. _sphx_glr_download_auto_examples_plot_active_contours.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_active_contours.ipynb <plot_active_contours.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_active_contours.py <plot_active_contours.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: plot_active_contours.zip <plot_active_contours.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
