TGeneralHoughSpace.h
Go to the documentation of this file.
1 #ifndef ialgo_TGeneralHoughSpace_included
2 #define ialgo_TGeneralHoughSpace_included
3 
4 
5 // Qt includes
6 #include <QtCore/QMultiMap>
7 
8 // ACF includes
9 #include <i2d/CVector2d.h>
10 #include <istd/TArray.h>
11 
12 // ACF-Solutions includes
13 #include <ialgo/TIHoughSpace.h>
14 
15 
16 namespace ialgo
17 {
18 
19 
23 template <int Dimensions, class Element = double>
25  public istd::TArray<Element, Dimensions>,
26  virtual public TIHoughSpace<Dimensions, Element>
27 {
28 public:
31 
34 
38  template <typename Operation>
39  void ApplyOperation(Operation operation);
40 
44  template <typename Operation>
45  void CombineWithSpace(const TGeneralHoughSpace& space, Operation operation);
46 
51  void SetDimensionWrapped(int dimensionIndex, bool state);
52 
56  void SetExtensionBorder(int dimensionIndex, bool state);
57 
61  double GetDistScalingFactor(int dimensionIndex) const;
65  void SetDistScalingFactor(int dimensionIndex, double factor);
66 
67  // reimplemented (ialgo::TIHoughSpace)
68  virtual istd::TIndex<Dimensions> GetSpaceSize() const;
69  virtual bool CreateHoughSpace(const istd::TIndex<Dimensions>& size, const Element& initValue = 0);
70  virtual bool IsDimensionWrapped(int dimensionIndex) const;
71  virtual typename BaseClass2::ExtensionMode GetExtensionMode(int dimensionIndex) const;
72  virtual void IncreaseValueAt(const imath::TVector<Dimensions>& position, Element value);
73  virtual void SmoothHoughSpace(const istd::TIndex<Dimensions>& iterations);
74  virtual bool AnalyseHoughSpace(
75  const Element& minValue,
76  typename BaseClass2::ResultsConsumer& resultProcessor) const;
77  virtual bool ExtractToBitmap(iimg::IBitmap& bitmap) const;
78  virtual bool GetSpacePosition(const imath::TVector<Dimensions>& position, imath::TVector<Dimensions>& result) const;
79  virtual double GetSpaceDistance(const imath::TVector<Dimensions>& position1, const imath::TVector<Dimensions>& position2) const;
80  virtual double GetSpaceDistance2(const imath::TVector<Dimensions>& position1, const imath::TVector<Dimensions>& position2) const;
81 
82  // reimplemented (iser::ISerializable)
83  virtual bool Serialize(iser::IArchive& archive);
84 
85 protected:
86  void SmoothSingleDimension(int dimensionIndex, int iterations);
87 
88 private:
89  bool m_isWrapped[Dimensions];
90  bool m_extensionModeBorders[Dimensions];
91  double m_distScalingFactors[Dimensions];
92 };
93 
94 
95 // inline methods
96 
97 template <int Dimensions, class Element>
99 {
100  return qSqrt(GetSpaceDistance2(position1, position2));
101 }
102 
103 
104 template <int Dimensions, class Element>
106 {
107  double distance2 = 0;
108 
109  for (int i = 0; i < Dimensions; ++i){
110  double diff = position2[i] - position1[i];
111 
112  if (m_isWrapped[i]){
113  double offset = BaseClass::m_sizes[i] * 0.5;
114 
115  diff = std::fmod(diff + offset + BaseClass::m_sizes[i], BaseClass::m_sizes[i]) - offset;
116  }
117 
118  diff *= m_distScalingFactors[i];
119 
120  distance2 += diff * diff;
121  }
122 
123  return distance2;
124 }
125 
126 
127 // public methods
128 
129 template <int Dimensions, class Element>
131 {
132 }
133 
134 
135 template <int Dimensions, class Element>
137 {
139 }
140 
141 
142 template <int Dimensions, class Element>
144 {
145  Q_ASSERT(dimensionIndex >= 0);
146  Q_ASSERT(dimensionIndex < Dimensions);
147 
148  m_isWrapped[dimensionIndex] = state;
149 }
150 
151 
152 template <int Dimensions, class Element>
154 {
155  Q_ASSERT(dimensionIndex >= 0);
156  Q_ASSERT(dimensionIndex < Dimensions);
157 
158  m_extensionModeBorders[dimensionIndex] = state;
159 }
160 
161 
162 template <int Dimensions, class Element>
164 {
165  Q_ASSERT(dimensionIndex >= 0);
166  Q_ASSERT(dimensionIndex < Dimensions);
167 
168  return m_distScalingFactors[dimensionIndex];
169 }
170 
171 
172 template <int Dimensions, class Element>
174 {
175  Q_ASSERT(dimensionIndex >= 0);
176  Q_ASSERT(dimensionIndex < Dimensions);
177 
178  m_distScalingFactors[dimensionIndex] = factor;
179 }
180 
181 
182 // reimplemented (ialgo::TIHoughSpace)
183 
184 template <int Dimensions, class Element>
186 {
187  return BaseClass::GetSizes();
188 }
189 
190 
191 template <int Dimensions, class Element>
193 {
194  istd::CChangeNotifier notifier(this);
195 
196  for (int i = 0; i < Dimensions; ++i){
197  m_isWrapped[i] = false;
198  m_extensionModeBorders[i] = false;
199 
200  m_distScalingFactors[i] = 1;
201  }
202 
203  BaseClass::SetSizes(size);
204  BaseClass::SetAllElements(initValue);
205 
206  return true;
207 }
208 
209 
210 template <int Dimensions, class Element>
212 {
213  Q_ASSERT(dimensionIndex >= 0);
214  Q_ASSERT(dimensionIndex < Dimensions);
215 
216  return m_isWrapped[dimensionIndex];
217 }
218 
219 
220 template <int Dimensions, class Element>
222 {
223  Q_ASSERT(dimensionIndex >= 0);
224  Q_ASSERT(dimensionIndex < Dimensions);
225 
226  return m_extensionModeBorders[dimensionIndex]? BaseClass2::EM_ZERO: BaseClass2::EM_BORDER;
227 }
228 
229 
230 template <int Dimensions, class Element>
232 {
234 
235  int elementOffset = 0;
236  for (int i = Dimensions - 1; i >= 0; --i){
237  int singleIndex = int(position[i]);
238  int size = BaseClass::m_sizes[i];
239 
240  elementOffset *= size;
241 
242  if (m_isWrapped[i]){ // correct the position if is wrapped
243  singleIndex = (singleIndex + size) % size;
244  }
245  else{
246  if ((singleIndex < 0) || (singleIndex >= size)){
247  return;
248  }
249  }
250 
251  Q_ASSERT(singleIndex >= 0);
252  Q_ASSERT(singleIndex < size);
253 
254  elementOffset += singleIndex;
255  }
256 
257  BaseClass::m_elements[elementOffset] += Element(value);
258 }
259 
260 
261 template <int Dimensions, class Element>
263 {
264  for (int i = 0; i < Dimensions; ++i){
265  if (BaseClass::m_sizes[i] >= 3){
266  int iterCount = iterations[i];
267  if (iterCount > 0){
268  SmoothSingleDimension(i, iterCount);
269  }
270  }
271  }
272 }
273 
274 
275 template <int Dimensions, class Element>
277  const Element& minValue,
278  typename BaseClass2::ResultsConsumer& resultProcessor) const
279 {
280  QList<int> supportedNeighboursCount = resultProcessor.GetSupportedNeghboursCount();
281  if (!supportedNeighboursCount.contains(Dimensions * 2) && !supportedNeighboursCount.isEmpty()){
282  return false;
283  }
284 
285  for (int i = 0; i < Dimensions; ++i){
286  if (BaseClass::m_sizes[i] < 1){
287  return false;
288  }
289  }
290 
291  resultProcessor.OnProcessingBegin(*this, minValue);
292 
293  Element neighbours[Dimensions * 2];
294 
295  Element currentMinValue(minValue);
296 
297  typename BaseClass::IndexType index = BaseClass::IndexType::GetZero();
298  if (index.IsInside(BaseClass::m_sizes)){
299  do{
300  Element value = BaseClass::GetAt(index);
301  if (value >= currentMinValue){
302  for (int i = 0; i < Dimensions; ++i){
303  int size = BaseClass::m_sizes[i];
304  if (size >= 1){
305  if (m_isWrapped[i]){
306  typename BaseClass::IndexType prevIndex = index;
307  prevIndex[i] = (index[i] + size - 1) % size;
308  Element prevValue = BaseClass::GetAt(prevIndex);
309  if (prevValue >= value){
310  goto nextElement;
311  }
312 
313  typename BaseClass::IndexType nextIndex = index;
314  nextIndex[i] = (index[i] + 1) % size;
315  Element nextValue = BaseClass::GetAt(nextIndex);
316  if (nextValue > value){
317  goto nextElement;
318  }
319 
320  neighbours[i * 2] = prevValue;
321  neighbours[i * 2 + 1] = nextValue;
322  }
323  else{
324  if (index[i] > 0){
325  typename BaseClass::IndexType prevIndex = index;
326  prevIndex[i] = index[i] - 1;
327  Element prevValue = BaseClass::GetAt(prevIndex);
328  if (prevValue >= value){
329  goto nextElement;
330  }
331 
332  neighbours[i * 2] = prevValue;
333  }
334  else if (m_extensionModeBorders[i]){
335  neighbours[i * 2] = value;
336  }
337  else{
338  neighbours[i * 2] = 0;
339  }
340 
341  if (index[i] < size - 1){
342  typename BaseClass::IndexType nextIndex = index;
343  nextIndex[i] = index[i] + 1;
344  Element nextValue = BaseClass::GetAt(nextIndex);
345  if (nextValue > value){
346  goto nextElement;
347  }
348 
349  neighbours[i * 2 + 1] = nextValue;
350  }
351  else if (m_extensionModeBorders[i]){
352  neighbours[i * 2 + 1] = value;
353  }
354  else{
355  neighbours[i * 2 + 1] = 0;
356  }
357  }
358  }
359  else{
360  neighbours[i * 2] = value;
361  neighbours[i * 2 + 1] = value;
362  }
363  }
364 
365  if (resultProcessor.OnMaximumFound(*this, index, value, neighbours, Dimensions * 2, currentMinValue)){
366  resultProcessor.OnProcessingEnd(*this);
367 
368  return true;
369  }
370  }
371 
372  nextElement:;
373  } while (index.Increase(BaseClass::m_sizes));
374  }
375 
376  resultProcessor.OnProcessingEnd(*this);
377 
378  return true;
379 }
380 
381 
382 template <int Dimensions, class Element>
384 {
385  istd::CIndex2d bitmapSize(0, 1);
386 
387  for (int i = 0; i < Dimensions; ++i){
388  if (i == 0){
389  bitmapSize[0] = BaseClass::m_sizes[i];
390  }
391  else{
392  bitmapSize[1] *= BaseClass::m_sizes[i];
393  }
394  }
395 
396  if (!bitmap.CreateBitmap(iimg::IBitmap::PF_GRAY, bitmapSize)){
397  return false;
398  }
399 
400  Element maxValue = 0;
401  for ( typename BaseClass::Elements::const_iterator iter = BaseClass::m_elements.begin();
402  iter != BaseClass::m_elements.end();
403  ++iter){
404  Element value = *iter;
405 
406  if (value > maxValue){
407  maxValue = value;
408  }
409  }
410 
411  if (maxValue <= 0){
412  bitmap.ClearImage();
413 
414  return true;
415  }
416 
417  typename BaseClass::Elements::const_iterator iter = BaseClass::m_elements.begin();
418  for (int y = 0; y < bitmapSize.GetY(); ++y){
419  quint8* outputLinePtr = (quint8*)bitmap.GetLinePtr(y);
420 
421  for (int x = 0; x < bitmapSize.GetX(); ++x){
422  outputLinePtr[x] = quint8(*iter * 255 / maxValue);
423 
424  ++iter;
425  }
426  }
427 
428  return true;
429 }
430 
431 
432 template <int Dimensions, class Element>
434 {
435  result = position;
436 
437  bool retVal = true;
438 
439  for (int i = 0; i < Dimensions; ++i){
440  int size = BaseClass::m_sizes[i];
441 
442  if (m_isWrapped[i]){ // correct the position if is wrapped
443  result[i] = fmod(result[i] + size, size);
444  }
445 
446  retVal = retVal && (result[i] >= 0) && (result[i] < size);
447  }
448 
449  return retVal;
450 }
451 
452 
453 // template methods
454 
455 template <int Dimensions, class Element>
456 template <typename Operation>
458 {
459  for ( typename BaseClass::Iterator iter = BaseClass::Begin();
460  iter != BaseClass::End();
461  ++iter){
462  Element& value = *iter;
463 
464  value = operation(value);
465  }
466 }
467 
468 
469 template <int Dimensions, class Element>
470 template <typename Operation>
472 {
473  istd::TIndex<Dimensions> commonSize;
474  for (int i = 0; i < Dimensions; ++i){
475  commonSize[i] = qMin(BaseClass::m_sizes[i], space.m_sizes[i]);
476  }
477 
479  if (index.IsInside(commonSize)){
480  do{
481  Element& destValue = BaseClass::GetAt(index);
482  const Element& secondValue = space.BaseClass::GetAt(index);
483 
484  destValue = operation(destValue, secondValue);
485  } while (index.Increase(commonSize));
486  }
487 }
488 
489 
490 // reimplemented (iser::ISerializable)
491 template <int Dimensions, class Element>
493 {
494  static iser::CArchiveTag spaceSizeTag("SpaceSize", "Size of Hough space", iser::CArchiveTag::TT_MULTIPLE);
495  static iser::CArchiveTag dimensionSizeTag("DimensionSize", "Size of single dimension", iser::CArchiveTag::TT_GROUP, &spaceSizeTag);
496  static iser::CArchiveTag elementsTag("Elements", "List of space elements", iser::CArchiveTag::TT_GROUP, &spaceSizeTag);
497 
498  bool retVal = true;
499 
500  bool isStoring = archive.IsStoring();
501 
502  typename BaseClass::IndexType spaceSize = BaseClass::GetSizes();
503  int dimensionsCount = Dimensions;
504 
505  retVal = retVal && archive.BeginMultiTag(spaceSizeTag, dimensionSizeTag, dimensionsCount);
506  if (dimensionsCount != Dimensions){
507  return false;
508  }
509 
510  for (int dimensionIndex = 0; dimensionIndex < Dimensions; ++dimensionIndex){
511  retVal = retVal && archive.BeginTag(dimensionSizeTag);
512  retVal = retVal && archive.Process(spaceSize[dimensionIndex]);
513  retVal = retVal && archive.EndTag(dimensionSizeTag);
514  }
515  retVal = retVal && archive.EndTag(spaceSizeTag);
516 
517  if (!isStoring){
518  if (!BaseClass::SetSizes(spaceSize)){
519  return false;
520  }
521  }
522 
523  retVal = retVal && archive.BeginTag(elementsTag);
524  for ( typename BaseClass::Iterator iter = BaseClass::Begin();
525  iter != BaseClass::End();
526  ++iter){
527  retVal = retVal && archive.Process(*iter);
528  }
529  retVal = retVal && archive.EndTag(elementsTag);
530 
531  return retVal;
532 }
533 
534 
535 // protected methods
536 
537 template <int Dimensions, class Element>
539 {
540  int elementDiff = 1;
541  int blocksCount = 1;
542  int elementsCount = int(BaseClass::m_elements.size());
543 
544  for (int i = 0; i < Dimensions; ++i){
545  if (i < dimensionIndex){
546  elementDiff *= BaseClass::m_sizes[i];
547  }
548  else if (i > dimensionIndex){
549  blocksCount *= BaseClass::m_sizes[i];
550  }
551  }
552 
553  int smoothAxisSize = BaseClass::m_sizes[dimensionIndex];
554 
555  int outerElementOffset = 0;
556  for (int outerIndex = 0; outerIndex < blocksCount; ++outerIndex){
557  for (int internIndex = 0; internIndex < elementDiff; ++internIndex){
558  int axisElementOffset = outerElementOffset + internIndex;
559 
560  for (int iterIndex = 0; iterIndex < iterations; ++iterIndex){
561  int elementOffset = axisElementOffset;
562  int nextPos;
563  Element value;
564  Element prevValue;
565  Element storedValue;
566 
567  if (m_isWrapped[dimensionIndex]){
568  value = BaseClass::m_elements[elementOffset];
569  nextPos = 0;
570  prevValue = BaseClass::m_elements[axisElementOffset + (smoothAxisSize - 1) * elementDiff];
571  storedValue = value;
572  }
573  else{
574  value = BaseClass::m_elements[elementOffset];
575  nextPos = 1;
576  prevValue = 0;
577  storedValue = 0;
578  }
579 
580  for (; nextPos < smoothAxisSize; ++nextPos){
581  int nextElementOffset = (elementOffset + elementDiff) % elementsCount;
582 
583  Element nextValue = BaseClass::m_elements[nextElementOffset];
584 
585  BaseClass::m_elements[elementOffset] = (value * 2 + prevValue + nextValue) / 4;
586 
587  prevValue = value;
588  value = nextValue;
589 
590  elementOffset = nextElementOffset;
591  }
592 
593  BaseClass::m_elements[elementOffset] = (value * 2 + prevValue + storedValue) / 4;
594  }
595  }
596 
597  outerElementOffset += smoothAxisSize * elementDiff;
598  }
599 }
600 
601 
602 } // namespace ialgo
603 
604 
605 #endif // !ialgo_TGeneralHoughSpace_included
606 
607 
void ApplyOperation(Operation operation)
Apply some operation to each element.
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.
ExtensionMode
Describe how the space is extended, it means how the area outside of space should be interpreted...
Definition: TIHoughSpace.h:65
virtual istd::TIndex< Dimensions > GetSpaceSize() const
Get size of this Hough space.
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 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.
virtual void IncreaseValueAt(const imath::TVector< Dimensions > &position, Element value)
Increase the value at specified position.
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...
double GetDistScalingFactor(int dimensionIndex) const
Get the distance scaling factors used to calculate how far are elements in this space.
virtual bool AnalyseHoughSpace(const Element &minValue, typename BaseClass2::ResultsConsumer &resultProcessor) const
Analyse this Hough space to find set of local maximums.
void CombineWithSpace(const TGeneralHoughSpace &space, Operation operation)
Combine this space with some other space.
virtual bool BeginMultiTag(const CArchiveTag &tag, const CArchiveTag &subTag, int &count)=0
virtual QList< int > GetSupportedNeghboursCount() const =0
Get list of number of neighbours supprted by this consumer.
virtual void OnProcessingBegin(const TIHoughSpace< Dimensions, Element > &space, const Element &minValue)=0
Called when processing is started.
void SetDimensionWrapped(int dimensionIndex, bool state)
Set if this space to be wrapped horizontaly or not.
TIHoughSpace< Dimensions, Element > BaseClass2
virtual bool GetSpacePosition(const imath::TVector< Dimensions > &position, imath::TVector< Dimensions > &result) const
Get position in space for some input.
virtual bool ExtractToBitmap(iimg::IBitmap &bitmap) const
Extract this Hough space to some gray scale bitmap.
virtual bool Serialize(iser::IArchive &archive)
void SmoothSingleDimension(int dimensionIndex, int iterations)
void SetDistScalingFactor(int dimensionIndex, double factor)
Set 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)
Create Hough space with specified size.
virtual BaseClass2::ExtensionMode GetExtensionMode(int dimensionIndex) const
Get extension mode for single dimension.
General Hough space.
virtual void SmoothHoughSpace(const istd::TIndex< Dimensions > &iterations)
Smooth this space with specified stronness.
istd::TArray< Element, Dimensions > BaseClass
Template interface for Hough space.
Definition: TIHoughSpace.h:21
virtual void OnProcessingEnd(const TIHoughSpace< Dimensions, Element > &space)=0
Called when processing is finished.
SizesType m_sizes
void SetExtensionBorder(int dimensionIndex, bool state)
Set mode of extension mode to border or not.

© 2007-2017 Witold Gantzke and Kirill Lepskiy