ConvectionKernels_EndpointSelector.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #pragma once
  2. #ifndef __CVTT_ENDPOINTSELECTOR_H__
  3. #define __CVTT_ENDPOINTSELECTOR_H__
  4. #include "ConvectionKernels_ParallelMath.h"
  5. #include "ConvectionKernels_UnfinishedEndpoints.h"
  6. #include "ConvectionKernels_PackedCovarianceMatrix.h"
  7. namespace cvtt
  8. {
  9. namespace Internal
  10. {
  11. static const int NumEndpointSelectorPasses = 3;
  12. template<int TVectorSize, int TIterationCount>
  13. class EndpointSelector
  14. {
  15. public:
  16. typedef ParallelMath::Float MFloat;
  17. EndpointSelector()
  18. {
  19. for (int ch = 0; ch < TVectorSize; ch++)
  20. {
  21. m_centroid[ch] = ParallelMath::MakeFloatZero();
  22. m_direction[ch] = ParallelMath::MakeFloatZero();
  23. }
  24. m_weightTotal = ParallelMath::MakeFloatZero();
  25. m_minDist = ParallelMath::MakeFloat(FLT_MAX);
  26. m_maxDist = ParallelMath::MakeFloat(-FLT_MAX);
  27. }
  28. void ContributePass(const MFloat *value, int pass, const MFloat &weight)
  29. {
  30. if (pass == 0)
  31. ContributeCentroid(value, weight);
  32. else if (pass == 1)
  33. ContributeDirection(value, weight);
  34. else if (pass == 2)
  35. ContributeMinMax(value);
  36. }
  37. void FinishPass(int pass)
  38. {
  39. if (pass == 0)
  40. FinishCentroid();
  41. else if (pass == 1)
  42. FinishDirection();
  43. }
  44. UnfinishedEndpoints<TVectorSize> GetEndpoints(const float channelWeights[TVectorSize]) const
  45. {
  46. MFloat unweightedBase[TVectorSize];
  47. MFloat unweightedOffset[TVectorSize];
  48. for (int ch = 0; ch < TVectorSize; ch++)
  49. {
  50. MFloat min = m_centroid[ch] + m_direction[ch] * m_minDist;
  51. MFloat max = m_centroid[ch] + m_direction[ch] * m_maxDist;
  52. float safeWeight = channelWeights[ch];
  53. if (safeWeight == 0.f)
  54. safeWeight = 1.0f;
  55. unweightedBase[ch] = min / channelWeights[ch];
  56. unweightedOffset[ch] = (max - min) / channelWeights[ch];
  57. }
  58. return UnfinishedEndpoints<TVectorSize>(unweightedBase, unweightedOffset);
  59. }
  60. private:
  61. void ContributeCentroid(const MFloat *value, const MFloat &weight)
  62. {
  63. for (int ch = 0; ch < TVectorSize; ch++)
  64. m_centroid[ch] = m_centroid[ch] + value[ch] * weight;
  65. m_weightTotal = m_weightTotal + weight;
  66. }
  67. void FinishCentroid()
  68. {
  69. MFloat denom = m_weightTotal;
  70. ParallelMath::MakeSafeDenominator(denom);
  71. for (int ch = 0; ch < TVectorSize; ch++)
  72. m_centroid[ch] = m_centroid[ch] / denom;
  73. }
  74. void ContributeDirection(const MFloat *value, const MFloat &weight)
  75. {
  76. MFloat diff[TVectorSize];
  77. for (int ch = 0; ch < TVectorSize; ch++)
  78. diff[ch] = value[ch] - m_centroid[ch];
  79. m_covarianceMatrix.Add(diff, weight);
  80. }
  81. void FinishDirection()
  82. {
  83. MFloat approx[TVectorSize];
  84. for (int ch = 0; ch < TVectorSize; ch++)
  85. approx[ch] = ParallelMath::MakeFloat(1.0f);
  86. for (int i = 0; i < TIterationCount; i++)
  87. {
  88. MFloat product[TVectorSize];
  89. m_covarianceMatrix.Product(product, approx);
  90. MFloat largestComponent = product[0];
  91. for (int ch = 1; ch < TVectorSize; ch++)
  92. largestComponent = ParallelMath::Max(largestComponent, product[ch]);
  93. // product = largestComponent*newApprox
  94. ParallelMath::MakeSafeDenominator(largestComponent);
  95. for (int ch = 0; ch < TVectorSize; ch++)
  96. approx[ch] = product[ch] / largestComponent;
  97. }
  98. // Normalize
  99. MFloat approxLen = ParallelMath::MakeFloatZero();
  100. for (int ch = 0; ch < TVectorSize; ch++)
  101. approxLen = approxLen + approx[ch] * approx[ch];
  102. approxLen = ParallelMath::Sqrt(approxLen);
  103. ParallelMath::MakeSafeDenominator(approxLen);
  104. for (int ch = 0; ch < TVectorSize; ch++)
  105. m_direction[ch] = approx[ch] / approxLen;
  106. }
  107. void ContributeMinMax(const MFloat *value)
  108. {
  109. MFloat dist = ParallelMath::MakeFloatZero();
  110. for (int ch = 0; ch < TVectorSize; ch++)
  111. dist = dist + m_direction[ch] * (value[ch] - m_centroid[ch]);
  112. m_minDist = ParallelMath::Min(m_minDist, dist);
  113. m_maxDist = ParallelMath::Max(m_maxDist, dist);
  114. }
  115. ParallelMath::Float m_centroid[TVectorSize];
  116. ParallelMath::Float m_direction[TVectorSize];
  117. PackedCovarianceMatrix<TVectorSize> m_covarianceMatrix;
  118. ParallelMath::Float m_weightTotal;
  119. ParallelMath::Float m_minDist;
  120. ParallelMath::Float m_maxDist;
  121. };
  122. }
  123. }
  124. #endif