ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
itkRankHistogram.h
Go to the documentation of this file.
1/*=========================================================================
2 *
3 * Copyright NumFOCUS
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18// histogram from the moving histogram operations
19#ifndef itkRankHistogram_h
20#define itkRankHistogram_h
21
22#include "itkIntTypes.h"
23#include "itkNumericTraits.h"
24
25#include <map>
26#include <vector>
27
28namespace itk::Function
29{
30
31/* \class RankHistogram
32 * \brief A simple histogram class hierarchy. One specialization will
33 * be maps, the other vectors.
34 *
35 * This version is intended for keeping track of arbitrary ranks. It
36 * is based on the code from consolidatedMorphology.
37 *
38 * This is a modified version for use with masks. Need to allow for
39 * the situation in which the map is empty.
40 *
41 * This code was contributed in the Insight Journal paper:
42 * "Efficient implementation of kernel filtering"
43 * by Beare R., Lehmann G
44 * https://doi.org/10.54294/igq8fn
45 *
46 * /sa VectorRankHistogram
47 */
48template <typename TInputPixel>
50{
51public:
52 using Compare = std::less<TInputPixel>;
53
55
56 {
57 m_Below = m_Entries = 0;
58 // can't set m_RankIt until something has been put in the histogram
60 {
62 }
63 else
64 {
66 }
68 m_RankIt = m_Map.begin(); // equivalent to setting to the initial value
69 }
70
71 ~RankHistogram() = default;
72
75 {
76 if (this != &hist)
77 {
78 m_Map = hist.m_Map;
79 m_Rank = hist.m_Rank;
80 m_Below = hist.m_Below;
81 m_Entries = hist.m_Entries;
82 m_InitVal = hist.m_InitVal;
85 if (m_Initialized)
86 {
88 }
89 }
90 return *this;
91 }
92
93 void
94 AddPixel(const TInputPixel & p)
95 {
96 m_Map[p]++;
97 if (!m_Initialized)
98 {
99 m_Initialized = true;
100 m_RankIt = m_Map.begin();
101 m_Entries = m_Below = 0;
102 m_RankValue = p;
103 }
104 if (m_Compare(p, m_RankValue) || p == m_RankValue)
105 {
106 ++m_Below;
107 }
108 ++m_Entries;
109 }
110
111 void
112 RemovePixel(const TInputPixel & p)
113 {
114 m_Map[p]--;
115 if (m_Compare(p, m_RankValue) || p == m_RankValue)
116 {
117 --m_Below;
118 }
119 --m_Entries;
120 // this is the change that makes this version less efficient. The
121 // simplest approach I can think of with maps, though
122 if (m_Entries <= 0)
123 {
124 m_Initialized = false;
125 m_Below = 0;
126 m_Map.clear();
127 }
128 }
129
130 bool
132 {
133 return m_Initialized;
134 }
135
136 TInputPixel
138 {
139 SizeValueType count = 0;
140 SizeValueType target = static_cast<int>(m_Rank * (m_Entries - 1)) + 1;
141 for (typename MapType::iterator it = m_Map.begin(); it != m_Map.end(); ++it)
142 {
143 count += it->second;
144 if (count >= target)
145 {
146 return it->first;
147 }
148 }
150 }
151
152 TInputPixel
153 GetValue(const TInputPixel &)
154 {
155 const SizeValueType target = (SizeValueType)(m_Rank * (m_Entries - 1)) + 1;
156 SizeValueType total = m_Below;
157
158 bool eraseFlag = false;
159
160 if (total < target)
161 {
162 auto searchIt = m_RankIt;
163 typename MapType::iterator eraseIt;
164
165 while (searchIt != m_Map.end())
166 {
167 // cleaning up the map - probably a better way of organising
168 // the loop. Currently makes sure that the search iterator is
169 // incremented before deleting
170 ++searchIt;
171 SizeValueType ThisBin = searchIt->second;
172 total += ThisBin;
173 if (eraseFlag)
174 {
175 m_Map.erase(eraseIt);
176 eraseFlag = false;
177 }
178 if (ThisBin <= 0)
179 {
180 eraseFlag = true;
181 eraseIt = searchIt;
182 }
183 if (total >= target)
184 {
185 break;
186 }
187 }
188 if (searchIt == m_Map.end())
189 {
190 --searchIt;
191 }
192 m_RankValue = searchIt->first;
193 m_RankIt = searchIt;
194 }
195 else
196 {
197 auto searchIt = m_RankIt;
198 typename MapType::iterator eraseIt;
199
200 while (searchIt != m_Map.begin())
201 {
202 SizeValueType ThisBin = searchIt->second;
203 const unsigned int tbelow = total - ThisBin;
204 if (tbelow < target) // we've overshot
205 {
206 break;
207 }
208 if (eraseFlag)
209 {
210 m_Map.erase(eraseIt);
211 eraseFlag = false;
212 }
213 if (ThisBin <= 0)
214 {
215 eraseIt = searchIt;
216 eraseFlag = true;
217 }
218 total = tbelow;
219
220 --searchIt;
221 }
222 m_RankValue = searchIt->first;
223 m_RankIt = searchIt;
224 }
225
226 m_Below = total;
227 itkAssertInDebugAndIgnoreInReleaseMacro(m_RankValue == GetValueBruteForce());
228 return (m_RankValue);
229 }
230
231 void
232 SetRank(float rank)
233 {
234 m_Rank = rank;
235 }
236
237 void
239 {}
240
241 void
244
245 static bool
247 {
248 return false;
249 }
250
251protected:
252 float m_Rank{ 0.5 };
253
254private:
255 using MapType = typename std::map<TInputPixel, SizeValueType, Compare>;
256
260 TInputPixel m_RankValue;
261 TInputPixel m_InitVal;
263 bool m_Initialized{ false };
264
265 // This iterator will point at the desired rank value
266 typename MapType::iterator m_RankIt;
267};
268
269
270template <typename TInputPixel>
272{
273public:
274 using Compare = std::less<TInputPixel>;
275
293
295
296 bool
298 {
299 return m_Entries > 0;
300 }
301
302 TInputPixel
304 {
305 SizeValueType count = 0;
306 const SizeValueType target = (SizeValueType)(m_Rank * (m_Entries - 1)) + 1;
307 for (SizeValueType i = 0; i < m_Size; ++i)
308 {
309 count += m_Vec[i];
310 if (count >= target)
311 {
313 }
314 }
316 }
317
318 TInputPixel
319 GetValue(const TInputPixel &)
320 {
321 return GetValueBruteForce();
322 }
323
324 void
325 AddPixel(const TInputPixel & p)
326 {
328
329 m_Vec[q]++;
330 if (m_Compare(p, m_RankValue) || p == m_RankValue)
331 {
332 ++m_Below;
333 }
334 ++m_Entries;
335 }
336
337 void
338 RemovePixel(const TInputPixel & p)
339 {
341
342 itkAssertInDebugAndIgnoreInReleaseMacro(q >= 0);
343 itkAssertInDebugAndIgnoreInReleaseMacro(q < static_cast<int>(m_Vec.size()));
344 itkAssertInDebugAndIgnoreInReleaseMacro(m_Entries >= 1);
345 itkAssertInDebugAndIgnoreInReleaseMacro(m_Vec[q] > 0);
346
347 m_Vec[q]--;
348 --m_Entries;
349
350 if (m_Compare(p, m_RankValue) || p == m_RankValue)
351 {
352 --m_Below;
353 }
354 }
355
356 void
357 SetRank(float rank)
358 {
359 m_Rank = rank;
360 }
361
362 void
364 {}
365
366 void
369
370 static bool
372 {
373 return true;
374 }
375
376protected:
377 float m_Rank;
378
379private:
380 using VecType = typename std::vector<SizeValueType>;
381
385 TInputPixel m_RankValue;
386 TInputPixel m_InitVal;
389};
390
391// now create MorphologicalGradientHistogram specializations using the VectorMorphologicalGradientHistogram
392// as base class
393
395
396template <>
397class RankHistogram<unsigned char> : public VectorRankHistogram<unsigned char>
398{};
399
400template <>
401class RankHistogram<signed char> : public VectorRankHistogram<signed char>
402{};
403
404template <>
405class ITK_TEMPLATE_EXPORT RankHistogram<bool> : public VectorRankHistogram<bool>
406{};
407
409
410} // namespace itk::Function
411#endif
std::less< TInputPixel > Compare
TInputPixel GetValue(const TInputPixel &)
typename std::map< TInputPixel, SizeValueType, Compare > MapType
RankHistogram & operator=(const RankHistogram &hist)
void AddPixel(const TInputPixel &p)
void RemovePixel(const TInputPixel &p)
typename std::vector< SizeValueType > VecType
void RemovePixel(const TInputPixel &p)
void AddPixel(const TInputPixel &p)
TInputPixel GetValue(const TInputPixel &)
Define additional traits for native types such as int or float.
static constexpr T NonpositiveMin()
static constexpr T max(const T &)
unsigned long SizeValueType
Definition itkIntTypes.h:86
long OffsetValueType
Definition itkIntTypes.h:97