This is a follow-up question for An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++ and histogram Template Function Implementation for Image in C++. Considering the answer provided by user555045 and the answer provided by Cris Luengo, the limitation of using std::array is obvious:
If
ElementTis a signed type and the image has negative values, using image value as array index is not working.If
ElementTis a 64-bit / floating-point type, array can not be allocated.
Therefore, I use std::map to represent the histogram of an image here.
The experimental implementation
histogramtemplate function implementation// histogram template function implementation template<class ElementT = int> constexpr static auto histogram(const Image<ElementT>& input) { std::map<ElementT, std::size_t> 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]]; } else { histogram_output.emplace(image_data[i], std::size_t{ 1 }); } } return histogram_output; }histogramtemplate function implementation for typestd::uint8_tandstd::uint16_tFor type
std::uint8_tandstd::uint16_t,histogramtemplate function still usesstd::array.// histogram template function implementation // https://codereview.stackexchange.com/q/295419/231235 template<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(const Image<ElementT>& input) { std::array<std::size_t, 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]]; } return histogram_output; }rgb2hsvtemplate function implementation// rgb2hsv template function implementation template<typename ElementT, typename OutputT = HSV> requires (std::same_as<ElementT, RGB> || std::same_as<ElementT, RGB_DOUBLE>) constexpr static auto rgb2hsv(const Image<ElementT>& input) { return pixelwiseOperation([](ElementT input) { return rgb2hsv(input); }, input); } // rgb2hsv template function implementation template<class ExPo, typename ElementT, typename OutputT = HSV> requires (std::same_as<ElementT, RGB> || std::same_as<ElementT, RGB_DOUBLE>) && (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) constexpr static auto rgb2hsv(ExPo execution_policy, const Image<ElementT>& input) { return pixelwiseOperation(execution_policy, [](ElementT input) { return rgb2hsv(input); }, input); } // rgb2hsv function implementation static auto rgb2hsv(RGB_DOUBLE input) { RGB rgb{static_cast<std::uint8_t>(input.channels[0]), static_cast<std::uint8_t>(input.channels[1]), static_cast<std::uint8_t>(input.channels[2])}; return rgb2hsv(rgb); } // rgb2hsv function implementation static auto rgb2hsv(RGB input) { HSV output{}; std::uint8_t Red = input.channels[0], Green = input.channels[1], Blue = input.channels[2]; std::vector<std::uint8_t> v{ Red, Green, Blue }; std::ranges::sort(v); std::uint8_t Max = v[2], Mid = v[1], Min = v[0]; auto H1 = std::acos(0.5 * ((Red - Green) + (Red - Blue)) / std::sqrt(((std::pow((Red - Green), 2.0)) + (Red - Blue) * (Green - Blue)))) * (180.0 / std::numbers::pi); if (Max == Min) { output.channels[0] = 0.0; } else if (Blue <= Green) { output.channels[0] = H1; } else { output.channels[0] = 360.0 - H1; } if (Max == 0) { output.channels[1] = 0.0; } else { output.channels[1] = 1.0 - (static_cast<double>(Min) / static_cast<double>(Max)); } output.channels[2] = Max; return output; }
The usage of histogram 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(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 (const auto& elem : histogram_result1)
{
std::cout << elem.first << " count: " << elem.second << "\n";
sum += elem.second;
}
std::cout << "Sum = " << sum << '\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.101583
0 count: 1966
1 count: 65
2 count: 72
3 count: 75
4 count: 71
5 count: 49
6 count: 67
7 count: 52
8 count: 78
9 count: 58
10 count: 60
11 count: 58
12 count: 66
13 count: 75
14 count: 86
15 count: 98
16 count: 105
17 count: 139
18 count: 301
19 count: 554
20 count: 1052
21 count: 1551
22 count: 2407
23 count: 3593
24 count: 5618
25 count: 8144
26 count: 10541
27 count: 12335
28 count: 14096
29 count: 15881
30 count: 16950
31 count: 17881
32 count: 18950
33 count: 19432
34 count: 20085
35 count: 20687
36 count: 21367
37 count: 21758
38 count: 22450
39 count: 23288
40 count: 23501
41 count: 23818
42 count: 24173
43 count: 23949
44 count: 23445
45 count: 22823
46 count: 22218
47 count: 21807
48 count: 21137
49 count: 20491
50 count: 19820
51 count: 19644
52 count: 19148
53 count: 18567
54 count: 18190
55 count: 17536
56 count: 16935
57 count: 16640
58 count: 15821
59 count: 15337
60 count: 14813
61 count: 14085
62 count: 13722
63 count: 13101
64 count: 12752
65 count: 12188
66 count: 11973
67 count: 11385
68 count: 11036
69 count: 10681
70 count: 10205
71 count: 9761
72 count: 9574
73 count: 9162
74 count: 9056
75 count: 8700
76 count: 8270
77 count: 8096
78 count: 7671
79 count: 7575
80 count: 7366
81 count: 7262
82 count: 7011
83 count: 6692
84 count: 6533
85 count: 6459
86 count: 5996
87 count: 5783
88 count: 5764
89 count: 5554
90 count: 5413
91 count: 5310
92 count: 5069
93 count: 5021
94 count: 5026
95 count: 4816
96 count: 4788
97 count: 4561
98 count: 4528
99 count: 4296
100 count: 4308
101 count: 4316
102 count: 4123
103 count: 4023
104 count: 3850
105 count: 3873
106 count: 3731
107 count: 3737
108 count: 3685
109 count: 3566
110 count: 3505
111 count: 3462
112 count: 3383
113 count: 3350
114 count: 3264
115 count: 3204
116 count: 3216
117 count: 3187
118 count: 3191
119 count: 3163
120 count: 2903
121 count: 3040
122 count: 2956
123 count: 2899
124 count: 2802
125 count: 2916
126 count: 2833
127 count: 2745
128 count: 2918
129 count: 2843
130 count: 2795
131 count: 2718
132 count: 2758
133 count: 2781
134 count: 2821
135 count: 2755
136 count: 2763
137 count: 2739
138 count: 2770
139 count: 2705
140 count: 2812
141 count: 2733
142 count: 2766
143 count: 2792
144 count: 2790
145 count: 2813
146 count: 2674
147 count: 2655
148 count: 2544
149 count: 2562
150 count: 2542
151 count: 2668
152 count: 2586
153 count: 2521
154 count: 2525
155 count: 2497
156 count: 2503
157 count: 2513
158 count: 2517
159 count: 2406
160 count: 2526
161 count: 2571
162 count: 2531
163 count: 2504
164 count: 2536
165 count: 2454
166 count: 2529
167 count: 2651
168 count: 2530
169 count: 2519
170 count: 2522
171 count: 2600
172 count: 2614
173 count: 2603
174 count: 2748
175 count: 2711
176 count: 2783
177 count: 2877
178 count: 2921
179 count: 2909
180 count: 2814
181 count: 2747
182 count: 2648
183 count: 2615
184 count: 2510
185 count: 2526
186 count: 2363
187 count: 2284
188 count: 2036
189 count: 2022
190 count: 1908
191 count: 1912
192 count: 1920
193 count: 1818
194 count: 1896
195 count: 1977
196 count: 2016
197 count: 2030
198 count: 2004
199 count: 1855
200 count: 1660
201 count: 1485
202 count: 1395
203 count: 1314
204 count: 1278
205 count: 1064
206 count: 899
207 count: 850
208 count: 847
209 count: 824
210 count: 834
211 count: 838
212 count: 839
213 count: 833
214 count: 913
215 count: 844
216 count: 807
217 count: 827
218 count: 837
219 count: 846
220 count: 889
221 count: 863
222 count: 871
223 count: 931
224 count: 909
225 count: 924
226 count: 950
227 count: 878
228 count: 895
229 count: 833
230 count: 909
231 count: 959
232 count: 870
233 count: 943
234 count: 915
235 count: 870
236 count: 897
237 count: 986
238 count: 925
239 count: 1003
240 count: 999
241 count: 1016
242 count: 1003
243 count: 1032
244 count: 1067
245 count: 1062
246 count: 1148
247 count: 1188
248 count: 1311
249 count: 1391
250 count: 1522
251 count: 1704
252 count: 2114
253 count: 2766
254 count: 4315
255 count: 39663
Sum = 1393326
Computation finished at Sun Feb 23 21:35:00 2025
elapsed time: 1.10037
Furthermore, because the key of std::map is ElementT, histogram template function can also be used like:
auto histogram_result1 = TinyDIP::histogram(hsv_image);
Then the output:
Width of the input image: 454
Height of the input image: 341
Size of the input image(Byte): 464442
elapsed time: 0.97611
{0, 0, 0} count: 1966
{0, 0, 1} count: 27
{0, 0, 2} count: 22
{0, 0, 3} count: 23
{0, 0, 4} count: 27
{0, 0, 5} count: 17
{0, 0, 6} count: 22
{0, 0, 7} count: 16
{0, 0, 8} count: 22
{0, 0, 9} count: 17
{0, 0, 10} count: 15
{0, 0, 11} count: 15
{0, 0, 12} count: 15
{0, 0, 13} count: 15
{0, 0, 14} count: 11
{0, 0, 15} count: 17
{0, 0, 16} count: 11
{0, 0, 17} count: 7
{0, 0, 18} count: 18
{0, 0, 19} count: 13
{0, 0, 20} count: 11
{0, 0, 21} count: 13
{0, 0, 22} count: 29
{0, 0, 23} count: 26
{0, 0, 24} count: 28
{0, 0, 25} count: 24
{0, 0, 26} count: 28
{0, 0, 27} count: 28
{0, 0, 28} count: 27
{0, 0, 29} count: 36
{0, 0, 30} count: 35
{0, 0, 31} count: 54
{0, 0, 32} count: 55
{0, 0, 33} count: 67
{0, 0, 34} count: 76
{0, 0, 35} count: 85
{0, 0, 36} count: 83
{0, 0, 37} count: 88
{0, 0, 38} count: 93
{0, 0, 39} count: 99
{0, 0, 40} count: 100
{0, 0, 41} count: 114
{0, 0, 42} count: 100
{0, 0, 43} count: 113
{0, 0, 44} count: 118
{0, 0, 45} count: 116
{0, 0, 46} count: 110
{0, 0, 47} count: 100
{0, 0, 48} count: 97
{0, 0, 49} count: 109
{0, 0, 50} count: 99
{0, 0, 51} count: 84
{0, 0, 52} count: 88
{0, 0, 53} count: 82
{0, 0, 54} count: 81
{0, 0, 55} count: 77
{0, 0, 56} count: 67
{0, 0, 57} count: 67
{0, 0, 58} count: 78
{0, 0, 59} count: 62
{0, 0, 60} count: 76
{0, 0, 61} count: 67
{0, 0, 62} count: 45
{0, 0, 63} count: 58
{0, 0, 64} count: 62
{0, 0, 65} count: 74
{0, 0, 66} count: 50
{0, 0, 67} count: 46
{0, 0, 68} count: 60
{0, 0, 69} count: 43
{0, 0, 70} count: 47
{0, 0, 71} count: 23
{0, 0, 72} count: 47
{0, 0, 73} count: 47
{0, 0, 74} count: 36
{0, 0, 75} count: 30
{0, 0, 76} count: 30
{0, 0, 77} count: 30
{0, 0, 78} count: 35
{0, 0, 79} count: 42
{0, 0, 80} count: 33
{0, 0, 81} count: 27
{0, 0, 82} count: 20
{0, 0, 83} count: 21
{0, 0, 84} count: 38
{0, 0, 85} count: 28
{0, 0, 86} count: 32
{0, 0, 87} count: 24
{0, 0, 88} count: 27
{0, 0, 89} count: 26
{0, 0, 90} count: 27
{0, 0, 91} count: 13
{0, 0, 92} count: 16
{0, 0, 93} count: 19
{0, 0, 94} count: 25
{0, 0, 95} count: 25
{0, 0, 96} count: 16
{0, 0, 97} count: 10
{0, 0, 98} count: 13
{0, 0, 99} count: 17
{0, 0, 100} count: 23
{0, 0, 101} count: 16
{0, 0, 102} count: 18
{0, 0, 103} count: 22
{0, 0, 104} count: 12
{0, 0, 105} count: 16
{0, 0, 106} count: 20
{0, 0, 107} count: 22
{0, 0, 108} count: 16
{0, 0, 109} count: 12
{0, 0, 110} count: 17
{0, 0, 111} count: 11
{0, 0, 112} count: 21
{0, 0, 113} count: 24
{0, 0, 114} count: 14
{0, 0, 115} count: 17
{0, 0, 116} count: 15
{0, 0, 117} count: 22
{0, 0, 118} count: 11
{0, 0, 119} count: 24
{0, 0, 120} count: 14
{0, 0, 121} count: 13
{0, 0, 122} count: 31
{0, 0, 123} count: 18
{0, 0, 124} count: 18
{0, 0, 125} count: 30
{0, 0, 126} count: 17
{0, 0, 127} count: 17
{0, 0, 128} count: 19
{0, 0, 129} count: 12
{0, 0, 130} count: 12
{0, 0, 131} count: 20
{0, 0, 132} count: 20
{0, 0, 133} count: 27
{0, 0, 134} count: 19
{0, 0, 135} count: 26
{0, 0, 136} count: 27
{0, 0, 137} count: 26
{0, 0, 138} count: 19
{0, 0, 139} count: 26
{0, 0, 140} count: 33
{0, 0, 141} count: 32
{0, 0, 142} count: 21
{0, 0, 143} count: 29
{0, 0, 144} count: 13
{0, 0, 145} count: 22
{0, 0, 146} count: 21
{0, 0, 147} count: 22
{0, 0, 148} count: 25
{0, 0, 149} count: 24
{0, 0, 150} count: 26
{0, 0, 151} count: 27
{0, 0, 152} count: 30
{0, 0, 153} count: 27
{0, 0, 154} count: 14
{0, 0, 155} count: 14
{0, 0, 156} count: 12
{0, 0, 157} count: 19
{0, 0, 158} count: 20
{0, 0, 159} count: 32
{0, 0, 160} count: 23
{0, 0, 161} count: 26
{0, 0, 162} count: 23
{0, 0, 163} count: 16
{0, 0, 164} count: 26
{0, 0, 165} count: 19
{0, 0, 166} count: 27
{0, 0, 167} count: 18
{0, 0, 168} count: 20
{0, 0, 169} count: 23
{0, 0, 170} count: 31
{0, 0, 171} count: 28
{0, 0, 172} count: 23
{0, 0, 173} count: 18
{0, 0, 174} count: 26
{0, 0, 175} count: 24
{0, 0, 176} count: 27
{0, 0, 177} count: 40
{0, 0, 178} count: 28
{0, 0, 179} count: 28
{0, 0, 180} count: 20
{0, 0, 181} count: 27
{0, 0, 182} count: 33
{0, 0, 183} count: 34
{0, 0, 184} count: 22
{0, 0, 185} count: 31
{0, 0, 186} count: 31
{0, 0, 187} count: 25
{0, 0, 188} count: 18
{0, 0, 189} count: 20
{0, 0, 190} count: 19
{0, 0, 191} count: 18
{0, 0, 192} count: 17
{0, 0, 193} count: 11
{0, 0, 194} count: 17
{0, 0, 195} count: 18
{0, 0, 196} count: 19
{0, 0, 197} count: 16
{0, 0, 198} count: 9
{0, 0, 199} count: 12
{0, 0, 200} count: 11
{0, 0, 201} count: 14
{0, 0, 202} count: 24
{0, 0, 203} count: 13
{0, 0, 204} count: 15
{0, 0, 205} count: 18
{0, 0, 206} count: 15
{0, 0, 207} count: 13
{0, 0, 208} count: 9
{0, 0, 209} count: 8
{0, 0, 210} count: 13
{0, 0, 211} count: 9
{0, 0, 212} count: 18
{0, 0, 213} count: 11
{0, 0, 214} count: 11
{0, 0, 215} count: 24
{0, 0, 216} count: 19
{0, 0, 217} count: 18
{0, 0, 218} count: 12
{0, 0, 219} count: 10
{0, 0, 220} count: 16
{0, 0, 221} count: 22
{0, 0, 222} count: 22
{0, 0, 223} count: 14
{0, 0, 224} count: 20
{0, 0, 225} count: 14
{0, 0, 226} count: 9
{0, 0, 227} count: 21
{0, 0, 228} count: 22
{0, 0, 229} count: 14
{0, 0, 230} count: 23
{0, 0, 231} count: 14
{0, 0, 232} count: 12
{0, 0, 233} count: 14
{0, 0, 234} count: 20
{0, 0, 235} count: 22
{0, 0, 236} count: 10
{0, 0, 237} count: 17
{0, 0, 238} count: 15
{0, 0, 239} count: 9
{0, 0, 240} count: 15
{0, 0, 241} count: 11
{0, 0, 242} count: 13
{0, 0, 243} count: 16
{0, 0, 244} count: 12
{0, 0, 245} count: 18
{0, 0, 246} count: 16
{0, 0, 247} count: 13
{0, 0, 248} count: 19
{0, 0, 249} count: 14
{0, 0, 250} count: 22
{0, 0, 251} count: 18
{0, 0, 252} count: 26
{0, 0, 253} count: 27
{0, 0, 254} count: 215
{0, 0, 255} count: 10122
{0, 0.00392157, 255} count: 95
{0, 0.00393701, 254} count: 21
{0, 0.00395257, 253} count: 3
{0, 0.00396825, 252} count: 3
{0, 0.00398406, 251} count: 1
{0, 0.00406504, 246} count: 1
{0, 0.00421941, 237} count: 1
{0, 0.00423729, 236} count: 1
{0, 0.0046729, 214} count: 1
{0, 0.00502513, 199} count: 1
{0, 0.00507614, 197} count: 1
{0, 0.00510204, 196} count: 2
{0, 0.00512821, 195} count: 2
{0, 0.00515464, 194} count: 2
{0, 0.00518135, 193} count: 3
{0, 0.00520833, 192} count: 5
{0, 0.0052356, 191} count: 5
{0, 0.00529101, 189} count: 7
{0, 0.00531915, 188} count: 7
{0, 0.00534759, 187} count: 6
{0, 0.00537634, 186} count: 4
{0, 0.00540541, 185} count: 3
{0, 0.00543478, 184} count: 6
{0, 0.00546448, 183} count: 4
{0, 0.00549451, 182} count: 5
{0, 0.00552486, 181} count: 16
{0, 0.00555556, 180} count: 7
{0, 0.00558659, 179} count: 10
{0, 0.00561798, 178} count: 5
{0, 0.00564972, 177} count: 10
{0, 0.00568182, 176} count: 13
{0, 0.00571429, 175} count: 2
{0, 0.00574713, 174} count: 4
{0, 0.00578035, 173} count: 6
{0, 0.00581395, 172} count: 4
{0, 0.00584795, 171} count: 5
{0, 0.00588235, 170} count: 8
{0, 0.00591716, 169} count: 7
{0, 0.00595238, 168} count: 3
{0, 0.00598802, 167} count: 6
{0, 0.0060241, 166} count: 4
{0, 0.00606061, 165} count: 7
{0, 0.00609756, 164} count: 6
{0, 0.00613497, 163} count: 5
{0, 0.00617284, 162} count: 4
{0, 0.00621118, 161} count: 3
{0, 0.00625, 160} count: 5
{0, 0.00628931, 159} count: 4
{0, 0.00632911, 158} count: 9
{0, 0.00636943, 157} count: 5
{0, 0.00641026, 156} count: 8
{0, 0.00645161, 155} count: 4
{0, 0.00649351, 154} count: 10
{0, 0.00653595, 153} count: 4
{0, 0.00657895, 152} count: 3
{0, 0.00662252, 151} count: 9
{0, 0.00666667, 150} count: 6
{0, 0.00671141, 149} count: 6
{0, 0.00675676, 148} count: 8
{0, 0.00680272, 147} count: 4
{0, 0.00684932, 146} count: 6
{0, 0.00689655, 145} count: 14
{0, 0.00694444, 144} count: 11
{0, 0.00699301, 143} count: 10
{0, 0.00704225, 142} count: 13
{0, 0.0070922, 141} count: 7
{0, 0.00714286, 140} count: 10
{0, 0.00719424, 139} count: 11
{0, 0.00724638, 138} count: 11
{0, 0.00729927, 137} count: 9
{0, 0.00735294, 136} count: 12
{0, 0.00740741, 135} count: 12
{0, 0.00746269, 134} count: 2
{0, 0.0075188, 133} count: 11
{0, 0.00757576, 132} count: 12
{0, 0.00763359, 131} count: 10
{0, 0.00769231, 130} count: 5
{0, 0.00775194, 129} count: 8
{0, 0.0078125, 128} count: 12
{0, 0.00784314, 255} count: 15
{0, 0.00787402, 127} count: 7
{0, 0.00787402, 254} count: 15
{0, 0.00790514, 253} count: 9
{0, 0.00793651, 126} count: 9
{0, 0.00793651, 252} count: 1
{0, 0.00796813, 251} count: 2
{0, 0.008, 125} count: 4
{0, 0.008, 250} count: 1
{0, 0.00806452, 124} count: 1
{0, 0.00813008, 123} count: 4
{0, 0.00819672, 122} count: 6
{0, 0.00819672, 244} count: 1
{0, 0.00826446, 121} count: 6
{0, 0.00833333, 120} count: 8
{0, 0.00840336, 119} count: 6
{0, 0.00847458, 118} count: 4
{0, 0.00854701, 117} count: 5
{0, 0.00862069, 116} count: 5
{0, 0.00869565, 115} count: 6
{0, 0.00877193, 114} count: 5
{0, 0.00884956, 113} count: 7
{0, 0.00892857, 112} count: 5
{0, 0.00900901, 111} count: 8
{0, 0.00909091, 110} count: 9
{0, 0.00909091, 220} count: 1
...
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++ and
What changes has been made in the code since last question?
I implemented
histogramtemplate function withstd::mapin this post.Why a new review is being asked for?
Please review the implementation of
histogramtemplate function and its tests.