A crash course on Numpy for images
----------------------------------

Images manipulated by ``scikit-image`` are simply NumPy arrays. Hence, a
large fraction of operations on images will just consist in using NumPy::

    >>> from skimage import data
    >>> camera = data.camera()

Retrieving the geometry of the image and the number of pixels: ::

    >>> camera.shape
    (512, 512)
    >>> camera.size
    262144

Retrieving statistical information about gray values: ::

    >>> camera.min(), camera.max()
    (0, 255)
    >>> camera.mean()
    118.31400299072266

Numpy arrays representing images can be of different integer of float
numerical types. See :ref:`data_types` for more information about data
types.

Numpy indexing can be used both for looking at pixel values, and to
modify pixel values: ::

    >>> # Value of pixel on 10th line and 20th column
    >>> camera[10, 20]
    153
    >>> # Turn to black pixel on 3rd line and 10th column
    >>> camera[3, 10] = 0

Be careful that the first dimension (``camera.shape[0]``) corresponds to
lines, while the second dimension (``camera.shape[1]``) stands for
columns.

Beyond individual pixels, it is possible to access / modify values of
whole sets of pixels, using the different indexing possibilities of
NumPy.

Slicing::

    >>> # Set to black the ten first lines
    >>> camera[:10] = 0

Masking (indexing with masks of booleans)::

    >>> mask = camera < 87
    >>> # Set to "white" (255) pixels where mask is True
    >>> camera[mask] = 255

Fancy indexing (indexing with sets of indices) ::

    >>> inds_x = np.arange(len(camera))
    >>> inds_y = 4 * inds_x % len(camera)
    >>> camera[inds_x, inds_y] = 0

Using masks, especially, is very useful to select a set of pixels on
which to perform further manipulations. The mask can be any boolean array
of same shape as the image (or at least a shape broadcastable to the
image shape). This can be useful to define a region of interest, as a
disk: ::

    >>> l_x, l_y = camera.shape[0], camera.shape[1]
    >>> X, Y = np.ogrid[:l_x, :l_y]
    >>> outer_disk_mask = (X - l_x / 2)**2 + (Y - l_y / 2)**2 < (l_x / 2)**2
    >>> camera[outer_disk_mask] = 0

.. image:: ../../_images/plot_camera_numpy_1.png
    :width: 45%
    :target: ../auto_examples/plot_camera_numpy.html

Boolean arithmetics can be used to define more complex masks: ::

    >>> lower_half = X > l_x / 2
    >>> lower_half_disk = np.logical_and(lower_half, outer_disk_mask)
    >>> camera = data.camera()
    >>> camera[lower_half_disk] = 0 
