Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add histogram class and related functionality #499

Merged
merged 31 commits into from
Jan 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6f9be17
Test implementation of histogram functionality
codejaeger May 29, 2020
1912366
Implement suggested changes to histogram
codejaeger Jun 2, 2020
cb69be7
Adds histogram class and code refactor :
codejaeger Jun 12, 2020
f043750
Updates histogram class example file
codejaeger Jun 12, 2020
5f24786
Remove file in concepts
codejaeger Jun 12, 2020
deb9f0f
Fixed bug in test for histogram class
codejaeger Jun 16, 2020
9580792
Add sub-histogram computing for histogram class
codejaeger Jun 16, 2020
4606a17
Try to fix Appveyor Bug
codejaeger Jun 17, 2020
0631223
Add tuple compatible check function
codejaeger Jun 18, 2020
10c2faf
Fix Appveyor Bug
codejaeger Jun 19, 2020
6160b67
Code Cleanup :
codejaeger Jun 22, 2020
795760f
Add cumulative histogram
codejaeger Jun 22, 2020
c332397
Code formatting using clang-format
codejaeger Jun 23, 2020
de90ff6
Override clang formatting for histogram.hpp
codejaeger Jun 23, 2020
771d344
Update hashing mechanism for tuple
codejaeger Jun 23, 2020
28bf4ec
Separate histogram tests
codejaeger Jun 23, 2020
043c3e1
Add Doxygen comments
codejaeger Jun 26, 2020
06bccfe
Rename example file
codejaeger Jun 29, 2020
ace3e71
Make changes:
codejaeger Jun 30, 2020
90dd9e2
Rename example file
codejaeger Jul 1, 2020
42b7697
Make changes:
Jul 5, 2020
3fa023f
Add normalize histogram
codejaeger Jul 5, 2020
d24b725
Add test for nearest key
codejaeger Jul 7, 2020
68d2109
Make a self review
codejaeger Jul 12, 2020
6789232
Changes:
codejaeger Jul 28, 2020
5f10c81
Make the following changes:
codejaeger Jul 30, 2020
8c22800
Modify histogram example file
codejaeger Jul 31, 2020
897778d
Update histogram class with commenting
codejaeger Jul 31, 2020
e9e8ce6
Fix bug in example file
codejaeger Aug 8, 2020
43562e1
Update to histogram class for algorithms
codejaeger Aug 16, 2020
c8330a7
Update tests for fill histogram
codejaeger Aug 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ local sources =
resize.cpp
sobel_scharr.cpp
threshold.cpp
tutorial_histogram.cpp
x_gradient.cpp
;

Expand Down
71 changes: 37 additions & 34 deletions example/histogram.cpp
Original file line number Diff line number Diff line change
@@ -1,49 +1,52 @@
//
// Copyright 2005-2007 Adobe Systems Incorporated
// Copyright 2020 Debabrata Mandal <mandaldebabrata123@gmail.com>
mloskot marked this conversation as resolved.
Show resolved Hide resolved
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/gil.hpp>
#include <boost/gil/extension/io/jpeg.hpp>

#include <algorithm>
#include <fstream>
#include <boost/gil.hpp>
#include <boost/gil/extension/io/png.hpp>
#include <boost/gil/io/read_image.hpp>

// Example file to demonstrate a way to compute histogram
#include <iostream>

using namespace boost::gil;

template <typename GrayView, typename R>
void gray_image_hist(GrayView const& img_view, R& hist)
{
for (auto it = img_view.begin(); it != img_view.end(); ++it)
++hist[*it];

// Alternatively, prefer the algorithm with lambda
// for_each_pixel(img_view, [&hist](gray8_pixel_t const& pixel) {
// ++hist[pixel];
// });
}

template <typename V, typename R>
void get_hist(const V& img_view, R& hist) {
gray_image_hist(color_converted_view<gray8_pixel_t>(img_view), hist);
}

