.. only:: html

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

        Click :ref:`here <sphx_glr_download_auto_examples_features_detection_plot_windowed_histogram.py>`     to download the full example code or to run this example in your browser via Binder
    .. rst-class:: sphx-glr-example-title

    .. _sphx_glr_auto_examples_features_detection_plot_windowed_histogram.py:


========================
Sliding window histogram
========================

Histogram matching can be used for object detection in images [1]_. This
example extracts a single coin from the ``skimage.data.coins`` image and uses
histogram matching to attempt to locate it within the original image.

First, a box-shaped region of the image containing the target coin is
extracted and a histogram of its greyscale values is computed.

Next, for each pixel in the test image, a histogram of the greyscale values in
a region of the image surrounding the pixel is computed.
``skimage.filters.rank.windowed_histogram`` is used for this task, as it employs
an efficient sliding window based algorithm that is able to compute these
histograms quickly [2]_. The local histogram for the region surrounding each
pixel in the image is compared to that of the single coin, with a similarity
measure being computed and displayed.

The histogram of the single coin is computed using ``numpy.histogram`` on a box
shaped region surrounding the coin, while the sliding window histograms are
computed using a disc shaped structural element of a slightly different size.
This is done in aid of demonstrating that the technique still finds similarity
in spite of these differences.

To demonstrate the rotational invariance of the technique, the same test is
performed on a version of the coins image rotated by 45 degrees.

References
----------
.. [1] Porikli, F. "Integral Histogram: A Fast Way to Extract Histograms
       in Cartesian Spaces" CVPR, 2005. Vol. 1. IEEE, 2005
.. [2] S.Perreault and P.Hebert. Median filtering in constant time.
       Trans. Image Processing, 16(9):2389-2394, 2007.



.. image:: /auto_examples/features_detection/images/sphx_glr_plot_windowed_histogram_001.png
    :class: sphx-glr-single-img






.. code-block:: default


    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt

    from skimage import data, transform
    from skimage.util import img_as_ubyte
    from skimage.morphology import disk
    from skimage.filters import rank


    matplotlib.rcParams['font.size'] = 9


    def windowed_histogram_similarity(image, selem, reference_hist, n_bins):
        # Compute normalized windowed histogram feature vector for each pixel
        px_histograms = rank.windowed_histogram(image, selem, n_bins=n_bins)

        # Reshape coin histogram to (1,1,N) for broadcast when we want to use it in
        # arithmetic operations with the windowed histograms from the image
        reference_hist = reference_hist.reshape((1, 1) + reference_hist.shape)

        # Compute Chi squared distance metric: sum((X-Y)^2 / (X+Y));
        # a measure of distance between histograms
        X = px_histograms
        Y = reference_hist

        num = (X - Y) ** 2
        denom = X + Y
        denom[denom == 0] = np.infty
        frac = num / denom

        chi_sqr = 0.5 * np.sum(frac, axis=2)

        # Generate a similarity measure. It needs to be low when distance is high
        # and high when distance is low; taking the reciprocal will do this.
        # Chi squared will always be >= 0, add small value to prevent divide by 0.
        similarity = 1 / (chi_sqr + 1.0e-4)

        return similarity


    # Load the `skimage.data.coins` image
    img = img_as_ubyte(data.coins())

    # Quantize to 16 levels of greyscale; this way the output image will have a
    # 16-dimensional feature vector per pixel
    quantized_img = img // 16

    # Select the coin from the 4th column, second row.
    # Co-ordinate ordering: [x1,y1,x2,y2]
    coin_coords = [184, 100, 228, 148]   # 44 x 44 region
    coin = quantized_img[coin_coords[1]:coin_coords[3],
                         coin_coords[0]:coin_coords[2]]

    # Compute coin histogram and normalize
    coin_hist, _ = np.histogram(coin.flatten(), bins=16, range=(0, 16))
    coin_hist = coin_hist.astype(float) / np.sum(coin_hist)

    # Compute a disk shaped mask that will define the shape of our sliding window
    # Example coin is ~44px across, so make a disk 61px wide (2 * rad + 1) to be
    # big enough for other coins too.
    selem = disk(30)

    # Compute the similarity across the complete image
    similarity = windowed_histogram_similarity(quantized_img, selem, coin_hist,
                                               coin_hist.shape[0])

    # Now try a rotated image
    rotated_img = img_as_ubyte(transform.rotate(img, 45.0, resize=True))
    # Quantize to 16 levels as before
    quantized_rotated_image = rotated_img // 16
    # Similarity on rotated image
    rotated_similarity = windowed_histogram_similarity(quantized_rotated_image,
                                                       selem, coin_hist,
                                                       coin_hist.shape[0])

    fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10))

    axes[0, 0].imshow(quantized_img, cmap='gray')
    axes[0, 0].set_title('Quantized image')
    axes[0, 0].axis('off')

    axes[0, 1].imshow(coin, cmap='gray')
    axes[0, 1].set_title('Coin from 2nd row, 4th column')
    axes[0, 1].axis('off')

    axes[1, 0].imshow(img, cmap='gray')
    axes[1, 0].imshow(similarity, cmap='hot', alpha=0.5)
    axes[1, 0].set_title('Original image with overlaid similarity')
    axes[1, 0].axis('off')

    axes[1, 1].imshow(rotated_img, cmap='gray')
    axes[1, 1].imshow(rotated_similarity, cmap='hot', alpha=0.5)
    axes[1, 1].set_title('Rotated image with overlaid similarity')
    axes[1, 1].axis('off')

    plt.tight_layout()
    plt.show()


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

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


.. _sphx_glr_download_auto_examples_features_detection_plot_windowed_histogram.py:


.. only :: html

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


  .. container:: binder-badge

    .. image:: https://mybinder.org/badge_logo.svg
      :target: https://mybinder.org/v2/gh/scikit-image/scikit-image/v0.17.x?filepath=notebooks/auto_examples/features_detection/plot_windowed_histogram.ipynb
      :width: 150 px


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

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



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

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


.. only:: html

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

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