Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

Modules/ImageProcessor/GT2005ImageProcessor/GT2005GoalRecognizer.h

Go to the documentation of this file.
00001 /**
00002 * @file GT2005GoalRecognizer.h
00003 *
00004 * @author <a href="mailto:oberlies@sim.tu-darmstadt.de">Tobias Oberlies</a>
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  * Macro to handle the stupid problem, that the DEBUG_IMAGE_SET_PIXEL_xxx macros need the 
00019  * debug image identifier at compile time. There are two instances of this class, and one of 
00020  * them uses imageProcessorGoal1 and the other imageProcessorGoal2.
00021  * @param targetcolor A variable that contains the goal colour at runtime.
00022  * @param x The x-value of the pixel to be set (at runtime).
00023  * @param y The y-value of the pixel to be set (at runtime).
00024  * @param drawcolor Text suitable to complete DEBUG_IMAGE_SET_PIXEL_ at compile time.
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  * @class GT2005GoalRecognizer
00056  *
00057  * TODO: Write Summary
00058  * 
00059  * @author <a href="mailto:oberlies@sim.tu-darmstadt.de"Tobias Oberlies</a>
00060  */ 
00061 class GT2005GoalRecognizer
00062 {
00063 private: // nested classes and enums
00064 
00065   /**
00066    * TODO: Write Summary
00067    */
00068   enum EdgeType
00069   {
00070     none = 0,
00071     edge,
00072     deviationWithoutEdge,
00073     imageBorder       // Must be the last one
00074   };
00075 
00076   /**
00077    * TODO: Write Summary
00078    */
00079   class EdgeDetector
00080   {
00081   public:
00082     /** Constructor. */
00083     EdgeDetector(colorClass target);
00084     EdgeDetector(colorClass target, Vector3<int> referenceColor, int referenceColorBase);
00085 
00086     /**
00087      * Investigates the next pixel and reports, wether an edge, or repeated deviation of 
00088      * the pixel colours (without the indications of an edge) have been detected. It is 
00089      * assumed that edges are quite sharp and that the color beyond the edge is 
00090      * significantly different to the goal colour. In case of a blurred edge or a steady
00091      * color gradient the method will (eventually) return deviationWithoutEdge.
00092      */
00093     inline EdgeType inspectPixel(const Vector2<int>& point, int index, const colorClass& colorCls, const Vector3<int>& color)
00094     {
00095       // Check, if pixel is in target colour class
00096       if (colorCls == targetColorClass)
00097       {
00098         // Store as possible edge point
00099         lastPointInClass = point;
00100         lastPointInClassIndex = index;
00101         connectedToClass = true;
00102 
00103         // Update the reference colour
00104         // The reference colour is an average of the colour of the last pixels. If
00105         // this method has been called on less than eight pixels, the average is 
00106         // equally weighted. Otherwise recent pixels have a higher weight (1/8 for 
00107         // the last one etc.)
00108         referenceColor = (referenceColor * referenceColorBase + color) / (referenceColorBase+1);
00109         if (referenceColorBase < 7)
00110           ++referenceColorBase;
00111 
00112         // Decrease deviation counter (since this pixel has no deviation)
00113         deviationCounter = deviationCounter<=4 ? 0 : deviationCounter-4;
00114 
00115         // Reset edge counter (assuming no pixels in the goal color class beyond the edge)
00116         edgeCounter = 0;
00117       }
00118       else if (colorCls != noColor && colorCls != ignoredClassification && colorCls != gray)
00119       {
00120         // Pixel is classified as a different colour. Take this as an indication for
00121         // an edge.
00122         ++edgeCounter;
00123         deviationCounter = deviationCounter + 2;
00124 
00125         // From now on don't use pixels with tolerable (but non-zero) pixels as 
00126         // lastPointInClass, because they're likely to be noise
00127         connectedToClass = false;
00128     
00129         // Check whether an edge or excessive deviation have been detected
00130         if (edgeCounter >= 3)
00131           return edge;
00132         else if (deviationCounter >= 10)
00133           return deviationWithoutEdge;
00134 
00135       }
00136       else
00137       {
00138         // Pixel is not classified in any color class, so calculate the distance to 
00139         // the reference color for further investigations
00140         int dist = distance(color);
00141 
00142         // Update deviation and edge counters
00143         if (dist < classThreshold)
00144         {
00145           // This pixel very likely to be part of the goal.
00146           if (edgeCounter > 0)
00147             --edgeCounter;
00148           ++deviationCounter;
00149 
00150           // Store as possible edge point if there haven't been any (strong) 
00151           // indications for an edge since the last pixel in the target class
00152           if (connectedToClass)
00153           {
00154             lastPointInClass = point;
00155             lastPointInClassIndex = index;
00156           }
00157         }
00158         else if(dist < edgeThreshold)
00159         {
00160           // This pixel is neither likely to be part of the goal, nor to be bejond
00161           // the edge. Since we're looking for a reasonably sharp edge, only few
00162           // pixels in this distance range are expected to occur.
00163           deviationCounter = deviationCounter + 2;
00164           connectedToClass = false;
00165         }
00166         else
00167         {
00168           // This pixel is likely to be beyond the edge of the goal. In this case
00169           // the edge counter is increased more than the deviation counter (with 
00170           // respect to their trigger thresholds 3 and 10). Hence in case of a 
00171           // clear edge, the edge will trigger before the deviation.
00172           ++edgeCounter;
00173           deviationCounter = deviationCounter + 2;
00174           connectedToClass = false;
00175         }
00176 
00177         // Check whether an edge or excessive deviation have been detected
00178         if (edgeCounter >= 3)
00179           return edge;
00180         else if (deviationCounter >= 10)
00181           return deviationWithoutEdge;
00182       }
00183 
00184       return none;
00185     }
00186 
00187     /**
00188      * Returns the last point in or near the target colour class. If inspectPixel 
00189      * returned the value edge the returned point is located just before the edge. 
00190      */
00191     inline Vector2<int> getLastPointInClass()
00192     {
00193       return lastPointInClass;
00194     };
00195 
00196     /**
00197      * Similar to getLastPointInClass().
00198      */
00199     inline void getLastPointInClass(Vector2<int>& point)
00200     {
00201       point = lastPointInClass;
00202     }
00203 
00204     /**
00205      * Similar to getLastPointInClass(), but also returns the index of the 
00206      * lastPointInClass.
00207      */
00208     inline void getLastPointInClass(Vector2<int>& point, int& index)
00209     {
00210       point = lastPointInClass;
00211       index = lastPointInClassIndex;
00212     }
00213 
00214     /**
00215      * Similar to getLastPointInClass(), but returns the index of the lastPointInClass
00216      * instead of the poinst itself.
00217      */
00218     inline int getLastIndexInClass()
00219     {
00220       return lastPointInClassIndex;
00221     }
00222 
00223     /**
00224      * Resets the edge detection state while keeping the reference colour.
00225      * @param defaultLast The value returned by getLastPointInClass if none of the
00226      * inspected pixels is in or near the target colour class.
00227      * @param connectedToClass Assume that the first pixel that is inspected is 
00228      * connected to the target colour class.
00229      */
00230     void clear(const Vector2<int>& defaultLast, bool connectedToClass)
00231     {
00232       // Reset the counters
00233       deviationCounter = 0;
00234       edgeCounter = 0;
00235 
00236       // Set provided default values
00237       this->lastPointInClass = defaultLast;
00238       this->lastPointInClassIndex = -1;
00239       this->connectedToClass = connectedToClass;
00240     }
00241 
00242     /**
00243      * Reset the edge detection state while keeping the reference colour.
00244      */
00245     void clear()
00246     {
00247       // Reset the counters
00248       deviationCounter = 0;
00249       edgeCounter = 0;
00250 
00251       // Keep the lastPointInClass value assuming that the scan begins there (hence
00252       // first pixel inspected is connected to the class)
00253       lastPointInClassIndex = -1;
00254       connectedToClass = true;
00255     }
00256 
00257     /**
00258      * Reset the reference colour and the edge detector state.
00259      */
00260     void reset()
00261     {
00262       // Reset the reference colour
00263       referenceColorBase = 0;
00264 
00265       // Reset the counters
00266       deviationCounter = 0;
00267       edgeCounter = 0;
00268 
00269       // Keep the lastPointInClass value assuming that the scan begins there (hence
00270       // first pixel inspected is connected to the class)
00271       lastPointInClassIndex = -1;
00272       connectedToClass = false;
00273     }
00274 
00275     /**
00276      * Sets the reference colour.
00277      */
00278     void setReferenceColor(const Vector3<int>& color, int referenceColorBase)
00279     {
00280       this->referenceColor = color;
00281       this->referenceColorBase = referenceColorBase;
00282     };
00283 
00284     /**
00285      * Returns the reference colour.
00286      */
00287     void getReferenceColor(Vector3<int>& result)
00288     {
00289       result = this->referenceColor;
00290     };
00291 
00292   private: // methods
00293     
00294     /**
00295      * The inverse covariance matrix of the goal color variation (needed for the 
00296      * Mahalalanobis distance).
00297      * @param goalColour the goal colour class
00298      * TODO: load these values from a file
00299      **/
00300     static Matrix3x3<int> inverseCovarianceMatrix(colorClass goalColor);
00301 
00302     /**
00303      * Calculates the Mahalanobis distance of the given colour to the reference colour.
00304      */
00305     inline int distance(const Vector3<int>& color)
00306     {
00307       // Calculate difference in each channel
00308       Vector3<int> difference = color - referenceColor;
00309 
00310       // Weigh with respect to usual variation
00311       return (invCovar * difference) * difference;  // in MATLAB syntax: difference'*invCovar*difference
00312     }
00313 
00314   private: // class members
00315 
00316     /** The maximum distance from the reference colour that is tolerated for a pixel to
00317         be considered in the target colour class. */
00318     static const float classThreshold;
00319 
00320     /** The minimum distance from the reference colour that pixels on the other side of
00321         an edge need to have. This value is greater than classThreshold. */
00322     static const float edgeThreshold;
00323 
00324 
00325   private: // members
00326 
00327     /** The colour class of the goal. */
00328     const colorClass targetColorClass;
00329 
00330     /** Colour class that is not considered as an indication for an edge. */
00331     const colorClass ignoredClassification;
00332 
00333     /** The inverse covariance matrix of the goal colour. It is used to calculate the
00334         Mahalanobis distance between the reference colour and the current colour for 
00335         pixels in no colour class (or an ignored one). */
00336     const Matrix3x3<int> invCovar;
00337 
00338     /** The reference colour for distance calculations. It is an average of recent 
00339         pixels that were classified in the target colour class. */
00340     Vector3<int> referenceColor;
00341     int referenceColorBase;
00342 
00343     /** Counter to detect the end of an area in target colour without an edge. */
00344     int deviationCounter;
00345 
00346     /** Counter to detect an edge. */
00347     int edgeCounter;
00348 
00349 
00350     /** Last pixel in the target colour class (or within tolerable distance). */
00351     Vector2<int> lastPointInClass;
00352 
00353     /** The index of the last point in/near the target colour class. By default, this
00354         value is -1, so it can be used to check whether any pixel was considered to be
00355         in/near the target colour class. */
00356     int lastPointInClassIndex;
00357 
00358     /** Current pixel is connected via to a pixel in the target colour class only via 
00359         pixels within tolerable distance, i.e. there hasn't been a pixel with a distance
00360         greater than the classDistance threshold since the last pixel classified in the
00361         target class (without distance). As long as this variable is true, points with
00362         tolerable distance will be stored as lastPointInClass. */
00363     bool connectedToClass;
00364     
00365   }; // class GT2005GoalRecognizer::EdgeDetector
00366 
00367   
00368   /**
00369    * TODO: Write Summary
00370    */
00371   struct EdgePointList
00372   {
00373   private: // members
00374     
00375     // Arrays to store the edge points and their type
00376     enum {maxPoints = 20};
00377     Vector2<int> edgePoint[maxPoints];
00378     GT2005GoalRecognizer::EdgeType edgeType[maxPoints];
00379 
00380     // Current number of edge points
00381     int numberOfPoints;
00382 
00383     // Number of edge points of a certain type
00384     int numberOfType[imageBorder+1];
00385 
00386 
00387   public: // methods
00388 
00389     /** Constructs an empty list. */
00390     EdgePointList()
00391       : numberOfPoints(0)
00392     {
00393       for (int i=0; i<=imageBorder; ++i)
00394         numberOfType[i] = 0;
00395     }
00396 
00397     /** Add an edge point to the list. */
00398     inline void add(Vector2<int>& point, GT2005GoalRecognizer::EdgeType type)
00399     {
00400       // Ignore if too many points
00401       if (numberOfPoints>=maxPoints)
00402         return;
00403 
00404       // Store point and increase counters
00405       edgePoint[numberOfPoints] = point;
00406       edgeType[numberOfPoints] = type;
00407       ++numberOfPoints;
00408       ++numberOfType[type];
00409     }
00410 
00411     /** Returns the current size of the list. */
00412     inline int size()
00413     {
00414       return numberOfPoints;
00415     }
00416 
00417     /** Returns the number of edge points of a certain type. */
00418     inline int getCount(GT2005GoalRecognizer::EdgeType type)
00419     {
00420       return numberOfType[type];
00421     }
00422 
00423     /** Returns an element of the list. */
00424     inline Vector2<int>& operator[](int index)
00425     {
00426       return edgePoint[index];
00427     }
00428 
00429     /** Returns the type of an edge points. */
00430     inline GT2005GoalRecognizer::EdgeType getType(int index)
00431     {
00432       return edgeType[index];
00433     }
00434   }; // struct EdgePointList
00435 
00436 
00437   /**
00438    *
00439    */
00440   struct Goalpost
00441   {
00442     /** Constructs an empty goalpost hypothesis. */
00443     Goalpost() {};
00444 
00445     /** Top endpoints of the goalposts. Might not be aligned with the edge 
00446         horizontally. */
00447     Vector2<int> topPoint;
00448     Vector2<double> topPointH;
00449     bool topPointInImage; // FILL
00450 
00451     /** Bottom endpoints of the goalpost. Might not be aligned with the edge 
00452         horizontally. */
00453     Vector2<int> bottomPoint;
00454     Vector2<double> bottomPointH;
00455 
00456     /** Goalpost is standing on the green field. */
00457     bool onGreen;
00458 
00459     /** Height and height not conting the image border. */
00460     int height;
00461     int visibleHeight; // FILL
00462 
00463     /** A point aligned with the edge of the goalpost. */
00464     Vector2<int> edgePoint;
00465     Vector2<double> edgePointH;
00466 
00467     /** Number of strong and weak edge points detected. */
00468     int strongEdgeCount;
00469     int weakEdgeCount;
00470 
00471     /** Straightness */
00472     /** Slope */
00473 
00474     /** Scans towards the edge detected unbound goal-coloured areas. This often happens 
00475         when the goal is detected again after the scan along the cross bar failed. If 
00476         this value is set to true, all other values are invalid.*/
00477     bool nonExistant;
00478 
00479     /** Average colour of some pixels near the goalpost. This value is used to 
00480         detect the free part of goal (is done in the interpretation after the entire
00481         image was scanned) or straightnes checks. */
00482     Vector3<int> color;
00483 
00484   }; // struct Goalpost
00485 
00486   /**
00487    * TODO: Write Summary
00488    */
00489   struct GoalHypothesis : public Streamable
00490   {
00491     /** Constructs an empty GoalHypothesis with default values. */
00492     GoalHypothesis(){};
00493     
00494     /** The left and right goalpost. */
00495     Goalpost goalpost[2];
00496 
00497     /** Right end of cross bar. */
00498     Vector2<int> crossBarEndpoint;
00499     Vector2<double> crossBarEndpointH;
00500 
00501     /** Goal width. */
00502     int width;
00503 
00504     /** Goal height (the maximum of the goalpost heights). */
00505     int height;
00506 
00507     /** Cross bar is in image -> if true, height cannot be determined. */
00508     bool crossBarInImage;
00509     // TODO: set top left point to begin of visible crossbar (if higher)
00510 
00511     /** There is green below the goal hypthesis. */
00512     bool onGreen;
00513 
00514 
00515     /** Streaming operators */
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       //STREAM(goalpost[0].strongEdgeCount);
00525       //STREAM(goalpost[0].weakEdgeCount);
00526       STREAM(goalpost[0].visibleHeight);
00527       STREAM(goalpost[0].nonExistant);
00528       STREAM(goalpost[1].height);
00529       STREAM(goalpost[1].onGreen);
00530       //STREAM(goalpost[1].strongEdgeCount);
00531       //STREAM(goalpost[1].weakEdgeCount);
00532       STREAM(goalpost[1].visibleHeight);
00533       STREAM(goalpost[1].nonExistant);
00534       STREAM_REGISTER_FINISH();
00535     }
00536 
00537   }; // struct GoalHypothesis
00538 
00539 
00540   /**
00541    * TODO: Write Summary
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 // class GT2005GoalRecognizer
00562 
00563 public:
00564 
00565   /**
00566    * Initializes the GT2005GoadRecognizer.
00567    */
00568   GT2005GoalRecognizer(colorClass color, const ImageProcessorInterfaces& interfaces, const ColorCorrector& colorCorrector, const ImageInfo& horizonInfo);
00569   
00570   /**
00571    * Destructor
00572    */
00573   ~GT2005GoalRecognizer() {};
00574   
00575   /**
00576    * Call this method on every new image before the first call of inspect pixel.
00577    */
00578   void notifyAboutNewImage();
00579   
00580   /**
00581    * Call this method to use seen flags (from the LandmarkPercept object) as areas 
00582    * where not to look for goals.
00583    */
00584   void notifyAboutFlags();
00585 
00586   /**
00587    *
00588    */
00589   void notifyAboutFinish();
00590 
00591 
00592   inline void notifyAboutNewScanline(const Vector2<int>& scanLineStart)
00593   {
00594     // Reset counter for detection of goal candidates
00595     detectionCounter = 0;
00596 
00597     // Calculate how many pixels on this scanline should be skipped in order to prevent 
00598     // previously recognized goals to be found again
00599     calculateLockedPixels(scanLineStart);
00600   };
00601 
00602 
00603   inline void inspectPixel(const Vector2<int>& point, const colorClass& color)
00604   {
00605     // Check if this pixel is inside the area that has been analysed before
00606     if (--lockedPixels < 0)
00607     {
00608 
00609       // Check if pixel has target colour 
00610       if (color == goalColor)
00611       {
00612         // Increase counter
00613         ++detectionCounter;
00614 
00615         // When counter reaches 3, start the actual goal detection routine
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)//inspectNeighbourhood(point))
00622           {
00623             // Analyze this blob
00624             analyzeGoal(point);
00625 
00626             // Recalculate the number of locked pixels on this scanline
00627             recalculateLockedPixels(point);
00628 
00629             //testDone = true;
00630             //testNow = false;
00631             detectionCounter = 0;
00632           }
00633           else
00634           {
00635             // Take into account that there were only few goal-coloured pixels in
00636             // the neighbourhood of the current pixel
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         // Decrease counter
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: // methods
00658   
00659   /** */
00660   bool inspectNeighbourhood(const Vector2<int>& point);
00661 
00662   /** 
00663    * point copied on purpose
00664    */
00665   void analyzeGoal(Vector2<int> startPoint);
00666 
00667 
00668   /** 
00669    * direction of edge normalized!!
00670    * imageBorderScanned: to prevent that one image border is scanned again, never necessary
00671    * in correct goal case
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    * scans first from focus+scanLineOffset, using detector[0]!!
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    * case noBorder mustn't be ignored -> scanning hasn't been done before or doesn't make sense 
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    * direction of edge normalized!!
00723    * bottomPoint copied on purpose!!
00724    */
00725   bool detectGreenBelowGoalpost(Vector2<int> bottomPoint, 
00726                                 const Vector2<double>& directionOfEdge, 
00727                                 int goalpostHeight);
00728 
00729   /**
00730    * Returns true if the point is within one pixel distance to the image border.
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    * pop lock, chekc flag intersection, calculate locked pixels
00767    */
00768   void calculateLockedPixels(const Vector2<int>& scanLineStart);
00769 
00770   /** 
00771    * Recalculates the number of locked pixels after a goal has been detected. The scan
00772    * will continue on the same scanline where it was before, so in this case it is not
00773    * necessary to manage (i.e. remove) locked areas and to check if the scanline is 
00774    * near the flags.
00775    */
00776   void recalculateLockedPixels(const Vector2<int>& currentPoint);
00777 
00778 
00779 private: // members
00780 
00781   /** The colour class of the goal to be detected by this object. */
00782   const colorClass goalColor;
00783 
00784   /** Collection of references to objects that are needed by this object, e.g. the current 
00785       image, objects used to store the processing results, etc. */
00786   const ImageProcessorInterfaces& interfaces;
00787 
00788   /** Object containing useful information related to the current horizon. */
00789   const ImageInfo& horizonInfo;
00790 
00791   /** Reference to the color correction object. */
00792   const ColorCorrector& colorCorrector;
00793 
00794 
00795   /** Counter to detect accumulations of goal-coloured pixels. Used by the method 
00796       inspectPixel. */ 
00797   int detectionCounter;
00798 
00799   /** Number of pixels that will not be inspected, because they are inside previously 
00800       analysed areas. */
00801   int lockedPixels;
00802 
00803   /** Stack containing the locked area from previous goal analysises. This is to prevent 
00804       that goal-coloured blobs are analysed twice. With inspectPixel being called on pixel 
00805       from left to right and top to bottom, it is sufficient to store the bottom left point 
00806       of the locked areas. */
00807   //TODO: There is a rare case when this doesn't work as intended (i.e. a goal is scannede 3 or more times) -> search the problem
00808   enum {lockAreaStackSize = 2};
00809   Vector2<double> lockAreaStack[lockAreaStackSize];
00810   int lockAreaCount;
00811 
00812   /** HY-Ranges where flags have been detected. Scanlines that are within that range are 
00813       not scanned at all to avoid that goals are detected within flags. */
00814   enum {maxFlagLocks = 3};
00815   Range<double> flagLock[maxFlagLocks];
00816   int flagLockCount;
00817   unsigned long frameNumberImage, frameNumberFlags;
00818 
00819 
00820   /** Detected goal hypothesises. */
00821   enum {maxHypothesises = 5};
00822   GoalHypothesis hypothesis[maxHypothesises];
00823   int hypothesisCount;
00824 
00825   /** Declare raster image which will take debug information.
00826       NB: due to the f**king macros, I have to declare both images, even though only need 
00827       one per instance. */
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

Generated on Mon Mar 20 21:59:47 2006 for GT2005 by doxygen 1.3.6