Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

FunctorKalman.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Array_Trait_FuncKalman_h
00002 #define Impala_Core_Array_Trait_FuncKalman_h
00003 
00004 #include <deque>
00005 
00006 namespace Impala
00007 {
00008 namespace Core
00009 {
00010 namespace Array
00011 {
00012 namespace Element
00013 {
00014 
00015 inline double EuclidDistSquare(const Vec3Real64& p1, const Vec3Real64& p2)
00016 {
00017     double t,d;
00018     t = p1.X() - p2.X();
00019     d = t*t;
00020     t = p1.Y() - p2.Y();
00021     d += t*t;
00022     t = p1.Z() - p2.Z();
00023     d += t*t;
00024     return d;
00025 }
00026 
00027 } // namespace Element
00028 
00029 namespace Trait
00030 {
00031 
00040 class FuncKalman
00041 {
00042 private:
00043     Array2dScalarUInt8* mOutCounter;
00044     std::deque<double> mPastResiduals;
00045     double mOutlierTreshold;
00046 public:
00047     double mSigmaI, mSigmaW, mSigmaG;
00048     double mAlpha, mBeta, mGamma, mN_omax, mK, mPixelCount;
00049     int mOutliers;
00050     double mResidualThisFrame,mResidualAvrg;
00051     bool mInitialised,mOcclusion;
00052 
00053     typedef Pattern::TagTransVar TransVarianceCategory;
00054     typedef Pattern::TagCallValue CallCategory;
00055         typedef Vec3Int32 DstArithT;
00056         typedef Vec3Int32 SrcArithT;
00057 
00061     FuncKalman(int w, int h)
00062     {
00063         // 'static' properties
00064         mAlpha = 2.5;
00065         mBeta = 1.1;
00066         mGamma = 0.4;
00067         mN_omax = 20;
00068         mK = 20;
00069 
00070         mOutCounter = 0;
00071         Reset(w,h);
00072     }
00073 
00083     void Reset(int w, int h)
00084     {
00085         if(mOutCounter)
00086             delete mOutCounter;
00087         mOutCounter = new Array2dScalarUInt8(w,h,0,0);
00088         int i;
00089         for(i=0 ; i<w*h ; i++)
00090             mOutCounter->mData[i] = 0;
00091 
00092         mOutlierTreshold = 196608;
00093         mSigmaI = mSigmaW = 0;
00094         mSigmaG = 1;
00095         mPastResiduals.clear();
00096         mResidualThisFrame = 0;
00097         mPixelCount = 0;
00098         mOutliers = 0;
00099         mInitialised = false;
00100         mOcclusion = false;
00101     }
00102 
00107     Vec3Real64
00108         doIt(const Vec3Real64& p1, const Vec3Real64& p2, int x, int y)
00109     {
00110         double r2;
00111         r2 = EuclidDistSquare(p1,p2);
00112 
00113         //(part of)eq.14
00114         mResidualThisFrame += r2;
00115         mPixelCount++;
00116         //eq.12
00117         if(r2 < mOutlierTreshold)
00118         {
00119             mOutCounter->mData[y*mOutCounter->CW() + x] = 0;
00120             //eq.10
00121             return (p1*mSigmaI + p2*mSigmaG) / (mSigmaI+mSigmaG);
00122         }
00123         else
00124         {
00125             mOutliers++;
00126             if(mOcclusion) // this extra check to leave the outlier counters intact during occlusion
00127                 return p1; 
00128             else
00129             {
00130                 if(mOutCounter->mData[y*mOutCounter->CW() + x] >= mN_omax)
00131                 {
00132                     mOutCounter->mData[y*mOutCounter->CW() + x] = 0;
00133                     return p2;
00134                 }
00135                 else
00136                 {
00137                     mOutCounter->mData[y*mOutCounter->CW() + x]++;
00138                     return p1;
00139                 }
00140             }
00141         }
00142     }
00143 
00147     void InitialiseSigma()
00148     {
00149         //eq.16
00150         mSigmaW = 0;
00151         mSigmaI = 0.5*mResidualAvrg;
00152         mSigmaG = 0.5*mResidualAvrg;
00153         mInitialised = true;
00154     }
00155 
00158     void UpdateKalman()
00159     {
00160         //eq.14
00161         mResidualThisFrame /= mPixelCount;
00162         mResidualThisFrame *= mBeta;
00163         if(mResidualThisFrame == 0)
00164             mResidualThisFrame = 1; 
00165 
00166         if(mPixelCount * mGamma > mOutliers) // if no occlusion
00167         {
00168             mOcclusion = false;
00169             ComputeResiduals();
00170             if(!mInitialised)
00171                 InitialiseSigma();
00172             //eq.11
00173             mSigmaG = (mSigmaG*mSigmaI)/(mSigmaG+mSigmaI);
00174             //eq.15
00175             mSigmaW = mResidualAvrg - mSigmaI - mSigmaG;
00176             // following found in Hieus code, makes some sense, but only because the
00177             // assumption about residual and sigmas are incorrect (I can't define them, sorry)
00178             if(mSigmaW<0)
00179                 mSigmaW = 0;
00180             //eq.9 (prediction of sigmaG for the next time step)
00181             mSigmaG += mSigmaW;
00182         }
00183         else
00184         {
00185             if(!mOcclusion)
00186             {
00187                 //undo prediction of sigmaG (eq.9) (only if the last time sigmaG was predicted)
00188                 mSigmaG -= mSigmaW;
00189             }
00190             mOcclusion = true;
00191         }
00192         mPixelCount = 0;
00193         mOutliers = 0;
00194     }
00195 
00196     void ComputeResiduals()
00197     {
00198         //eq.13
00199         mPastResiduals.push_back(mResidualThisFrame);
00200         mResidualThisFrame = 0;
00201         mResidualAvrg = 0;
00202         std::deque<double>::iterator i;
00203         for(i=mPastResiduals.begin() ; i!=mPastResiduals.end() ; i++)
00204         {
00205             mResidualAvrg += *i;
00206         }
00207         mResidualAvrg /= mPastResiduals.size();
00208         mOutlierTreshold = mResidualAvrg * mAlpha;
00209         while(mPastResiduals.size() > mK)
00210             mPastResiduals.pop_front();
00211     }
00212 
00213 };
00214 
00215 /**************************** FuncKalmanColor ****************************/
00220 class FuncKalmanColor
00221 {
00222 private:
00223     Array2dScalarUInt8* mOutCounter;
00224     std::deque<double> mPastResiduals[3];
00225     double mOutlierTreshold;
00226 public:
00227     double mSigmaI[3], mSigmaW[3], mSigmaG[3];
00228     double mChi2, mGamma, mN_omax, mK, mPixelCount;
00229     int mOutliers;
00230     double mResidualThisFrame[3], mResidualAvrg[3];
00231     bool mInitialised, mOcclusion;
00232 
00233     typedef Pattern::TagTransVar TransVarianceCategory;
00234     typedef Pattern::TagCallPointer CallCategory;
00235         typedef Vec3Int32 DstArithT;
00236         typedef Vec3Int32 SrcArithT;
00237 
00241     FuncKalmanColor()
00242     {
00243         CmdOptions& options = CmdOptions::GetInstance();
00244         // 'static' properties
00245         mChi2 = options.GetDouble("appearance_kalman.kalman.chi^2", 13); //is (Chi_d,delta)^2 where d=3 and delta=0.99
00246         mGamma = options.GetDouble("appearance_kalman.kalman.gamma", 0.3);
00247         mN_omax = options.GetDouble("appearance_kalman.kalman.N_omax", 40);
00248         mK = options.GetDouble("appearance_kalman.kalman.K", 20);
00249 
00250         mOutCounter = 0;
00251         Reset(0,0);
00252     }
00253 
00263     void Reset(int w, int h)
00264     {
00265         if(mOutCounter)
00266             delete mOutCounter;
00267         mOutCounter = new Array2dScalarUInt8(w,h,0,0);
00268         int i;
00269         for(i=0 ; i<w*h ; i++)
00270             mOutCounter->mData[i] = 0;
00271 
00272         mOutlierTreshold = 196608; //todo make a paramater out of this!
00273         for(i=0 ; i<3 ; i++)
00274         {
00275             mSigmaI[i] = 0;
00276             mSigmaW[i] = 0;
00277             mSigmaG[i] = 1;
00278             mPastResiduals[i].clear();
00279             mResidualThisFrame[i] = 0;
00280         }
00281         mPixelCount = 0;
00282         mOutliers = 0;
00283         mInitialised = false;
00284         mOcclusion = false;
00285     }
00286 
00290     double MahalanobisDist(double* p1, double* p2)
00291     {
00292         double r, err=0;
00293         for(int i=0 ; i<3 ; i++)
00294         {
00295             r = p1[i] - p2[i];
00296             err += r*r/(mSigmaG[i]+mSigmaI[i]);
00297             mResidualThisFrame[i] += r*r;
00298         }
00299         return err;
00300     }
00301 
00306     void
00307         DoIt(double* out, double* p1, double* p2, int x, int y)
00308     {
00309         double err;
00310         err = MahalanobisDist(p1,p2); // mahalanobis dist
00311 
00312         mPixelCount++;
00313         //eq.11
00314         if(err < mChi2 || !mInitialised)
00315         {
00316             mOutCounter->mData[y*mOutCounter->CW() + x] = 0;
00317             //eq.9
00318             for(int i=0 ; i<3 ; i++)
00319                 out[i] = (p1[i] * mSigmaI[i] + p2[i] * mSigmaG[i]) / (mSigmaI[i]+mSigmaG[i]);
00320             return;
00321         }
00322         else
00323         {
00324             mOutliers++;
00325             if(mOcclusion)
00326             {
00327                 for(int i=0 ; i<3 ; i++)
00328                     out[i] = p1[i];
00329                 return;
00330             }
00331             else
00332             {
00333                 if(mOutCounter->mData[y*mOutCounter->CW() + x] >= mN_omax)
00334                 {
00335                     mOutCounter->mData[y*mOutCounter->CW() + x] = 0;
00336                     for(int i=0 ; i<3 ; i++)
00337                         out[i] = p2[i];
00338                     return;
00339                 }
00340                 else
00341                 {
00342                     mOutCounter->mData[y*mOutCounter->CW() + x]++;
00343                     for(int i=0 ; i<3 ; i++)
00344                         out[i] = p1[i];
00345                     return;
00346                 }
00347             }
00348         }
00349     }
00350 
00354     void InitialiseSigma()
00355     {
00356         for(int i=0 ; i<3 ; i++)
00357         {
00358             //eq.15
00359             mSigmaW[i] = 0;
00360             mSigmaI[i] = 0.5*mResidualAvrg[i];
00361             mSigmaG[i] = 0.5*mResidualAvrg[i];
00362         }
00363         mInitialised = true;
00364     }
00365 
00368     void UpdateKalman()
00369     {
00370         int i;
00371         for(i=0 ; i<3 ; i++)
00372         {
00373             //eq.12
00374             mResidualThisFrame[i] /= mPixelCount;
00375             if(mResidualThisFrame[i] == 0)
00376                 mResidualThisFrame[i] = 1; 
00377         }
00378 
00379         if(mPixelCount * mGamma > mOutliers) // if no occlusion
00380         {
00381             mOcclusion = false;
00382             ComputeResiduals();
00383             if(!mInitialised)
00384                 InitialiseSigma();
00385             for(i=0 ; i<3 ; i++)
00386             {
00387                 //eq.10
00388                 mSigmaG[i] = (mSigmaG[i]*mSigmaI[i])/(mSigmaG[i]+mSigmaI[i]);
00389                 //eq.14
00390                 mSigmaW[i] = mResidualAvrg[i] - mSigmaI[i] - mSigmaG[i];
00391                 // following found in Hieus code, makes some sense, but only because the
00392                 // assumption about residual and sigmas are incorrect (I can't define them, sorry)
00393                 if(mSigmaW[i]<0)
00394                     mSigmaW[i] = 0;
00395                 //eq.8 (prediction of sigmaG for the next time step)
00396                 mSigmaG[i] += mSigmaW[i];
00397             }
00398         }
00399         else
00400         {
00401             if(!mOcclusion)
00402             {
00403                 //undo prediction of sigmaG (eq.8) (only if the last time sigmaG was predicted)
00404                 for(i=0 ; i<3 ; i++)
00405                     mSigmaG[i] -= mSigmaW[i];
00406             }
00407             mOcclusion = true;
00408 
00409             /* *
00410                 \note augmentation to hieus algorithm: increment sigma G so that the algorithm
00411                 leaves occlusion mode with increasing probability 
00412                 */
00413             
00414             for(i=0 ; i<3 ; i++)
00415                 mSigmaG[i] *= 1.15;
00416             
00417         }
00418         mPixelCount = 0;
00419         mOutliers = 0;
00420     }
00421 
00422     void ComputeResiduals()
00423     {
00424         //eq.13
00425         for(int i=0 ; i<3 ; i++)
00426         {
00427             mPastResiduals[i].push_back(mResidualThisFrame[i]);
00428             mResidualThisFrame[i] = 0;
00429             mResidualAvrg[i] = 0;
00430             std::deque<double>::iterator it;
00431             for(it=mPastResiduals[i].begin() ; it!=mPastResiduals[i].end() ; it++)
00432             {
00433                 mResidualAvrg[i] += *it;
00434             }
00435             mResidualAvrg[i] /= mPastResiduals[i].size();
00436             mOutlierTreshold = mResidualAvrg[i];
00437             while(mPastResiduals[i].size() > mK)
00438                 mPastResiduals[i].pop_front();
00439         }
00440     }
00441 };
00442 
00443 
00444 /**************************** FuncBpoRobustMahalanobis ****************************/
00451 class FuncBpoRobustMahalanobis
00452 {
00453 public:
00454     typedef Pattern::TagTransInVar TransVarianceCategory;
00455     typedef Pattern::TagCallPointer CallCategory;
00456 
00457         typedef Vec3Int32 DstArithT;
00458         typedef Vec3Int32 Src1ArithT;
00459         typedef Vec3Int32 Src2ArithT;
00460 
00461     double mSigma[3];
00462     double mError;
00463     double mChi;
00464     
00465     FuncBpoRobustMahalanobis() 
00466     {
00467         mSigma[0] = mSigma[1] = mSigma[2] = 1;
00468         mError = 0;
00469         mChi = 3.5;
00470     }
00471 
00472     void
00473         DoIt(double* res, double* p1, double* p2)
00474         {
00475         double r, err=0;
00476         for(int i=0 ; i<3 ; i++)
00477         {
00478             r = p1[i] - p2[i];
00479             err += r*r/(mSigma[i]);
00480         }
00481 
00482         // implements Hubers functon (eq.3)
00483         if(err < mChi)
00484         {
00485             double r = 0.5 * err * err;
00486             res[0] = res[1] = res[2] = r;
00487             mError += r;
00488         }
00489         else
00490         {
00491             double r = mChi*(err - mChi/2);
00492             res[0] = res[1] = res[2] = r;
00493             mError += r;
00494         }
00495         }
00496 };
00497 
00498 } // namespace Element
00499 } // namespace Array
00500 } // namespace Core
00501 } // namespace Impala
00502 
00503 #endif //Impala_Core_Array_Trait_FuncKalman_h

Generated on Fri Mar 19 09:31:22 2010 for ImpalaSrc by  doxygen 1.5.1