00001
00002
00003
00004
00005
00006
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
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
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
00060
00061 vector<list<LinePair> > segs;
00062 createSegmentsFromLines2(rows,segs,spaceX,spaceY);
00063 if (segs.empty()) return;
00064
00065
00066
00067
00068
00069
00070 sort<vector<list<LinePair> >::iterator>(segs.begin(),segs.end(),ListSizeOrder());
00071 edgeScanner.threshold = minEdgeThreshold;
00072
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
00101 LinePair lp(temp,Vector2<int>(x,y));
00102
00103
00104
00105 rows.push_back(lp);
00106
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
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
00133 }
00134
00135 void RBallSpecialist2::addBallPercept(Geometry::Circle &circle,double validity)
00136 {
00137
00138
00139
00140 if (roundness < 0.6 || validity < 0.3) return;
00141
00142
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
00164 Vector2<int> center((int)circle.center.x,(int)circle.center.y);
00165
00166
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
00185 }
00186
00187 double RBallSpecialist2::validateCircle(Geometry::Circle &circle)
00188 {
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 double size = 1;
00200
00201 double maxRadius = 25 ;
00202 size = circle.radius;
00203
00204 if (size > maxRadius ) size = maxRadius;
00205 size = size/maxRadius;
00206
00207
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
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
00228
00229 int margin = (int) (((maxX - minX) + (maxY - minY))/(2*counts) + (double)0.5);
00230
00231 if (margin < 2) margin = 2;
00232
00233
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
00262
00263
00264
00265
00266
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
00372 if (distance > best) continue;
00373 best = distance;
00374 circle = current;
00375 }
00376
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
00450
00451
00452
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
00484
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
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547