This is a follow-up question for An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++, histogram Template Function Implementation for Image in C++ and Histogram of Image using std::map in C++.
A histogram usually is defined by bins.
In this post, both histogram_normalized and histogram_with_bins template functions have been proposed.
The experimental implementation
histogram_normalizedtemplate function implementationProvide the normalized histogram of an image.
// histogram_normalized template function implementation // https://codereview.stackexchange.com/q/295419/231235 template<class ElementT = std::uint8_t, class ProbabilityType = double> requires (std::same_as<ElementT, std::uint8_t> or std::same_as<ElementT, std::uint16_t>) constexpr static auto histogram_normalized(const Image<ElementT>& input) { std::array<ProbabilityType, std::numeric_limits<ElementT>::max() - std::numeric_limits<ElementT>::lowest() + 1> histogram_output{}; auto image_data = input.getImageData(); for (std::size_t i = 0; i < image_data.size(); ++i) { histogram_output[image_data[i]] += (1.0 / static_cast<ProbabilityType>(input.count())); } return histogram_output; } // histogram_normalized template function implementation template<class ElementT = int, class ProbabilityType = double> constexpr static auto histogram_normalized(const Image<ElementT>& input) { std::map<ElementT, ProbabilityType> histogram_output{}; auto image_data = input.getImageData(); for (std::size_t i = 0; i < image_data.size(); ++i) { if (histogram_output.contains(image_data[i])) { histogram_output[image_data[i]] += (1.0 / static_cast<ProbabilityType>(input.count())); } else { histogram_output.emplace(image_data[i], 1.0 / static_cast<ProbabilityType>(input.count())); } } return histogram_output; }histogram_with_binstemplate function implementationCalculate the histogram with given bins.
// histogram_with_bins template function implementation template<std::size_t bins_count = 8, class ElementT = std::uint8_t> requires (std::same_as<ElementT, std::uint8_t> or std::same_as<ElementT, std::uint16_t>) constexpr static auto histogram_with_bins(const Image<ElementT>& input) { std::array<std::size_t, bins_count + 1> histogram_output{}; constexpr auto max = std::numeric_limits<ElementT>::max(); constexpr auto lowest = std::numeric_limits<ElementT>::lowest(); auto image_data = input.getImageData(); for (std::size_t i = 0; i < image_data.size(); ++i) { std::size_t bin_index = std::floor((static_cast<double>(image_data[i]) * static_cast<double>(bins_count)) / (static_cast<double>(max) - static_cast<double>(lowest))); ++histogram_output[bin_index]; } return histogram_output; }
The usage of histogram_normalized template function:
/* Developed by Jimmy Hu */
#include <chrono>
#include "../base_types.h"
#include "../basic_functions.h"
#include "../image.h"
#include "../image_io.h"
#include "../image_operations.h"
template<class ExPo, class ElementT>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr static auto HistogramTest(
ExPo execution_policy,
const TinyDIP::Image<ElementT>& input,
std::ostream& os = std::cout
)
{
auto hsv_image = TinyDIP::rgb2hsv(execution_policy, input);
auto start1 = std::chrono::system_clock::now();
auto histogram_result1 = TinyDIP::histogram_normalized(TinyDIP::im2uint8(TinyDIP::getVplane(hsv_image)));
auto end1 = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds1 = end1 - start1;
os << "elapsed time: " << elapsed_seconds1.count() << '\n';
return histogram_result1;
}
int main()
{
auto start = std::chrono::system_clock::now();
std::string image_filename = "1.bmp";
auto image_input = TinyDIP::bmp_read(image_filename.c_str(), true);
image_input = TinyDIP::copyResizeBicubic(image_input, 3 * image_input.getWidth(), 3 * image_input.getHeight());
auto histogram_result1 = HistogramTest(std::execution::par, image_input);
double sum = 0.0;
for (std::size_t i = 0; i < histogram_result1.size(); ++i)
{
std::cout << i << " count: " << histogram_result1[i] << "\n";
sum += histogram_result1[i];
}
std::cout << "Sum = " << sum << '\n';
std::cout << "image_input.count = " << image_input.count() << '\n';
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
return EXIT_SUCCESS;
}
The output of the test code above:
Width of the input image: 454
Height of the input image: 341
Size of the input image(Byte): 464442
elapsed time: 0.0388117
0 count: 0.00141101
1 count: 4.6651e-05
2 count: 5.16749e-05
3 count: 5.3828e-05
4 count: 5.09572e-05
5 count: 3.51676e-05
6 count: 4.80864e-05
7 count: 3.73208e-05
8 count: 5.59812e-05
9 count: 4.1627e-05
10 count: 4.30624e-05
11 count: 4.1627e-05
12 count: 4.73687e-05
13 count: 5.3828e-05
14 count: 6.17228e-05
15 count: 7.03353e-05
16 count: 7.53592e-05
17 count: 9.97613e-05
18 count: 0.00021603
19 count: 0.00039761
20 count: 0.000755028
21 count: 0.00111316
22 count: 0.00172752
23 count: 0.00257872
24 count: 0.00403208
25 count: 0.00584501
26 count: 0.00756535
27 count: 0.00885292
28 count: 0.0101168
29 count: 0.0113979
30 count: 0.0121651
31 count: 0.0128333
32 count: 0.0136006
33 count: 0.0139465
34 count: 0.0144151
35 count: 0.0148472
36 count: 0.0153352
37 count: 0.0156159
38 count: 0.0161125
39 count: 0.016714
40 count: 0.0168668
41 count: 0.0170943
42 count: 0.0173491
43 count: 0.0171884
44 count: 0.0168266
45 count: 0.0163802
46 count: 0.015946
47 count: 0.015651
48 count: 0.0151702
49 count: 0.0147065
50 count: 0.014225
51 count: 0.0140986
52 count: 0.0137427
53 count: 0.0133257
54 count: 0.0130551
55 count: 0.0125857
56 count: 0.0121544
57 count: 0.0119426
58 count: 0.0113548
59 count: 0.0110075
60 count: 0.0106314
61 count: 0.0101089
62 count: 0.00984838
63 count: 0.00940268
64 count: 0.0091522
65 count: 0.00874741
66 count: 0.00859311
67 count: 0.0081711
68 count: 0.00792062
69 count: 0.00766583
70 count: 0.0073242
71 count: 0.00700554
72 count: 0.00687133
73 count: 0.00657563
74 count: 0.00649956
75 count: 0.00624405
76 count: 0.00593544
77 count: 0.00581056
78 count: 0.00550553
79 count: 0.00543663
80 count: 0.00528663
81 count: 0.00521199
82 count: 0.00503184
83 count: 0.0048029
84 count: 0.00468878
85 count: 0.00463567
86 count: 0.00430337
87 count: 0.0041505
88 count: 0.00413686
89 count: 0.00398615
90 count: 0.00388495
91 count: 0.00381102
92 count: 0.00363806
93 count: 0.00360361
94 count: 0.0036072
95 count: 0.00345648
96 count: 0.00343638
97 count: 0.00327346
98 count: 0.00324978
99 count: 0.00308327
100 count: 0.00309188
101 count: 0.00309762
102 count: 0.00295911
103 count: 0.00288734
104 count: 0.00276317
105 count: 0.00277968
106 count: 0.00267777
107 count: 0.00268207
108 count: 0.00264475
109 count: 0.00255934
110 count: 0.00251556
111 count: 0.0024847
112 count: 0.002428
113 count: 0.00240432
114 count: 0.0023426
115 count: 0.00229953
116 count: 0.00230815
117 count: 0.00228733
118 count: 0.0022902
119 count: 0.00227011
120 count: 0.0020835
121 count: 0.00218183
122 count: 0.00212154
123 count: 0.00208063
124 count: 0.00201102
125 count: 0.00209283
126 count: 0.00203326
127 count: 0.00197011
128 count: 0.00209427
129 count: 0.00204044
130 count: 0.00200599
131 count: 0.00195073
132 count: 0.00197944
133 count: 0.00199594
134 count: 0.00202465
135 count: 0.00197728
136 count: 0.00198302
137 count: 0.0019658
138 count: 0.00198805
139 count: 0.0019414
140 count: 0.00201819
141 count: 0.00196149
142 count: 0.00198518
143 count: 0.00200384
144 count: 0.0020024
145 count: 0.00201891
146 count: 0.00191915
147 count: 0.00190551
148 count: 0.00182585
149 count: 0.00183877
150 count: 0.00182441
151 count: 0.00191484
152 count: 0.00185599
153 count: 0.00180934
154 count: 0.00181221
155 count: 0.00179211
156 count: 0.00179642
157 count: 0.0018036
158 count: 0.00180647
159 count: 0.0017268
160 count: 0.00181293
161 count: 0.00184523
162 count: 0.00181652
163 count: 0.00179714
164 count: 0.00182011
165 count: 0.00176125
166 count: 0.00181508
167 count: 0.00190264
168 count: 0.0018158
169 count: 0.0018079
170 count: 0.00181006
171 count: 0.00186604
172 count: 0.00187609
173 count: 0.00186819
174 count: 0.00197226
175 count: 0.0019457
176 count: 0.00199738
177 count: 0.00206484
178 count: 0.00209642
179 count: 0.00208781
180 count: 0.00201963
181 count: 0.00197154
182 count: 0.00190049
183 count: 0.0018768
184 count: 0.00180144
185 count: 0.00181293
186 count: 0.00169594
187 count: 0.00163924
188 count: 0.00146125
189 count: 0.0014512
190 count: 0.00136939
191 count: 0.00137226
192 count: 0.001378
193 count: 0.00130479
194 count: 0.00136077
195 count: 0.00141891
196 count: 0.0014469
197 count: 0.00145695
198 count: 0.00143829
199 count: 0.00133135
200 count: 0.00119139
201 count: 0.0010658
202 count: 0.0010012
203 count: 0.000943067
204 count: 0.00091723
205 count: 0.00076364
206 count: 0.000645219
207 count: 0.000610051
208 count: 0.000607898
209 count: 0.000591391
210 count: 0.000598568
211 count: 0.000601439
212 count: 0.000602156
213 count: 0.00059785
214 count: 0.000655267
215 count: 0.000605745
216 count: 0.00057919
217 count: 0.000593544
218 count: 0.000600721
219 count: 0.00060718
220 count: 0.000638042
221 count: 0.000619381
222 count: 0.000625123
223 count: 0.000668185
224 count: 0.000652396
225 count: 0.000663161
226 count: 0.000681822
227 count: 0.000630147
228 count: 0.000642348
229 count: 0.00059785
230 count: 0.000652396
231 count: 0.000688281
232 count: 0.000624405
233 count: 0.000676798
234 count: 0.000656702
235 count: 0.000624405
236 count: 0.000643783
237 count: 0.000707659
238 count: 0.000663879
239 count: 0.00071986
240 count: 0.000716989
241 count: 0.00072919
242 count: 0.00071986
243 count: 0.000740674
244 count: 0.000765794
245 count: 0.000762205
246 count: 0.000823928
247 count: 0.000852636
248 count: 0.000940914
249 count: 0.000998331
250 count: 0.00109235
251 count: 0.00122297
252 count: 0.00151723
253 count: 0.00198518
254 count: 0.00309691
255 count: 0.0284664
Sum = 1
image_input.count = 1393326
Computation finished at Thu Feb 27 14:00:56 2025
elapsed time: 2.81971
The usage of histogram_with_bins template function:
/* Developed by Jimmy Hu */
#include <chrono>
#include "../base_types.h"
#include "../basic_functions.h"
#include "../image.h"
#include "../image_io.h"
#include "../image_operations.h"
template<class ExPo, class ElementT>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr static auto HistogramTest(
ExPo execution_policy,
const TinyDIP::Image<ElementT>& input,
std::ostream& os = std::cout
)
{
auto hsv_image = TinyDIP::rgb2hsv(execution_policy, input);
auto start1 = std::chrono::system_clock::now();
auto histogram_result1 = TinyDIP::histogram_with_bins(TinyDIP::im2uint8(TinyDIP::getVplane(hsv_image)));
auto end1 = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds1 = end1 - start1;
os << "elapsed time: " << elapsed_seconds1.count() << '\n';
return histogram_result1;
}
int main()
{
auto start = std::chrono::system_clock::now();
std::string image_filename = "1.bmp";
auto image_input = TinyDIP::bmp_read(image_filename.c_str(), true);
image_input = TinyDIP::copyResizeBicubic(image_input, 3 * image_input.getWidth(), 3 * image_input.getHeight());
auto histogram_result1 = HistogramTest(std::execution::par, image_input);
std::size_t sum = 0;
for (std::size_t i = 0; i < histogram_result1.size(); ++i)
{
std::cout << "Bin index = " << i << " count: " << histogram_result1[i] << "\n";
sum += histogram_result1[i];
}
std::cout << "Sum = " << sum << '\n';
std::cout << "image_input.count = " << image_input.count() << '\n';
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
return EXIT_SUCCESS;
}
The output of the test code above:
Width of the input image: 454
Height of the input image: 341
Size of the input image(Byte): 464442
elapsed time: 0.0248806
Bin index = 0 count: 114144
Bin index = 1 count: 628738
Bin index = 2 count: 253160
Bin index = 3 count: 113404
Bin index = 4 count: 85785
Bin index = 5 count: 81024
Bin index = 6 count: 39104
Bin index = 7 count: 38304
Bin index = 8 count: 39663
Sum = 1393326
image_input.count = 1393326
Computation finished at Thu Feb 27 12:22:25 2025
elapsed time: 0.635443
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++,
histogram Template Function Implementation for Image in C++ and
What changes has been made in the code since last question?
I implemented
histogram_normalizedandhistogram_with_binstemplate functions in this post.Why a new review is being asked for?
Please review the implementation of
histogram_normalizedandhistogram_with_binstemplate functions and its tests.