36 #ifndef _vpMbtTukeyEstimator_h_ 37 #define _vpMbtTukeyEstimator_h_ 40 #include <visp3/core/vpColVector.h> 42 #ifndef DOXYGEN_SHOULD_SKIP_THIS 44 template <
typename T>
class vpMbtTukeyEstimator
47 void MEstimator(
const std::vector<T> &residues, std::vector<T> &weights,
const T NoiseThreshold);
51 T getMedian(std::vector<T> &vec);
52 void MEstimator_impl(
const std::vector<T> &residues, std::vector<T> &weights,
const T NoiseThreshold);
53 void MEstimator_impl_ssse3(
const std::vector<T> &residues, std::vector<T> &weights,
const T NoiseThreshold);
54 void psiTukey(
const T sig, std::vector<T> &x, std::vector<T> &weights);
55 void psiTukey(
const T sig, std::vector<T> &x,
vpColVector &weights);
57 std::vector<T> m_normres;
58 std::vector<T> m_residues;
60 #endif //#ifndef DOXYGEN_SHOULD_SKIP_THIS 80 #include <visp3/core/vpCPUFeatures.h> 82 #define USE_TRANSFORM 1 83 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) && USE_TRANSFORM 84 #define HAVE_TRANSFORM 1 91 #if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2) 92 #include <emmintrin.h> 93 #define VISP_HAVE_SSE2 1 95 #if defined __SSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) 96 #include <pmmintrin.h> 97 #define VISP_HAVE_SSE3 1 99 #if defined __SSSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) 100 #include <tmmintrin.h> 101 #define VISP_HAVE_SSSE3 1 105 #define USE_ORIGINAL_TUKEY_CODE 1 107 #ifndef DOXYGEN_SHOULD_SKIP_THIS 112 template <
typename T>
struct AbsDiff :
public std::binary_function<T, T, T> {
113 T operator()(
const T a,
const T b)
const {
return std::fabs(a - b); }
118 template class vpMbtTukeyEstimator<float>;
119 template class vpMbtTukeyEstimator<double>;
124 inline __m128 abs_ps(__m128 x)
126 static const __m128 sign_mask = _mm_set1_ps(-0.f);
127 return _mm_andnot_ps(sign_mask, x);
132 template <
typename T> T vpMbtTukeyEstimator<T>::getMedian(std::vector<T> &vec)
135 int index = (int)(ceil(vec.size() / 2.0)) - 1;
136 std::nth_element(vec.begin(), vec.begin() + index, vec.end());
146 template <
typename T>
147 void vpMbtTukeyEstimator<T>::MEstimator_impl(
const std::vector<T> &residues, std::vector<T> &weights,
148 const T NoiseThreshold)
150 if (residues.empty()) {
154 m_residues = residues;
156 T med = getMedian(m_residues);
157 m_normres.resize(residues.size());
160 std::transform(residues.begin(), residues.end(), m_normres.begin(),
161 std::bind(AbsDiff<T>(), std::placeholders::_1, med));
163 for (
size_t i = 0; i < m_residues.size(); i++) {
164 m_normres[i] = (std::fabs(residues[i] - med));
168 m_residues = m_normres;
169 T normmedian = getMedian(m_residues);
172 T sigma =
static_cast<T
>(1.4826 * normmedian);
176 if (sigma < NoiseThreshold) {
177 sigma = NoiseThreshold;
180 psiTukey(sigma, m_normres, weights);
184 inline void vpMbtTukeyEstimator<float>::MEstimator_impl_ssse3(
const std::vector<float> &residues, std::vector<float> &weights,
185 const float NoiseThreshold)
188 if (residues.empty()) {
192 m_residues = residues;
194 float med = getMedian(m_residues);
195 m_normres.resize(residues.size());
198 __m128 med_128 = _mm_set_ps1(med);
200 if (m_residues.size() >= 4) {
201 for (i = 0; i <= m_residues.size() - 4; i += 4) {
202 __m128 residues_128 = _mm_loadu_ps(residues.data() + i);
203 _mm_storeu_ps(m_normres.data() + i, abs_ps(_mm_sub_ps(residues_128, med_128)));
207 for (; i < m_residues.size(); i++) {
208 m_normres[i] = (std::fabs(residues[i] - med));
211 m_residues = m_normres;
212 float normmedian = getMedian(m_residues);
215 float sigma = 1.4826f * normmedian;
219 if (sigma < NoiseThreshold) {
220 sigma = NoiseThreshold;
223 psiTukey(sigma, m_normres, weights);
227 (void)NoiseThreshold;
232 inline void vpMbtTukeyEstimator<double>::MEstimator_impl_ssse3(
const std::vector<double> &residues,
233 std::vector<double> &weights,
const double NoiseThreshold)
236 if (residues.empty()) {
240 m_residues = residues;
242 double med = getMedian(m_residues);
243 m_normres.resize(residues.size());
246 std::transform(residues.begin(), residues.end(), m_normres.begin(),
247 std::bind(AbsDiff<double>(), std::placeholders::_1, med));
249 for (
size_t i = 0; i < m_residues.size(); i++) {
250 m_normres[i] = (std::fabs(residues[i] - med));
254 m_residues = m_normres;
255 double normmedian = getMedian(m_residues);
258 double sigma = 1.4826 * normmedian;
262 if (sigma < NoiseThreshold) {
263 sigma = NoiseThreshold;
266 psiTukey(sigma, m_normres, weights);
270 (void)NoiseThreshold;
275 inline void vpMbtTukeyEstimator<float>::MEstimator(
const std::vector<float> &residues, std::vector<float> &weights,
276 const float NoiseThreshold)
284 MEstimator_impl_ssse3(residues, weights, NoiseThreshold);
286 MEstimator_impl(residues, weights, NoiseThreshold);
290 inline void vpMbtTukeyEstimator<double>::MEstimator(
const std::vector<double> &residues, std::vector<double> &weights,
291 const double NoiseThreshold)
299 MEstimator_impl_ssse3(residues, weights, NoiseThreshold);
301 MEstimator_impl(residues, weights, NoiseThreshold);
304 template <
typename T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x,
vpColVector &weights)
306 T cst_const =
static_cast<T
>(4.6851);
307 T inv_cst_const = 1 / cst_const;
310 for (
unsigned int i = 0; i < (
unsigned int)x.size(); i++) {
311 #if USE_ORIGINAL_TUKEY_CODE 312 if (std::fabs(sig) <= std::numeric_limits<T>::epsilon() &&
313 std::fabs(weights[i]) > std::numeric_limits<double>::epsilon()
323 double xi_sig = x[(size_t)i] * inv_sig;
325 if ((std::fabs(xi_sig) <= cst_const)
326 #
if USE_ORIGINAL_TUKEY_CODE
327 && std::fabs(weights[i]) > std::numeric_limits<double>::epsilon()
331 weights[i] = (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const)) *
332 (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const));
344 const double NoiseThreshold)
346 if (residues.
size() == 0) {
351 m_residues.reserve(residues.
size());
352 m_residues.insert(m_residues.end(), &residues.
data[0], &residues.
data[residues.
size()]);
354 double med = getMedian(m_residues);
356 m_normres.resize(residues.
size());
357 for (
size_t i = 0; i < m_residues.size(); i++) {
358 m_normres[i] = std::fabs(residues[(
unsigned int)i] - med);
361 m_residues = m_normres;
362 double normmedian = getMedian(m_residues);
365 double sigma = 1.4826 * normmedian;
369 if (sigma < NoiseThreshold) {
370 sigma = NoiseThreshold;
373 psiTukey(sigma, m_normres, weights);
378 const double NoiseThreshold)
380 if (residues.
size() == 0) {
384 m_residues.resize(0);
385 m_residues.reserve(residues.
size());
386 for (
unsigned int i = 0; i < residues.
size(); i++) {
387 m_residues.push_back((
float)residues[i]);
390 float med = getMedian(m_residues);
392 m_normres.resize(residues.
size());
393 for (
size_t i = 0; i < m_residues.size(); i++) {
394 m_normres[i] = (float)std::fabs(residues[(
unsigned int)i] - med);
397 m_residues = m_normres;
398 float normmedian = getMedian(m_residues);
401 float sigma = 1.4826f * normmedian;
405 if (sigma < NoiseThreshold) {
406 sigma = (float)NoiseThreshold;
409 psiTukey(sigma, m_normres, weights);
412 template <
class T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x, std::vector<T> &weights)
414 T cst_const =
static_cast<T
>(4.6851);
415 T inv_cst_const = 1 / cst_const;
418 for (
size_t i = 0; i < x.size(); i++) {
419 #if USE_ORIGINAL_TUKEY_CODE 420 if (std::fabs(sig) <= std::numeric_limits<T>::epsilon() &&
421 std::fabs(weights[i]) > std::numeric_limits<T>::epsilon()
429 T xi_sig = x[i] * inv_sig;
431 if ((std::fabs(xi_sig) <= cst_const)
432 #if USE_ORIGINAL_TUKEY_CODE 433 && std::fabs(weights[i]) > std::numeric_limits<T>::epsilon()
438 weights[i] = (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const)) *
439 (1 - (xi_sig * inv_cst_const) * (xi_sig * inv_cst_const));
446 #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()
void resize(unsigned int i, bool flagNullify=true)
Implementation of column vector and the associated operations.