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

Modules/ImageProcessor/RasterImageProcessor/RBallSpecialist2.cpp

Go to the documentation of this file.
00001 /**
00002 * @file RBallSpecialist2.cpp
00003 * 
00004 * This file contains the implementation of class RBallSpecialist2.
00005 *
00006 * @author <a href="mailto:sadprofessor@web.de">Bernd Schmidt</a>
00007 */
00008 #include "RBallSpecialist2.h"
00009 #include <algorithm>
00010 #include <stdlib.h>
00011 #include <time.h>
00012 #include <list>
00013 #include <bitset>
00014 #include "Tools/Location.h"
00015 #include "Tools/RingBuffer.h"
00016 
00017 using namespace std;
00018 
00019 RBallSpecialist2::RBallSpecialist2(RasterImageProcessor &processor,RasterStrategy &strat):
00020   RasterSpecialist(processor),
00021 //  edgeDetector(4),
00022   edgeScanner(processor),
00023   numberOfEdgePoints(0),
00024   points(MAX_EDGE_POINTS),
00025   roundness(0)
00026 {   
00027   strategy = &strat;
00028   preScanNeeded = true;
00029   postScanNeeded = true;
00030 
00031   InBinaryFile stream(getLocation().getFilename("ball.thr"));
00032 
00033   if(stream.exists()){ 
00034     stream >> threshold;
00035     stream >> minEdgeThreshold;
00036   }
00037     else{ 
00038     threshold = 30;
00039     minEdgeThreshold = 30;
00040   }
00041 
00042   OUTPUT(idText,text,"ball-thr: " << threshold);
00043   OUTPUT(idText,text,"edge-thr: " << minEdgeThreshold);
00044 
00045 }
00046 
00047 RBallSpecialist2::~RBallSpecialist2()
00048 {
00049 
00050 }
00051 /** Executes the post-processing. */
00052 void RBallSpecialist2::executePostProcessing()
00053 {   
00054   Geometry::Circle circle;
00055   double validity = 0;
00056   int spaceX = 2;
00057   int spaceY = 8;
00058   RasterSpecialist::Box bounds(0,0,0,0);
00059   //OUTPUT(idText,text,"ball post process");
00060   
00061   vector<list<LinePair> > segs;
00062   createSegmentsFromLines2(rows,segs,spaceX,spaceY);
00063   if (segs.empty()) return;
00064 
00065   //DEBUG-CODE
00066   //for (int i = 0;i<segs.size();i++){
00067   //  OUTPUT(idText,text,"ball: seg: " << segs[i].size());  
00068   //}
00069 
00070   sort<vector<list<LinePair> >::iterator>(segs.begin(),segs.end(),ListSizeOrder());
00071   edgeScanner.threshold = minEdgeThreshold;
00072   //TODO: algo für 1 - 3 Punkte implementieren (Spezialfälle)
00073   if (createBox(segs.back(),bounds)){   
00074     int width = bounds.maxX-bounds.minX;
00075     int height = bounds.minY-bounds.maxY;
00076     int size = width > height ? width : height;
00077     if (size > rip->image.cameraInfo.resolutionHeight/2)
00078       edgeScanner.threshold = minEdgeThreshold;
00079     else{
00080       edgeScanner.threshold = threshold;
00081       if (size < 20)
00082         edgeScanner.threshold += 15;
00083     }
00084     if (size > 4){
00085       validity = calculateLargeCircle(bounds,circle);
00086     }
00087     else{
00088       if (!filterBallPoints(segs.back())) return;   
00089       if (numberOfEdgePoints < 4) validity = calculateSmallCircle(circle);
00090       else validity = calculateCircleByEdges(circle);
00091     }
00092   }
00093   addBallPercept(circle,validity);  
00094 }
00095 
00096 void RBallSpecialist2::invokeOnPreScan(int x,int y){
00097   
00098   if (!strategy->insideBall) temp = Vector2<int>(x,y);
00099   else{
00100     //sich ein Paar merken
00101     LinePair lp(temp,Vector2<int>(x,y));
00102     //edgeScanner.ballScanWest(lp.v1.x,lp.v1.y);
00103     //edgeScanner.ballScanEast(lp.v2.x,lp.v2.y);
00104   
00105     rows.push_back(lp);
00106     //OUTPUT(idText,text,"pair accepted: " << x << " " << y);
00107     LINE(imageProcessor_ball1,
00108       lp.v1.x,lp.v1.y, 
00109       lp.v2.x,lp.v2.y, 
00110       0.5, Drawings::ps_solid, Drawings::red);    
00111   }
00112 }
00113 
00114 void RBallSpecialist2::invokeOnPostScan(int x,int y)
00115 {
00116   //not needed
00117 }
00118 int RBallSpecialist2::getType()
00119 {
00120   return __RBallSpecialist; 
00121 }
00122 
00123 void RBallSpecialist2::init()
00124 { 
00125   postScanNeeded = true;
00126   preScanNeeded = true;
00127   roundness = 0;
00128   rows.clear();
00129   
00130   edgeScanner.threshold = minEdgeThreshold;
00131 
00132 //  OUTPUT(idText,text,"lines-size: " << lines.size());
00133 }
00134 
00135 void RBallSpecialist2::addBallPercept(Geometry::Circle &circle,double validity)
00136 { 
00137 //  OUTPUT(idText,text,"Dirty-test: " << validity);
00138 //  OUTPUT(idText,text,"Roundness-test: " << roundness);
00139 
00140   if (roundness < 0.6 || validity < 0.3) return;
00141   
00142   //putting both together and test again
00143   validity = (roundness + validity)/2.0f;
00144   if(validity < 0.5) return;
00145 
00146 
00147   if (Geometry::getDistanceToLine(rip->getHorizon(),circle.center) > 0) return;
00148 
00149   
00150   Vector2<int> bottomPoint((int)circle.center.x,(int)(circle.center.y + circle.radius));
00151   Vector2<int> pointOnField;
00152   if(!Geometry::calculatePointOnField(bottomPoint.x,bottomPoint.y,
00153     rip->cameraMatrix,rip->image.cameraInfo,pointOnField)) return;
00154 
00155   
00156 
00157   CIRCLE(imageProcessor_ball1,
00158     (int)circle.center.x, 
00159     (int)circle.center.y, 
00160     (int)circle.radius,
00161     1, Drawings::ps_solid, Drawings::blue);
00162     
00163 //  OUTPUT(idText,text,"Ball-Validity: " << validity);
00164     Vector2<int> center((int)circle.center.x,(int)circle.center.y);
00165 
00166   //Ball zum Percept hinzufügen
00167   Vector2<double> angles;
00168     Geometry::calculateAnglesForPoint(
00169     center,
00170     rip->cameraMatrix, rip->image.cameraInfo, angles);
00171 
00172 
00173   
00174   
00175   rip->ballPercept.add(
00176     rip->image.cameraInfo,
00177     center,
00178     circle.radius,
00179     angles, 
00180     Geometry::pixelSizeToAngleSize(circle.radius,rip->image.cameraInfo),
00181     rip->cameraMatrix.translation, 
00182     rip->cameraMatrix.isValid);
00183 
00184   //OUTPUT(idText,text,"Ball-Distance: " << rip->ballPercept.getDistanceSizeBased());
00185 }
00186 
00187 double RBallSpecialist2::validateCircle(Geometry::Circle &circle)
00188 { 
00189 
00190   /*CIRCLE(imageProcessor_ball1,
00191   (int)circle.center.x, 
00192   (int)circle.center.y, 
00193   (int)circle.radius,
00194   0.3, Drawings::ps_solid, Drawings::white);
00195   */
00196   
00197   
00198   /*Validity using size of the radius */
00199   double size = 1;
00200   
00201   double maxRadius =  25  /*((double)176)/(double)7*/;
00202   size = circle.radius;
00203 
00204   if (size > maxRadius ) size = maxRadius;
00205   size = size/maxRadius;
00206 
00207   /*Validity using dirty Points*/
00208   double pValidity = 1;
00209   int points = 1;
00210   int validPoints = 1;
00211   int counts = 7;
00212 
00213   double r2 = circle.radius * circle.radius;
00214   
00215   int minX = (int) (circle.center.x - circle.radius);
00216   int minY = (int) (circle.center.y - circle.radius);
00217   int maxX = (int) (circle.center.x + circle.radius);
00218   int maxY = (int) (circle.center.y + circle.radius);
00219 
00220   //merging imageBounds with circle Bounds
00221 
00222   if (minX < 0) minX = 0;
00223   if (minY < 0) minY = 0;
00224   if (maxX > rip->image.cameraInfo.resolutionWidth) maxX = rip->image.cameraInfo.resolutionWidth;
00225   if (maxY > rip->image.cameraInfo.resolutionHeight) maxY = rip->image.cameraInfo.resolutionHeight;
00226   
00227   //if (maxX > 176) maxX = 176;
00228   //if (maxY > 144) maxY = 144;
00229   int margin = (int) (((maxX - minX) + (maxY - minY))/(2*counts) + (double)0.5);
00230   //OUTPUT(idText,text,"Margin: " << margin);
00231   if (margin < 2) margin = 2;
00232 
00233   //counting validPoints
00234   if (maxX > margin) maxX -= margin;
00235   if (maxY > margin) maxY -= margin;
00236   
00237   for (int x = minX; x < maxX; x += margin)
00238     for (int y = minY; y < maxY - margin; y+= margin){
00239     points++;
00240     
00241     colorClass color = getColor(x,y);
00242     
00243     if (Geometry::insideCircle(circle,r2,x,y)){
00244       if (color == orange)
00245         validPoints++;
00246       else{
00247         DOT(imageProcessor_ball1, x, y, Drawings::white, Drawings::red);
00248       }
00249     }
00250     else if (color == green || color == white || color == gray || 
00251          color == yellow || color == skyblue){
00252       validPoints++;
00253     }
00254     else{
00255       DOT(imageProcessor_ball1, x, y, Drawings::white, Drawings::red);
00256     }
00257     
00258   }
00259 
00260   pValidity = (double)validPoints/(double)points;
00261   //OUTPUT(idText,text,"validPoints: " << validPoints);
00262   //OUTPUT(idText,text,"allPoints: " << points);
00263   //OUTPUT(idText,text,"Size-Validity: " << size);
00264   //OUTPUT(idText,text,"DirtyPoints-Validity: " << pValidity);
00265   //OUTPUT(idText,text,"Ball-Validity: " << (size + pValidity*4)/5);
00266   //return (size + pValidity*2)/3 ;
00267   return pValidity;
00268 }
00269 
00270 bool RBallSpecialist2::filterBallPoints(std::list<LinePair>& segment){
00271   numberOfEdgePoints = 0;
00272   if (segment.empty()) return false;
00273 
00274   list<LinePair>::iterator it = segment.begin();
00275   list<LinePair>::iterator temp;
00276   int row = it->v1.y;
00277 
00278   if (isEdge(it->v1.x,it->v1.y)){
00279     points[numberOfEdgePoints] = it->v1;
00280     numberOfEdgePoints++;
00281     DOT(imageProcessor_ball1, it->v1.x, it->v1.y,
00282       Drawings::white, Drawings::green);
00283   }
00284   temp = it;
00285 
00286   for (it++;it!=segment.end();it++){
00287     if (row != it->v1.y) row = it->v1.y;
00288     else {
00289       temp = it;
00290       continue;
00291     };
00292     
00293     if (isEdge(temp->v2.x,temp->v2.y)){
00294       points[numberOfEdgePoints] = temp->v2;
00295       numberOfEdgePoints++;
00296       DOT(imageProcessor_ball1, it->v2.x, it->v2.y,
00297         Drawings::white, Drawings::green);
00298       if (numberOfEdgePoints == MAX_EDGE_POINTS){
00299           return true;
00300       }
00301     }
00302 
00303     if (isEdge(it->v1.x,it->v1.y)){
00304       points[numberOfEdgePoints] = it->v1;
00305       numberOfEdgePoints++;
00306       DOT(imageProcessor_ball1, it->v1.x, it->v1.y,
00307         Drawings::white, Drawings::green);
00308       if (numberOfEdgePoints == MAX_EDGE_POINTS){
00309           return true;
00310       }
00311     }
00312     temp = it;
00313   }
00314   it = --segment.end();
00315   if (isEdge(it->v1.x,it->v1.y)){
00316     points[numberOfEdgePoints] = it->v1;
00317     numberOfEdgePoints++;
00318     DOT(imageProcessor_ball1, it->v1.x, it->v1.y,
00319         Drawings::white, Drawings::green);
00320   }
00321 
00322   if (numberOfEdgePoints > 3) return true;
00323   else return false;
00324 }
00325 
00326 double RBallSpecialist2::validateEdgePoints(Geometry::Circle &circle){
00327   double validity = 0;
00328   int validPoints = 0;
00329   double dist = 0;
00330   
00331   for (int i = 0;i<numberOfEdgePoints;i++){
00332     Vector2<double> vertex(points[i].x,points[i].y);
00333     dist = fabs((circle.center - vertex).abs() - circle.radius);
00334     if (dist < MAX_CIRCLE_DIST) validPoints++;
00335   }
00336   validity = ((double)validPoints)/(double)numberOfEdgePoints;
00337 
00338   return validity;
00339 }
00340 
00341 double RBallSpecialist2::middleEdgePointDist(Geometry::Circle &circle){
00342   double validity = 0;
00343   double dist = 0;
00344   
00345   for (int i = 0;i<numberOfEdgePoints;i++){
00346     Vector2<double> vertex(points[i].x,points[i].y);
00347     dist += fabs((circle.center - vertex).abs() - circle.radius);
00348   }
00349   validity = dist/(double)numberOfEdgePoints;
00350 
00351   return validity;
00352 }
00353 
00354 double RBallSpecialist2::calculateCircleByEdges(Geometry::Circle& circle){
00355   Geometry::Circle current;
00356   int chances = 20;
00357   double best = 1000;
00358   double validity = 0;
00359   double distance = 0;
00360   int r1 = 0;
00361   int r2 = 0;
00362   int r3 = 0;
00363 
00364   for(int i = 0;i<chances;i++){
00365     r1 = rand()%numberOfEdgePoints;
00366     do{ r2 = rand()%numberOfEdgePoints; }while(r2 == r1);
00367     do{ r3 = rand()%numberOfEdgePoints; }while(r3 == r1 || r3 == r2);
00368     current = Geometry::getCircle(points[r1],points[r2],points[r3]);
00369     
00370     distance = middleEdgePointDist(current);
00371     //OUTPUT(idText,text,"dist-test: " << distance);
00372     if (distance > best) continue;
00373     best = distance;
00374     circle = current;
00375   }
00376   //OUTPUT(idText,text,"dist-best: " << best);
00377   roundness = validateEdgePoints(circle);
00378   validity = validateCircle(circle);
00379   return validity;
00380 }
00381 
00382 bool RBallSpecialist2::createBox(std::list<LinePair>& segment,
00383                  RasterSpecialist::Box& box){
00384   if (segment.empty()) return false;
00385   list<LinePair>::iterator it = segment.begin();
00386   list<LinePair>::iterator temp = it;
00387   int row = it->v1.y;
00388 
00389   box.minY = row;
00390   box.maxY = segment.back().v1.y;
00391   box.minX = +100000;
00392   box.maxX = -100000;
00393 
00394 
00395   for (it++;it!=segment.end();it++){
00396     if (row != it->v1.y) row = it->v1.y;
00397     else {
00398       temp = it;
00399       continue;
00400     };
00401     if (temp->v2.x > box.maxX) box.maxX = temp->v2.x;
00402     if (temp->v1.x < box.minX) box.minX = temp->v1.x;
00403     temp = it;
00404   }
00405 
00406   LINE(imageProcessor_ball1,
00407   box.minX,box.minY, 
00408   box.maxX,box.minY, 
00409   2, Drawings::ps_solid, Drawings::orange);
00410   
00411   LINE(imageProcessor_ball1,
00412   box.maxX,box.minY,  
00413   box.maxX,box.maxY, 
00414   2, Drawings::ps_solid, Drawings::orange); 
00415 
00416   LINE(imageProcessor_ball1,
00417   box.maxX,box.maxY,
00418   box.minX,box.maxY, 
00419   2, Drawings::ps_solid, Drawings::orange); 
00420 
00421   LINE(imageProcessor_ball1,
00422   box.minX,box.maxY, 
00423   box.minX,box.minY, 
00424   2, Drawings::ps_solid, Drawings::orange); 
00425 
00426 
00427   return true;
00428 }
00429 
00430 double RBallSpecialist2::calculateLargeCircle(
00431     const Box& input,Geometry::Circle& circle)
00432 { 
00433   numberOfEdgePoints = 0;
00434   int cx = (input.minX + input.maxX)/2;
00435   int cy = (input.minY + input.maxY)/2;
00436 
00437     
00438   Vector2<int> start,aim,scan;
00439   double step = pi2/MAX_EDGE_POINTS;
00440   start.x = cx;
00441   start.y = cy;
00442   for (int i = 0;i<MAX_EDGE_POINTS;i++)
00443   {
00444     scan = start;
00445     Vector2<double> dir;
00446     getCoordinatesByAngle((double)i*step,dir.x,dir.y);
00447     aim.x = (int)dir.x + start.x;
00448     aim.y = (int)dir.y + start.y;
00449     /*LINE(imageProcessor_ball1,
00450       aim.x,aim.y, 
00451       start.x,start.y, 
00452       1, Drawings::ps_solid, Drawings::orange);*/ 
00453     
00454     if(edgeScanner.scan(scan.x,scan.y,dir))
00455     {
00456       points[numberOfEdgePoints++] = scan;
00457       LINE(imageProcessor_ball1,
00458         scan.x,scan.y, 
00459         start.x,start.y, 
00460         1, Drawings::ps_solid, Drawings::white); 
00461     }
00462     
00463   }
00464   if (numberOfEdgePoints<3) return 0;
00465   return calculateCircleByEdges(circle);
00466 
00467 }
00468 
00469 double RBallSpecialist2::calculateSmallCircle(Geometry::Circle& circle){
00470   switch (numberOfEdgePoints){
00471   case 3: 
00472     circle = Geometry::getCircle(points[0],points[1],points[2]);
00473     if (circle.radius > 5){
00474       circle.radius = 5;
00475       roundness = 0.61f;
00476       return 0;
00477     }
00478     roundness = 0.61f;
00479     return validateCircle(circle);
00480   case 2: 
00481     circle.center.x = (points[0].x + points[1].x)/2;
00482     circle.center.y = (points[0].x + points[1].x)/2;
00483     //only guessed, the radius could be approximated whith a few
00484     //scanlines through the area of the two points
00485     circle.radius = (points[0] - points[1]).abs()/1.6;
00486     if (circle.radius > 5){
00487       circle.radius = 5;
00488       roundness = 0.61f;
00489       return 0;
00490     }
00491     return validateCircle(circle);
00492   case 1:
00493     circle.center.x = points[0].x;
00494     circle.center.y = points[0].y;
00495     circle.radius = 1.5;
00496     roundness = 0.61f;
00497     return validateCircle(circle);
00498   default:
00499     roundness = 0;
00500     return 0;
00501 
00502   }
00503 };
00504 
00505 void RBallSpecialist2::setThreshold(int threshold){
00506   this->threshold = threshold;
00507 }
00508 
00509 /*
00510 * Change log :
00511 * 
00512 * $Log: RBallSpecialist2.cpp,v $
00513 * Revision 1.5  2004/09/06 12:02:26  schmidtb
00514 * commented almost all members, removed warnings in documentation
00515 
00516 * did further code clean up
00517 *
00518 * Revision 1.4  2004/09/03 11:32:13  nistico
00519 * References to MSH2004ColorCorrector removed, now uses the unified ColorCorrector
00520 *
00521 * Revision 1.3  2004/09/02 07:59:29  schmidtb
00522 * Added RasterImageProcessor to repository, because we used it for the OpenChallenge.
00523 *
00524 * Revision 1.4  2004/05/25 13:27:33  schmidtb
00525 * modified version of rip for open-challenge
00526 *
00527 * Revision 1.9  2004/05/22 16:01:49  pg_besc
00528 * -modified version of rip for bridge-recognition
00529 *
00530 * Revision 1.6  2004/04/22 16:57:26  pg_besc
00531 * new version of RBallSpecialist2, now omidirectional scans for detection
00532 *
00533 * Revision 1.5  2004/04/20 07:50:27  pg_besc
00534 * new version of pre scan
00535 *
00536 * Revision 1.4  2004/04/15 19:09:02  pg_besc
00537 * merged code
00538 *
00539 * Revision 1.3  2004/03/25 16:15:22  nistico
00540 * Compatibility with MSH2004BallLocator restored
00541 *
00542 * Revision 1.2  2004/03/25 15:26:10  pg_besc
00543 * made some changes
00544 *
00545 *
00546 *
00547 */

Generated on Thu Sep 23 19:57:30 2004 for GT2004 by doxygen 1.3.6