00001
00002
00003
00004
00005
00006
00007 #ifndef GT2005GoalRecognizer_h_
00008 #define GT2005GoalRecognizer_h_
00009
00010 #include "Modules/ImageProcessor/ImageProcessor.h"
00011 #include "Modules/ImageProcessor/ImageProcessorTools/ImageProcessorUtilityClasses.h"
00012 #include "Modules/ImageProcessor/ImageProcessorTools/BresenhamLineScan.h"
00013 #include "Modules/ImageProcessor/ImageProcessorTools/ColorCorrector.h"
00014 #include "Tools/Range.h"
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef NDEBUG
00027 #define STUPID_DEBUG_IMAGE_SET_PIXEL(targetcolor, x, y, drawcolor) \
00028 if (targetcolor == yellow) \
00029 { \
00030 DEBUG_IMAGE_SET_PIXEL_##drawcolor(imageProcessorGoal1, (x), (y)); \
00031 } \
00032 else \
00033 { \
00034 DEBUG_IMAGE_SET_PIXEL_##drawcolor(imageProcessorGoal2, (x), (y)); \
00035 }
00036
00037 #define N_STUPID_DEBUG_IMAGE_SET_PIXEL(targetcolor, x, y, drawcolor) \
00038 if (targetcolor == yellow) \
00039 { \
00040 N_SET_COLORED_PIXEL_IN_GRAY_SCALE_IMAGE(goalRecognizerYellow, (x), (y), (drawcolor)); \
00041 } \
00042 else \
00043 { \
00044 N_SET_COLORED_PIXEL_IN_GRAY_SCALE_IMAGE(goalRecognizerBlue, (x), (y), (drawcolor)); \
00045 }
00046
00047 #else
00048
00049 #define STUPID_DEBUG_IMAGE_SET_PIXEL(targetcolor, x, y, drawcolor) ;
00050 #define N_STUPID_DEBUG_IMAGE_SET_PIXEL(targetcolor, x, y, drawcolor) ;
00051
00052 #endif
00053
00054
00055
00056
00057
00058
00059
00060
00061 class GT2005GoalRecognizer
00062 {
00063 private:
00064
00065
00066
00067
00068 enum EdgeType
00069 {
00070 none = 0,
00071 edge,
00072 deviationWithoutEdge,
00073 imageBorder
00074 };
00075
00076
00077
00078
00079 class EdgeDetector
00080 {
00081 public:
00082
00083 EdgeDetector(colorClass target);
00084 EdgeDetector(colorClass target, Vector3<int> referenceColor, int referenceColorBase);
00085
00086
00087
00088
00089
00090
00091
00092
00093 inline EdgeType inspectPixel(const Vector2<int>& point, int index, const colorClass& colorCls, const Vector3<int>& color)
00094 {
00095
00096 if (colorCls == targetColorClass)
00097 {
00098
00099 lastPointInClass = point;
00100 lastPointInClassIndex = index;
00101 connectedToClass = true;
00102
00103
00104
00105
00106
00107
00108 referenceColor = (referenceColor * referenceColorBase + color) / (referenceColorBase+1);
00109 if (referenceColorBase < 7)
00110 ++referenceColorBase;
00111
00112
00113 deviationCounter = deviationCounter<=4 ? 0 : deviationCounter-4;
00114
00115
00116 edgeCounter = 0;
00117 }
00118 else if (colorCls != noColor && colorCls != ignoredClassification && colorCls != gray)
00119 {
00120
00121
00122 ++edgeCounter;
00123 deviationCounter = deviationCounter + 2;
00124
00125
00126
00127 connectedToClass = false;
00128
00129
00130 if (edgeCounter >= 3)
00131 return edge;
00132 else if (deviationCounter >= 10)
00133 return deviationWithoutEdge;
00134
00135 }
00136 else
00137 {
00138
00139
00140 int dist = distance(color);
00141
00142
00143 if (dist < classThreshold)
00144 {
00145
00146 if (edgeCounter > 0)
00147 --edgeCounter;
00148 ++deviationCounter;
00149
00150
00151
00152 if (connectedToClass)
00153 {
00154 lastPointInClass = point;
00155 lastPointInClassIndex = index;
00156 }
00157 }
00158 else if(dist < edgeThreshold)
00159 {
00160
00161
00162
00163 deviationCounter = deviationCounter + 2;
00164 connectedToClass = false;
00165 }
00166 else
00167 {
00168
00169
00170
00171
00172 ++edgeCounter;
00173 deviationCounter = deviationCounter + 2;
00174 connectedToClass = false;
00175 }
00176
00177
00178 if (edgeCounter >= 3)
00179 return edge;
00180 else if (deviationCounter >= 10)
00181 return deviationWithoutEdge;
00182 }
00183
00184 return none;
00185 }
00186
00187
00188
00189
00190
00191 inline Vector2<int> getLastPointInClass()
00192 {
00193 return lastPointInClass;
00194 };
00195
00196
00197
00198
00199 inline void getLastPointInClass(Vector2<int>& point)
00200 {
00201 point = lastPointInClass;
00202 }
00203
00204
00205
00206
00207
00208 inline void getLastPointInClass(Vector2<int>& point, int& index)
00209 {
00210 point = lastPointInClass;
00211 index = lastPointInClassIndex;
00212 }
00213
00214
00215
00216
00217
00218 inline int getLastIndexInClass()
00219 {
00220 return lastPointInClassIndex;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230 void clear(const Vector2<int>& defaultLast, bool connectedToClass)
00231 {
00232
00233 deviationCounter = 0;
00234 edgeCounter = 0;
00235
00236
00237 this->lastPointInClass = defaultLast;
00238 this->lastPointInClassIndex = -1;
00239 this->connectedToClass = connectedToClass;
00240 }
00241
00242
00243
00244
00245 void clear()
00246 {
00247
00248 deviationCounter = 0;
00249 edgeCounter = 0;
00250
00251
00252
00253 lastPointInClassIndex = -1;
00254 connectedToClass = true;
00255 }
00256
00257
00258
00259
00260 void reset()
00261 {
00262
00263 referenceColorBase = 0;
00264
00265
00266 deviationCounter = 0;
00267 edgeCounter = 0;
00268
00269
00270
00271 lastPointInClassIndex = -1;
00272 connectedToClass = false;
00273 }
00274
00275
00276
00277
00278 void setReferenceColor(const Vector3<int>& color, int referenceColorBase)
00279 {
00280 this->referenceColor = color;
00281 this->referenceColorBase = referenceColorBase;
00282 };
00283
00284
00285
00286
00287 void getReferenceColor(Vector3<int>& result)
00288 {
00289 result = this->referenceColor;
00290 };
00291
00292 private:
00293
00294
00295
00296
00297
00298
00299
00300 static Matrix3x3<int> inverseCovarianceMatrix(colorClass goalColor);
00301
00302
00303
00304
00305 inline int distance(const Vector3<int>& color)
00306 {
00307
00308 Vector3<int> difference = color - referenceColor;
00309
00310
00311 return (invCovar * difference) * difference;
00312 }
00313
00314 private:
00315
00316
00317
00318 static const float classThreshold;
00319
00320
00321
00322 static const float edgeThreshold;
00323
00324
00325 private:
00326
00327
00328 const colorClass targetColorClass;
00329
00330
00331 const colorClass ignoredClassification;
00332
00333
00334
00335
00336 const Matrix3x3<int> invCovar;
00337
00338
00339
00340 Vector3<int> referenceColor;
00341 int referenceColorBase;
00342
00343
00344 int deviationCounter;
00345
00346
00347 int edgeCounter;
00348
00349
00350
00351 Vector2<int> lastPointInClass;
00352
00353
00354
00355
00356 int lastPointInClassIndex;
00357
00358
00359
00360
00361
00362
00363 bool connectedToClass;
00364
00365 };
00366
00367
00368
00369
00370
00371 struct EdgePointList
00372 {
00373 private:
00374
00375
00376 enum {maxPoints = 20};
00377 Vector2<int> edgePoint[maxPoints];
00378 GT2005GoalRecognizer::EdgeType edgeType[maxPoints];
00379
00380
00381 int numberOfPoints;
00382
00383
00384 int numberOfType[imageBorder+1];
00385
00386
00387 public:
00388
00389
00390 EdgePointList()
00391 : numberOfPoints(0)
00392 {
00393 for (int i=0; i<=imageBorder; ++i)
00394 numberOfType[i] = 0;
00395 }
00396
00397
00398 inline void add(Vector2<int>& point, GT2005GoalRecognizer::EdgeType type)
00399 {
00400
00401 if (numberOfPoints>=maxPoints)
00402 return;
00403
00404
00405 edgePoint[numberOfPoints] = point;
00406 edgeType[numberOfPoints] = type;
00407 ++numberOfPoints;
00408 ++numberOfType[type];
00409 }
00410
00411
00412 inline int size()
00413 {
00414 return numberOfPoints;
00415 }
00416
00417
00418 inline int getCount(GT2005GoalRecognizer::EdgeType type)
00419 {
00420 return numberOfType[type];
00421 }
00422
00423
00424 inline Vector2<int>& operator[](int index)
00425 {
00426 return edgePoint[index];
00427 }
00428
00429
00430 inline GT2005GoalRecognizer::EdgeType getType(int index)
00431 {
00432 return edgeType[index];
00433 }
00434 };
00435
00436
00437
00438
00439
00440 struct Goalpost
00441 {
00442
00443 Goalpost() {};
00444
00445
00446
00447 Vector2<int> topPoint;
00448 Vector2<double> topPointH;
00449 bool topPointInImage;
00450
00451
00452
00453 Vector2<int> bottomPoint;
00454 Vector2<double> bottomPointH;
00455
00456
00457 bool onGreen;
00458
00459
00460 int height;
00461 int visibleHeight;
00462
00463
00464 Vector2<int> edgePoint;
00465 Vector2<double> edgePointH;
00466
00467
00468 int strongEdgeCount;
00469 int weakEdgeCount;
00470
00471
00472
00473
00474
00475
00476
00477 bool nonExistant;
00478
00479
00480
00481
00482 Vector3<int> color;
00483
00484 };
00485
00486
00487
00488
00489 struct GoalHypothesis : public Streamable
00490 {
00491
00492 GoalHypothesis(){};
00493
00494
00495 Goalpost goalpost[2];
00496
00497
00498 Vector2<int> crossBarEndpoint;
00499 Vector2<double> crossBarEndpointH;
00500
00501
00502 int width;
00503
00504
00505 int height;
00506
00507
00508 bool crossBarInImage;
00509
00510
00511
00512 bool onGreen;
00513
00514
00515
00516 virtual void serialize(In* in, Out* out)
00517 {
00518 STREAM_REGISTER_BEGIN();
00519 STREAM(height);
00520 STREAM(width);
00521 STREAM(crossBarInImage);
00522 STREAM(goalpost[0].height);
00523 STREAM(goalpost[0].onGreen);
00524
00525
00526 STREAM(goalpost[0].visibleHeight);
00527 STREAM(goalpost[0].nonExistant);
00528 STREAM(goalpost[1].height);
00529 STREAM(goalpost[1].onGreen);
00530
00531
00532 STREAM(goalpost[1].visibleHeight);
00533 STREAM(goalpost[1].nonExistant);
00534 STREAM_REGISTER_FINISH();
00535 }
00536
00537 };
00538
00539
00540
00541
00542
00543 enum ImageBorderSide
00544 {
00545 topBorder = 0,
00546 leftBorder = 1,
00547 bottomBorder = 2,
00548 rightBorder = 3,
00549 noBorder
00550 };
00551
00552 enum FreeSide
00553 {
00554 noFreeSide,
00555 leftSide,
00556 rightSide,
00557 bothSides
00558 };
00559
00560
00561
00562
00563 public:
00564
00565
00566
00567
00568 GT2005GoalRecognizer(colorClass color, const ImageProcessorInterfaces& interfaces, const ColorCorrector& colorCorrector, const ImageInfo& horizonInfo);
00569
00570
00571
00572
00573 ~GT2005GoalRecognizer() {};
00574
00575
00576
00577
00578 void notifyAboutNewImage();
00579
00580
00581
00582
00583
00584 void notifyAboutFlags();
00585
00586
00587
00588
00589 void notifyAboutFinish();
00590
00591
00592 inline void notifyAboutNewScanline(const Vector2<int>& scanLineStart)
00593 {
00594
00595 detectionCounter = 0;
00596
00597
00598
00599 calculateLockedPixels(scanLineStart);
00600 };
00601
00602
00603 inline void inspectPixel(const Vector2<int>& point, const colorClass& color)
00604 {
00605
00606 if (--lockedPixels < 0)
00607 {
00608
00609
00610 if (color == goalColor)
00611 {
00612
00613 ++detectionCounter;
00614
00615
00616 if (detectionCounter >= 4)
00617 {
00618 STUPID_DEBUG_IMAGE_SET_PIXEL(goalColor, point.x, point.y, BLUE);
00619 N_STUPID_DEBUG_IMAGE_SET_PIXEL(goalColor, point.x, point.y, goalColor);
00620
00621 if (true)
00622 {
00623
00624 analyzeGoal(point);
00625
00626
00627 recalculateLockedPixels(point);
00628
00629
00630
00631 detectionCounter = 0;
00632 }
00633 else
00634 {
00635
00636
00637 detectionCounter = 1;
00638 }
00639 }
00640 else
00641 STUPID_DEBUG_IMAGE_SET_PIXEL(goalColor, point.x, point.y, BLUE);
00642 N_STUPID_DEBUG_IMAGE_SET_PIXEL(goalColor, point.x, point.y, goalColor);
00643 }
00644 else
00645 {
00646
00647 --detectionCounter;
00648 if (detectionCounter<0)
00649 detectionCounter = 0;
00650 STUPID_DEBUG_IMAGE_SET_PIXEL(goalColor, point.x, point.y, GRAY);
00651 N_STUPID_DEBUG_IMAGE_SET_PIXEL(goalColor, point.x, point.y, gray);
00652 }
00653 }
00654 };
00655
00656
00657 private:
00658
00659
00660 bool inspectNeighbourhood(const Vector2<int>& point);
00661
00662
00663
00664
00665 void analyzeGoal(Vector2<int> startPoint);
00666
00667
00668
00669
00670
00671
00672
00673 void analyzeGoalpost(GT2005GoalRecognizer::EdgeDetector* detector,
00674 const Vector2<double>& directionOfEdge,
00675 bool leftGoalpost,
00676 Vector2<int>& focus,
00677 GT2005GoalRecognizer::Goalpost& result,
00678 bool* imageBorderScanned);
00679
00680
00681 void scanCrossBar(GT2005GoalRecognizer::EdgeDetector* detector,
00682 Vector2<int>& focus,
00683 GT2005GoalRecognizer::GoalHypothesis& result,
00684 bool* imageBorderScanned);
00685
00686
00687
00688
00689 GT2005GoalRecognizer::EdgeType detectEdgeTwice(GT2005GoalRecognizer::EdgeDetector* detector,
00690 Vector2<int>& focus,
00691 BresenhamLineScan& scanLine,
00692 const Vector2<int>& scanLineOffset,
00693 int maxScanLength,
00694 EdgePointList& edgePoints);
00695
00696
00697
00698 GT2005GoalRecognizer::EdgeType detectEdge(GT2005GoalRecognizer::EdgeDetector& detector,
00699 Vector2<int>& focus,
00700 BresenhamLineScan& direction,
00701 int maxScanLength,
00702 int& pixelsUntilEdge);
00703
00704
00705 GT2005GoalRecognizer::EdgeType scanAlongLine(GT2005GoalRecognizer::EdgeDetector* detector,
00706 Vector2<int>& focus,
00707 BresenhamLineScan& scanLine,
00708 const Vector2<int>& scanLineOffset,
00709 int maximumScan,
00710 int& pixelsScanned);
00711
00712
00713
00714
00715 GT2005GoalRecognizer::ImageBorderSide scanOnImageBorder(GT2005GoalRecognizer::EdgeDetector* detector,
00716 Vector2<int>& focus,
00717 const Vector2<double>& targetDirection,
00718 int maxBorderDistance,
00719 bool* scannedSides);
00720
00721
00722
00723
00724
00725 bool detectGreenBelowGoalpost(Vector2<int> bottomPoint,
00726 const Vector2<double>& directionOfEdge,
00727 int goalpostHeight);
00728
00729
00730
00731
00732 inline bool nearImageBorder(const Vector2<int>& point, int maxDistance)
00733 {
00734 return point.x <= maxDistance ||
00735 point.y <= maxDistance ||
00736 point.x >= horizonInfo.maxImageCoordinates.x-maxDistance ||
00737 point.y >= horizonInfo.maxImageCoordinates.y-maxDistance;
00738 }
00739
00740
00741 void mergeFragments(bool* deletedHypothesises);
00742
00743
00744
00745 void interpretResults(GT2005GoalRecognizer::EdgeDetector* detector, bool* deletedHypothesises);
00746
00747
00748 void publishResults(const GT2005GoalRecognizer::GoalHypothesis& goal,
00749 const bool* visibleGoalpost,
00750 const GT2005GoalRecognizer::FreeSide freeSide,
00751 const Vector2<int>& endpointOfFreePart,
00752 const bool* freePartOnImageBorder);
00753
00754
00755
00756 GT2005GoalRecognizer::FreeSide detectFreePartOfGoal(GT2005GoalRecognizer::EdgeDetector* detector,
00757 const GT2005GoalRecognizer::GoalHypothesis& goal,
00758 int& freeWidth,
00759 Vector2<int>& otherSide,
00760 bool* onImageBorder);
00761
00762
00763 void lockArea(double x, double y, bool onGreen);
00764
00765
00766
00767
00768 void calculateLockedPixels(const Vector2<int>& scanLineStart);
00769
00770
00771
00772
00773
00774
00775
00776 void recalculateLockedPixels(const Vector2<int>& currentPoint);
00777
00778
00779 private:
00780
00781
00782 const colorClass goalColor;
00783
00784
00785
00786 const ImageProcessorInterfaces& interfaces;
00787
00788
00789 const ImageInfo& horizonInfo;
00790
00791
00792 const ColorCorrector& colorCorrector;
00793
00794
00795
00796
00797 int detectionCounter;
00798
00799
00800
00801 int lockedPixels;
00802
00803
00804
00805
00806
00807
00808 enum {lockAreaStackSize = 2};
00809 Vector2<double> lockAreaStack[lockAreaStackSize];
00810 int lockAreaCount;
00811
00812
00813
00814 enum {maxFlagLocks = 3};
00815 Range<double> flagLock[maxFlagLocks];
00816 int flagLockCount;
00817 unsigned long frameNumberImage, frameNumberFlags;
00818
00819
00820
00821 enum {maxHypothesises = 5};
00822 GoalHypothesis hypothesis[maxHypothesises];
00823 int hypothesisCount;
00824
00825
00826
00827
00828 DECLARE_DEBUG_IMAGE(imageProcessorGoal1);
00829 DECLARE_DEBUG_IMAGE(imageProcessorGoal2);
00830 N_DECLARE_DEBUG_GRAY_SCALE_IMAGE(goalRecognizerYellow);
00831 N_DECLARE_DEBUG_GRAY_SCALE_IMAGE(goalRecognizerBlue);
00832
00833 };
00834 #endif // GT2005GoalRecognizer