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

TrackerBackFore.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Tracking_TrackerBackFore_h
00002 #define Impala_Core_Tracking_TrackerBackFore_h
00003 
00004 #include <iosfwd>
00005 
00006 #include "Core/Array/Arrays.h"
00007 #include "Core/Array/SetVal.h"
00008 #include "Core/Array/AddVal.h"
00009 #include "Core/Array/MulVal.h"
00010 #include "Core/Array/MakeFromData.h"
00011 #include "Core/Array/Pattern/FuncGenConv2d.h"
00012 #include "Core/Array/Pattern/PatSet.h"
00013 #include "Core/Array/Pattern/PatInOutOp.h"
00014 #include "Core/Array/Trait/ExportMinMaxPos.h"
00015 
00016 #include "Util/TimeStats.h"
00017 #include "Core/Geometry/PointZ.h"
00018 #include "Core/Geometry/Rectangle.h"
00019 
00020 #include "Core/Tracking/Tracker.h"
00021 #include "Core/Tracking/ConvolutionTraits.h"
00022 #include "Core/Tracking/FrameRegionTable.h"
00023 #include "Core/Tracking/GaborFilter.h"
00024 #include "Core/Tracking/Classifier.h"
00025 
00026 namespace Impala
00027 {
00028 namespace Core
00029 {
00030 namespace Tracking
00031 {
00032 
00033 const int cColorNum = 3;
00034 
00036 class TrackerBackFore : public Tracker
00037 {
00038 public:
00039     TrackerBackFore(CmdOptions& options) :
00040         mSampleSpacing(options.GetInt("fore_back.sampleSpacing", 5)),
00041         mFilterSize(options.GetInt("fore_back.filterSize", 19)),
00042         mGabor(options.GetInt("fore_back.gabor.scale", 4),
00043                options.GetInt("fore_back.gabor.frequency", 2),
00044                options.GetInt("fore_back.gabor.directionCount", 2),
00045                mFilterSize)
00046     {
00047         mDimensionality = mGabor.GetFilterCount() * cColorNum; //the times 2 is because the gabor filters have a sine and cosine fliter
00048         mInput = 0;
00049         mSearchKernel = 0;
00050         mSearchResult = new Array::Array2dScalarReal64(21, 21, 0, 0);
00051         mReconstruction = 0;
00052         //mSimilarityPerFrame = 0;
00053         mClassifier = new Classifier(0, mDimensionality);
00054 
00055         mStats.AddGroup("features");
00056         mStats.AddGroup("statistics");
00057         mStats.AddGroup("backproject");
00058         mStats.AddGroup("search");
00059 
00060         mTrack = 0;
00061         mDebugFile.open(options.GetString("fore_back.tracker-debug-file").c_str());
00062 
00063     }
00064 
00065     virtual ~TrackerBackFore() // note: destructor not implemented correctly
00066     {
00067         if (mInput)
00068             delete mInput;
00069         if (mReconstruction)
00070             delete mReconstruction;
00071         if (mSearchKernel)
00072             delete mSearchKernel;
00073         delete mSearchResult;
00074         mDebugFile.close();
00075     }
00076 
00077 
00078     void Initialize(Array::Array2dVec3UInt8* startImage, Tracking::FrameRegion* startPos, FrameRegionTable* resultTrack)
00079     {
00080         mTrack = resultTrack;
00081         // TODO: configure the color model, the types of filters and the number of orientations
00082         if (mInput)
00083             delete mInput;
00084         mWidth = startImage->W();
00085         mHeight = startImage->H();
00086 
00087         mTrack->Add(*startPos);
00088 
00089         mInput = new Array::Array2dVec3Real64(mWidth, mHeight, 21, 21);
00090         Array::Pattern::PatSet(mInput, startImage, 2, 2);
00091 
00092         if (mReconstruction)
00093             delete mReconstruction;
00094         mReconstruction = new Array::Array2dVec3UInt8(mWidth, mHeight, 0, 0);
00095         Geometry::Rectangle r = startPos->GetRectangle();
00096         NewPosition(r.mLeft, r.mTop, r.mRight, r.mBottom);
00097         mInitialLikelyhood = 0;
00098     }
00099 
00100     void Process(Array::Array2dVec3UInt8* image)
00101     {
00102         Array::Pattern::PatSet(mInput, image, 2, 2);
00103         Array::Pattern::PatSet(mReconstruction, mInput);
00104         if (ObjectVisible())
00105         {
00106             SearchObject();
00107             UpdateObject();
00108         }
00109         mTrack->Add(Core::Geometry::Rectangle(mPosition.mLeft,mPosition.mTop,mPosition.mRight,mPosition.mBottom));
00110         //Array::Array2dScalarReal64* copy = 0;
00111         //Array::MakeFromData2(copy, mSearchResult);
00112         //mSimilarityPerFrame->push_back(copy);
00113     }
00114 
00115     Array::Array2dVec3UInt8* GetReconstruction()
00116     {
00117         return mReconstruction;
00118     }
00119 
00120     bool ObjectVisible()
00121     {
00122         if (mPosition.mLeft >= mInput->CW())
00123             return false;
00124         if (mPosition.mTop >= mInput->CH())
00125             return false;
00126         if (mPosition.mRight <= 0)
00127             return false;
00128         if (mPosition.mBottom <= 0)
00129             return false;
00130         return true;
00131     }
00132 
00133     void GetFilterFromPosition(int x, int y, int& filterX, int& filterY)
00134     {
00135         if(x >= mSearchKernel->CW() || y >= mSearchKernel->CH())
00136             return;
00137 
00138         int w, h;
00139         w = mPosition.Width()/mSampleSpacing;
00140         h = mPosition.Height()/mSampleSpacing;
00141         x -= mFilterSize/2;
00142         y -= mFilterSize/2;
00143 
00144         filterX = x/mSampleSpacing;
00145         if (filterX < 0)
00146             filterX = 0;
00147         if (filterX >= w)
00148             filterX = w-1;
00149 
00150         filterY = y/mSampleSpacing;
00151         if (filterY < 0)
00152             filterY = 0;
00153         if (filterY >= h)
00154             filterY = h-1;
00155     }
00156 
00157     //DataArray* GetSimilarityData(); //transfers possession to caller
00158 
00159     double mLikelyhood;
00160     double mInitialLikelyhood;
00161 
00162 private:
00163     void SearchObject()
00164     {
00165         // find best match using the classifiers (eq.10)
00166         Array::Array2dScalarReal64 response(mDimensionality, 1, 0, 0);
00167         Array::SetVal<Array::Array2dVec3Real64>(mSearchKernel, mSearchKernel, 0);
00168         int w,h;
00169         w = mPosition.Width()/mSampleSpacing;
00170         h = mPosition.Height()/mSampleSpacing;
00171         int i,j;
00172 
00173         mStats.SelectGroup(2);
00174         mStats.StartTime();
00175         for(j=0 ; j<h ; j++)
00176         {
00177             for(i=0 ; i<w ; i++)
00178             {
00179                 mClassifier->GetClassifiers(i+j*w, response);
00180                 mGabor.Reconstruct(*mSearchKernel, response, i*mSampleSpacing, j*mSampleSpacing);
00181             }
00182         }
00183         mStats.StopTime();
00184 
00185         mStats.SelectGroup(3);
00186         mStats.StartTime();
00187         int bw = mSearchKernel->CW()/2 +1;
00188         int bh = mSearchKernel->CH()/2 +1;
00189 
00190         Array::Array2dVec3Real64* searchArea = new Array::Array2dVec3Real64(21, 21, bw, bh);
00191         FillSearchArea(searchArea, bw, bh);
00192         SetVal(mSearchResult, mSearchResult, 0); //weird that this is necessary, you'd expect that the convolution would initialise the result
00193 
00194         TraitBpoInproduct prod;
00195         TraitBpoAddAssignPtr bpoAdd;
00196         searchArea->FindNaN("searchArea");
00197         mSearchKernel->FindNaN("mSearchKernel");
00198         mSearchResult->FindNaN("mSearchResult");
00199         Array::Pattern::FuncGenConv2dDispatch(mSearchResult, searchArea, mSearchKernel, prod, bpoAdd); // why didn't i use the pattern? maybe because the pattern reallocates the destination...
00200         mSearchResult->FindNaN("mSearchResult2");
00201 
00202         Array::Trait::ExportMinMaxPos<double, Array::Array2dScalarReal64> minmax;
00203         Array::Pattern::PatInOutOp(mSearchResult, minmax);
00204 
00205         mPosition.mLeft += minmax.mMaxPos.mX - 10;
00206         mPosition.mTop += minmax.mMaxPos.mY - 10;
00207         mPosition.mRight += minmax.mMaxPos.mX - 10; 
00208         mPosition.mBottom += minmax.mMaxPos.mY - 10;
00209 
00210         FormBackground();
00211         mStats.StopTime();
00212 
00213         // warning apparently mSearchResult can contain 'not-a-number's which yields a faulty position
00214         if(minmax.mMaxVal < -10000)
00215             mLikelyhood = mInitialLikelyhood * 0.1;
00216         else
00217         {
00218             // to really get a likelyhood we should devide by the maximum possible score, but what's that?
00219             mLikelyhood = mSearchResult->Value(minmax.mMaxPos.mX, minmax.mMaxPos.mY);
00220         }
00221         if(mInitialLikelyhood == 0)
00222             mInitialLikelyhood = mLikelyhood;
00223 
00224         delete searchArea;
00225     }
00226 
00227     void UpdateObject()
00228     {
00229         // Get gabor response in the foreground (eq.4)
00230         // blend with the current foreground (eq.17)
00231         int w,h;
00232         w = mPosition.Width()/mSampleSpacing;
00233         h = mPosition.Height()/mSampleSpacing;
00234 
00235         mStats.SelectGroup(0);
00236         mStats.StartTime();
00237         Array::Array2dScalarReal64 response(mDimensionality, 1, 0, 0);
00238         int i,j;
00239         for(j=0 ; j<h ; j++)
00240         {
00241             for(i=0 ; i<w; i++)
00242             {
00243                 int x = mPosition.mLeft+mSampleOffset.mX+(i*mSampleSpacing);
00244                 int y = mPosition.mTop+mSampleOffset.mY+(j*mSampleSpacing);
00245                 mGabor.Apply(response.CPB(0, 0), *mInput, x, y);
00246                 mClassifier->UpdateVec(response,i+j*w);
00247             }
00248         }
00249         mStats.StopTime();
00250 
00251         mStats.SelectGroup(1);
00252         mStats.StartTime();
00253         Array::Array2dScalarReal64 background(mDimensionality, mBackMaxPoints, 0, 0);
00254         ComputeBackgroundResponse(background);
00255         mClassifier->Update(background);
00256         mClassifier->WriteSimpleDebug(mDebugFile);
00257     }
00258 
00259     void NewPosition(int left, int top, int right, int bottom)
00260     {
00261         mStats.Reset();
00262 
00263         // clip against the image
00264         if (left < 0)
00265             left = 0;
00266         if (top < 0)
00267             top = 0;
00268         if (right >= mInput->CW())
00269             right = mInput->CW() - 1;
00270         if (bottom >= mInput->CH())
00271             bottom = mInput->CH() - 1;
00272 
00273         mPosition.mLeft = left;
00274         mPosition.mTop = top;
00275         mPosition.mRight = right;
00276         mPosition.mBottom = bottom;
00277         mSampleOffset.mX = ((mPosition.Width() % mSampleSpacing) + mSampleSpacing) / 2;
00278         mSampleOffset.mY = ((mPosition.Height() % mSampleSpacing) + mSampleSpacing) / 2;
00279 
00280         FormBackground();
00281         if(mSearchKernel)
00282             delete mSearchKernel;
00283 
00284         int w = mPosition.Width() / mSampleSpacing;
00285         int h = mPosition.Height() / mSampleSpacing;
00286         mSearchKernel = new Array::Array2dVec3Real64(mFilterSize + (w-1)*mSampleSpacing, mFilterSize + (h-1)*mSampleSpacing, 0, 0);
00287 
00288         // this intialises the classifier
00289         SetForeground();
00290         Array::Array2dScalarReal64 background(mDimensionality, mBackMaxPoints, 0, 0);
00291         ComputeBackgroundResponse(background);
00292         mClassifier->SetBackground(background);
00293     }
00294 
00295 
00296     void SetForeground()
00297     {
00298         // this funtion implements eq.4 of the paper
00299         Array::Array2dScalarReal64 response(mDimensionality, 1, 0, 0);
00300         int w,h;
00301         w = mPosition.Width()/mSampleSpacing;
00302         h = mPosition.Height()/mSampleSpacing;
00303 
00304         delete mClassifier;
00305         mClassifier = new Classifier(w*h, mDimensionality);
00306 
00307         int left = mSampleOffset.mX + mPosition.mLeft;
00308         int top = mSampleOffset.mY + mPosition.mTop;
00309         for(int j=0 ; j<h ; j++)
00310             for(int i=0 ; i<w; i++)
00311             {
00312                 mGabor.Apply(response.CPB(0,0), *mInput, left+(i*mSampleSpacing), top+(j*mSampleSpacing));
00313                 mClassifier->SetVec(response, i+j*w);
00314             }
00315     }
00316 
00317     void FormBackground()
00318     {
00319         mBack[0].mLeft = mPosition.mLeft - 3*mSampleSpacing;
00320         mBack[0].mTop = mPosition.mTop - 3*mSampleSpacing;
00321         mBack[0].mRight = mPosition.mRight + 3*mSampleSpacing -1;
00322         mBack[0].mBottom = mPosition.mTop -1;
00323 
00324         mBack[1].mLeft = mPosition.mLeft - 3*mSampleSpacing;
00325         mBack[1].mTop = mPosition.mTop - mSampleSpacing;
00326         mBack[1].mRight = mPosition.mLeft -1;
00327         mBack[1].mBottom = mPosition.mBottom + mSampleSpacing -1;
00328 
00329         mBack[2].mLeft = mPosition.mRight;
00330         mBack[2].mTop = mPosition.mTop - mSampleSpacing;
00331         mBack[2].mRight = mPosition.mRight + 3*mSampleSpacing -1;
00332         mBack[2].mBottom = mPosition.mBottom + mSampleSpacing -1;
00333 
00334         mBack[3].mLeft = mPosition.mLeft - 3*mSampleSpacing;
00335         mBack[3].mTop = mPosition.mBottom;
00336         mBack[3].mRight = mPosition.mRight + 3*mSampleSpacing -1;
00337         mBack[3].mBottom = mPosition.mBottom + 3*mSampleSpacing -1;
00338 
00339         if(mPosition.mLeft < 3*mSampleSpacing)
00340         {
00341             mBack[0].mLeft = 0;
00342             mBack[1].mLeft = 0;
00343             mBack[3].mLeft = 0;
00344         }
00345         if(mPosition.mTop < 3*mSampleSpacing)
00346         {
00347             mBack[0].mTop = 0;
00348         }
00349         if(mPosition.mRight+3*mSampleSpacing >= mWidth)
00350         {
00351             mBack[0].mRight = mWidth;
00352             mBack[2].mRight = mWidth;
00353             mBack[3].mRight = mWidth;
00354         }
00355         if(mPosition.mBottom+3*mSampleSpacing >= mHeight)
00356         {
00357             mBack[3].mBottom = mHeight;
00358         }
00359 
00360         int w = mBack[0].Width()/mSampleSpacing;
00361         int h = mBack[1].Height()/mSampleSpacing;
00362         ILOG_DEBUG("rect[0].w=" << w << " rect[1].h=" << h);
00363         w--;
00364         h--;
00365         ILOG_DEBUG("sample space = " << mSampleSpacing);
00366         mBackMaxPoints = (w * 4) + (h * 4);
00367         ILOG_DEBUG("maxpoints = "<<mBackMaxPoints<<" (4*"<<w<<" + 4*"<<h<<")");
00368     }
00369 
00370     void ComputeBackgroundResponse(Array::Array2dScalarReal64& background)
00371     {
00372         // get response of the background (eq.5)
00373         int count = 0;
00374         for(int b=0 ; b<4 ; b++)
00375         {
00376             int w,h;
00377             w = mBack[b].Width()/mSampleSpacing;
00378             h = mBack[b].Height()/mSampleSpacing;
00379             ILOG_DEBUG("rect = "<<mBack[b]<<", w="<<w<<", h="<<h);
00380             int i,j;
00381             for(j=1 ; j<h ; j++)
00382             {
00383                 for(i=1 ; i<w; i++)
00384                 {
00385                     double* data = background.CPB(0, count);
00386                     count++;
00387                     mGabor.Apply(data, *mInput, 
00388                                  mBack[b].mLeft+(i*mSampleSpacing),
00389                                  mBack[b].mTop+(j*mSampleSpacing));
00390                 }
00391             }
00392             ILOG_DEBUG("count = "<<count);
00393         }
00394         while(count < background.CH()) // this actually never occurs
00395         {
00396             double* data = background.CPB(0, count);
00397             for(int j=0 ; j<background.CW() ; j++)
00398                 data[j] = 0;
00399             count++;
00400         }
00401     }
00402 
00403     void FillSearchArea(Array::Array2dVec3Real64* searchArea, int bw, int bh)
00404     {
00407 
00408 
00409         // first cheat with the sizes of the searchArea
00410         int w = searchArea->W();
00411         int h = searchArea->H();
00412         searchArea->mBW = 0;
00413         searchArea->mBH = 0;
00414         searchArea->mCW = w;
00415         searchArea->mCH = h;
00416         SetVal(searchArea, searchArea, 0); 
00417         int x = mPosition.mLeft + mPosition.Width()/2;
00418         int y = mPosition.mTop + mPosition.Height()/2;
00419 
00420         // see if the search area lies partially outside the image
00421         Core::Geometry::Rectangle overflow;
00422         if (x - bw - 10 < 0)
00423             overflow.mLeft = -(x - bw - 10);
00424         if (y - bh - 10 < 0)
00425             overflow.mTop  = -(y - bh - 10);
00426         if (x + bw + 10 >= mInput->CW())
00427             overflow.mRight = x + bw + 10 - mInput->CW() + 1;
00428         if (y + bh + 10 >= mInput->CH())
00429             overflow.mBottom = y + bh + 10 - mInput->CH() + 1;
00430 
00431         // copy the data
00432         Array::Pattern::PatSet
00433             (searchArea, mInput,
00434             x - bw - 10 + overflow.mLeft,
00435             y - bh - 10 + overflow.mTop,
00436             2*bw + 21 - (overflow.mLeft + overflow.mRight),
00437             2*bh + 21 - (overflow.mTop + overflow.mBottom),
00438             0, 0);
00439 
00440         // restore correct dimensions
00441         searchArea->mCW = 21;
00442         searchArea->mCH = 21;
00443         searchArea->mBW = bw;
00444         searchArea->mBH = bh;
00445     }
00446 
00447     FrameRegionTable* mTrack;
00448 
00449     Array::Array2dVec3Real64* mInput;
00450     Util::TimeStats mStats;
00451 
00452     // data for tracking
00453     int mHeight, mWidth;
00454     Core::Geometry::Rectangle mPosition;
00455     Core::Geometry::PointZ mSampleOffset;
00456     Core::Geometry::Rectangle mBack[4];
00457     int mBackMaxPoints;
00458     Array::Array2dVec3Real64* mSearchKernel;
00459     Array::Array2dVec3UInt8* mReconstruction;
00460     Array::Array2dScalarReal64* mSearchResult;
00461     //DataArray* mSimilarityPerFrame;
00462     Classifier* mClassifier;
00463     int mSampleSpacing, mFilterSize;
00464     int mDimensionality;
00465     int mDirectionCount;
00466     GaborFilterSet mGabor;
00467     std::ofstream mDebugFile;
00468 
00469     static log4cpp::Category& sLog;
00470 };
00471 
00472 ILOG_VAR_INIT(TrackerBackFore, Impala.Core.Tracking);
00473 
00474 }//namespace Tracking
00475 }//namespace Core
00476 }//namespace Impala
00477 
00478 #endif // !Impala_Core_Tracking_TrackerBackFore_h

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