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;
00048 mInput = 0;
00049 mSearchKernel = 0;
00050 mSearchResult = new Array::Array2dScalarReal64(21, 21, 0, 0);
00051 mReconstruction = 0;
00052
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()
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
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
00111
00112
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
00158
00159 double mLikelyhood;
00160 double mInitialLikelyhood;
00161
00162 private:
00163 void SearchObject()
00164 {
00165
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);
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);
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
00214 if(minmax.mMaxVal < -10000)
00215 mLikelyhood = mInitialLikelyhood * 0.1;
00216 else
00217 {
00218
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
00230
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
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
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
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
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())
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
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
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
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
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
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
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 }
00475 }
00476 }
00477
00478 #endif // !Impala_Core_Tracking_TrackerBackFore_h