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