40 #include <visp3/core/vpCPUFeatures.h> 41 #include <visp3/core/vpConfig.h> 42 #include <visp3/mbt/vpMbtTukeyEstimator.h> 44 #define USE_TRANSFORM 1 45 #if defined(VISP_HAVE_CPP11_COMPATIBILITY) && USE_TRANSFORM 46 #define HAVE_TRANSFORM 1 53 #if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2) 54 #include <emmintrin.h> 55 #define VISP_HAVE_SSE2 1 57 #if defined __SSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) 58 #include <pmmintrin.h> 59 #define VISP_HAVE_SSE3 1 61 #if defined __SSSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) 62 #include <tmmintrin.h> 63 #define VISP_HAVE_SSSE3 1 67 #define USE_ORIGINAL_TUKEY_CODE 1 69 #ifndef DOXYGEN_SHOULD_SKIP_THIS 74 template <
typename T>
struct AbsDiff :
public std::binary_function<T, T, T> {
75 double operator()(
const T a,
const T b)
const {
return std::fabs(a - b); }
80 template class vpMbtTukeyEstimator<float>;
81 template class vpMbtTukeyEstimator<double>;
86 inline __m128 abs_ps(__m128 x)
88 static const __m128 sign_mask = _mm_set1_ps(-0.f);
89 return _mm_andnot_ps(sign_mask, x);
94 template <
typename T> T vpMbtTukeyEstimator<T>::getMedian(std::vector<T> &vec)
97 int index = (int)(ceil(vec.size() / 2.0)) - 1;
98 std::nth_element(vec.begin(), vec.begin() + index, vec.end());
108 template <
typename T>
109 void vpMbtTukeyEstimator<T>::MEstimator_impl(
const std::vector<T> &residues, std::vector<T> &weights,
110 const T NoiseThreshold)
112 if (residues.empty()) {
116 m_residues = residues;
118 T med = getMedian(m_residues);
119 m_normres.resize(residues.size());
122 std::transform(residues.begin(), residues.end(), m_normres.begin(),
123 std::bind(AbsDiff<T>(), std::placeholders::_1, med));
125 for (
size_t i = 0; i < m_residues.size(); i++) {
126 m_normres[i] = (std::fabs(residues[i] - med));
130 m_residues = m_normres;
131 T normmedian = getMedian(m_residues);
134 T sigma =
static_cast<T
>(1.4826 * normmedian);
138 if (sigma < NoiseThreshold) {
139 sigma = NoiseThreshold;
142 psiTukey(sigma, m_normres, weights);
146 void vpMbtTukeyEstimator<float>::MEstimator_impl_ssse3(
const std::vector<float> &residues, std::vector<float> &weights,
147 const float NoiseThreshold)
150 if (residues.empty()) {
154 m_residues = residues;
156 float med = getMedian(m_residues);
157 m_normres.resize(residues.size());
160 __m128 med_128 = _mm_set_ps1(med);
162 if (m_residues.size() >= 4) {
163 for (i = 0; i <= m_residues.size() - 4; i += 4) {
164 __m128 residues_128 = _mm_loadu_ps(residues.data() + i);
165 _mm_storeu_ps(m_normres.data() + i, abs_ps(_mm_sub_ps(residues_128, med_128)));
169 for (; i < m_residues.size(); i++) {
170 m_normres[i] = (std::fabs(residues[i] - med));
173 m_residues = m_normres;
174 float normmedian = getMedian(m_residues);
177 float sigma = 1.4826f * normmedian;
181 if (sigma < NoiseThreshold) {
182 sigma = NoiseThreshold;
185 psiTukey(sigma, m_normres, weights);
189 (void)NoiseThreshold;
194 void vpMbtTukeyEstimator<double>::MEstimator_impl_ssse3(
const std::vector<double> &residues,
195 std::vector<double> &weights,
const double NoiseThreshold)
198 if (residues.empty()) {
202 m_residues = residues;
204 double med = getMedian(m_residues);
205 m_normres.resize(residues.size());
208 std::transform(residues.begin(), residues.end(), m_normres.begin(),
209 std::bind(AbsDiff<double>(), std::placeholders::_1, med));
211 for (
size_t i = 0; i < m_residues.size(); i++) {
212 m_normres[i] = (std::fabs(residues[i] - med));
216 m_residues = m_normres;
217 double normmedian = getMedian(m_residues);
220 double sigma = 1.4826 * normmedian;
224 if (sigma < NoiseThreshold) {
225 sigma = NoiseThreshold;
228 psiTukey(sigma, m_normres, weights);
232 (void)NoiseThreshold;
237 void vpMbtTukeyEstimator<float>::MEstimator(
const std::vector<float> &residues, std::vector<float> &weights,
238 const float NoiseThreshold)
246 MEstimator_impl_ssse3(residues, weights, NoiseThreshold);
248 MEstimator_impl(residues, weights, NoiseThreshold);
252 void vpMbtTukeyEstimator<double>::MEstimator(
const std::vector<double> &residues, std::vector<double> &weights,
253 const double NoiseThreshold)
261 MEstimator_impl_ssse3(residues, weights, NoiseThreshold);
263 MEstimator_impl(residues, weights, NoiseThreshold);
266 template <
typename T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x,
vpColVector &weights)
268 T cst_const =
static_cast<T
>(4.6851);
269 T inv_cst_const = 1 / cst_const;
272 for (
unsigned int i = 0; i < (
unsigned int)x.size(); i++) {
273 #if USE_ORIGINAL_TUKEY_CODE 274 if (std::fabs(sig) <= std::numeric_limits<T>::epsilon() &&
275 std::fabs(weights[i]) > std::numeric_limits<double>::epsilon()
285 double xi_sig = x[(size_t)i] * inv_sig;
287 if ((std::fabs(xi_sig) <= cst_const)
288 #
if USE_ORIGINAL_TUKEY_CODE
289 && std::fabs(weights[i]) > std::numeric_limits<double>::epsilon()
293 weights[i] = (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const)) *
294 (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const));
306 const double NoiseThreshold)
308 if (residues.
size() == 0) {
313 m_residues.reserve(residues.
size());
314 m_residues.insert(m_residues.end(), &residues.
data[0], &residues.
data[residues.
size()]);
316 double med = getMedian(m_residues);
318 m_normres.resize(residues.
size());
319 for (
size_t i = 0; i < m_residues.size(); i++) {
320 m_normres[i] = std::fabs(residues[(
unsigned int)i] - med);
323 m_residues = m_normres;
324 double normmedian = getMedian(m_residues);
327 double sigma = 1.4826 * normmedian;
331 if (sigma < NoiseThreshold) {
332 sigma = NoiseThreshold;
335 psiTukey(sigma, m_normres, weights);
340 const double NoiseThreshold)
342 if (residues.
size() == 0) {
346 m_residues.resize(0);
347 m_residues.reserve(residues.
size());
348 for (
unsigned int i = 0; i < residues.
size(); i++) {
349 m_residues.push_back((
float)residues[i]);
352 float med = getMedian(m_residues);
354 m_normres.resize(residues.
size());
355 for (
size_t i = 0; i < m_residues.size(); i++) {
356 m_normres[i] = (float)std::fabs(residues[(
unsigned int)i] - med);
359 m_residues = m_normres;
360 float normmedian = getMedian(m_residues);
363 float sigma = 1.4826f * normmedian;
367 if (sigma < NoiseThreshold) {
368 sigma = (float)NoiseThreshold;
371 psiTukey(sigma, m_normres, weights);
374 template <
class T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x, std::vector<T> &weights)
376 T cst_const =
static_cast<T
>(4.6851);
377 T inv_cst_const = 1 / cst_const;
380 for (
size_t i = 0; i < x.size(); i++) {
381 #if USE_ORIGINAL_TUKEY_CODE 382 if (std::fabs(sig) <= std::numeric_limits<T>::epsilon() &&
383 std::fabs(weights[i]) > std::numeric_limits<T>::epsilon()
391 T xi_sig = x[i] * inv_sig;
393 if ((std::fabs(xi_sig) <= cst_const)
394 #if USE_ORIGINAL_TUKEY_CODE 395 && std::fabs(weights[i]) > std::numeric_limits<T>::epsilon()
400 weights[i] = (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const)) *
401 (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const));
408 #endif //#ifndef DOXYGEN_SHOULD_SKIP_THIS Type * data
Address of the first element of the data array.
unsigned int size() const
Return the number of elements of the 2D array.
VISP_EXPORT bool checkSSSE3()
Implementation of column vector and the associated operations.
void resize(const unsigned int i, const bool flagNullify=true)