10#include <QtCore/QMultiMap>
25template <
int Dimensions,
class Element =
double>
40 template <
typename Operation>
46 template <
typename Operation>
77 const Element& minValue,
91 bool m_isWrapped[Dimensions];
92 bool m_extensionModeBorders[Dimensions];
93 double m_distScalingFactors[Dimensions];
99template <
int Dimensions,
class Element>
102 return qSqrt(GetSpaceDistance2(position1, position2));
106template <
int Dimensions,
class Element>
109 double distance2 = 0;
111 for (
int i = 0; i < Dimensions; ++i){
112 double diff = position2[i] - position1[i];
115 double offset = BaseClass::m_sizes[i] * 0.5;
117 diff = std::fmod(diff + offset + BaseClass::m_sizes[i], BaseClass::m_sizes[i]) - offset;
120 diff *= m_distScalingFactors[i];
122 distance2 += diff * diff;
131template <
int Dimensions,
class Element>
137template <
int Dimensions,
class Element>
144template <
int Dimensions,
class Element>
147 Q_ASSERT(dimensionIndex >= 0);
148 Q_ASSERT(dimensionIndex < Dimensions);
150 m_isWrapped[dimensionIndex] = state;
154template <
int Dimensions,
class Element>
157 Q_ASSERT(dimensionIndex >= 0);
158 Q_ASSERT(dimensionIndex < Dimensions);
160 m_extensionModeBorders[dimensionIndex] = state;
164template <
int Dimensions,
class Element>
167 Q_ASSERT(dimensionIndex >= 0);
168 Q_ASSERT(dimensionIndex < Dimensions);
170 return m_distScalingFactors[dimensionIndex];
174template <
int Dimensions,
class Element>
177 Q_ASSERT(dimensionIndex >= 0);
178 Q_ASSERT(dimensionIndex < Dimensions);
180 m_distScalingFactors[dimensionIndex] = factor;
186template <
int Dimensions,
class Element>
189 return BaseClass::GetSizes();
193template <
int Dimensions,
class Element>
198 for (
int i = 0; i < Dimensions; ++i){
199 m_isWrapped[i] =
false;
200 m_extensionModeBorders[i] =
false;
202 m_distScalingFactors[i] = 1;
205 BaseClass::SetSizes(size);
206 BaseClass::SetAllElements(initValue);
212template <
int Dimensions,
class Element>
215 Q_ASSERT(dimensionIndex >= 0);
216 Q_ASSERT(dimensionIndex < Dimensions);
218 return m_isWrapped[dimensionIndex];
222template <
int Dimensions,
class Element>
225 Q_ASSERT(dimensionIndex >= 0);
226 Q_ASSERT(dimensionIndex < Dimensions);
228 return m_extensionModeBorders[dimensionIndex]? BaseClass2::EM_ZERO: BaseClass2::EM_BORDER;
232template <
int Dimensions,
class Element>
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];
242 elementOffset *= size;
245 singleIndex = (singleIndex + size) % size;
248 if ((singleIndex < 0) || (singleIndex >= size)){
253 Q_ASSERT(singleIndex >= 0);
254 Q_ASSERT(singleIndex < size);
256 elementOffset += singleIndex;
259 BaseClass::m_elements[elementOffset] += Element(value);
263template <
int Dimensions,
class Element>
266 for (
int i = 0; i < Dimensions; ++i){
267 if (BaseClass::m_sizes[i] >= 3){
268 int iterCount = iterations[i];
270 SmoothSingleDimension(i, iterCount);
277template <
int Dimensions,
class Element>
279 const Element& minValue,
283 if (!supportedNeighboursCount.contains(Dimensions * 2) && !supportedNeighboursCount.isEmpty()){
287 for (
int i = 0; i < Dimensions; ++i){
288 if (BaseClass::m_sizes[i] < 1){
295 Element neighbours[Dimensions * 2];
297 Element currentMinValue(minValue);
300 if (index.
IsInside(BaseClass::m_sizes)){
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];
309 prevIndex[i] = (index[i] + size - 1) % size;
310 Element prevValue = BaseClass::GetAt(prevIndex);
311 if (prevValue >= value){
316 nextIndex[i] = (index[i] + 1) % size;
317 Element nextValue = BaseClass::GetAt(nextIndex);
318 if (nextValue > value){
322 neighbours[i * 2] = prevValue;
323 neighbours[i * 2 + 1] = nextValue;
328 prevIndex[i] = index[i] - 1;
329 Element prevValue = BaseClass::GetAt(prevIndex);
330 if (prevValue >= value){
334 neighbours[i * 2] = prevValue;
336 else if (m_extensionModeBorders[i]){
337 neighbours[i * 2] = value;
340 neighbours[i * 2] = 0;
343 if (index[i] < size - 1){
345 nextIndex[i] = index[i] + 1;
346 Element nextValue = BaseClass::GetAt(nextIndex);
347 if (nextValue > value){
351 neighbours[i * 2 + 1] = nextValue;
353 else if (m_extensionModeBorders[i]){
354 neighbours[i * 2 + 1] = value;
357 neighbours[i * 2 + 1] = 0;
362 neighbours[i * 2] = value;
363 neighbours[i * 2 + 1] = value;
367 if (resultProcessor.
OnMaximumFound(*
this, index, value, neighbours, Dimensions * 2, currentMinValue)){
375 }
while (index.
Increase(BaseClass::m_sizes));
384template <
int Dimensions,
class Element>
389 for (
int i = 0; i < Dimensions; ++i){
391 bitmapSize[0] = BaseClass::m_sizes[i];
394 bitmapSize[1] *= BaseClass::m_sizes[i];
402 Element maxValue = 0;
403 for (
typename BaseClass::Elements::const_iterator iter = BaseClass::m_elements.begin();
404 iter != BaseClass::m_elements.end();
406 Element value = *iter;
408 if (value > maxValue){
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);
423 for (
int x = 0; x < bitmapSize.
GetX(); ++x){
424 outputLinePtr[x] = quint8(*iter * 255 / maxValue);
434template <
int Dimensions,
class Element>
441 for (
int i = 0; i < Dimensions; ++i){
442 int size = BaseClass::m_sizes[i];
445 result[i] = fmod(result[i] + size, size);
448 retVal = retVal && (result[i] >= 0) && (result[i] < size);
457template <
int Dimensions,
class Element>
458template <
typename Operation>
462 iter != BaseClass::End();
464 Element& value = *iter;
466 value = operation(value);
471template <
int Dimensions,
class Element>
472template <
typename Operation>
476 for (
int i = 0; i < Dimensions; ++i){
477 commonSize[i] = qMin(BaseClass::m_sizes[i], space.
m_sizes[i]);
483 Element& destValue = BaseClass::GetAt(index);
484 const Element& secondValue = space.BaseClass::GetAt(index);
486 destValue = operation(destValue, secondValue);
487 }
while (index.
Increase(commonSize));
493template <
int Dimensions,
class Element>
506 int dimensionsCount = Dimensions;
508 retVal = retVal && archive.
BeginMultiTag(spaceSizeTag, dimensionSizeTag, dimensionsCount);
509 if (dimensionsCount != Dimensions){
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);
518 retVal = retVal && archive.
EndTag(spaceSizeTag);
521 if (!BaseClass::SetSizes(spaceSize)){
526 retVal = retVal && archive.
BeginTag(elementsTag);
528 iter != BaseClass::End();
530 retVal = retVal && archive.
Process(*iter);
532 retVal = retVal && archive.
EndTag(elementsTag);
540template <
int Dimensions,
class Element>
545 int elementsCount = int(BaseClass::m_elements.size());
547 for (
int i = 0; i < Dimensions; ++i){
548 if (i < dimensionIndex){
549 elementDiff *= BaseClass::m_sizes[i];
551 else if (i > dimensionIndex){
552 blocksCount *= BaseClass::m_sizes[i];
556 int smoothAxisSize = BaseClass::m_sizes[dimensionIndex];
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;
563 for (
int iterIndex = 0; iterIndex < iterations; ++iterIndex){
564 int elementOffset = axisElementOffset;
570 if (m_isWrapped[dimensionIndex]){
571 value = BaseClass::m_elements[elementOffset];
573 prevValue = BaseClass::m_elements[axisElementOffset + (smoothAxisSize - 1) * elementDiff];
577 value = BaseClass::m_elements[elementOffset];
583 for (; nextPos < smoothAxisSize; ++nextPos){
584 int nextElementOffset = (elementOffset + elementDiff) % elementsCount;
586 Element nextValue = BaseClass::m_elements[nextElementOffset];
588 BaseClass::m_elements[elementOffset] = (value * 2 + prevValue + nextValue) / 4;
593 elementOffset = nextElementOffset;
596 BaseClass::m_elements[elementOffset] = (value * 2 + prevValue + storedValue) / 4;
600 outerElementOffset += smoothAxisSize * elementDiff;
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.
@ PF_GRAY
8-bit grayscale bitmap.
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.
Process tag used to group data in archive stream.
@ TT_GROUP
Normal tag used for grouping of tags or processed elements.
@ TT_MULTIPLE
Multiple tag containing variable number of child tags.
Represent input/output persistence archive.
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.
Multidimensional array with fixed number of dimensions.
Multidimensional index used to addressing fixed-size array.
static const TIndex< Dimensions > & GetZero()
Get global instance of zero index.
bool Increase(const TIndex &boundaries)
Increase this index inside the boundaries.
bool IsInside(const TIndex &boundaries) const
Check if index is inside boundaries.
Contains implementations of interfaces and components of common algorithms with no association to ano...