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

Generated on Thu Jan 13 09:04:40 2011 for ImpalaSrc by  doxygen 1.5.1