36 #ifndef _vpMbtTukeyEstimator_h_
37 #define _vpMbtTukeyEstimator_h_
40 #include <visp3/core/vpConfig.h>
41 #include <visp3/core/vpColVector.h>
43 #ifndef DOXYGEN_SHOULD_SKIP_THIS
46 template <
typename T>
class vpMbtTukeyEstimator
49 void MEstimator(
const std::vector<T> &residues, std::vector<T> &weights, T NoiseThreshold);
53 T getMedian(std::vector<T> &vec);
54 void MEstimator_impl(
const std::vector<T> &residues, std::vector<T> &weights, T NoiseThreshold);
55 void MEstimator_impl_simd(
const std::vector<T> &residues, std::vector<T> &weights, T NoiseThreshold);
56 void psiTukey(
const T sig, std::vector<T> &x, std::vector<T> &weights);
57 void psiTukey(
const T sig, std::vector<T> &x,
vpColVector &weights);
59 std::vector<T> m_normres;
60 std::vector<T> m_residues;
82 #include <visp3/core/vpCPUFeatures.h>
84 #define USE_TRANSFORM 1
85 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) && USE_TRANSFORM
86 #define HAVE_TRANSFORM 1
90 #if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2)
91 #include <emmintrin.h>
92 #define VISP_HAVE_SSE2 1
94 #if defined __SSE3__ || (defined _MSC_VER && _MSC_VER >= 1500)
95 #include <pmmintrin.h>
96 #define VISP_HAVE_SSE3 1
98 #if defined __SSSE3__ || (defined _MSC_VER && _MSC_VER >= 1500)
99 #include <tmmintrin.h>
100 #define VISP_HAVE_SSSE3 1
104 #if defined _WIN32 && defined(_M_ARM64)
105 # define _ARM64_DISTINCT_NEON_TYPES
107 # include <arm_neon.h>
108 # define VISP_HAVE_NEON 1
109 #elif (defined(__ARM_NEON__) || defined (__ARM_NEON)) && defined(__aarch64__)
110 # include <arm_neon.h>
111 # define VISP_HAVE_NEON 1
114 #ifndef DOXYGEN_SHOULD_SKIP_THIS
120 #if ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
121 auto AbsDiff = [](
const auto &a,
const auto &b) {
return std::fabs(a - b); };
123 template <
typename T>
struct AbsDiff :
public std::binary_function<T, T, T>
125 T operator()(
const T a,
const T b)
const {
return std::fabs(a - b); }
132 template class vpMbtTukeyEstimator<float>;
133 template class vpMbtTukeyEstimator<double>;
138 inline __m128 abs_ps(__m128 x)
140 static const __m128 sign_mask = _mm_set1_ps(-0.f);
141 return _mm_andnot_ps(sign_mask, x);
146 template <
typename T> T vpMbtTukeyEstimator<T>::getMedian(std::vector<T> &vec)
149 int index = (int)(ceil(vec.size() / 2.0)) - 1;
150 std::nth_element(vec.begin(), vec.begin() + index, vec.end());
160 template <
typename T>
161 void vpMbtTukeyEstimator<T>::MEstimator_impl(
const std::vector<T> &residues, std::vector<T> &weights,
162 const T NoiseThreshold)
164 if (residues.empty()) {
168 m_residues = residues;
170 T med = getMedian(m_residues);
171 m_normres.resize(residues.size());
175 #if ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
176 std::transform(residues.begin(), residues.end(), m_normres.begin(), std::bind(AbsDiff, std::placeholders::_1, med));
178 std::transform(residues.begin(), residues.end(), m_normres.begin(),
179 std::bind(AbsDiff<T>(), std::placeholders::_1, med));
182 for (
size_t i = 0; i < m_residues.size(); i++) {
183 m_normres[i] = (std::fabs(residues[i] - med));
187 m_residues = m_normres;
188 T normmedian = getMedian(m_residues);
191 T sigma =
static_cast<T
>(1.4826 * normmedian);
195 if (sigma < NoiseThreshold) {
196 sigma = NoiseThreshold;
199 psiTukey(sigma, m_normres, weights);
203 inline void vpMbtTukeyEstimator<float>::MEstimator_impl_simd(
const std::vector<float> &residues,
204 std::vector<float> &weights,
205 float NoiseThreshold)
207 #if VISP_HAVE_SSSE3 || VISP_HAVE_NEON
208 if (residues.empty()) {
212 m_residues = residues;
214 float med = getMedian(m_residues);
215 m_normres.resize(residues.size());
219 __m128 med_128 = _mm_set_ps1(med);
221 float32x4_t med_128 = vdupq_n_f32(med);
224 if (m_residues.size() >= 4) {
225 for (i = 0; i <= m_residues.size() - 4; i += 4) {
227 __m128 residues_128 = _mm_loadu_ps(residues.data() + i);
228 _mm_storeu_ps(m_normres.data() + i, abs_ps(_mm_sub_ps(residues_128, med_128)));
230 float32x4_t residues_128 = vld1q_f32(residues.data() + i);
231 vst1q_f32(m_normres.data() + i, vabsq_f32(vsubq_f32(residues_128, med_128)));
236 for (; i < m_residues.size(); i++) {
237 m_normres[i] = (std::fabs(residues[i] - med));
240 m_residues = m_normres;
241 float normmedian = getMedian(m_residues);
244 float sigma = 1.4826f * normmedian;
248 if (sigma < NoiseThreshold) {
249 sigma = NoiseThreshold;
252 psiTukey(sigma, m_normres, weights);
256 (void)NoiseThreshold;
264 inline void vpMbtTukeyEstimator<double>::MEstimator_impl_simd(
const std::vector<double> &residues,
265 std::vector<double> &weights,
266 double NoiseThreshold)
268 #if VISP_HAVE_SSSE3 || VISP_HAVE_NEON
269 if (residues.empty()) {
273 m_residues = residues;
275 double med = getMedian(m_residues);
276 m_normres.resize(residues.size());
280 #if ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
281 std::transform(residues.begin(), residues.end(), m_normres.begin(), std::bind(AbsDiff, std::placeholders::_1, med));
283 std::transform(residues.begin(), residues.end(), m_normres.begin(),
284 std::bind(AbsDiff<double>(), std::placeholders::_1, med));
287 for (
size_t i = 0; i < m_residues.size(); i++) {
288 m_normres[i] = (std::fabs(residues[i] - med));
292 m_residues = m_normres;
293 double normmedian = getMedian(m_residues);
296 double sigma = 1.4826 * normmedian;
300 if (sigma < NoiseThreshold) {
301 sigma = NoiseThreshold;
304 psiTukey(sigma, m_normres, weights);
308 (void)NoiseThreshold;
316 inline void vpMbtTukeyEstimator<float>::MEstimator(
const std::vector<float> &residues, std::vector<float> &weights,
317 float NoiseThreshold)
319 #if defined(VISP_HAVE_SIMDLIB)
324 #if !VISP_HAVE_SSSE3 && !VISP_HAVE_NEON
329 MEstimator_impl_simd(residues, weights, NoiseThreshold);
331 MEstimator_impl(residues, weights, NoiseThreshold);
338 inline void vpMbtTukeyEstimator<double>::MEstimator(
const std::vector<double> &residues, std::vector<double> &weights,
339 double NoiseThreshold)
341 #if defined(VISP_HAVE_SIMDLIB)
346 #if !VISP_HAVE_SSSE3 && !VISP_HAVE_NEON
351 MEstimator_impl_simd(residues, weights, NoiseThreshold);
353 MEstimator_impl(residues, weights, NoiseThreshold);
359 template <
typename T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x,
vpColVector &weights)
361 double C = sig * 4.6851;
364 for (
unsigned int i = 0; i < (
unsigned int)x.size(); i++) {
365 double xi = x[i] / C;
384 double NoiseThreshold)
386 if (residues.
size() == 0) {
391 m_residues.reserve(residues.
size());
392 m_residues.insert(m_residues.end(), &residues.
data[0], &residues.
data[residues.
size()]);
394 double med = getMedian(m_residues);
396 m_normres.resize(residues.
size());
397 for (
size_t i = 0; i < m_residues.size(); i++) {
398 m_normres[i] = std::fabs(residues[(
unsigned int)i] - med);
401 m_residues = m_normres;
402 double normmedian = getMedian(m_residues);
405 double sigma = 1.4826 * normmedian;
409 if (sigma < NoiseThreshold) {
410 sigma = NoiseThreshold;
413 psiTukey(sigma, m_normres, weights);
421 double NoiseThreshold)
423 if (residues.
size() == 0) {
427 m_residues.resize(0);
428 m_residues.reserve(residues.
size());
429 for (
unsigned int i = 0; i < residues.
size(); i++) {
430 m_residues.push_back((
float)residues[i]);
433 float med = getMedian(m_residues);
435 m_normres.resize(residues.
size());
436 for (
size_t i = 0; i < m_residues.size(); i++) {
437 m_normres[i] = (float)std::fabs(residues[(
unsigned int)i] - med);
440 m_residues = m_normres;
441 float normmedian = getMedian(m_residues);
444 float sigma = 1.4826f * normmedian;
448 if (sigma < NoiseThreshold) {
449 sigma = (float)NoiseThreshold;
452 psiTukey(sigma, m_normres, weights);
458 template <
class T>
void vpMbtTukeyEstimator<T>::psiTukey(
const T sig, std::vector<T> &x, std::vector<T> &weights)
460 T C =
static_cast<T
>(4.6851) * sig;
461 weights.resize(x.size());
464 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.
void resize(unsigned int i, bool flagNullify=true)
VISP_EXPORT bool checkSSSE3()
VISP_EXPORT bool checkNeon()