ICF 3.0.5.47
Technical documentation of ICF Libraries
TGeneralHoughSpace.h
Go to the documentation of this file.
1/********************************************************************************
2** This file is part of the ICF Framework. Copyright (C) Witold Gantzke & Kirill Lepskiy
3** ICF Framework may be used under the terms of the LGPL License v. 2.1 by the Free Software Foundation.
4********************************************************************************/
5
6#pragma once
7
8
9// Qt includes
10#include <QtCore/QMultiMap>
11
12// ICF includes
13#include <i2d/CVector2d.h>
14#include <istd/TArray.h>
15#include <ialgo/TIHoughSpace.h>
16
17
18namespace ialgo
19{
20
21
25template <int Dimensions, class Element = double>
27 public istd::TArray<Element, Dimensions>,
28 virtual public TIHoughSpace<Dimensions, Element>
29{
30public:
33
36
40 template <typename Operation>
41 void ApplyOperation(Operation operation);
42
46 template <typename Operation>
47 void CombineWithSpace(const TGeneralHoughSpace& space, Operation operation);
48
53 void SetDimensionWrapped(int dimensionIndex, bool state);
54
58 void SetExtensionBorder(int dimensionIndex, bool state);
59
63 double GetDistScalingFactor(int dimensionIndex) const;
67 void SetDistScalingFactor(int dimensionIndex, double factor);
68
69 // reimplemented (ialgo::TIHoughSpace)
71 virtual bool CreateHoughSpace(const istd::TIndex<Dimensions>& size, const Element& initValue = 0);
72 virtual bool IsDimensionWrapped(int dimensionIndex) const;
73 virtual typename BaseClass2::ExtensionMode GetExtensionMode(int dimensionIndex) const;
74 virtual void IncreaseValueAt(const imath::TVector<Dimensions>& position, Element value);
75 virtual void SmoothHoughSpace(const istd::TIndex<Dimensions>& iterations);
76 virtual bool AnalyseHoughSpace(
77 const Element& minValue,
78 typename BaseClass2::ResultsConsumer& resultProcessor) const;
79 virtual bool ExtractToBitmap(iimg::IBitmap& bitmap) const;
80 virtual bool GetSpacePosition(const imath::TVector<Dimensions>& position, imath::TVector<Dimensions>& result) const;
81 virtual double GetSpaceDistance(const imath::TVector<Dimensions>& position1, const imath::TVector<Dimensions>& position2) const;
82 virtual double GetSpaceDistance2(const imath::TVector<Dimensions>& position1, const imath::TVector<Dimensions>& position2) const;
83
84 // reimplemented (iser::ISerializable)
85 virtual bool Serialize(iser::IArchive& archive);
86
87protected:
88 void SmoothSingleDimension(int dimensionIndex, int iterations);
89
90private:
91 bool m_isWrapped[Dimensions];
92 bool m_extensionModeBorders[Dimensions];
93 double m_distScalingFactors[Dimensions];
94};
95
96
97// inline methods
98
99template <int Dimensions, class Element>
101{
102 return qSqrt(GetSpaceDistance2(position1, position2));
103}
104
105
106template <int Dimensions, class Element>
108{
109 double distance2 = 0;
110
111 for (int i = 0; i < Dimensions; ++i){
112 double diff = position2[i] - position1[i];
113
114 if (m_isWrapped[i]){
115 double offset = BaseClass::m_sizes[i] * 0.5;
116
117 diff = std::fmod(diff + offset + BaseClass::m_sizes[i], BaseClass::m_sizes[i]) - offset;
118 }
119
120 diff *= m_distScalingFactors[i];
121
122 distance2 += diff * diff;
123 }
124
125 return distance2;
126}
127
128
129// public methods
130
131template <int Dimensions, class Element>
135
136
137template <int Dimensions, class Element>
142
143
144template <int Dimensions, class Element>
146{
147 Q_ASSERT(dimensionIndex >= 0);
148 Q_ASSERT(dimensionIndex < Dimensions);
149
150 m_isWrapped[dimensionIndex] = state;
151}
152
153
154template <int Dimensions, class Element>
156{
157 Q_ASSERT(dimensionIndex >= 0);
158 Q_ASSERT(dimensionIndex < Dimensions);
159
160 m_extensionModeBorders[dimensionIndex] = state;
161}
162
163
164template <int Dimensions, class Element>
166{
167 Q_ASSERT(dimensionIndex >= 0);
168 Q_ASSERT(dimensionIndex < Dimensions);
169
170 return m_distScalingFactors[dimensionIndex];
171}
172
173
174template <int Dimensions, class Element>
176{
177 Q_ASSERT(dimensionIndex >= 0);
178 Q_ASSERT(dimensionIndex < Dimensions);
179
180 m_distScalingFactors[dimensionIndex] = factor;
181}
182
183
184// reimplemented (ialgo::TIHoughSpace)
185
186template <int Dimensions, class Element>
188{
189 return BaseClass::GetSizes();
190}
191
192
193template <int Dimensions, class Element>
195{
196 istd::CChangeNotifier notifier(this);
197
198 for (int i = 0; i < Dimensions; ++i){
199 m_isWrapped[i] = false;
200 m_extensionModeBorders[i] = false;
201
202 m_distScalingFactors[i] = 1;
203 }
204
205 BaseClass::SetSizes(size);
206 BaseClass::SetAllElements(initValue);
207
208 return true;
209}
210
211
212template <int Dimensions, class Element>
214{
215 Q_ASSERT(dimensionIndex >= 0);
216 Q_ASSERT(dimensionIndex < Dimensions);
217
218 return m_isWrapped[dimensionIndex];
219}
220
221
222template <int Dimensions, class Element>
224{
225 Q_ASSERT(dimensionIndex >= 0);
226 Q_ASSERT(dimensionIndex < Dimensions);
227
228 return m_extensionModeBorders[dimensionIndex]? BaseClass2::EM_ZERO: BaseClass2::EM_BORDER;
229}
230
231
232template <int Dimensions, class Element>
234{
236
237 int elementOffset = 0;
238 for (int i = Dimensions - 1; i >= 0; --i){
239 int singleIndex = int(position[i]);
240 int size = BaseClass::m_sizes[i];
241
242 elementOffset *= size;
243
244 if (m_isWrapped[i]){ // correct the position if is wrapped
245 singleIndex = (singleIndex + size) % size;
246 }
247 else{
248 if ((singleIndex < 0) || (singleIndex >= size)){
249 return;
250 }
251 }
252
253 Q_ASSERT(singleIndex >= 0);
254 Q_ASSERT(singleIndex < size);
255
256 elementOffset += singleIndex;
257 }
258
259 BaseClass::m_elements[elementOffset] += Element(value);
260}
261
262
263template <int Dimensions, class Element>
265{
266 for (int i = 0; i < Dimensions; ++i){
267 if (BaseClass::m_sizes[i] >= 3){
268 int iterCount = iterations[i];
269 if (iterCount > 0){
270 SmoothSingleDimension(i, iterCount);
271 }
272 }
273 }
274}
275
276
277template <int Dimensions, class Element>
279 const Element& minValue,
280 typename BaseClass2::ResultsConsumer& resultProcessor) const
281{
282 QList<int> supportedNeighboursCount = resultProcessor.GetSupportedNeghboursCount();
283 if (!supportedNeighboursCount.contains(Dimensions * 2) && !supportedNeighboursCount.isEmpty()){
284 return false;
285 }
286
287 for (int i = 0; i < Dimensions; ++i){
288 if (BaseClass::m_sizes[i] < 1){
289 return false;
290 }
291 }
292
293 resultProcessor.OnProcessingBegin(*this, minValue);
294
295 Element neighbours[Dimensions * 2];
296
297 Element currentMinValue(minValue);
298
299 typename BaseClass::IndexType index = BaseClass::IndexType::GetZero();
300 if (index.IsInside(BaseClass::m_sizes)){
301 do{
302 Element value = BaseClass::GetAt(index);
303 if (value >= currentMinValue){
304 for (int i = 0; i < Dimensions; ++i){
305 int size = BaseClass::m_sizes[i];
306 if (size >= 1){
307 if (m_isWrapped[i]){
308 typename BaseClass::IndexType prevIndex = index;
309 prevIndex[i] = (index[i] + size - 1) % size;
310 Element prevValue = BaseClass::GetAt(prevIndex);
311 if (prevValue >= value){
312 goto nextElement;
313 }
314
315 typename BaseClass::IndexType nextIndex = index;
316 nextIndex[i] = (index[i] + 1) % size;
317 Element nextValue = BaseClass::GetAt(nextIndex);
318 if (nextValue > value){
319 goto nextElement;
320 }
321
322 neighbours[i * 2] = prevValue;
323 neighbours[i * 2 + 1] = nextValue;
324 }
325 else{
326 if (index[i] > 0){
327 typename BaseClass::IndexType prevIndex = index;
328 prevIndex[i] = index[i] - 1;
329 Element prevValue = BaseClass::GetAt(prevIndex);
330 if (prevValue >= value){
331 goto nextElement;
332 }
333
334 neighbours[i * 2] = prevValue;
335 }
336 else if (m_extensionModeBorders[i]){
337 neighbours[i * 2] = value;
338 }
339 else{
340 neighbours[i * 2] = 0;
341 }
342
343 if (index[i] < size - 1){
344 typename BaseClass::IndexType nextIndex = index;
345 nextIndex[i] = index[i] + 1;
346 Element nextValue = BaseClass::GetAt(nextIndex);
347 if (nextValue > value){
348 goto nextElement;
349 }
350
351 neighbours[i * 2 + 1] = nextValue;
352 }
353 else if (m_extensionModeBorders[i]){
354 neighbours[i * 2 + 1] = value;
355 }
356 else{
357 neighbours[i * 2 + 1] = 0;
358 }
359 }
360 }
361 else{
362 neighbours[i * 2] = value;
363 neighbours[i * 2 + 1] = value;
364 }
365 }
366
367 if (resultProcessor.OnMaximumFound(*this, index, value, neighbours, Dimensions * 2, currentMinValue)){
368 resultProcessor.OnProcessingEnd(*this);
369
370 return true;
371 }
372 }
373
374 nextElement:;
375 } while (index.Increase(BaseClass::m_sizes));
376 }
377
378 resultProcessor.OnProcessingEnd(*this);
379
380 return true;
381}
382
383
384template <int Dimensions, class Element>
386{
387 istd::CIndex2d bitmapSize(0, 1);
388
389 for (int i = 0; i < Dimensions; ++i){
390 if (i == 0){
391 bitmapSize[0] = BaseClass::m_sizes[i];
392 }
393 else{
394 bitmapSize[1] *= BaseClass::m_sizes[i];
395 }
396 }
397
398 if (!bitmap.CreateBitmap(iimg::IBitmap::PF_GRAY, bitmapSize)){
399 return false;
400 }
401
402 Element maxValue = 0;
403 for ( typename BaseClass::Elements::const_iterator iter = BaseClass::m_elements.begin();
404 iter != BaseClass::m_elements.end();
405 ++iter){
406 Element value = *iter;
407
408 if (value > maxValue){
409 maxValue = value;
410 }
411 }
412
413 if (maxValue <= 0){
414 bitmap.ClearImage();
415
416 return true;
417 }
418
419 typename BaseClass::Elements::const_iterator iter = BaseClass::m_elements.begin();
420 for (int y = 0; y < bitmapSize.GetY(); ++y){
421 quint8* outputLinePtr = (quint8*)bitmap.GetLinePtr(y);
422
423 for (int x = 0; x < bitmapSize.GetX(); ++x){
424 outputLinePtr[x] = quint8(*iter * 255 / maxValue);
425
426 ++iter;
427 }
428 }
429
430 return true;
431}
432
433
434template <int Dimensions, class Element>
436{
437 result = position;
438
439 bool retVal = true;
440
441 for (int i = 0; i < Dimensions; ++i){
442 int size = BaseClass::m_sizes[i];
443
444 if (m_isWrapped[i]){ // correct the position if is wrapped
445 result[i] = fmod(result[i] + size, size);
446 }
447
448 retVal = retVal && (result[i] >= 0) && (result[i] < size);
449 }
450
451 return retVal;
452}
453
454
455// template methods
456
457template <int Dimensions, class Element>
458template <typename Operation>
460{
461 for ( typename BaseClass::iterator iter = BaseClass::Begin();
462 iter != BaseClass::End();
463 ++iter){
464 Element& value = *iter;
465
466 value = operation(value);
467 }
468}
469
470
471template <int Dimensions, class Element>
472template <typename Operation>
474{
475 istd::TIndex<Dimensions> commonSize;
476 for (int i = 0; i < Dimensions; ++i){
477 commonSize[i] = qMin(BaseClass::m_sizes[i], space.m_sizes[i]);
478 }
479
481 if (index.IsInside(commonSize)){
482 do{
483 Element& destValue = BaseClass::GetAt(index);
484 const Element& secondValue = space.BaseClass::GetAt(index);
485
486 destValue = operation(destValue, secondValue);
487 } while (index.Increase(commonSize));
488 }
489}
490
491
492// reimplemented (iser::ISerializable)
493template <int Dimensions, class Element>
495{
496 static iser::CArchiveTag spaceSizeTag("SpaceSize", "Size of Hough space", iser::CArchiveTag::TT_MULTIPLE);
497 static iser::CArchiveTag dimensionSizeTag("DimensionSize", "Size of single dimension", iser::CArchiveTag::TT_GROUP, &spaceSizeTag);
498 static iser::CArchiveTag elementsTag("Elements", "List of space elements", iser::CArchiveTag::TT_GROUP, &spaceSizeTag);
499
500 bool retVal = true;
501
502 bool isChanging = archive.IsChanging();
503 istd::CChangeNotifier notifier(isChanging? this: nullptr);
504
505 typename BaseClass::IndexType spaceSize = BaseClass::GetSizes();
506 int dimensionsCount = Dimensions;
507
508 retVal = retVal && archive.BeginMultiTag(spaceSizeTag, dimensionSizeTag, dimensionsCount);
509 if (dimensionsCount != Dimensions){
510 return false;
511 }
512
513 for (int dimensionIndex = 0; dimensionIndex < Dimensions; ++dimensionIndex){
514 retVal = retVal && archive.BeginTag(dimensionSizeTag);
515 retVal = retVal && archive.Process(spaceSize[dimensionIndex]);
516 retVal = retVal && archive.EndTag(dimensionSizeTag);
517 }
518 retVal = retVal && archive.EndTag(spaceSizeTag);
519
520 if (isChanging){
521 if (!BaseClass::SetSizes(spaceSize)){
522 return false;
523 }
524 }
525
526 retVal = retVal && archive.BeginTag(elementsTag);
527 for ( typename BaseClass::iterator iter = BaseClass::Begin();
528 iter != BaseClass::End();
529 ++iter){
530 retVal = retVal && archive.Process(*iter);
531 }
532 retVal = retVal && archive.EndTag(elementsTag);
533
534 return retVal;
535}
536
537
538// protected methods
539
540template <int Dimensions, class Element>
542{
543 int elementDiff = 1;
544 int blocksCount = 1;
545 int elementsCount = int(BaseClass::m_elements.size());
546
547 for (int i = 0; i < Dimensions; ++i){
548 if (i < dimensionIndex){
549 elementDiff *= BaseClass::m_sizes[i];
550 }
551 else if (i > dimensionIndex){
552 blocksCount *= BaseClass::m_sizes[i];
553 }
554 }
555
556 int smoothAxisSize = BaseClass::m_sizes[dimensionIndex];
557
558 int outerElementOffset = 0;
559 for (int outerIndex = 0; outerIndex < blocksCount; ++outerIndex){
560 for (int internIndex = 0; internIndex < elementDiff; ++internIndex){
561 int axisElementOffset = outerElementOffset + internIndex;
562
563 for (int iterIndex = 0; iterIndex < iterations; ++iterIndex){
564 int elementOffset = axisElementOffset;
565 int nextPos;
566 Element value;
567 Element prevValue;
568 Element storedValue;
569
570 if (m_isWrapped[dimensionIndex]){
571 value = BaseClass::m_elements[elementOffset];
572 nextPos = 0;
573 prevValue = BaseClass::m_elements[axisElementOffset + (smoothAxisSize - 1) * elementDiff];
574 storedValue = value;
575 }
576 else{
577 value = BaseClass::m_elements[elementOffset];
578 nextPos = 1;
579 prevValue = 0;
580 storedValue = 0;
581 }
582
583 for (; nextPos < smoothAxisSize; ++nextPos){
584 int nextElementOffset = (elementOffset + elementDiff) % elementsCount;
585
586 Element nextValue = BaseClass::m_elements[nextElementOffset];
587
588 BaseClass::m_elements[elementOffset] = (value * 2 + prevValue + nextValue) / 4;
589
590 prevValue = value;
591 value = nextValue;
592
593 elementOffset = nextElementOffset;
594 }
595
596 BaseClass::m_elements[elementOffset] = (value * 2 + prevValue + storedValue) / 4;
597 }
598 }
599
600 outerElementOffset += smoothAxisSize * elementDiff;
601 }
602}
603
604
605} // namespace ialgo
606
607
void ApplyOperation(Operation operation)
Apply some operation to each element.
virtual void IncreaseValueAt(const imath::TVector< Dimensions > &position, Element value)
virtual BaseClass2::ExtensionMode GetExtensionMode(int dimensionIndex) const
Get extension mode for single dimension.
void SetDistScalingFactor(int dimensionIndex, double factor)
Set the distance scaling factors used to calculate how far are elements in this space.
istd::TArray< Element, Dimensions > BaseClass
virtual bool ExtractToBitmap(iimg::IBitmap &bitmap) const
Extract this Hough space to some gray scale bitmap.
virtual bool IsDimensionWrapped(int dimensionIndex) const
Check if this space is wrapped horizontaly, it means the the left pixel is neighbour of the right one...
void SetDimensionWrapped(int dimensionIndex, bool state)
Set if this space to be wrapped horizontaly or not.
virtual double GetSpaceDistance2(const imath::TVector< Dimensions > &position1, const imath::TVector< Dimensions > &position2) const
Get square of distance between two hough space positions considering the space wrapping.
void CombineWithSpace(const TGeneralHoughSpace &space, Operation operation)
Combine this space with some other space.
virtual void SmoothHoughSpace(const istd::TIndex< Dimensions > &iterations)
Smooth this space with specified stronness.
void SetExtensionBorder(int dimensionIndex, bool state)
Set mode of extension mode to border or not.
virtual istd::TIndex< Dimensions > GetSpaceSize() const
Get size of this Hough space.
TIHoughSpace< Dimensions, Element > BaseClass2
virtual double GetSpaceDistance(const imath::TVector< Dimensions > &position1, const imath::TVector< Dimensions > &position2) const
Get distance between two hough space positions considering the space wrapping.
void SmoothSingleDimension(int dimensionIndex, int iterations)
virtual bool GetSpacePosition(const imath::TVector< Dimensions > &position, imath::TVector< Dimensions > &result) const
Get position in space for some input.
double GetDistScalingFactor(int dimensionIndex) const
Get the distance scaling factors used to calculate how far are elements in this space.
virtual bool CreateHoughSpace(const istd::TIndex< Dimensions > &size, const Element &initValue=0)
virtual bool Serialize(iser::IArchive &archive)
Load or store state of this object as a archive stream.
virtual bool AnalyseHoughSpace(const Element &minValue, typename BaseClass2::ResultsConsumer &resultProcessor) const
virtual bool OnMaximumFound(const TIHoughSpace< Dimensions, Element > &space, const istd::TIndex< Dimensions > &position, const Element &value, const Element *neghboursPtr, int neghboursCount, Element &minValue)=0
Will be called when some local maximum is reached.
virtual void OnProcessingBegin(const TIHoughSpace< Dimensions, Element > &space, const Element &minValue)=0
Called when processing is started.
virtual void OnProcessingEnd(const TIHoughSpace< Dimensions, Element > &space)=0
Called when processing is finished.
virtual QList< int > GetSupportedNeghboursCount() const =0
Get list of number of neighbours supported by this consumer.
Template interface for Hough space.
ExtensionMode
Describe how the space is extended, it means how the area outside of space should be interpreted.
Definition of single plane bitmap.
Definition IBitmap.h:24
@ PF_GRAY
8-bit grayscale bitmap.
Definition IBitmap.h:44
virtual const void * GetLinePtr(int positionY) const =0
Get pointer to buffer for single line.
virtual bool CreateBitmap(PixelFormat pixelFormat, const istd::CIndex2d &size, int pixelBitsCount=0, int componentsCount=0)=0
Create bitmap with specified size and format.
virtual void ClearImage()=0
Cleat this image.
Implementation of fixed-size mathematical vector with specified type of elements.
Definition TVector.h:32
Process tag used to group data in archive stream.
Definition CArchiveTag.h:25
@ TT_GROUP
Normal tag used for grouping of tags or processed elements.
Definition CArchiveTag.h:40
@ TT_MULTIPLE
Multiple tag containing variable number of child tags.
Definition CArchiveTag.h:45
Represent input/output persistence archive.
Definition IArchive.h:33
virtual bool Process(bool &value)=0
Process primitive type.
virtual bool EndTag(const CArchiveTag &tag)=0
End of archive tag.
virtual bool BeginMultiTag(const CArchiveTag &tag, const CArchiveTag &subTag, int &count)=0
Begin of archive tag containing set of subelements of the same type.
virtual bool IsChanging() const =0
Check if this archive processing change the object state.
virtual bool BeginTag(const CArchiveTag &tag)=0
Begin of archive tag.
Help class which provides the automatic update mechanism of the model.
Index implementation for addressing elements in 2D-space.
Definition CIndex2d.h:25
int GetX() const
Definition CIndex2d.h:105
int GetY() const
Definition CIndex2d.h:117
Multidimensional array with fixed number of dimensions.
Definition TArray.h:28
SizesType m_sizes
Definition TArray.h:179
Multidimensional index used to addressing fixed-size array.
Definition TIndex.h:22
static const TIndex< Dimensions > & GetZero()
Get global instance of zero index.
Definition TIndex.h:553
bool Increase(const TIndex &boundaries)
Increase this index inside the boundaries.
Definition TIndex.h:475
bool IsInside(const TIndex &boundaries) const
Check if index is inside boundaries.
Definition TIndex.h:460
Contains implementations of interfaces and components of common algorithms with no association to ano...

© Witold Gantzke and Kirill Lepskiy