int main() {
rgb8_image_t img;
read_image("test.jpg", img, jpeg_tag());
/*
This file explains how to use the histogram class and some of its features
that can be applied for a variety of tasks.
*/

int histogram[256];
std::fill(histogram,histogram + 256, 0);
get_hist(const_view(img), histogram);

std::fstream histo_file("out-histogram.txt", std::ios::out);
for(std::size_t ii = 0; ii < 256; ++ii)
histo_file << histogram[ii] << std::endl;
histo_file.close();
int main()
{
// Create a histogram class. Use uint or unsigned short as the default axes type in most cases.
histogram<unsigned char> h;

// Fill histogram with GIL images (of any color space)
gray8_image_t g;
read_image("test_adaptive.png", g, png_tag{});

fill_histogram
(
view(g), // Input image view
h, // Histogram to be filled
1, // Histogram bin widths
false, // Specify whether to accumulate over the values already present in h (default = false)
true, // Specify whether to have a sparse or continuous histogram (default = true)
false, // Specify if image mask is to be specified
{{}}, // Mask as a 2D vector. Used only if prev argument specified
{0}, // Lower limit on the values in histogram (default numeric_limit::min() on axes)
{255}, // Upper limit on the values in histogram (default numeric_limit::max() on axes)
true // Use specified limits if this is true (default is false)
);

// Normalize the histogram
h.normalize();

// Get a cumulative histogram from the histogram
auto h2 = cumulative_histogram(h);

return 0;
}
49 changes: 49 additions & 0 deletions example/tutorial_histogram.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Copyright 2005-2007 Adobe Systems Incorporated
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/gil.hpp>
#include <boost/gil/extension/io/jpeg.hpp>

#include <algorithm>
#include <fstream>

// Example file to demonstrate a way to compute histogram

using namespace boost::gil;

template <typename GrayView, typename R>
void gray_image_hist(GrayView const& img_view, R& hist)
{
for (auto it = img_view.begin(); it != img_view.end(); ++it)
++hist[*it];

// Alternatively, prefer the algorithm with lambda
// for_each_pixel(img_view, [&hist](gray8_pixel_t const& pixel) {
// ++hist[pixel];
// });
}

template <typename V, typename R>
void get_hist(const V& img_view, R& hist) {
gray_image_hist(color_converted_view<gray8_pixel_t>(img_view), hist);
}

int main() {
rgb8_image_t img;
read_image("test.jpg", img, jpeg_tag());

int histogram[256];
std::fill(histogram,histogram + 256, 0);
get_hist(const_view(img), histogram);

std::fstream histo_file("out-histogram.txt", std::ios::out);
for(std::size_t ii = 0; ii < 256; ++ii)
histo_file << histogram[ii] << std::endl;
histo_file.close();

return 0;
}
1 change: 1 addition & 0 deletions include/boost/gil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <boost/gil/deprecated.hpp>
#include <boost/gil/device_n.hpp>
#include <boost/gil/gray.hpp>
#include <boost/gil/histogram.hpp>
#include <boost/gil/image.hpp>
#include <boost/gil/image_view.hpp>
#include <boost/gil/image_view_factory.hpp>
Expand Down
172 changes: 172 additions & 0 deletions include/boost/gil/extension/histogram/std.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//
// Copyright 2020 Debabrata Mandal <mandaldebabrata123@gmail.com>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//

#ifndef BOOST_GIL_EXTENSION_HISTOGRAM_STL_HISTOGRAM_HPP
#define BOOST_GIL_EXTENSION_HISTOGRAM_STL_HISTOGRAM_HPP

#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/gray.hpp>
#include <boost/gil/histogram.hpp>
#include <boost/gil/image_view.hpp>
#include <boost/gil/image_view_factory.hpp>

#include <array>
#include <map>
#include <utility>
#include <vector>

namespace boost { namespace gil {

//////////////////////////////////////////////////////////
/// Histogram extension for STL container
//////////////////////////////////////////////////////////
/// \defgroup Histogram - STL Containers
/// \brief Collection of functions to provide histogram support in GIL using Standard
/// Template Library Containers
/// The conversion from Boost.GIL images to compatible histograms are provided. The supported
/// container types would be std::vector, std::array, std::map.
///
/// Some general constraints on STL extension:-
/// 1. Supports only 1D histogram.
/// 2. Cannot use signed images with compatible random access containers.
/// 3. Automatic resize of std::array in case of shortage of bins, to ensure
/// correctness comes before performance.
/// 4. Container key type (if exists) has to be one of std::integral types to be
/// GIL compatible.
/// 5. Container value type has to be of std::arithmetic types.
///

///
/// \ingroup Histogram - STL Containers
/// \brief Overload for std::vector of fill_histogram
///
template <typename SrcView, typename T>
void fill_histogram(SrcView const& srcview, std::vector<T>& histogram, bool accumulate = false)
{
gil_function_requires<ImageViewConcept<SrcView>>();
static_assert(std::is_arithmetic<T>::value, "Improper container type for images.");
static_assert(
std::is_unsigned<typename channel_type<SrcView>::type>::value,
"Improper container type for signed images.");

using channel_t = typename channel_type<SrcView>::type;
using pixel_t = pixel<channel_t, gray_layout_t>;

if (!accumulate)
histogram.clear();
histogram.resize(std::numeric_limits<channel_t>::max() + 1);

for_each_pixel(color_converted_view<pixel_t>(srcview), [&](pixel_t const& p) {
++histogram[static_cast<std::size_t>(p)];
});
}

/// \ingroup Histogram - STL Containers
/// \brief Overload for std::array of fill_histogram
///
template <typename SrcView, typename T, std::size_t N>
void fill_histogram(SrcView const& srcview, std::array<T, N>& histogram, bool accumulate = false)
{
gil_function_requires<ImageViewConcept<SrcView>>();
static_assert(std::is_arithmetic<T>::value && N > 0, "Improper container type for images.");
static_assert(
std::is_unsigned<typename channel_type<SrcView>::type>::value,
"Improper container type for signed images.");

using channel_t = typename channel_type<SrcView>::type;
using pixel_t = pixel<channel_t, gray_layout_t>;

const size_t pixel_max = std::numeric_limits<channel_t>::max();
const float scale = (histogram.size() - 1.0f) / pixel_max;

if (!accumulate)
std::fill(std::begin(histogram), std::end(histogram), 0);

for_each_pixel(color_converted_view<pixel_t>(srcview), [&](pixel_t const& p) {
++histogram[static_cast<std::size_t>(p * scale)];
});
}

/// \ingroup Histogram - STL Containers
/// \brief Overload for std::map of fill_histogram
///
template <typename SrcView, typename T1, typename T2>
void fill_histogram(SrcView const& srcview, std::map<T1, T2>& histogram, bool accumulate = false)
{
gil_function_requires<ImageViewConcept<SrcView>>();
static_assert(
std::is_arithmetic<T1>::value && std::is_integral<T2>::value,
"Improper container type for images.");

using channel_t = typename channel_type<SrcView>::type;
using pixel_t = pixel<channel_t, gray_layout_t>;

if (!accumulate)
histogram.clear();

for_each_pixel(color_converted_view<pixel_t>(srcview), [&](pixel_t const& p) {
++histogram[static_cast<std::size_t>(p)];
});
}

/// \ingroup Histogram - STL Containers
/// \brief Overload for std::vector of cumulative_histogram
///
template <typename T>
std::vector<T> cumulative_histogram(std::vector<T>& hist)
{
std::vector<T> cumulative_hist(hist.size());
static_assert(std::is_arithmetic<T>::value, "Improper container type for images.");
T cumulative_counter = 0;
for (std::size_t i = 0; i < hist.size(); i++)
{
cumulative_counter += hist[i];
cumulative_hist[i] = cumulative_counter;
}
return cumulative_hist;
}

/// \ingroup Histogram - STL Containers
/// \brief Overload for std::array of cumulative_histogram
///
template <typename T, std::size_t N>
std::array<T, N> cumulative_histogram(std::array<T, N>& histogram)
{
std::array<T, N> cumulative_hist;
static_assert(std::is_arithmetic<T>::value && N > 0, "Improper container type for images.");
T cumulative_counter = 0;
for (std::size_t i = 0; i < N; i++)
{
cumulative_counter += histogram[i];
cumulative_hist[i] = cumulative_counter;
}
return cumulative_hist;
}

/// \ingroup Histogram - STL Containers
/// \brief Overload for std::map of cumulative_histogram
///
template <typename T1, typename T2>
std::map<T1, T2> cumulative_histogram(std::map<T1, T2>& histogram)
{
std::map<T1, T2> cumulative_hist;
static_assert(
std::is_arithmetic<T1>::value && std::is_integral<T2>::value,
"Improper container type for images.");
T2 cumulative_counter = 0;
for (auto const& it : histogram)
{
cumulative_counter += it.second;
cumulative_hist[it.first] = cumulative_counter;
}
return cumulative_hist;
}

}} // namespace boost::gil

#endif
Loading