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