summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--facetracknoir/gain-control.hpp198
-rw-r--r--facetracknoir/tracker.cpp6
-rw-r--r--ftnoir_filter_ewma2/ftnoir_ewma_filtercontrols.ui662
-rw-r--r--ftnoir_filter_ewma2/ftnoir_filter_ewma2.cpp91
-rw-r--r--ftnoir_filter_ewma2/ftnoir_filter_ewma2.h8
-rw-r--r--qfunctionconfigurator/functionconfig.cpp4
6 files changed, 330 insertions, 639 deletions
diff --git a/facetracknoir/gain-control.hpp b/facetracknoir/gain-control.hpp
deleted file mode 100644
index 081d4b6f..00000000
--- a/facetracknoir/gain-control.hpp
+++ /dev/null
@@ -1,198 +0,0 @@
-#pragma once
-
-/* still WIP, not usable yet! -sh 20141012 */
-
-#include <algorithm>
-#undef NDEBUG
-#include <cassert>
-#include <iterator>
-#include <tuple>
-#include <deque>
-#include <vector>
-
-#include <cstdio>
-
-#include "timer.hpp"
-
-#include <opencv2/core/core.hpp>
-#include <opencv2/highgui/highgui.hpp>
-#include <opencv2/imgproc/imgproc.hpp>
-
-#include <QDebug>
-
-namespace detail {
- template<typename t1, typename t2, typename t, typename m = t>
- class zip_iterator : public std::iterator<std::forward_iterator_tag, t>
- {
- private:
- using self = zip_iterator<t1, t2, t, m>;
- t1 x1, z1;
- t2 x2, z2;
- void maybe_end() { if (x1 == z1 || x2 == z2) *this = end(); }
- public:
- zip_iterator(const t1& it1, const t1& end1, const t2& it2, const t2& end2)
- : x1(it1), z1(end1), x2(it2), z2(end2) { maybe_end(); }
- constexpr zip_iterator() {}
-
- static constexpr self end() { return self(); }
-
- self operator++() { x1++; x2++; self tmp = *this; maybe_end(); return tmp; }
- self operator++(int) { self tmp(*this); x1++; x2++; maybe_end(); return tmp; }
- bool operator==(const self& rhs) const { return x1 == rhs.x1 && x2 == rhs.x2; }
- bool operator!=(const self& rhs) const { return !this->operator ==(rhs); }
- t operator*() { return m(*x1, *x2); }
- };
-}
-
-class Gain {
-private:
- static constexpr bool use_box_filter = true;
- static constexpr int box_size = 16 / 640.;
- static constexpr double control_upper_bound = 1.0; // XXX FIXME implement for logitech crapola
- static constexpr int GAIN_HISTORY_COUNT = 50, GAIN_HISTORY_EVERY_MS = 998;
-
- using t_frame = cv::Mat_<unsigned char>;
-
- int control;
- double step, eps;
-
- t_frame last_frame;
- std::deque<double> means_history;
- Timer debug_timer, history_timer;
-
- typedef unsigned char px;
- template<typename t1, typename t2, typename t, typename m = t>
- using zip_iterator = detail::zip_iterator<t1, t2, t, m>;
-
- static double mean(const cv::Mat& frame)
- {
- // grayscale only
- assert(frame.channels() == 1);
- assert(frame.elemSize() == 1);
- assert(!frame.empty());
-
- return std::accumulate(frame.begin<px>(), frame.end<px>(), 0.) / (frame.rows * frame.cols);
- }
-
- static double get_variance(const cv::Mat& frame, double mean)
- {
- struct variance {
- private:
- double mu;
- public:
- variance(double mu) : mu(mu) {}
- double operator()(double seed, px p)
- {
- double tmp = p - mu;
- return seed + tmp * tmp;
- }
- } logic(mean);
-
- return std::accumulate(frame.begin<unsigned char>(), frame.end<unsigned char>(), 0., logic) / (frame.rows * frame.cols);
- }
-
- static double get_covariance(const cv::Mat& frame, const cv::Mat& old_frame)
- {
- double mean_0 = mean(frame), mean_1 = mean(old_frame);
-
- struct covariance {
- public:
- using pair = std::tuple<px, px>;
- private:
- double mu_0, mu_1;
-
- inline double Cov(double seed, const pair& t)
- {
- px p0 = std::get<0>(t);
- px p1 = std::get<1>(t);
- return seed + (p0 - mu_0) * (p1 - mu_1);
- }
- public:
- covariance(double mu_0, double mu_1) : mu_0(mu_0), mu_1(mu_1) {}
-
- double operator()(double seed, const pair& t)
- {
- return Cov(seed, t);
- }
- } logic(mean_0, mean_1);
-
- const double N = frame.rows * frame.cols;
-
- using zipper = zip_iterator<cv::MatConstIterator_<px>,
- cv::MatConstIterator_<px>,
- std::tuple<px, px>>;
-
- zipper zip(frame.begin<px>(),
- frame.end<px>(),
- old_frame.begin<px>(),
- old_frame.end<px>());
- std::vector<covariance::pair> values(zip, zipper::end());
-
- return std::accumulate(values.begin(), values.end(), 0., logic) / N;
- }
-
-#pragma GCC diagnostic ignored "-Wsign-compare"
-
-public:
- Gain(int control = CV_CAP_PROP_GAIN, double step = 0.3, double eps = 0.02) :
- control(control), step(step), eps(eps)
- {
- }
-
- void tick(cv::VideoCapture&, const cv::Mat& frame_)
- {
- cv::Mat frame;
-
- if (use_box_filter)
- {
- cv::Mat tmp(frame_);
- static constexpr int min_box = 3;
- static constexpr int box = 2 * box_size;
- cv::blur(frame_, tmp, cv::Size(min_box + box * frame_.cols, min_box + box * frame_.rows));
- frame = tmp;
- }
- else
- frame = frame_;
-
- if (last_frame.rows != frame.rows || last_frame.cols != frame.cols)
- last_frame = t_frame();
-
- if (last_frame.empty())
- {
- last_frame = frame.clone();
- //return;
- }
-
- if (history_timer.elapsed_ms() > GAIN_HISTORY_EVERY_MS)
- {
- //const double cov = get_covariance(frame, last_frame);
- history_timer.start();
- last_frame = frame.clone();
-
- if (means_history.size() == GAIN_HISTORY_COUNT)
- means_history.pop_back();
- }
-
- if (debug_timer.elapsed_ms() > 1000)
- {
- const double mu = mean(frame);
- // XXX move to HSL/HSV color space for it to work! -sh 20141012
- const double var = get_variance(frame, mu);
-
- debug_timer.start();
- qDebug() << "---- gain:" << "mean" << mu << "variance" << var;
-
- const int sz = means_history.size();
-
- if (sz)
- {
- fprintf(stderr, "covs{%d}: ", sz);
-
- for (int i = 0; i < sz; i++)
- fprintf(stderr, "%f ", means_history[i]);
-
- fprintf(stderr, "\n");
- }
- }
- }
-};
diff --git a/facetracknoir/tracker.cpp b/facetracknoir/tracker.cpp
index f17b257f..0f299153 100644
--- a/facetracknoir/tracker.cpp
+++ b/facetracknoir/tracker.cpp
@@ -150,8 +150,10 @@ void Tracker::run() {
logic();
- const long q = 1000L * std::max(0L, sleep_ms - t.elapsed_ms());
- usleep(q);
+ double q = sleep_ms * 1000L;
+ q -= t.elapsed();
+ q = std::max(0., q);
+ usleep((long)q);
}
#if defined(_WIN32)
diff --git a/ftnoir_filter_ewma2/ftnoir_ewma_filtercontrols.ui b/ftnoir_filter_ewma2/ftnoir_ewma_filtercontrols.ui
index 1a798a45..9387f0d5 100644
--- a/ftnoir_filter_ewma2/ftnoir_ewma_filtercontrols.ui
+++ b/ftnoir_filter_ewma2/ftnoir_ewma_filtercontrols.ui
@@ -9,16 +9,10 @@
<rect>
<x>0</x>
<y>0</y>
- <width>404</width>
+ <width>448</width>
<height>380</height>
</rect>
</property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>380</height>
- </size>
- </property>
<property name="windowTitle">
<string>EWMA2 filter settings</string>
</property>
@@ -35,43 +29,258 @@
<property name="styleSheet">
<string notr="true"/>
</property>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="geometry">
- <rect>
- <x>204</x>
- <y>351</y>
- <width>164</width>
- <height>25</height>
- </rect>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- <widget class="QLabel" name="label_4">
- <property name="geometry">
- <rect>
- <x>4</x>
- <y>143</y>
- <width>396</width>
- <height>204</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">background-color: rgb(214, 214, 214);
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QFrame" name="frame">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="lblInvert1_6">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string>Min</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSlider" name="minSmooth">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="pageStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>2</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::NoTicks</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QSpinBox" name="spinMinSmooth">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background:none;</string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::PlusMinus</enum>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>120</number>
+ </property>
+ <property name="singleStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>2</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="lblInvert1_7">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string>Max</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSlider" name="maxSmooth">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="pageStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::NoTicks</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QSpinBox" name="spinMaxSmooth">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background:none;</string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::PlusMinus</enum>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>120</number>
+ </property>
+ <property name="singleStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="lblInvert1_8">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string>Curve</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSlider" name="powCurve">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="pageStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::NoTicks</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QSpinBox" name="spinPowCurve">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background:none;</string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::PlusMinus</enum>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="singleStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(214, 214, 214);
border-color: rgb(0, 0, 0);</string>
- </property>
- <property name="frameShape">
- <enum>QFrame::Box</enum>
- </property>
- <property name="text">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::Box</enum>
+ </property>
+ <property name="text">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
@@ -87,287 +296,20 @@ p, li { white-space: pre-wrap; }
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;Defines the filters 'readiness' to respond to speed changes;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;Higher value = &lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600;&quot;&gt;faster&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt; response;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="margin">
- <number>5</number>
- </property>
- </widget>
- <widget class="QLabel" name="lblInvert1_6">
- <property name="geometry">
- <rect>
- <x>5</x>
- <y>5</y>
- <width>27</width>
- <height>16</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>16777215</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true"/>
- </property>
- <property name="text">
- <string>Min</string>
- </property>
- </widget>
- <widget class="QSlider" name="maxSmooth">
- <property name="geometry">
- <rect>
- <x>47</x>
- <y>32</y>
- <width>84</width>
- <height>23</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>45</width>
- <height>15</height>
- </size>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>100</number>
- </property>
- <property name="pageStep">
- <number>10</number>
- </property>
- <property name="value">
- <number>10</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="tickPosition">
- <enum>QSlider::NoTicks</enum>
- </property>
- </widget>
- <widget class="QSpinBox" name="spinMaxSmooth">
- <property name="geometry">
- <rect>
- <x>135</x>
- <y>32</y>
- <width>52</width>
- <height>23</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>40</width>
- <height>22</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">background:none;</string>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>120</number>
- </property>
- <property name="singleStep">
- <number>5</number>
- </property>
- <property name="value">
- <number>10</number>
- </property>
- </widget>
- <widget class="QSpinBox" name="spinPowCurve">
- <property name="geometry">
- <rect>
- <x>135</x>
- <y>59</y>
- <width>52</width>
- <height>23</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>40</width>
- <height>22</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">background:none;</string>
- </property>
- <property name="maximum">
- <number>100</number>
- </property>
- <property name="singleStep">
- <number>5</number>
- </property>
- <property name="value">
- <number>10</number>
- </property>
- </widget>
- <widget class="QSlider" name="powCurve">
- <property name="geometry">
- <rect>
- <x>47</x>
- <y>59</y>
- <width>84</width>
- <height>23</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>45</width>
- <height>15</height>
- </size>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>100</number>
- </property>
- <property name="pageStep">
- <number>10</number>
- </property>
- <property name="value">
- <number>10</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="tickPosition">
- <enum>QSlider::NoTicks</enum>
- </property>
- </widget>
- <widget class="QLabel" name="lblInvert1_8">
- <property name="geometry">
- <rect>
- <x>5</x>
- <y>59</y>
- <width>38</width>
- <height>16</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>16777215</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true"/>
- </property>
- <property name="text">
- <string>Curve</string>
- </property>
- </widget>
- <widget class="QLabel" name="lblInvert1_7">
- <property name="geometry">
- <rect>
- <x>5</x>
- <y>32</y>
- <width>32</width>
- <height>16</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>16777215</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true"/>
- </property>
- <property name="text">
- <string>Max</string>
- </property>
- </widget>
- <widget class="QSlider" name="minSmooth">
- <property name="geometry">
- <rect>
- <x>47</x>
- <y>5</y>
- <width>84</width>
- <height>23</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>45</width>
- <height>15</height>
- </size>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>100</number>
- </property>
- <property name="pageStep">
- <number>10</number>
- </property>
- <property name="value">
- <number>2</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="tickPosition">
- <enum>QSlider::NoTicks</enum>
- </property>
- </widget>
- <widget class="QSpinBox" name="spinMinSmooth">
- <property name="geometry">
- <rect>
- <x>135</x>
- <y>5</y>
- <width>52</width>
- <height>23</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>40</width>
- <height>22</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">background:none;</string>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>120</number>
- </property>
- <property name="singleStep">
- <number>5</number>
- </property>
- <property name="value">
- <number>2</number>
- </property>
- </widget>
+ </property>
+ <property name="margin">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
<resources>
<include location="ewma-filter.qrc"/>
@@ -380,28 +322,12 @@ p, li { white-space: pre-wrap; }
<slot>setValue(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>199</x>
- <y>22</y>
+ <x>303</x>
+ <y>33</y>
</hint>
<hint type="destinationlabel">
- <x>337</x>
- <y>23</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>spinMinSmooth</sender>
- <signal>valueChanged(int)</signal>
- <receiver>minSmooth</receiver>
- <slot>setValue(int)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>330</x>
- <y>12</y>
- </hint>
- <hint type="destinationlabel">
- <x>185</x>
- <y>17</y>
+ <x>391</x>
+ <y>36</y>
</hint>
</hints>
</connection>
@@ -412,28 +338,12 @@ p, li { white-space: pre-wrap; }
<slot>setValue(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>181</x>
- <y>48</y>
- </hint>
- <hint type="destinationlabel">
- <x>335</x>
- <y>54</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>spinMaxSmooth</sender>
- <signal>valueChanged(int)</signal>
- <receiver>maxSmooth</receiver>
- <slot>setValue(int)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>324</x>
- <y>42</y>
+ <x>281</x>
+ <y>61</y>
</hint>
<hint type="destinationlabel">
- <x>259</x>
- <y>43</y>
+ <x>390</x>
+ <y>74</y>
</hint>
</hints>
</connection>
@@ -444,28 +354,12 @@ p, li { white-space: pre-wrap; }
<slot>setValue(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>145</x>
- <y>74</y>
- </hint>
- <hint type="destinationlabel">
- <x>339</x>
- <y>78</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>spinPowCurve</sender>
- <signal>valueChanged(int)</signal>
- <receiver>powCurve</receiver>
- <slot>setValue(int)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>330</x>
- <y>69</y>
+ <x>236</x>
+ <y>101</y>
</hint>
<hint type="destinationlabel">
- <x>176</x>
- <y>76</y>
+ <x>391</x>
+ <y>98</y>
</hint>
</hints>
</connection>
diff --git a/ftnoir_filter_ewma2/ftnoir_filter_ewma2.cpp b/ftnoir_filter_ewma2/ftnoir_filter_ewma2.cpp
index c7169faa..320b95ad 100644
--- a/ftnoir_filter_ewma2/ftnoir_filter_ewma2.cpp
+++ b/ftnoir_filter_ewma2/ftnoir_filter_ewma2.cpp
@@ -1,19 +1,9 @@
-/*** Written by Donovan Baarda
-*
-* This program is free software; you can redistribute it and/or modify it *
-* under the terms of the GNU General Public License as published by the *
-* Free Software Foundation; either version 3 of the License, or (at your *
-* option) any later version. *
-* *
-* This program is distributed in the hope that it will be useful, but *
-* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
-* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
-* more details. *
-* *
-* You should have received a copy of the GNU General Public License along *
-* with this program; if not, see <http://www.gnu.org/licenses/>. *
-* *
-********************************************************************************/
+/* Copyright (c) 2014 Donovan Baarda <abo@minkirri.apana.org.au>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
#include "ftnoir_filter_ewma2.h"
#include <cmath>
#include <QDebug>
@@ -22,12 +12,26 @@
#include <algorithm>
#include <QMutexLocker>
+// Exponentially Weighted Moving Average (EWMA) Filter with dynamic smoothing.
+//
+// This filter tries to adjust the amount of filtering to minimize lag when
+// moving, and minimize noise when still. It uses the delta filtered over the
+// last 1/60sec (16ms) compared to the delta's average noise variance over
+// the last 60sec to try and detect movement vs noise. As the delta increases
+// from 0 to 3 stdevs of the noise, the filtering scales down from maxSmooth
+// to minSmooth at a rate controlled by the powCurve setting.
+
+
FTNoIR_Filter::FTNoIR_Filter() :
first_run(true),
- // Deltas are smoothed over the last 3 frames (0.1sec at 30fps).
- delta_smoothing(1.0/3.0),
- // Noise is smoothed over the last 3600 frames (~2mins at 30fps).
- noise_smoothing(1.0/3600.0)
+ // Currently facetracknoir/tracker.cpp updates every dt=3ms. All
+ // filter alpha values are calculated as alpha=dt/(dt+RC) and
+ // need to be updated when tracker.cpp changes.
+ // TODO(abo): Change this to use a dynamic dt using a timer.
+ // Deltas are smoothed over the last 1/60sec (16ms).
+ delta_alpha(0.003/(0.003 + 0.016)),
+ // Noise is smoothed over the last 60sec.
+ noise_alpha(0.003/(0.003 + 60.0))
{
}
@@ -40,54 +44,39 @@ void FTNoIR_Filter::FilterHeadPoseData(const double *target_camera_position,
double *new_camera_position)
{
double new_delta, new_noise, norm_noise;
- double alpha;
+ double smoothing, RC, alpha;
- //On the first run, initialize to output=target and return.
+ //On the first run, initialize filter states to target intput.
if (first_run==true) {
for (int i=0;i<6;i++) {
- new_camera_position[i] = target_camera_position[i];
- current_camera_position[i] = target_camera_position[i];
+ output[i] = target_camera_position[i];
delta[i] = 0.0;
noise[i] = 0.0;
}
first_run=false;
- return;
- }
-
- bool new_frame = false;
-
- for (int i = 0; i < 6; i++)
- {
- if (target_camera_position[i] != current_camera_position[i])
- {
- new_frame = true;
- break;
- }
- }
-
- if (!new_frame)
- {
- for (int i = 0; i < 6; i++)
- new_camera_position[i] = current_camera_position[i];
- return;
}
// Calculate the new camera position.
for (int i=0;i<6;i++) {
// Calculate the current and smoothed delta.
- new_delta = target_camera_position[i]-current_camera_position[i];
- delta[i] = delta_smoothing*new_delta + (1.0-delta_smoothing)*delta[i];
+ new_delta = target_camera_position[i]-output[i];
+ delta[i] = delta_alpha*new_delta + (1.0-delta_alpha)*delta[i];
// Calculate the current and smoothed noise variance.
new_noise = delta[i]*delta[i];
- noise[i] = noise_smoothing*new_noise + (1.0-noise_smoothing)*noise[i];
+ noise[i] = noise_alpha*new_noise + (1.0-noise_alpha)*noise[i];
// Normalise the noise between 0->1 for 0->9 variances (0->3 stddevs).
norm_noise = std::min<double>(new_noise/(9.0*noise[i]), 1.0);
- // Calculate the alpha from the normalized noise.
+ // Calculate the smoothing 0.0->1.0 from the normalized noise.
// TODO(abo): change kSmoothingScaleCurve to a float where 1.0 is sqrt(norm_noise).
- alpha = 1.0/(s.kMinSmoothing+(1.0-pow(norm_noise,s.kSmoothingScaleCurve/20.0))*(s.kMaxSmoothing-s.kMinSmoothing));
- // Update the current camera position to the new position.
- double pos = alpha*target_camera_position[i] + (1.0-alpha)*current_camera_position[i];
- new_camera_position[i] = current_camera_position[i] = pos;
+ smoothing = 1.0 - pow(norm_noise, s.kSmoothingScaleCurve/20.0);
+ // Currently min/max smoothing are ints 0->100. We want 0.0->3.0 seconds.
+ // TODO(abo): Change kMinSmoothing, kMaxSmoothing to floats 0.0->3.0 seconds RC.
+ RC = 3.0*(s.kMinSmoothing + smoothing*(s.kMaxSmoothing - s.kMinSmoothing))/100.0;
+ // TODO(abo): Change this to use a dynamic dt using a timer.
+ alpha = 0.003/(0.003 + RC);
+ // Calculate the new output position.
+ output[i] = alpha*target_camera_position[i] + (1.0-alpha)*output[i];
+ new_camera_position[i] = output[i];
}
}
diff --git a/ftnoir_filter_ewma2/ftnoir_filter_ewma2.h b/ftnoir_filter_ewma2/ftnoir_filter_ewma2.h
index 8863348c..aacf4916 100644
--- a/ftnoir_filter_ewma2/ftnoir_filter_ewma2.h
+++ b/ftnoir_filter_ewma2/ftnoir_filter_ewma2.h
@@ -24,17 +24,17 @@ class FTNoIR_Filter : public IFilter
{
public:
FTNoIR_Filter();
- void reset() {}
+ void reset() { first_run=true; }
void FilterHeadPoseData(const double *target_camera_position,
double *new_camera_position);
void receiveSettings();
private:
bool first_run;
- double delta_smoothing;
- double noise_smoothing;
+ double delta_alpha;
+ double noise_alpha;
double delta[6];
double noise[6];
- double current_camera_position[6];
+ double output[6];
settings s;
};
diff --git a/qfunctionconfigurator/functionconfig.cpp b/qfunctionconfigurator/functionconfig.cpp
index a4d03ed8..a0715754 100644
--- a/qfunctionconfigurator/functionconfig.cpp
+++ b/qfunctionconfigurator/functionconfig.cpp
@@ -179,6 +179,10 @@ void Map::loadSettings(QSettings& settings, const QString& title) {
}
settings.endGroup();
+
+ if (max == 0)
+ points.append(QPointF(maxInput(), maxOutput()));
+
cur.input = points;
reload();
saved = cur;