34#ifndef VP_MBT_TUKEY_ESTIMATOR_H
35#define VP_MBT_TUKEY_ESTIMATOR_H
38#include <visp3/core/vpConfig.h>
39#include <visp3/core/vpColVector.h>
41#ifndef DOXYGEN_SHOULD_SKIP_THIS
61 template <
typename T>
class vpMbtTukeyEstimator
64 void MEstimator(
const std::vector<T> &residues, std::vector<T> &weights, T NoiseThreshold);
65 void MEstimator(
const vpColVector &residues, vpColVector &weights,
double NoiseThreshold);
68 T getMedian(std::vector<T> &vec);
69 void MEstimator_impl(
const std::vector<T> &residues, std::vector<T> &weights, T NoiseThreshold);
70 void MEstimator_impl_simd(
const std::vector<T> &residues, std::vector<T> &weights, T NoiseThreshold);
71 void psiTukey(
const T sig, std::vector<T> &x, std::vector<T> &weights);
72 void psiTukey(
const T sig, std::vector<T> &x, vpColVector &weights);
74 std::vector<T> m_normres;
75 std::vector<T> m_residues;
97#include <visp3/core/vpCPUFeatures.h>
99#define USE_TRANSFORM 1
100#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) && USE_TRANSFORM
101#define HAVE_TRANSFORM 1
105#if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2)
106#include <emmintrin.h>
107#define VISP_HAVE_SSE2 1
109#if defined __SSE3__ || (defined _MSC_VER && _MSC_VER >= 1500)
110#include <pmmintrin.h>
111#define VISP_HAVE_SSE3 1
113#if defined __SSSE3__ || (defined _MSC_VER && _MSC_VER >= 1500)
114#include <tmmintrin.h>
115#define VISP_HAVE_SSSE3 1
119#if defined _WIN32 && defined(_M_ARM64)
120# define _ARM64_DISTINCT_NEON_TYPES
122# include <arm_neon.h>
123# define VISP_HAVE_NEON 1
124#elif (defined(__ARM_NEON__) || defined (__ARM_NEON)) && defined(__aarch64__)
125# include <arm_neon.h>
126# define VISP_HAVE_NEON 1
129#ifndef DOXYGEN_SHOULD_SKIP_THIS
135#if ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
136auto AbsDiff = [](
const auto &a,
const auto &b) {
return std::fabs(a - b); };
138template <
typename T>
struct AbsDiff :
public std::binary_function<T, T, T>
140 T operator()(
const T a,
const T b)
const {
return std::fabs(a - b); }
147template class vpMbtTukeyEstimator<float>;
148template class vpMbtTukeyEstimator<double>;
153inline __m128 abs_ps(__m128 x)
155 static const __m128 sign_mask = _mm_set1_ps(-0.f);
156 return _mm_andnot_ps(sign_mask, x);
161template <
typename T> T vpMbtTukeyEstimator<T>::getMedian(std::vector<T> &vec)
164 size_t index =
static_cast<size_t>(ceil(
static_cast<double>(vec.size()) / 2.0)) - 1;
165 std::nth_element(vec.begin(), vec.begin() +
static_cast<long long>(index), vec.end());
176void vpMbtTukeyEstimator<T>::MEstimator_impl(
const std::vector<T> &residues, std::vector<T> &weights,
177 const T NoiseThreshold)
179 if (residues.empty()) {
183 m_residues = residues;
185 T med = getMedian(m_residues);
186 m_normres.resize(residues.size());
190#if ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
191 std::transform(residues.begin(), residues.end(), m_normres.begin(), std::bind(AbsDiff, std::placeholders::_1, med));
193 std::transform(residues.begin(), residues.end(), m_normres.begin(),
194 std::bind(AbsDiff<T>(), std::placeholders::_1, med));
197 for (
size_t i = 0;
i < m_residues.size();
i++) {
198 m_normres[
i] = (std::fabs(residues[i] - med));
202 m_residues = m_normres;
203 T normmedian = getMedian(m_residues);
206 T sigma =
static_cast<T
>(1.4826) * normmedian;
210 if (sigma < NoiseThreshold) {
211 sigma = NoiseThreshold;
214 psiTukey(sigma, m_normres, weights);
218inline void vpMbtTukeyEstimator<float>::MEstimator_impl_simd(
const std::vector<float> &residues,
219 std::vector<float> &weights,
220 float NoiseThreshold)
222#if VISP_HAVE_SSSE3 || VISP_HAVE_NEON
223 if (residues.empty()) {
227 m_residues = residues;
229 float med = getMedian(m_residues);
230 m_normres.resize(residues.size());
234 __m128 med_128 = _mm_set_ps1(med);
236 float32x4_t med_128 = vdupq_n_f32(med);
239 if (m_residues.size() >= 4) {
240 for (i = 0;
i <= m_residues.size() - 4;
i += 4) {
242 __m128 residues_128 = _mm_loadu_ps(residues.data() + i);
243 _mm_storeu_ps(m_normres.data() + i, abs_ps(_mm_sub_ps(residues_128, med_128)));
245 float32x4_t residues_128 = vld1q_f32(residues.data() + i);
246 vst1q_f32(m_normres.data() + i, vabsq_f32(vsubq_f32(residues_128, med_128)));
251 for (;
i < m_residues.size();
i++) {
252 m_normres[
i] = (std::fabs(residues[i] - med));
255 m_residues = m_normres;
256 float normmedian = getMedian(m_residues);
259 float sigma = 1.4826f * normmedian;
263 if (sigma < NoiseThreshold) {
264 sigma = NoiseThreshold;
267 psiTukey(sigma, m_normres, weights);
271 (void)NoiseThreshold;
279inline void vpMbtTukeyEstimator<double>::MEstimator_impl_simd(
const std::vector<double> &residues,
280 std::vector<double> &weights,
281 double NoiseThreshold)
283#if VISP_HAVE_SSSE3 || VISP_HAVE_NEON
284 if (residues.empty()) {
288 m_residues = residues;
290 double med = getMedian(m_residues);
291 m_normres.resize(residues.size());
295#if ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
296 std::transform(residues.begin(), residues.end(), m_normres.begin(), std::bind(AbsDiff, std::placeholders::_1, med));
298 std::transform(residues.begin(), residues.end(), m_normres.begin(),
299 std::bind(AbsDiff<double>(), std::placeholders::_1, med));
302 for (
size_t i = 0;
i < m_residues.size();
i++) {
303 m_normres[
i] = (std::fabs(residues[i] - med));
307 m_residues = m_normres;
308 double normmedian = getMedian(m_residues);
311 double sigma = 1.4826 * normmedian;
315 if (sigma < NoiseThreshold) {
316 sigma = NoiseThreshold;
319 psiTukey(sigma, m_normres, weights);
323 (void)NoiseThreshold;
331inline void vpMbtTukeyEstimator<float>::MEstimator(
const std::vector<float> &residues, std::vector<float> &weights,
332 float NoiseThreshold)
334#if defined(VISP_HAVE_SIMDLIB)
339#if !VISP_HAVE_SSSE3 && !VISP_HAVE_NEON
344 MEstimator_impl_simd(residues, weights, NoiseThreshold);
346 MEstimator_impl(residues, weights, NoiseThreshold);
353inline void vpMbtTukeyEstimator<double>::MEstimator(
const std::vector<double> &residues, std::vector<double> &weights,
354 double NoiseThreshold)
356#if defined(VISP_HAVE_SIMDLIB)
361#if !VISP_HAVE_SSSE3 && !VISP_HAVE_NEON
366 MEstimator_impl_simd(residues, weights, NoiseThreshold);
368 MEstimator_impl(residues, weights, NoiseThreshold);
374template <
typename T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x,
vpColVector &weights)
376 double C =
static_cast<double>(sig) * 4.6851;
379 for (
unsigned int i = 0; i < static_cast<unsigned int>(
x.size());
i++) {
380 double xi =
static_cast<double>(
x[
i]) / C;
399 double NoiseThreshold)
401 if (residues.
size() == 0) {
405 m_residues.resize(0);
406 m_residues.reserve(residues.
size());
407 m_residues.insert(m_residues.end(), &residues.
data[0], &residues.
data[residues.
size()]);
409 double med = getMedian(m_residues);
411 m_normres.resize(residues.
size());
412 for (
size_t i = 0;
i < m_residues.size();
i++) {
413 m_normres[
i] = std::fabs(residues[
static_cast<unsigned int>(i)] - med);
416 m_residues = m_normres;
417 double normmedian = getMedian(m_residues);
420 double sigma = 1.4826 * normmedian;
424 if (sigma < NoiseThreshold) {
425 sigma = NoiseThreshold;
428 psiTukey(sigma, m_normres, weights);
436 double NoiseThreshold)
438 if (residues.
size() == 0) {
442 m_residues.resize(0);
443 m_residues.reserve(residues.
size());
444 for (
unsigned int i = 0;
i < residues.
size();
i++) {
445 m_residues.push_back(
static_cast<float>(residues[i]));
448 float med = getMedian(m_residues);
450 m_normres.resize(residues.
size());
451 for (
size_t i = 0;
i < m_residues.size();
i++) {
452 m_normres[
i] =
static_cast<float>(std::fabs(
static_cast<float>(residues[
static_cast<unsigned int>(i)]) - med));
455 m_residues = m_normres;
456 float normmedian = getMedian(m_residues);
459 float sigma = 1.4826f * normmedian;
460 float noise_threshold =
static_cast<float>(NoiseThreshold);
464 if (sigma < noise_threshold) {
465 sigma = noise_threshold;
468 psiTukey(sigma, m_normres, weights);
474template <
class T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x, std::vector<T> &weights)
476 T C =
static_cast<T
>(4.6851) * sig;
477 weights.resize(
x.size());
478 T one =
static_cast<T
>(1.);
481 for (
size_t i = 0;
i <
x.size();
i++) {
Type * data
Address of the first element of the data array.
unsigned int size() const
Return the number of elements of the 2D array.
Implementation of column vector and the associated operations.
VISP_EXPORT bool checkSSSE3()
VISP_EXPORT bool checkNeon()