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
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()
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
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
00125
00126
00127
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
00177
00178 double mLikelyhood;
00179 double mInitialLikelyhood;
00180
00181 private:
00182 void
00183 SearchObject()
00184 {
00185
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);
00215
00216
00217
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
00226
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
00241
00242 if(minmax.mMaxVal < -10000)
00243 mLikelyhood = mInitialLikelyhood * 0.1;
00244 else
00245 {
00246
00247
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
00260
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
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
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
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
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())
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
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
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
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
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
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
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 }
00521 }
00522 }
00523
00524 #endif // !Impala_Core_Tracking_TrackerBackFore_h