6
\$\begingroup\$

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 ElementT is a signed type and the image has negative values, using image value as array index is not working.

  • If ElementT is 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

  • histogram template 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;
    }
    
  • histogram template function implementation for type std::uint8_t and std::uint16_t

    For type std::uint8_t and std::uint16_t, histogram template function still uses std::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;
    }
    
  • rgb2hsv template 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
...

TinyDIP on GitHub

All suggestions are welcome.

The summary information:

asked Feb 23 at 14:04
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

For an arbitrary floting-point image, it is unlikely that two pixels have the same value. (Sure, if you convert an 8-bit image to float there will be many pixels with the same values, but apply a Gaussian filter and you’ll see few counts in your histogram with a value above 1.) This is because you cannot, generally, do equality comparisons with floating-point numbers. Comparisons have to be approximate, they need a tolerance. And your map does equality comparison on the pixel value. Computing a histogram where most counts are 1 doesn’t really provide any new insight into the image data, it just sorts the pixel values.

A histogram usually is defined by bins. You divide the range of values into some number of bins, each bin will then span a section of that range. A pixel with a value of 0.145 and one with a value of 0.138 might fall in the same bin, one with a value of 0.137 might fall in another bin.

So, for example, say your data falls in the range [0,1], and you use 200 bins. The bin width will be 1/200 = 0.005. For each pixel you then compute:

std::size_t bin = std::floor(value / 0.005);

(obviously with bounds checking if necessary), and increment that histogram bin:

++histogram[bin];

Yes, this is more expensive, but it is the only way to compute a meaningful, useful histogram from floating-point data.

For 32-bit or 64-bit data the same applies: you can do equality comparisons, but you will be likely to have most counts be 1, because an image typically has many fewer pixels than you can address with 32 bits. You need to group intervals of values together to get a useful histogram.


It is good that you have a separate implementation for 8 and 16-bit unsigned integers. That code still uses std::numeric_limits<ElementT>::lowest(), which is always 0.

The biggest issue with your code for me would be that the value returned by the histogram function has a different type (with different member functions) depending on the data type of the input image. This makes it harder to write generic code. But that is something that is likely not as important for other people.

answered Feb 23 at 15:38
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Jimmy, I’m often telling you how things are usually done in image processing. You don’t need to follow convention, and you certainly don’t need to take my advice. But it is good to look at the conventional implementations, because people have been doing this for a long time, a lot of thought and reasoning has gone into them, which means there is stuff to learn from it. But it is still possible to improve on the conventional stuff, so don’t follow it blindly. \$\endgroup\$ Commented Feb 23 at 15:45

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.