00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040
00041 #include "Robots/Beobot2/Navigation/FOE_Navigation/FoeDetector.H"
00042
00043 #include <cstdio>
00044 #include "Image/Kernels.H"
00045 #include "Image/ColorOps.H"
00046 #include "Image/CutPaste.H"
00047 #include "Image/DrawOps.H"
00048 #include "Image/FilterOps.H"
00049 #include "Image/MathOps.H"
00050 #include "Image/Pixels.H"
00051 #include "Image/ShapeOps.H"
00052 #include "Image/SimpleFont.H"
00053
00054 #include "Util/Timer.H"
00055
00056 #define FOE_STEP 4
00057 #define INTEGRATION_WINDOW 5
00058
00059
00060
00061 FoeDetector::FoeDetector(OptionManager& mgr,
00062 const std::string& descrName,
00063 const std::string& tagName)
00064 :
00065 ModelComponent(mgr, descrName, tagName)
00066 {
00067
00068 itsCurrentRotMotionSpeed = 0.0;
00069 itsCurrentRotMotionDir = 0;
00070 itsCurrentRotMotionDi = 0.0;
00071 itsCurrentRotMotionDj = 0.0;
00072
00073
00074 itsCurrentFoeMapIndex = -1;
00075 itsRecentFoeMaps.resize(INTEGRATION_WINDOW);
00076
00077
00078 itsMT.reset(new MiddleTemporal());
00079
00080 itsWin.reset();
00081 }
00082
00083
00084 void FoeDetector::reset
00085 (uint numPyrLevels, uint numDirs, uint numSpeeds)
00086 {
00087 itsNumPyrLevels = numPyrLevels;
00088 itsNumDirs = numDirs;
00089 itsNumSpeeds = numSpeeds;
00090
00091 itsSpatioTemporalPyrBuilders.clear();
00092 itsSpatioTemporalPyrBuilders.resize(itsNumDirs);
00093 for(uint i = 0; i < itsNumDirs; i++)
00094 itsSpatioTemporalPyrBuilders[i].resize(itsNumSpeeds);
00095
00096 itsRawSpatioTemporalEnergy.clear();
00097 itsRawSpatioTemporalEnergy.resize(itsNumDirs);
00098 for(uint i = 0; i < itsNumDirs; i++)
00099 itsRawSpatioTemporalEnergy[i].resize(itsNumSpeeds);
00100
00101 itsSpatioTemporalEnergy.resize(itsNumDirs);
00102
00103
00104
00105
00106 itsMTfeatures.resize(itsNumDirs);
00107 itsMToptimalShift.resize(itsNumDirs);
00108
00109 LINFO("Using %d directions spanning [0..360]deg", itsNumDirs);
00110 for (uint i = 0; i < itsNumDirs; i++)
00111 {
00112 for (uint j = 0; j < itsNumSpeeds; j++)
00113 {
00114 float speed = pow(2.0, j);
00115
00116 itsSpatioTemporalPyrBuilders[i][j].reset
00117 (new SpatioTemporalEnergyPyrBuilder<float>
00118 (Oriented5,
00119 360.0 * double(i)/double(itsNumDirs),
00120 speed,
00121 itsNumPyrLevels));
00122 }
00123
00124
00125 }
00126 }
00127
00128
00129 FoeDetector::~FoeDetector()
00130 { }
00131
00132
00133 Point2D<int> FoeDetector::getFoe
00134 (Image<byte> lum, uint method, bool tempFilter)
00135 {
00136
00137 uint width = itsCurrentImage.getWidth();
00138 uint height = itsCurrentImage.getHeight();
00139
00140 uint lwidth = lum.getWidth();
00141 uint lheight = lum.getHeight();
00142
00143 if(width != lwidth || height != lheight)
00144 {
00145 width = lum.getWidth();
00146 height = lum.getHeight();
00147 itsFoeMap = Image<float>
00148 (width/MAX_NEIGHBORHOOD, height/MAX_NEIGHBORHOOD, ZEROS);
00149
00150
00151 resetDirectionWeights(width, height);
00152 }
00153
00154 itsCurrentImage = lum;
00155
00156 Timer tim(1000000);
00157
00158
00159 tim.reset();
00160 computeV1features();
00161
00162
00163
00164 Point2D<int> maxpt;
00165 if(itsRawSpatioTemporalEnergy[0][0].size() > 0)
00166 {
00167
00168 itsMT->computeMTfeatures(itsRawSpatioTemporalEnergy);
00169 itsMTfeatures = itsMT->getMTfeatures();
00170 itsMToptimalShift = itsMT->getMToptimalShift();
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 if(method == FOE_METHOD_TEMPLATE)
00185 maxpt = computeFoeTemplate();
00186 else if(method == FOE_METHOD_AVERAGE)
00187 maxpt = computeFoeAverage();
00188 else LFATAL("Unknown Foe Method");
00189
00190
00191 }
00192
00193
00194 if(tempFilter)
00195 itsFoe = temporalFilterFoeComputation();
00196 else
00197 itsFoe = maxpt;
00198
00199 return itsFoe;
00200 }
00201
00202
00203 Image<float> FoeDetector::getFoeMap
00204 (Image<byte> lum, uint method, bool tempFilter)
00205 {
00206 Point2D<int> pt = getFoe(lum, method, tempFilter);
00207 LDEBUG("pt: %d %d", pt.i, pt.j);
00208
00209 return itsFoeMap;
00210 }
00211
00212
00213 Point2D<int> FoeDetector::getFoe
00214 ( rutz::shared_ptr<OpticalFlow> flow, uint method, bool tempFilter)
00215 {
00216 Timer tim(1000000); tim.reset();
00217
00218
00219
00220 detectObserverRotation();
00221 correctForObserverRotation();
00222
00223
00224
00225
00226 Point2D<int> maxpt;
00227 if(method == FOE_METHOD_TEMPLATE)
00228 maxpt = computeFoeTemplate(flow);
00229 else if(method == FOE_METHOD_AVERAGE)
00230 maxpt = computeFoeAverage(flow);
00231 else LFATAL("Unknown Foe Method");
00232
00233
00234
00235
00236 if(tempFilter)
00237 itsFoe = temporalFilterFoeComputation();
00238 else
00239 itsFoe = maxpt;
00240
00241 return itsFoe;
00242 }
00243
00244
00245 Image<float> FoeDetector::getFoeMap
00246 ( rutz::shared_ptr<OpticalFlow> flow, uint method, bool tempFilter)
00247 {
00248 Point2D<int> pt = getFoe(flow, method, tempFilter);
00249 LDEBUG("pt: %d %d", pt.i, pt.j);
00250
00251 return itsFoeMap;
00252 }
00253
00254 Point2D<int> FoeDetector::getFoe
00255 ( std::vector <Image<float> > mtFeatures,
00256 std::vector <Image<float> > mtOptimalShift,
00257 uint method, bool tempFilter)
00258 {
00259 itsNumDirs = mtFeatures.size();
00260 itsMTfeatures = mtFeatures;
00261 itsMToptimalShift = mtOptimalShift;
00262
00263
00264
00265
00266
00267 float activityVal = detectObserverStationarity();
00268
00269
00270
00271 detectObserverRotation();
00272
00273
00274
00275 Point2D<int> maxpt;
00276 if(method == FOE_METHOD_TEMPLATE)
00277 maxpt = computeFoeTemplate();
00278 else if(method == FOE_METHOD_AVERAGE)
00279 maxpt = computeFoeAverage();
00280 else LFATAL("Unknown Foe Method");
00281
00282
00283 if(tempFilter)
00284 itsFoe = temporalFilterFoeComputation();
00285 else
00286 itsFoe = maxpt;
00287
00288
00289
00290 LINFO("maxpt: %d %d", maxpt.i, maxpt.j);
00291 float val = itsFoeMap.getVal(maxpt/MAX_NEIGHBORHOOD);
00292 if(val < .1)
00293 {
00294 LINFO("max val too low: "
00295 "must be radial motion (%f) or stationary (%f)",
00296 val, activityVal);
00297 itsFoeMap.clear(0.0);
00298 itsFoe = Point2D<int>(-1,-1);
00299 }
00300
00301 return itsFoe;
00302 }
00303
00304
00305 Point2D<int> FoeDetector::temporalFilterFoeComputation()
00306 {
00307 Point2D<int> foe;
00308 uint width = itsFoeMap.getWidth();
00309 uint height = itsFoeMap.getHeight();
00310
00311
00312 itsCurrentFoeMapIndex++;
00313 uint index = (itsCurrentFoeMapIndex)%INTEGRATION_WINDOW;
00314 itsRecentFoeMaps[index] = itsFoeMap;
00315
00316 uint numMaps = INTEGRATION_WINDOW;
00317 if (itsCurrentFoeMapIndex < INTEGRATION_WINDOW)
00318 numMaps = itsCurrentFoeMapIndex+1;
00319
00320 LINFO("start: %d",itsCurrentFoeMapIndex);
00321 Image<float> image = itsRecentFoeMaps[0];
00322 for(uint i = 1; i < numMaps; i++)
00323 image = image + itsRecentFoeMaps[i];
00324 itsFoeMap = image/numMaps;
00325
00326 float max = itsFoeMap.getVal(0,0);
00327 for(uint i = 0; i < width; i++)
00328 for(uint j = 0; j < height; j++)
00329 {
00330 float val = itsFoeMap.getVal(i,j);
00331 if(max < val)
00332 {
00333 foe = Point2D<int>(i*MAX_NEIGHBORHOOD,j*MAX_NEIGHBORHOOD);
00334 max = val;
00335 }
00336 }
00337
00338 LINFO("Integrated FOE: (%3d %3d): %15.5f", foe.i, foe.j, max);
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 return foe;
00365 }
00366
00367
00368 Image<float> FoeDetector::getFoeMap
00369 ( std::vector <Image<float> > mtFeatures,
00370 std::vector <Image<float> > mtOptimalShift,
00371 uint method, bool tempFilter)
00372 {
00373 Point2D<int> pt = getFoe(mtFeatures, mtOptimalShift,
00374 method, tempFilter);
00375 LDEBUG("pt: %d %d", pt.i, pt.j);
00376
00377 return itsFoeMap;
00378 }
00379
00380
00381 Point2D<int> FoeDetector::getFoe()
00382 {
00383 return itsFoe;
00384 }
00385
00386
00387 Image<float> FoeDetector::getFoeMap()
00388 {
00389 return itsFoeMap;
00390 }
00391
00392
00393 void FoeDetector::resetDirectionWeights(uint width, uint height)
00394 {
00395 float length = 1.0;
00396
00397 itsDirWeights.clear();
00398 itsDirWeights.resize(width/MAX_NEIGHBORHOOD/FOE_STEP);
00399 for(uint i = 0; i < width/MAX_NEIGHBORHOOD/FOE_STEP; i++)
00400 itsDirWeights[i].resize(width/MAX_NEIGHBORHOOD/FOE_STEP);
00401
00402 for(uint i = 0; i < width/MAX_NEIGHBORHOOD/FOE_STEP; i++)
00403 for(uint j = 0; j < height/MAX_NEIGHBORHOOD/FOE_STEP; j++)
00404 itsDirWeights[i][j].resize(itsNumDirs);
00405
00406
00407 for(uint i = 0; i < width/MAX_NEIGHBORHOOD/FOE_STEP; i++)
00408 for(uint j = 0; j < height/MAX_NEIGHBORHOOD/FOE_STEP; j++)
00409 for(uint k = 0; k < itsNumDirs; k++)
00410 {
00411 float mangle = (k*360.0)/itsNumDirs;
00412
00413 itsDirWeights[i][j][k] =
00414 Image<float>(width/MAX_NEIGHBORHOOD,
00415 height/MAX_NEIGHBORHOOD, NO_INIT);
00416
00417
00418 for(uint ii = 0; ii < width/MAX_NEIGHBORHOOD; ii++)
00419 for(uint jj = 0; jj < height/MAX_NEIGHBORHOOD; jj++)
00420 {
00421 float val = getDirectionWeight
00422 (Point2D<float>(ii,jj),
00423 Point2D<float>(i*FOE_STEP, j*FOE_STEP), length, mangle);
00424
00425 itsDirWeights[i][j][k].setVal(ii,jj, val);
00426 }
00427 }
00428 }
00429
00430
00431 void FoeDetector::computeV1features()
00432 {
00433
00434
00435
00436
00437 Timer tim(1000000);
00438
00439
00440 for (uint i = 0; i < itsNumDirs; i++)
00441 {
00442 tim.reset();
00443 for (uint j = 0; j < itsNumSpeeds; j++)
00444 {
00445 itsRawSpatioTemporalEnergy[i][j] =
00446 itsSpatioTemporalPyrBuilders[i][j]->build(itsCurrentImage);
00447 }
00448
00449 uint64 t1 = tim.get();
00450 LINFO("[%3d] ste: %f", i, t1/1000.0);
00451 }
00452 }
00453
00454
00455
00456 float FoeDetector::detectObserverStationarity()
00457 {
00458 if(itsMTfeatures.size() == 0 ||
00459 itsMTfeatures[0].getSize() == 0) return -1.0;
00460
00461 double max = mean(itsMTfeatures[0]); uint maxInd = 0;
00462 std::vector<double> maxs(itsNumDirs); double total = 0.0;
00463 LDEBUG("%3d: %10.3f max[%3d]: %10.3f ", 0, max, maxInd, max);
00464 for(uint i = 1; i < itsNumDirs; i++)
00465 {
00466 maxs[i] = mean(itsMTfeatures[i]);
00467 if(maxs[i] > max)
00468 {
00469 max = maxs[i];
00470 maxInd = i;
00471 }
00472 total += maxs[i];
00473 LDEBUG("%3d: %10.3f max[%3d]: %10.3f ", i, maxs[i], maxInd, max);
00474 }
00475 float avg = total/itsNumDirs;
00476 LINFO("avg activity: %f", avg);
00477 return avg;
00478 }
00479
00480
00481 void FoeDetector::detectObserverRotation()
00482 {
00483 if(itsMTfeatures.size() == 0 ||
00484 itsMTfeatures[0].getSize() == 0) return;
00485
00486
00487
00488 double max = maxMean(itsMTfeatures[0]); uint maxInd = 0;
00489 std::vector<double> maxs(itsNumDirs); double total = 0.0;
00490 LDEBUG("%3d: %10.3f max[%3d]: %10.3f ", 0, max, maxInd, max);
00491 for(uint i = 1; i < itsNumDirs; i++)
00492 {
00493 maxs[i] = maxMean(itsMTfeatures[i]);
00494 if(maxs[i] > max)
00495 {
00496 max = maxs[i];
00497 maxInd = i;
00498 }
00499 total += maxs[i];
00500 LDEBUG("%3d: %10.3f max[%3d]: %10.3f ", i, maxs[i], maxInd, max);
00501 }
00502
00503
00504 double rat = max/total;
00505 if(rat > 3.0/itsNumDirs) LINFO("Planar motion : %f", rat);
00506
00507 computeFoeAverage();
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 }
00529
00530
00531
00532 float FoeDetector::maxMean(Image<float> image)
00533 {
00534 uint width = image.getWidth();
00535 uint height = image.getHeight();
00536
00537 float max = 0.0; Rectangle rMax;
00538 for(uint i = 0; i < 5; i++)
00539 {
00540 uint sI = uint(i* width/8.0);
00541 uint eI = uint((i+4)* width/8.0 -1);
00542
00543 for(uint j = 0; j < 5; j++)
00544 {
00545 uint sJ = uint(j* height/8.0);
00546 uint eJ = uint((j+4)* height/8.0 - 1);
00547
00548 Rectangle r = Rectangle::tlbrI(sJ, sI, eJ, eI);
00549 LDEBUG("[%3d %3d %3d %3d]",
00550 r.top(), r.left(), r.bottomI(), r.rightI());
00551 Image<float> result = crop(image, r);
00552 float val = mean(result);
00553 LDEBUG("val: %f", val);
00554
00555
00556 if(max < val){ max = val; rMax = r; }
00557 }
00558 }
00559 LDEBUG("[%3d %3d %3d %3d]: %10.3f",
00560 rMax.top(), rMax.left(), rMax.bottomI(), rMax.rightI(), max);
00561
00562 return max;
00563 }
00564
00565
00566 void FoeDetector::setObserverRotation(uint dir, float speed)
00567 {
00568 itsCurrentRotMotionDir = dir;
00569 itsCurrentRotMotionSpeed = speed;
00570
00571 itsCurrentRotMotionDi =
00572 itsCurrentRotMotionSpeed *
00573 cos((2.0*M_PI * itsCurrentRotMotionDir)/itsNumDirs);
00574 itsCurrentRotMotionDj =
00575 itsCurrentRotMotionSpeed *
00576 sin((2.0*M_PI * itsCurrentRotMotionDir)/itsNumDirs);
00577
00578 LINFO("di,j: %f %f", itsCurrentRotMotionDi, itsCurrentRotMotionDj);
00579 }
00580
00581
00582 void FoeDetector::setObserverRotation(float di, float dj)
00583 {
00584 itsCurrentRotMotionDi = di;
00585 itsCurrentRotMotionDj = dj;
00586
00587 float angle = atan2(dj,di) / M_PI * 180.0;
00588 float nangle = fmod(angle+360.0, 360.0);
00589
00590 float max = 360.0; uint dir = 0;
00591 for(uint i = 0; i <itsNumDirs; i++)
00592 {
00593 float mangle = (i*360.0)/itsNumDirs;
00594
00595 float diff1 = fabs(nangle - mangle);
00596 float diff2 = 360.0 - diff1;
00597 float diff = diff1; if(diff1 > diff2) diff = diff2;
00598
00599 if(diff < max) { max = diff; dir = i; }
00600 }
00601
00602 itsCurrentRotMotionDir = dir;
00603 itsCurrentRotMotionSpeed = sqrt(di*di + dj*dj);
00604
00605 LINFO("di,j: %f %f", itsCurrentRotMotionDi, itsCurrentRotMotionDj);
00606 }
00607
00608
00609 void FoeDetector::correctForObserverRotation()
00610 {
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 }
00632
00633
00634 Point2D<int> FoeDetector::computeFoeTemplate()
00635 {
00636 Point2D<int> foeLoc(-1, -1);
00637 if(itsMTfeatures[0].size() == 0) return foeLoc;
00638
00639 int width = itsMTfeatures[0].getWidth();
00640 int height = itsMTfeatures[0].getHeight();
00641 itsFoeMap = Image<float>(width,height, ZEROS);
00642
00643 int foeStep = FOE_STEP;
00644 int border = 2*foeStep;
00645 Timer tim(1000000);
00646
00647 LDEBUG("dir: %d sp: %f", itsCurrentRotMotionDir, itsCurrentRotMotionSpeed);
00648
00649
00650
00651
00652
00653
00654
00655 float normalizer = 20.0/width/height;
00656 float max = 0.0; float min = 10000.0;
00657 for(int i = border; i < (width - border); i+=foeStep)
00658 {
00659 for(int j = border+ 4*foeStep; j < (height - border)-3*foeStep; j+=foeStep)
00660 {
00661 tim.reset();
00662 float val = computeFoeTemplateValue(i,j) * normalizer;
00663
00664
00665 if(val > max)
00666 {
00667 foeLoc = Point2D<int>(i*MAX_NEIGHBORHOOD,j*MAX_NEIGHBORHOOD);
00668 max = val;
00669 }
00670
00671 if(val < min) min = val;
00672 itsFoeMap.setVal(i,j,val);
00673 drawFilledRect
00674 (itsFoeMap,Rectangle::tlbrI(j,i,j+foeStep-1,i+foeStep-1), val);
00675
00676
00677 }
00678 }
00679 LINFO("Current FOE: (%3d %3d): %15.5f", foeLoc.i, foeLoc.j, max);
00680
00681 for(int i = 0; i < width; i+=foeStep)
00682 {
00683 for(int j = 0; j < height; j+=foeStep)
00684 {
00685 if((i < border) ||
00686 (j < border + 4*foeStep) ||
00687 (i >= (width - border)) ||
00688 (j >= (height - border)-3*foeStep))
00689 {
00690 drawFilledRect
00691 (itsFoeMap,Rectangle::tlbrI(j,i,j+foeStep-1,i+foeStep-1), min);
00692
00693 }
00694 }
00695 }
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711 return foeLoc;
00712 }
00713
00714
00715 float FoeDetector::computeFoeTemplateValue(uint foeI, uint foeJ)
00716 {
00717 float result = 0.0;
00718
00719 int width = itsFoeMap.getWidth();
00720 int height = itsFoeMap.getHeight();
00721 float diag = sqrt(width*width + height*height);
00722
00723
00724 Image<float>::iterator mtT[itsNumDirs];
00725 for (unsigned int i=0; i < itsNumDirs; i++)
00726 mtT[i] = itsMTfeatures[i].beginw();
00727
00728 Image<float>::iterator mtosT[itsNumDirs];
00729 for (unsigned int i=0; i < itsNumDirs; i++)
00730 mtosT[i] = itsMToptimalShift[i].beginw();
00731
00732
00733 for(uint dir = 0; dir < itsNumDirs; dir++)
00734 {
00735
00736
00737
00738
00739
00740 float mangle = (dir*360.0)/itsNumDirs;
00741
00742
00743 for(int j = 0; j < height; j++)
00744 {
00745 for(int i = 0; i < width; i++)
00746 {
00747
00748 float di = float(i) - float(foeI);
00749 float dj = float(j) - float(foeJ);
00750 float dist = sqrt(pow(di, 2.0) + pow(dj, 2.0));
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 float length = *mtosT[dir]++;
00773 float wDir = getDirectionWeight
00774 (Point2D<float>(i,j), Point2D<float>(foeI, foeJ), length, mangle);
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 float wLoc = 1.0;
00787 if(dist/diag < 1.0/8.0) wLoc = .1;
00788
00789
00790
00791 float val = *mtT[dir]++;
00792
00793 result += wDir*wLoc*val;
00794
00795
00796 }
00797 }
00798 }
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 return result;
00810 }
00811
00812
00813 float FoeDetector::getDirectionWeight
00814 (Point2D<float> pt, Point2D<float> foe, float length, float mangle)
00815 {
00816 if(length == 0.0) return 0.0;
00817
00818
00819
00820
00821 float mI = itsCurrentRotMotionDi;
00822 float mJ = itsCurrentRotMotionDj;
00823
00824
00825 float odi = (float(pt.i) - float(foe.i));
00826 float odj = (float(pt.j) - float(foe.j));
00827 float dist = sqrt(odi*odi + odj*odj);
00828 if(dist == 0.0) dist = 1.0;
00829
00830 float di = length*(float(pt.i) - float(foe.i))/dist + mI;
00831 float dj = length*(float(pt.j) - float(foe.j))/dist + mJ;
00832
00833 float angle = atan2(dj,di) / M_PI * 180.0;
00834 float nangle = fmod(angle +360.0, 360.0);
00835
00836
00837 float diff1 = fabs(nangle - mangle);
00838 float diff2 = 360.0 - diff1;
00839 float diff = diff1; if(diff1 > diff2) diff = diff2;
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 float val = 0.0;
00939
00940
00941
00942 if(diff <= 90.0) val = cos(diff/180.0*M_PI)*.4;
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984 return val;
00985 }
00986
00987
00988 float FoeDetector::getDirectionWeight2(uint quad, uint dir)
00989 {
00990 if(quad == dir) return 1.00;
00991 else return 0.25;
00992
00993
00994
00995
00996 }
00997
00998
00999 Point2D<int> FoeDetector::computeFoeTemplate
01000 (rutz::shared_ptr<OpticalFlow> flow)
01001 {
01002 Point2D<int> foeLoc(-1,-1);
01003
01004 Dims imSize = flow->getImageDims();
01005 int width = imSize.w()/MAX_NEIGHBORHOOD;
01006 int height = imSize.h()/MAX_NEIGHBORHOOD;
01007 itsFoeMap = Image<float>(width,height, ZEROS);
01008
01009 int foeStep = FOE_STEP;
01010 int border = 2*foeStep;
01011 Timer tim(1000000);
01012
01013 LDEBUG("dir: %d sp: %f", itsCurrentRotMotionDir, itsCurrentRotMotionSpeed);
01014
01015
01016
01017
01018
01019
01020
01021 float normalizer = 20.0/width/height;
01022 float max = 0.0; float min = 10000.0;
01023 for(int i = border; i < (width - border); i+=foeStep)
01024 {
01025 for(int j = border; j < (height - border); j+=foeStep)
01026 {
01027 tim.reset();
01028 float val = computeFoeTemplateValue
01029 (i*MAX_NEIGHBORHOOD,j*MAX_NEIGHBORHOOD, flow) * normalizer;
01030
01031
01032 if(val > max)
01033 {
01034 foeLoc = Point2D<int>(i*MAX_NEIGHBORHOOD,j*MAX_NEIGHBORHOOD);
01035 max = val;
01036 }
01037
01038 if(val < min) min = val;
01039
01040 itsFoeMap.setVal(i,j,val);
01041 drawFilledRect
01042 (itsFoeMap,Rectangle::tlbrI(j,i,j+foeStep-1,i+foeStep-1), val);
01043
01044 }
01045 }
01046 LINFO("Current FOE: (%3d %3d): %15.5f", foeLoc.i, foeLoc.j, max);
01047
01048 for(int i = 0; i < width; i+=foeStep)
01049 {
01050 for(int j = 0; j < height; j+=foeStep)
01051 {
01052 if((i < border) ||
01053 (j < border) ||
01054 (i >= (width - border)) ||
01055 (j >= (height - border)))
01056 {
01057 drawFilledRect
01058 (itsFoeMap,Rectangle::tlbrI(j,i,j+foeStep-1,i+foeStep-1), min);
01059
01060 }
01061 }
01062 }
01063
01064
01065
01066
01067
01068
01069
01070
01071 return foeLoc;
01072 }
01073
01074
01075 float FoeDetector::computeFoeTemplateValue
01076 (uint foeI, uint foeJ, rutz::shared_ptr<OpticalFlow> flow)
01077 {
01078 float result = 0.0;
01079
01080 Dims imSize = flow->getImageDims();
01081 int width = imSize.w();
01082 int height = imSize.h();
01083 float diag = sqrt(width*width + height*height);
01084
01085
01086 std::vector<rutz::shared_ptr<FlowVector> > flowVectors =
01087 flow->getFlowVectors();
01088
01089
01090 for(uint i = 0; i < flowVectors.size(); i++)
01091 {
01092
01093
01094 Point2D<float> pt1 = flowVectors[i]->p1;
01095
01096 float mangle = flowVectors[i]->angle;
01097 float length = flowVectors[i]->mag;
01098
01099
01100
01101
01102
01103
01104 float di = float(pt1.i) - float(foeI);
01105 float dj = float(pt1.j) - float(foeJ);
01106 float dist = sqrt(pow(di, 2.0) + pow(dj, 2.0));
01107
01108
01109 float wDir = getDirectionWeight
01110 (pt1, Point2D<float>(foeI, foeJ), length, mangle);
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121 float wLoc = 1.0;
01122 if(dist/diag < 1.0/8.0) wLoc = .1;
01123
01124
01125
01126
01127
01128 result += wDir*wLoc;
01129 }
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 return result;
01141 }
01142
01143
01144 Point2D<int> FoeDetector::computeFoeAverage()
01145 {
01146 Point2D<int> foeLoc(-1, -1);
01147 if(itsMTfeatures[0].size() == 0) return foeLoc;
01148
01149 float maxShift = 16.0;
01150
01151 uint width = itsMTfeatures[0].getWidth();
01152 uint height = itsMTfeatures[0].getHeight();
01153
01154 Image<float> tempH(width, height, ZEROS);
01155 Image<float> tempV(width, height, ZEROS);
01156 std::vector<Point2D<float> > hVals; std::vector<float> hW;
01157 std::vector<Point2D<float> > vVals; std::vector<float> vW;
01158
01159
01160
01161 for(uint d = 0; d < itsNumDirs; d++)
01162 {
01163 float sinAng = sin((2.0*M_PI * d)/itsNumDirs);
01164 float cosAng = cos((2.0*M_PI * d)/itsNumDirs);
01165
01166
01167 for(uint i = 0; i < width; i++)
01168 for(uint j = 0; j < height; j++)
01169 {
01170 float val = itsMTfeatures[d].getVal(i,j);
01171
01172
01173 float len = itsMToptimalShift[d].getVal(i,j);
01174 float dy = len * sinAng;
01175 float dx = len * cosAng;
01176
01177 uint lH = uint(width/2 - dy/maxShift*width/2);
01178 uint lV = uint(height/2 - dx/maxShift*height/2);
01179 if(lH == width) lH--; if(lV == height) lV--;
01180
01181
01182
01183
01184 float tH = tempH.getVal(lH, j);
01185 float tV = tempV.getVal(i, lV);
01186
01187 if(val > .20)
01188 {
01189 tempH.setVal(lH, j, val + tH);
01190 tempV.setVal(i, lV, val + tV);
01191
01192 hVals.push_back(Point2D<float>(j,dy)); hW.push_back(val);
01193 vVals.push_back(Point2D<float>(i,dx)); vW.push_back(val);
01194 }
01195 }
01196 }
01197
01198
01199 double sumXY = 0.0; double sumX = 0.0; double sumY = 0.0; double sumX2 = 0.0;
01200 double wsum = 0.0;
01201 for(uint i = 0; i < hVals.size(); i++)
01202 {
01203 wsum += hW[i];
01204
01205
01206 sumXY += hW[i] * (hVals[i].i * hVals[i].j);
01207
01208
01209 sumX += hW[i] * hVals[i].i;
01210
01211
01212 sumY += hW[i] * hVals[i].j;
01213
01214
01215 sumX2 += hW[i] * hVals[i].i*hVals[i].i;
01216 }
01217
01218 double n = wsum;
01219 double mH = (n*sumXY - sumX*sumY)/(n*sumX2 - sumX*sumX);
01220 double bH = (sumY - mH*sumX)/n;
01221 foeLoc.j = -bH/mH * MAX_NEIGHBORHOOD;
01222 LINFO("x = %10.5fx + %10.5f: %10.5f", mH, bH,-bH/mH);
01223
01224 sumXY = 0.0; sumX = 0.0; sumY = 0.0; sumX2 = 0.0;
01225 wsum = 0.0;
01226 for(uint i = 0; i < vVals.size(); i++)
01227 {
01228 wsum += vW[i];
01229
01230
01231 sumXY += vW[i] * (vVals[i].i * vVals[i].j);
01232
01233
01234 sumX += vW[i] * vVals[i].i;
01235
01236
01237 sumY += vW[i] * vVals[i].j;
01238
01239
01240 sumX2 += vW[i] * vVals[i].i*vVals[i].i;
01241 }
01242
01243 n = wsum;
01244 float mV = (n*sumXY - sumX*sumY)/(n*sumX2 - sumX*sumX);
01245 float bV = (sumY - mV*sumX)/n;
01246 foeLoc.i = -bV/mV * MAX_NEIGHBORHOOD;
01247 LINFO("y = %10.5fx + %10.5f: %10.5f", mV, bV,-bV/mV);
01248
01249 LINFO("FOE: (%3d %3d)", foeLoc.i, foeLoc.j);
01250
01251 tempH = zoomXY(tempH, MAX_NEIGHBORHOOD);
01252 tempV = zoomXY(tempV, MAX_NEIGHBORHOOD);
01253 uint dispW = width*MAX_NEIGHBORHOOD;
01254 uint dispH = height*MAX_NEIGHBORHOOD;
01255
01256 float spH = mH*0 + bH;
01257 float epH = mH*(height-1) + bH;
01258
01259 Point2D<int> sH((width/2 - spH/8.0*width/2)*MAX_NEIGHBORHOOD, 0);
01260 Point2D<int> eH((width/2 - epH/8.0*width/2)*MAX_NEIGHBORHOOD, dispH-1);
01261
01262 float spV = mV*0 + bV;
01263 float epV = mV*(width-1) + bV;
01264 Point2D<int> sV(0, (height/2 - spV/8.0*height/2)*MAX_NEIGHBORHOOD);
01265 Point2D<int> eV(dispW-1, (height/2 - epV/8.0*height/2)*MAX_NEIGHBORHOOD);
01266
01267
01268 float mn, mx;
01269 getMinMax(tempH, mn,mx);
01270 drawLine(tempH, sH, eH, mx, 1);
01271 drawLine(tempH, Point2D<int>(dispW/2,0),Point2D<int>(dispW/2,dispH-1),mx);
01272 drawLine(tempH, Point2D<int>(0,dispH/2),Point2D<int>(dispW-1,dispH/2),mx);
01273 drawLine(tempH, Point2D<int>(dispW-1,0),Point2D<int>(dispW-1,dispH-1),mx);
01274 drawDisk(tempH, Point2D<int>(dispW/2, foeLoc.j), 4, mx);
01275
01276 getMinMax(tempV, mn,mx);
01277 drawLine(tempV, sV, eV, mx, 1);
01278 drawLine(tempV, Point2D<int>(dispW/2,0),Point2D<int>(dispW/2,dispH-1),mx);
01279 drawLine(tempV, Point2D<int>(0,dispH/2),Point2D<int>(dispW-1,dispH/2),mx);
01280 drawDisk(tempV, Point2D<int>(foeLoc.i, dispH/2), 4, mx);
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297 itsFoeMap = gaussianBlob<float>(Dims(width, height),
01298 Point2D<int>(-bV/mV, -bH/mH), 7, 7);
01299 inplaceNormalize(itsFoeMap, 0.0F, 1.0F);
01300
01301
01302 return foeLoc;
01303
01304
01305
01306
01307
01308
01309 }
01310
01311
01312 Point2D<int> FoeDetector::computeFoeAverage
01313 (rutz::shared_ptr<OpticalFlow> flow)
01314 {
01315 Point2D<int> foeLoc(-1, -1);
01316
01317 float maxShift = 16.0;
01318
01319 Dims imSize = flow->getImageDims();
01320 uint width = imSize.w()/MAX_NEIGHBORHOOD;
01321 uint height = imSize.h()/MAX_NEIGHBORHOOD;
01322
01323 Image<float> tempH(width, height, ZEROS);
01324 Image<float> tempV(width, height, ZEROS);
01325 std::vector<Point2D<float> > hVals; std::vector<float> hW;
01326 std::vector<Point2D<float> > vVals; std::vector<float> vW;
01327
01328 std::vector<rutz::shared_ptr<FlowVector> > flowVectors =
01329 flow->getFlowVectors();
01330
01331
01332
01333
01334 for(uint i = 0; i < flowVectors.size(); i++)
01335 {
01336
01337 Point2D<float> pt1 = flowVectors[i]->p1;
01338
01339 float angle = flowVectors[i]->angle;
01340 float length = flowVectors[i]->mag;
01341 float val = 1;
01342
01343 float sinAng = sin(angle/180.0*M_PI);
01344 float cosAng = cos(angle/180.0*M_PI);
01345
01346
01347
01348 float dy = length * sinAng;
01349 if(dy > maxShift) dy = maxShift;
01350 if(dy < -maxShift) dy = -maxShift;
01351
01352 float dx = length * cosAng;
01353 if(dx > maxShift) dx = maxShift;
01354 if(dx < -maxShift) dx = -maxShift;
01355
01356 uint lH = uint(width/2 - dy/maxShift*width/2);
01357 uint lV = uint(height/2 - dx/maxShift*height/2);
01358 if(lH == width) lH--; if(lV == height) lV--;
01359 if(lH == width) lH--; if(lV == height) lV--;
01360
01361 int pi = int(pt1.i/MAX_NEIGHBORHOOD);
01362 int pj = int(pt1.j/MAX_NEIGHBORHOOD);
01363
01364
01365
01366
01367 float tH = tempH.getVal(lH, pj);
01368 float tV = tempV.getVal(pi, lV);
01369
01370 if(val > .20)
01371 {
01372 tempH.setVal(lH, pj, val + tH);
01373 tempV.setVal(pi, lV, val + tV);
01374
01375 hVals.push_back(Point2D<float>(pj,dy)); hW.push_back(val);
01376 vVals.push_back(Point2D<float>(pi,dx)); vW.push_back(val);
01377 }
01378 }
01379
01380
01381
01382
01383 double sumXY = 0.0; double sumX = 0.0;
01384 double sumY = 0.0; double sumX2 = 0.0;
01385 double wsum = 0.0;
01386 for(uint i = 0; i < hVals.size(); i++)
01387 {
01388 wsum += hW[i];
01389
01390
01391 sumXY += hW[i] * (hVals[i].i * hVals[i].j);
01392
01393
01394 sumX += hW[i] * hVals[i].i;
01395
01396
01397 sumY += hW[i] * hVals[i].j;
01398
01399
01400 sumX2 += hW[i] * hVals[i].i*hVals[i].i;
01401 }
01402
01403 double n = wsum;
01404 double mH = (n*sumXY - sumX*sumY)/(n*sumX2 - sumX*sumX);
01405 double bH = (sumY - mH*sumX)/n;
01406 foeLoc.j = -bH/mH * MAX_NEIGHBORHOOD;
01407 LINFO("x = %10.5fx + %10.5f: %10.5f", mH, bH,-bH/mH);
01408
01409 sumXY = 0.0; sumX = 0.0; sumY = 0.0; sumX2 = 0.0;
01410 wsum = 0.0;
01411 for(uint i = 0; i < vVals.size(); i++)
01412 {
01413 wsum += vW[i];
01414
01415
01416 sumXY += vW[i] * (vVals[i].i * vVals[i].j);
01417
01418
01419 sumX += vW[i] * vVals[i].i;
01420
01421
01422 sumY += vW[i] * vVals[i].j;
01423
01424
01425 sumX2 += vW[i] * vVals[i].i*vVals[i].i;
01426 }
01427
01428 n = wsum;
01429 float mV = (n*sumXY - sumX*sumY)/(n*sumX2 - sumX*sumX);
01430 float bV = (sumY - mV*sumX)/n;
01431 foeLoc.i = -bV/mV * MAX_NEIGHBORHOOD;
01432 LINFO("y = %10.5fx + %10.5f: %10.5f", mV, bV,-bV/mV);
01433
01434 LINFO("FOE: (%3d %3d)", foeLoc.i, foeLoc.j);
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452 tempH = zoomXY(tempH, MAX_NEIGHBORHOOD);
01453 tempV = zoomXY(tempV, MAX_NEIGHBORHOOD);
01454 uint dispW = width*MAX_NEIGHBORHOOD;
01455 uint dispH = height*MAX_NEIGHBORHOOD;
01456
01457 float spH = mH*0 + bH;
01458 float epH = mH*(height-1) + bH;
01459
01460 Point2D<int> sH((width/2 - spH/8.0*width/2)*MAX_NEIGHBORHOOD, 0);
01461 Point2D<int> eH((width/2 - epH/8.0*width/2)*MAX_NEIGHBORHOOD, dispH-1);
01462
01463 float spV = mV*0 + bV;
01464 float epV = mV*(width-1) + bV;
01465 Point2D<int> sV(0, (height/2 - spV/8.0*height/2)*MAX_NEIGHBORHOOD);
01466 Point2D<int> eV(dispW-1, (height/2 - epV/8.0*height/2)*MAX_NEIGHBORHOOD);
01467
01468
01469 float mn, mx;
01470 getMinMax(tempH, mn,mx);
01471 drawLine(tempH, sH, eH, mx, 1);
01472 drawLine(tempH, Point2D<int>(dispW/2,0),Point2D<int>(dispW/2,dispH-1),mx);
01473 drawLine(tempH, Point2D<int>(0,dispH/2),Point2D<int>(dispW-1,dispH/2),mx);
01474 drawLine(tempH, Point2D<int>(dispW-1,0),Point2D<int>(dispW-1,dispH-1),mx);
01475 drawDisk(tempH, Point2D<int>(dispW/2, foeLoc.j), 4, mx);
01476
01477 getMinMax(tempV, mn,mx);
01478 drawLine(tempV, sV, eV, mx, 1);
01479 drawLine(tempV, Point2D<int>(dispW/2,0),Point2D<int>(dispW/2,dispH-1),mx);
01480 drawLine(tempV, Point2D<int>(0,dispH/2),Point2D<int>(dispW-1,dispH/2),mx);
01481 drawDisk(tempV, Point2D<int>(foeLoc.i, dispH/2), 4, mx);
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495 itsFoeMap = gaussianBlob<float>(Dims(width, height),
01496 Point2D<int>(-bV/mV, -bH/mH), 7, 7);
01497 inplaceNormalize(itsFoeMap, 0.0F, 1.0F);
01498
01499
01500
01501
01502
01503 return foeLoc;
01504 }
01505
01506
01507 Layout<byte> FoeDetector::getMTfeaturesDisplay(Image<byte> image)
01508 {
01509 return itsMT->getMTfeaturesDisplay(image);
01510 }
01511
01512
01513 void FoeDetector::print
01514 (Image<float> img,
01515 uint si, uint ei, uint sj, uint ej, bool stop)
01516 {
01517 for(uint y = sj; y < ej; y++)
01518 {
01519 for(uint x = si; x < ei; x++)
01520 printf("%10.3f ", img.getVal(x,y));
01521 printf("\n");
01522 }
01523 if(stop) Raster::waitForKey();
01524 }
01525
01526
01527 void FoeDetector::display(Image<float> img, std::string info)
01528 {
01529 LINFO("%s", info.c_str());
01530 uint w = img.getWidth();
01531 uint h = img.getHeight();
01532 itsWin->setDims(Dims(w,h));
01533 itsWin->drawImage(img,0,0);
01534 Raster::waitForKey();
01535 }
01536
01537
01538 void FoeDetector::display(ImageSet<float> imgs, std::string info)
01539 {
01540 LINFO("%s", info.c_str());
01541 uint w = imgs[0].getWidth();
01542 uint h = imgs[0].getHeight();
01543 itsWin->setDims(Dims(w,h));
01544
01545 for(uint i = 0; i < imgs.size(); i++)
01546 {
01547 uint scale = uint(pow(2.0, i));
01548 itsWin->drawImage(zoomXY(imgs[i], scale),0,0);
01549 Raster::waitForKey();
01550 }
01551 }
01552
01553
01554
01555
01556
01557