-
Notifications
You must be signed in to change notification settings - Fork 164
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add histogram class and related functionality (#499)
A new histogram class proposed with close suport for gil image constructs. Shift the stl support implmentation to extension to serve as example for overloading fill_histogram. Add cumulative histogram and histogram normalization. Co-authored-by: debabrata1 <debabrata@goodhealthapp.com>
- Loading branch information
1 parent
0e372a1
commit 3e729e5
Showing
26 changed files
with
2,244 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ local sources = | |
resize.cpp | ||
sobel_scharr.cpp | ||
threshold.cpp | ||
tutorial_histogram.cpp | ||
x_gradient.cpp | ||
; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
// | ||
// 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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.