contrib/brl/bbas/bsta/algo/bsta_adaptive_updater.txx
Go to the documentation of this file.
00001 // This is brl/bbas/bsta/algo/bsta_adaptive_updater.txx
00002 #ifndef bsta_adaptive_updater_txx_
00003 #define bsta_adaptive_updater_txx_
00004 //:
00005 // \file
00006 #include "bsta_adaptive_updater.h"
00007 #include "bsta_gaussian_updater.h"
00008 #include "bsta_gaussian_stats.h"
00009 
00010 #include <vcl_iostream.h>
00011 #include <vcl_limits.h>
00012 
00013 // The update equations used here are based on the following
00014 // paper that extends the Stauffer-Grimson approach.
00015 //
00016 // Dar-Shyang Lee. Effective gaussian mixture learning for video
00017 // background subtraction. IEEE Transactions on Pattern Analysis
00018 // and Machine Intelligence, 27:827-832, May 2005.
00019 
00020 
00021 //: The update function
00022 template <class mix_dist_>
00023 void
00024 bsta_mg_statistical_updater<mix_dist_>::update( mix_dist_& mix, const vector_& sample, T alpha ) const
00025 {
00026   const unsigned num_components = mix.num_components();
00027 
00028   // prune components by mahalanobis distance
00029   static vcl_vector<T> probs;
00030   probs.resize(num_components,T(0));
00031   static vcl_vector<unsigned int> matched;
00032   matched.clear();
00033 
00034   for (unsigned int i=0; i<num_components; ++i) {
00035     obs_gaussian_& g = mix.distribution(i);
00036     T sqr_dist = g.sqr_mahalanobis_dist(sample);
00037     if (sqr_dist < gt2_) {
00038       matched.push_back(i);
00039       probs[i] = sqr_dist; // initially these are distances, not probabilities
00040     }
00041   }
00042 
00043   // if no matches add a new component
00044   if (matched.empty()) {
00045     this->insert(mix,sample,alpha);
00046     mix.normalize_weights();
00047   }
00048   else
00049   {
00050     // update the weights
00051     for (unsigned int i=0; i<num_components; ++i) {
00052       T weight = (T(1)-alpha) * mix.weight(i);
00053       mix.set_weight(i,weight);
00054     }
00055     // special case of 1 match - don't need to compute probabilites
00056     if (matched.size() == 1) {
00057       unsigned int m_idx = matched.front();
00058       mix.set_weight(m_idx,mix.weight(m_idx)+alpha);
00059       obs_gaussian_& g = mix.distribution(m_idx);
00060       g.num_observations += T(1);
00061       T rho =(T(1)-alpha)/g.num_observations + alpha;
00062       bsta_update_gaussian(g, rho, sample, min_var_);
00063     }
00064     else {
00065       // compute probabilites for each match
00066       typedef typename vcl_vector<unsigned int>::iterator m_itr;
00067       T sum_probs = T(0);
00068       for (m_itr itr = matched.begin(); itr != matched.end(); ++itr) {
00069         const unsigned int i = *itr;
00070         obs_gaussian_& g = mix.distribution(i);
00071         probs[i] = g.dist_prob_density(probs[i]) * mix.weight(i);
00072         sum_probs += probs[i];
00073       }
00074       // update each match
00075       for (m_itr itr = matched.begin(); itr != matched.end(); ++itr) {
00076         const unsigned int i = *itr;
00077         if (sum_probs != 0) {
00078           probs[i] /= sum_probs;
00079         }
00080         mix.set_weight(i,mix.weight(i)+alpha*probs[i]);
00081         obs_gaussian_& g = mix.distribution(i);
00082         g.num_observations += probs[i];
00083         T rho = probs[i] * ((1-alpha)/g.num_observations + alpha);
00084         bsta_update_gaussian(g, rho, sample, min_var_);
00085       }
00086     }
00087   }
00088 
00089   mix.sort(bsta_gaussian_fitness<gaussian_>::order);
00090 
00091   // try to clean up gaussian components with weights that have converged to zero
00092   if (mix.weight(mix.num_components()-1) < vcl_numeric_limits<T>::epsilon()) {
00093     mix.remove_last();
00094     T sum = 0;
00095     for (unsigned int i=0; i<mix.num_components(); ++i) {
00096       sum += mix.weight(i);
00097     }
00098     vcl_cout << "removed, total weight = " << sum << vcl_endl;
00099     mix.normalize_weights();
00100   }
00101 }
00102 
00103 
00104 //: The main function
00105 template <class mix_dist_>
00106 void
00107 bsta_mg_grimson_statistical_updater<mix_dist_>::update( mix_dist_& mix,
00108                                                         const vector_& sample,
00109                                                         T alpha ) const
00110 {
00111   int match = -1;
00112   unsigned int mix_nc = mix.num_components();
00113   for (unsigned int i=0; i<mix_nc; ++i) {
00114     obs_gaussian_& g = mix.distribution(i);
00115     T weight = (T(1)-alpha) * mix.weight(i);
00116     if (match<0 && g.sqr_mahalanobis_dist(sample) < gt2_) {
00117       weight += alpha;
00118       g.num_observations += T(1);
00119       T rho = (T(1)-alpha)/g.num_observations + alpha;
00120       bsta_update_gaussian(g, rho, sample, min_var_);
00121       match = i;
00122     }
00123     mix.set_weight(i, weight);
00124   }
00125   if (match<0) {
00126     this->insert(mix,sample,alpha);
00127     match = mix.num_components()-1;
00128   }
00129 
00130   if (match>0)
00131     mix.sort(bsta_gaussian_fitness<gaussian_>::order, match);
00132 }
00133 
00134 
00135 #define BSTA_ADAPTIVE_UPDATER_INSTANTIATE(T) \
00136 template class bsta_mg_statistical_updater<T >; \
00137 template class bsta_mg_grimson_statistical_updater<T >
00138 
00139 
00140 #endif // bsta_adaptive_updater_txx_