1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4
5 #include "../../precomp.hpp"
6 #include "tracking_online_mil.hpp"
7
8 namespace cv {
9 namespace detail {
10 inline namespace tracking {
11
12 #define sign(s) ((s > 0) ? 1 : ((s < 0) ? -1 : 0))
13
14 template <class T>
15 class SortableElementRev
16 {
17 public:
18 T _val;
19 int _ind;
SortableElementRev()20 SortableElementRev()
21 : _val(), _ind(0)
22 {
23 }
SortableElementRev(T val,int ind)24 SortableElementRev(T val, int ind)
25 {
26 _val = val;
27 _ind = ind;
28 }
operator <(SortableElementRev<T> & b)29 bool operator<(SortableElementRev<T>& b)
30 {
31 return (_val < b._val);
32 };
33 };
34
CompareSortableElementRev(const SortableElementRev<float> & i,const SortableElementRev<float> & j)35 static bool CompareSortableElementRev(const SortableElementRev<float>& i, const SortableElementRev<float>& j)
36 {
37 return i._val < j._val;
38 }
39
40 template <class T>
sort_order_des(std::vector<T> & v,std::vector<int> & order)41 void sort_order_des(std::vector<T>& v, std::vector<int>& order)
42 {
43 uint n = (uint)v.size();
44 std::vector<SortableElementRev<T>> v2;
45 v2.resize(n);
46 order.clear();
47 order.resize(n);
48 for (uint i = 0; i < n; i++)
49 {
50 v2[i]._ind = i;
51 v2[i]._val = v[i];
52 }
53 //std::sort( v2.begin(), v2.end() );
54 std::sort(v2.begin(), v2.end(), CompareSortableElementRev);
55 for (uint i = 0; i < n; i++)
56 {
57 order[i] = v2[i]._ind;
58 v[i] = v2[i]._val;
59 }
60 };
61
62 //implementations for strong classifier
63
Params()64 ClfMilBoost::Params::Params()
65 {
66 _numSel = 50;
67 _numFeat = 250;
68 _lRate = 0.85f;
69 }
70
ClfMilBoost()71 ClfMilBoost::ClfMilBoost()
72 : _numsamples(0)
73 , _counter(0)
74 {
75 _myParams = ClfMilBoost::Params();
76 _numsamples = 0;
77 }
78
~ClfMilBoost()79 ClfMilBoost::~ClfMilBoost()
80 {
81 _selectors.clear();
82 for (size_t i = 0; i < _weakclf.size(); i++)
83 delete _weakclf.at(i);
84 }
85
init(const ClfMilBoost::Params & parameters)86 void ClfMilBoost::init(const ClfMilBoost::Params& parameters)
87 {
88 _myParams = parameters;
89 _numsamples = 0;
90
91 //_ftrs = Ftr::generate( _myParams->_ftrParams, _myParams->_numFeat );
92 // if( params->_storeFtrHistory )
93 // Ftr::toViz( _ftrs, "haarftrs" );
94 _weakclf.resize(_myParams._numFeat);
95 for (int k = 0; k < _myParams._numFeat; k++)
96 {
97 _weakclf[k] = new ClfOnlineStump(k);
98 _weakclf[k]->_lRate = _myParams._lRate;
99 }
100 _counter = 0;
101 }
102
update(const Mat & posx,const Mat & negx)103 void ClfMilBoost::update(const Mat& posx, const Mat& negx)
104 {
105 int numneg = negx.rows;
106 int numpos = posx.rows;
107
108 // compute ftrs
109 //if( !posx.ftrsComputed() )
110 // Ftr::compute( posx, _ftrs );
111 //if( !negx.ftrsComputed() )
112 // Ftr::compute( negx, _ftrs );
113
114 // initialize H
115 static std::vector<float> Hpos, Hneg;
116 Hpos.clear();
117 Hneg.clear();
118 Hpos.resize(posx.rows, 0.0f), Hneg.resize(negx.rows, 0.0f);
119
120 _selectors.clear();
121 std::vector<float> posw(posx.rows), negw(negx.rows);
122 std::vector<std::vector<float>> pospred(_weakclf.size()), negpred(_weakclf.size());
123
124 // train all weak classifiers without weights
125 #ifdef _OPENMP
126 #pragma omp parallel for
127 #endif
128 for (int m = 0; m < _myParams._numFeat; m++)
129 {
130 _weakclf[m]->update(posx, negx);
131 pospred[m] = _weakclf[m]->classifySetF(posx);
132 negpred[m] = _weakclf[m]->classifySetF(negx);
133 }
134
135 // pick the best features
136 for (int s = 0; s < _myParams._numSel; s++)
137 {
138
139 // compute errors/likl for all weak clfs
140 std::vector<float> poslikl(_weakclf.size(), 1.0f), neglikl(_weakclf.size()), likl(_weakclf.size());
141 #ifdef _OPENMP
142 #pragma omp parallel for
143 #endif
144 for (int w = 0; w < (int)_weakclf.size(); w++)
145 {
146 float lll = 1.0f;
147 for (int j = 0; j < numpos; j++)
148 lll *= (1 - sigmoid(Hpos[j] + pospred[w][j]));
149 poslikl[w] = (float)-log(1 - lll + 1e-5);
150
151 lll = 0.0f;
152 for (int j = 0; j < numneg; j++)
153 lll += (float)-log(1e-5f + 1 - sigmoid(Hneg[j] + negpred[w][j]));
154 neglikl[w] = lll;
155
156 likl[w] = poslikl[w] / numpos + neglikl[w] / numneg;
157 }
158
159 // pick best weak clf
160 std::vector<int> order;
161 sort_order_des(likl, order);
162
163 // find best weakclf that isn't already included
164 for (uint k = 0; k < order.size(); k++)
165 if (std::count(_selectors.begin(), _selectors.end(), order[k]) == 0)
166 {
167 _selectors.push_back(order[k]);
168 break;
169 }
170
171 // update H = H + h_m
172 #ifdef _OPENMP
173 #pragma omp parallel for
174 #endif
175 for (int k = 0; k < posx.rows; k++)
176 Hpos[k] += pospred[_selectors[s]][k];
177 #ifdef _OPENMP
178 #pragma omp parallel for
179 #endif
180 for (int k = 0; k < negx.rows; k++)
181 Hneg[k] += negpred[_selectors[s]][k];
182 }
183
184 //if( _myParams->_storeFtrHistory )
185 //for ( uint j = 0; j < _selectors.size(); j++ )
186 // _ftrHist( _selectors[j], _counter ) = 1.0f / ( j + 1 );
187
188 _counter++;
189 /* */
190 return;
191 }
192
classify(const Mat & x,bool logR)193 std::vector<float> ClfMilBoost::classify(const Mat& x, bool logR)
194 {
195 int numsamples = x.rows;
196 std::vector<float> res(numsamples);
197 std::vector<float> tr;
198
199 for (uint w = 0; w < _selectors.size(); w++)
200 {
201 tr = _weakclf[_selectors[w]]->classifySetF(x);
202 #ifdef _OPENMP
203 #pragma omp parallel for
204 #endif
205 for (int j = 0; j < numsamples; j++)
206 {
207 res[j] += tr[j];
208 }
209 }
210
211 // return probabilities or log odds ratio
212 if (!logR)
213 {
214 #ifdef _OPENMP
215 #pragma omp parallel for
216 #endif
217 for (int j = 0; j < (int)res.size(); j++)
218 {
219 res[j] = sigmoid(res[j]);
220 }
221 }
222
223 return res;
224 }
225
226 //implementations for weak classifier
227
ClfOnlineStump()228 ClfOnlineStump::ClfOnlineStump()
229 : _mu0(0), _mu1(0), _sig0(0), _sig1(0)
230 , _q(0)
231 , _s(0)
232 , _log_n1(0), _log_n0(0)
233 , _e1(0), _e0(0)
234 , _lRate(0)
235 {
236 _trained = false;
237 _ind = -1;
238 init();
239 }
240
ClfOnlineStump(int ind)241 ClfOnlineStump::ClfOnlineStump(int ind)
242 : _mu0(0), _mu1(0), _sig0(0), _sig1(0)
243 , _q(0)
244 , _s(0)
245 , _log_n1(0), _log_n0(0)
246 , _e1(0), _e0(0)
247 , _lRate(0)
248 {
249 _trained = false;
250 _ind = ind;
251 init();
252 }
init()253 void ClfOnlineStump::init()
254 {
255 _mu0 = 0;
256 _mu1 = 0;
257 _sig0 = 1;
258 _sig1 = 1;
259 _lRate = 0.85f;
260 _trained = false;
261 }
262
update(const Mat & posx,const Mat & negx,const Mat_<float> &,const Mat_<float> &)263 void ClfOnlineStump::update(const Mat& posx, const Mat& negx, const Mat_<float>& /*posw*/, const Mat_<float>& /*negw*/)
264 {
265 //std::cout << " ClfOnlineStump::update" << _ind << std::endl;
266 float posmu = 0.0, negmu = 0.0;
267 if (posx.cols > 0)
268 posmu = float(mean(posx.col(_ind))[0]);
269 if (negx.cols > 0)
270 negmu = float(mean(negx.col(_ind))[0]);
271
272 if (_trained)
273 {
274 if (posx.cols > 0)
275 {
276 _mu1 = (_lRate * _mu1 + (1 - _lRate) * posmu);
277 cv::Mat diff = posx.col(_ind) - _mu1;
278 _sig1 = _lRate * _sig1 + (1 - _lRate) * float(mean(diff.mul(diff))[0]);
279 }
280 if (negx.cols > 0)
281 {
282 _mu0 = (_lRate * _mu0 + (1 - _lRate) * negmu);
283 cv::Mat diff = negx.col(_ind) - _mu0;
284 _sig0 = _lRate * _sig0 + (1 - _lRate) * float(mean(diff.mul(diff))[0]);
285 }
286
287 _q = (_mu1 - _mu0) / 2;
288 _s = sign(_mu1 - _mu0);
289 _log_n0 = std::log(float(1.0f / pow(_sig0, 0.5f)));
290 _log_n1 = std::log(float(1.0f / pow(_sig1, 0.5f)));
291 //_e1 = -1.0f/(2.0f*_sig1+1e-99f);
292 //_e0 = -1.0f/(2.0f*_sig0+1e-99f);
293 _e1 = -1.0f / (2.0f * _sig1 + std::numeric_limits<float>::min());
294 _e0 = -1.0f / (2.0f * _sig0 + std::numeric_limits<float>::min());
295 }
296 else
297 {
298 _trained = true;
299 if (posx.cols > 0)
300 {
301 _mu1 = posmu;
302 cv::Scalar scal_mean, scal_std_dev;
303 cv::meanStdDev(posx.col(_ind), scal_mean, scal_std_dev);
304 _sig1 = float(scal_std_dev[0]) * float(scal_std_dev[0]) + 1e-9f;
305 }
306
307 if (negx.cols > 0)
308 {
309 _mu0 = negmu;
310 cv::Scalar scal_mean, scal_std_dev;
311 cv::meanStdDev(negx.col(_ind), scal_mean, scal_std_dev);
312 _sig0 = float(scal_std_dev[0]) * float(scal_std_dev[0]) + 1e-9f;
313 }
314
315 _q = (_mu1 - _mu0) / 2;
316 _s = sign(_mu1 - _mu0);
317 _log_n0 = std::log(float(1.0f / pow(_sig0, 0.5f)));
318 _log_n1 = std::log(float(1.0f / pow(_sig1, 0.5f)));
319 //_e1 = -1.0f/(2.0f*_sig1+1e-99f);
320 //_e0 = -1.0f/(2.0f*_sig0+1e-99f);
321 _e1 = -1.0f / (2.0f * _sig1 + std::numeric_limits<float>::min());
322 _e0 = -1.0f / (2.0f * _sig0 + std::numeric_limits<float>::min());
323 }
324 }
325
classify(const Mat & x,int i)326 bool ClfOnlineStump::classify(const Mat& x, int i)
327 {
328 float xx = x.at<float>(i, _ind);
329 double log_p0 = (xx - _mu0) * (xx - _mu0) * _e0 + _log_n0;
330 double log_p1 = (xx - _mu1) * (xx - _mu1) * _e1 + _log_n1;
331 return log_p1 > log_p0;
332 }
333
classifyF(const Mat & x,int i)334 float ClfOnlineStump::classifyF(const Mat& x, int i)
335 {
336 float xx = x.at<float>(i, _ind);
337 double log_p0 = (xx - _mu0) * (xx - _mu0) * _e0 + _log_n0;
338 double log_p1 = (xx - _mu1) * (xx - _mu1) * _e1 + _log_n1;
339 return float(log_p1 - log_p0);
340 }
341
classifySetF(const Mat & x)342 inline std::vector<float> ClfOnlineStump::classifySetF(const Mat& x)
343 {
344 std::vector<float> res(x.rows);
345
346 #ifdef _OPENMP
347 #pragma omp parallel for
348 #endif
349 for (int k = 0; k < (int)res.size(); k++)
350 {
351 res[k] = classifyF(x, k);
352 }
353 return res;
354 }
355
356 }}} // namespace cv::detail::tracking
357