Skip to content

Commit

Permalink
Add docs for histogram (boostorg#503)
Browse files Browse the repository at this point in the history
* Add docs for histogram

* Add docs and make changes:

 - Made changes suggested in first review

 - Add docs for relevant files

* Rename docs file and correct typos

* Change doc for cumulative histogram

* Add docs for histogram equalization

* Make changes suggested in review

* Add docs

* Remove docs for algorithms

* Move images to test_images

Co-authored-by: Mateusz Łoskot <mateusz@loskot.net>
  • Loading branch information
2 people authored and meshtag committed Apr 21, 2021
1 parent 24ac759 commit b018b7c
Show file tree
Hide file tree
Showing 17 changed files with 493 additions and 0 deletions.
42 changes: 42 additions & 0 deletions doc/histogram/create.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.. _create_histogram:

Create a histogram
==================

**Method 1** - Using the histogram constructor

Syntax::

histogram<Type1, Type2, Type3,... TypeN>

``Type1`` .. ``TypeN`` correspond to the axis type of the N axes in the histogram

Example: If we want a 3D histogram of Axis1 of type ``int``, Axis2 of type ``float`` and Axis3 of type ``std::string``
we would do it this way::

histogram<int, float, std::string> h;

And done.


**Method 2** (TODO) - Using make_histogram()

There is an alternative to create the histogram directly from
a GIL image view.

This should be the preferred over method-1 when creating
histogram with GIL images, since it creates a histogram with axes configured
to match the GIL image.

Also it is easier than method-1.

Syntax::

auto h = make_histogram(view(image));

where ``image`` could be a ``gray8_image_t``/``rgb8_image_t`` object read from source.





29 changes: 29 additions & 0 deletions doc/histogram/cumulative.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.. _cumulative_histogram:

Making a cumulative histogram
=============================

Overview
--------

A cumulative histogram is a histogram in which each bin stores the count / frequency of itself
as well as all the bins with keys 'smaller' than the particular bin.
As such, a notion of ordering among its keys should be existant in the histogram.

The GIL histogram class has the ability to convert itself into its cumulative version.

Since the container needs to first get an ordering
over the keys a key sorting takes place before calculating the cumulative histogram.

Example:

.. code-block:: cpp
histogram<int, float> h;
/*
Fill histogram ...
*/
auto h1 = cumulative_histogram(h);
Tip: *In case you need to store the cumulative histogram elsewhere, consider creating a copy of the histogram
and then call the function*.
68 changes: 68 additions & 0 deletions doc/histogram/extend.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.. _extend_support:

Extending the class
===================

.. contents::
:local:
:depth: 1

User defined Axes
-----------------

In case you need a histogram with an axes of an arbitrary type that is not identified by
the C++ Standard Library, you need to provide a overload for the hashing function that is
used in the histogram class.

GIL's histogram class uses ``boost::hash_combine`` in a sub routine to generate a hash from
the key.

So we need to provide an overload of ``boost::hash_combine`` for the purpose.

For example, let's consider you need a histogram with an axis over class Test.

.. code-block:: cpp
// File : ./test.hpp
#include <cstddef>
#include <functional>
struct Test
{
int a{0};
Test() = default;
Test(int c) : a(c) {}
bool operator==(Test const& other) const
{
return (a == other.a);
}
};
namespace boost {
std::size_t hash_value(Test const& t)
{
// Replace with your hashing code
std::hash<int> hasher;
return hasher(t.a);
}
}
Now lets get to the usage example.

.. code-block:: cpp
#include <test.hpp>
#include <boost/gil.hpp>
#include <iostream>
// Mind the order of include i.e. test.hpp before boost/gil.hpp
using namespace boost::gil;
int main()
{
boost::gil::histogram<Test> h;
Test t(1);
h(t) = 1;
std::cout<<h(t);
}
12 changes: 12 additions & 0 deletions doc/histogram/extension/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Extensions
==========

The GIL documentation sections listed below are dedicated to describe the
usage of external containers as histograms for GIL images.

.. toctree::
:maxdepth: 1
:caption: Table of Contents

overview
std
32 changes: 32 additions & 0 deletions doc/histogram/extension/overview.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Overview
========

.. contents::
:local:
:depth: 1

Description
-----------
Apart from the default class supplied by Boost.GIL, there are also provisions to
use external containers like from std::vector, std::map, boost::histogram etc. These
are provided as extensions.


Extensions
----------
Currently the following are available:
#. std::vector (1D histogram support)
#. std::map (1D histogram support)
#. std::array (1D histogram support)
#. std::unordered_map (1D histogram support)
#. boost::histogram


Adding an external container
----------------------------
The workflow should be:
#. Provide overloads for fill_histogram(must), make_histogram(optional) etc. in a new file preferably named after the container type in extensions/histogram/.
#. Add tests to test/extensions/histogram.
#. Add docs to docs/histogram/extensions.
#. Other cmake, Jamfile, config etc. file changes.

45 changes: 45 additions & 0 deletions doc/histogram/extension/std.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.. _std:

STD extension
=============

Supported Types:
----------------

#. std\:\:vector (1D)
#. std\:\:map (1D)
#. std\:\:unordered_map (1D)
#. std\:\:array (1D)


Usage
-----

#. **fill_histogram()**

.. code-block:: cpp
// Demo for std::vector
std::vector<int> v;
gil::gray8_image_t img;
/*
Fill image ...
*/
gil::fill_histogram(view(img), v, false);
#. **cumulative_histogram()**

.. code-block:: cpp
// Demo for std::vector
std::vector<int> v;
/*
Fill vector...
*/
gil::cumulative_histogram(v);
103 changes: 103 additions & 0 deletions doc/histogram/fill.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
.. _fill_it:

Fill histogram
==============

.. contents::
:local:
:depth: 1

Overview
--------

We will demonstrate the available options for filling an instance of the `histogram` class with
values that cater from the most simplest to the complex needs that might arise.

Basic
-----

#. Use operator()

**Task** - Add value to a particular cell / key / bin in histogram

.. code-block:: cpp
histogram<int, int> h;
h(1, 2) = 1;
#. Use operator[]

This requires to input the indices in a format the histogram internally stores its keys,
which is of ``std::tuple`` due to its simple interface.

**Task** - Output value of a bin

.. code-block:: cpp
histogram<int, int> h;
h(1, 2) = 1;
h[{1, 2}] += 1; // Note the curly braces reqd. to construct a tuple
std::cout<<h[{1, 2}]; // Output - 2
#. Use another histogram (copy constructor or assignment)

**Task** - Fill a histogram using another

.. code-block:: cpp
histogram<int, int> A;
/*
Fill value in A
*/
histogram<int, int> B(A), C;
C = A;
#. Use a GIL image view

You can also use GIL images to directly fill histograms.

**Task** - Fill histogram using GIL image view

.. code-block:: cpp
gil::gray8_image_t img;
/*
Fill img ...
*/
histogram<int> h;
h.fill(view(img));
// OR
gil::fill_histogram(view(img), h, false); // false if histogram needs to be cleared before filling
Advanced
--------

#. Fill histogram using only a few dimensions of image

**Task** - Make an histogram over Red and Blue channel of an rgb image

.. code-block:: cpp
gil::rgb8_image_t img;
/*
Fill img ...
*/
histogram<int, int> h;
fill_histogram<0, 2>(view(img), h, false); // 0 - red, 1 - green, 2 - blue
#. Fill histogram using GIL pixel

**Task** - Fill histogram bin using pixel construct in GIL

.. code-block:: cpp
gil::gray8_image_t img;
/*
Fill img ...
*/
histogram<int> h;
gil::for_each_pixel(view(img), [](gil::gray8_pixel_t const& p){
++h[h.key_from_pixel(p)];
});
20 changes: 20 additions & 0 deletions doc/histogram/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Histogram
=========

The GIL documentation sections listed below are dedicated to describe the
histogram class and functions used in many image processing algorithms.

.. toctree::
:maxdepth: 1
:caption: Table of Contents

overview
create
fill
subhistogram
cumulative
stl_compatibility
utilities
extend
limitations
extension/index
6 changes: 6 additions & 0 deletions doc/histogram/limitations.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. _limitations:

Limitations
===========

*TODO*
28 changes: 28 additions & 0 deletions doc/histogram/overview.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Overview
========

.. contents::
:local:
:depth: 1

Description
-----------

The histogram class is built on top of std::unordered_map to keep it compatible with other
STL algorithms. It can support any number of axes (known at compile time i.e. during class
instantiation). Suitable conversion routines from GIL image constructs to the histogram bin
key are shipped with the class itself.


Tutorials
---------
The following flow is recommended:
#. :ref:`create_histogram`
#. :ref:`fill_it`
#. :ref:`sub_histogram`
#. :ref:`cumulative_histogram`
#. :ref:`stl_compatibility`
#. :ref:`extend_support`
#. :ref:`limitations`

.. note:: To try out these tutorials you need to get a clone of the repository, since it is not yet released.
Loading

0 comments on commit b018b7c

Please sign in to comment.