00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "GT2005ImageProcessor.h"
00011 #include "Tools/Debugging/Debugging.h"
00012 #include "Tools/Debugging/GenericDebugData.h"
00013 #include "Tools/FieldDimensions.h"
00014 #include "Tools/Math/Geometry.h"
00015 #include "GT2005ImageProcessorTools.h"
00016 #include "Representations/Perception/JPEGImage.h"
00017
00018
00019
00020 const double GT2005ImageProcessor::verticalScanLineTopAboveHorizon = 15.0;
00021 const double GT2005ImageProcessor::verticalScanLineLength13 = 55.0;
00022 const double GT2005ImageProcessor::verticalScanLineLength2 = 75.0;
00023 const double GT2005ImageProcessor::verticalScanLineSpacing = 4.0;
00024
00025
00026 #define PLOT(p,c) COMPLEX_DRAWING(imageProcessor_general,plot(p,c))
00027
00028 const int Y = 0,
00029 U = cameraResolutionWidth_ERS7,
00030 V = 2 * cameraResolutionWidth_ERS7;
00031
00032 const double GT2005ImageProcessor::minAngleBetweenFlagAndGoal = 0.05;
00033
00034
00035 GT2005ImageProcessor::GT2005ImageProcessor(const ImageProcessorInterfaces& interfaces)
00036 : ImageProcessor(interfaces),
00037 beaconDetector(image, cameraMatrix, imageInfo.previousCameraMatrix, imageInfo, colorTable, colorCorrector, landmarksPercept),
00038 goalSpecialistY(yellow, interfaces, colorCorrector, imageInfo),
00039 goalSpecialistB(skyblue, interfaces, colorCorrector, imageInfo),
00040 ballSpecialist(colorCorrector),
00041 playerSpecialist(colorCorrector,colorTable,image,imageInfo,linesPercept,cameraMatrix,playersPercept),
00042 ballClustering(),
00043 lineFinder(colorCorrector, colorTable),
00044 circleFinder(colorCorrector, colorTable)
00045 #ifdef OC_GUIDEDOG
00046 ,guideDogRobotSpecialist(image, cameraMatrix, imageInfo.previousCameraMatrix, colorTable, colorCorrector, playersPercept)
00047 #endif
00048 {
00049 yThreshold = 15;
00050 vThreshold = 8;
00051 beaconDetector.analyzeColorTable();
00052 double c = cos(-3*pi/4);
00053 double s = sin(-3*pi/4);
00054 rotation2x2 = Matrix2x2<double>(
00055 Vector2<double>(c,-s),
00056 Vector2<double>(s,c)
00057 );
00058 }
00059
00060 void GT2005ImageProcessor::execute()
00061 {
00062 INIT_DEBUG_IMAGE(imageProcessorPlayers, image);
00063 N_INIT_DEBUG_GRAY_SCALE_IMAGE(scanLines, image);
00064
00065 xFactor = yFactor = image.cameraInfo.focalLength;
00066
00067 numberOfScannedPixels = 0;
00068
00069 lastRedMidPoint.x = 1000;
00070 lastBlueMidPoint.x = 1000;
00071
00072
00073 landmarksPercept.reset(image.frameNumber);
00074 linesPercept.reset(image.frameNumber);
00075 ballPercept.reset(image.frameNumber);
00076 playersPercept.reset(image.frameNumber);
00077 obstaclesPercept.reset(image.frameNumber);
00078 circleFinder.reset();
00079 lineFinder.reset();
00080 goalSpecialistY.notifyAboutNewImage();
00081 goalSpecialistB.notifyAboutNewImage();
00082
00083
00084 DEBUG_RESPONSE_NOT("gt05-ip:disable-multiple-ball-candidates",
00085 ballClustering.reset();
00086 );
00087
00088 DEBUG_RESPONSE("gt05-ip:enable-edge-detection",
00089 edgesPercept.reset(image.frameNumber);
00090 edgeSpecialist.reset();
00091 );
00092
00093
00094 cmTricot = cameraMatrix;
00095 cmTricot.translation.z -= 100;
00096
00097 longestBallRun = 0;
00098
00099
00100 Vector3<double> vectorInDirectionOfViewCamera(1,0,0);
00101 Vector3<double> vectorInDirectionOfViewWorld;
00102 vectorInDirectionOfViewWorld = cameraMatrix.rotation * vectorInDirectionOfViewCamera;
00103
00104 const int visualizationScale = 20;
00105 Vector3<double> vectorInDirectionOfViewWorldOld;
00106 vectorInDirectionOfViewWorldOld = imageInfo.previousCameraMatrix.rotation * vectorInDirectionOfViewCamera;
00107 Vector3<double> cameraMotionVectorWorld = vectorInDirectionOfViewWorld - vectorInDirectionOfViewWorldOld;
00108 long frameNumber = cameraMatrix.frameNumber,
00109 prevFrameNumber = imageInfo.previousCameraMatrix.frameNumber;
00110 const RobotDimensions& r = getRobotConfiguration().getRobotDimensions();
00111 double timeDiff = (frameNumber - prevFrameNumber) * r.motionCycleTime;
00112 if (prevFrameNumber == 0)
00113 timeDiff = 0;
00114 Vector2<double> currentOnGround(vectorInDirectionOfViewWorld.x, vectorInDirectionOfViewWorld.y),
00115 oldOnGround(vectorInDirectionOfViewWorldOld.x, vectorInDirectionOfViewWorldOld.y);
00116 currentOnGround.normalize();
00117 oldOnGround.normalize();
00118 Vector3<double> cameraSpeedVectorWorld(0, 0, 0);
00119 double panningVelocity = 0;
00120 if (timeDiff > 0)
00121 {
00122 cameraSpeedVectorWorld = cameraMotionVectorWorld/timeDiff;
00123 double cosAng = currentOnGround*oldOnGround;
00124 if (cosAng > 1.0)
00125 cosAng = 1.0;
00126 else
00127 if (cosAng <-1.0)
00128 cosAng = -1.0;
00129 panningVelocity = normalize(acos(cosAng))/timeDiff;
00130 }
00131 Vector3<double> cameraSpeedVectorCamera = cameraMatrix.invert().rotation * cameraSpeedVectorWorld;
00132 Vector2<double> cameraSpeedVectorImg(cameraSpeedVectorCamera.y,
00133 cameraSpeedVectorCamera.z);
00134 cameraSpeedVectorImg /= cameraSpeedVectorCamera.x +
00135 image.cameraInfo.focalLength;
00136
00137 cameraSpeedVectorImg *= image.cameraInfo.focalLength*visualizationScale;
00138 Drawings::Color arrowColor = Drawings::blue;
00139 if (fabs(panningVelocity) > pi/6)
00140 arrowColor = Drawings::red;
00141 ARROW(imageProcessor_horizon,
00142 image.cameraInfo.opticalCenter.x, image.cameraInfo.opticalCenter.y,
00143 int(image.cameraInfo.opticalCenter.x-cameraSpeedVectorImg.x), int(image.cameraInfo.opticalCenter.y-cameraSpeedVectorImg.y),
00144 3, Drawings::ps_solid, arrowColor);
00145
00146 angleBetweenDirectionOfViewAndGround =
00147 toDegrees(
00148 atan2(
00149 vectorInDirectionOfViewWorld.z,
00150 sqrt(sqr(vectorInDirectionOfViewWorld.x) + sqr(vectorInDirectionOfViewWorld.y))
00151 )
00152 );
00153
00154
00155 imageInfo.maxImageCoordinates.x = image.cameraInfo.resolutionWidth - 1;
00156 imageInfo.maxImageCoordinates.y = image.cameraInfo.resolutionHeight - 1;
00157 imageInfo.horizon = Geometry::calculateHorizon(cameraMatrix, image.cameraInfo);
00158 imageInfo.horizon.normalizeDirection();
00159
00160 imageInfo.horizonInImage = Geometry::getIntersectionPointsOfLineAndRectangle(
00161 Vector2<int>(0,0), imageInfo.maxImageCoordinates, imageInfo.horizon,
00162 imageInfo.horizonStart, imageInfo.horizonEnd);
00163
00164 imageInfo.vertLine = imageInfo.horizon;
00165 imageInfo.vertLine.direction.x = -imageInfo.vertLine.direction.y;
00166 imageInfo.vertLine.direction.y = imageInfo.horizon.direction.x;
00167
00168
00169
00170 imageInfo.rotation.c[0] = imageInfo.horizon.direction;
00171 imageInfo.rotation.c[1] = imageInfo.vertLine.direction;
00172 imageInfo.invRotation = imageInfo.rotation.invert();
00173
00174
00175
00176
00177 imageInfo.distanceTopLeftCorner = (imageInfo.invRotation*imageInfo.horizon.base).y;
00178
00179
00180
00181 landmarksPercept.cameraOffset = cameraMatrix.translation;
00182 if(imageInfo.horizonInImage)
00183 {
00184 beaconDetector.execute();
00185 }
00186
00187
00188
00189 goalSpecialistY.notifyAboutFlags();
00190 goalSpecialistB.notifyAboutFlags();
00191
00192
00193
00194 noRedCount = noBlueCount = 100;
00195 closestBottom = 40000;
00196 goalAtBorder = false;
00197
00198
00199 scanColumns();
00200 scanRows();
00201
00202
00203 goalSpecialistY.notifyAboutFinish();
00204 goalSpecialistB.notifyAboutFinish();
00205
00206
00207
00208 Vector2<double> circleMidPoint;
00209 lineFinder.execute(linesPercept, cameraMatrix, image, imageInfo, robotPose, circleFinder.getCircle(circleMidPoint), circleMidPoint);
00210
00211 DEBUG_DRAWING_FINISHED(circlePoints_image);
00212 DEBUG_DRAWING_FINISHED(circlePoints_Field);
00213
00214 DEBUG_RESPONSE("gt05-ip:enable-edge-detection",
00215
00216
00217
00218 edgeSpecialist.getEdgesPercept(edgesPercept, cameraMatrix, imageInfo.previousCameraMatrix, image);
00219 );
00220
00221
00222 ballSpecialist.resetMultiplePerceptsList(ballPercept);
00223
00224
00225
00226 DEBUG_RESPONSE_NOT("gt05-ip:disable-multiple-ball-candidates",
00227 if (longestBallRun > 2)
00228 {
00229 int numberOfCandidates = ballClustering.getSize();
00230 for (int i=0; i<numberOfCandidates; i++)
00231 {
00232 Vector2<double> temp = ballClustering.getMidpoint(i);
00233 ballCandidate.x = (int)temp.x;
00234 ballCandidate.y = (int)temp.y;
00235 DOT(imageProcessor_ball3, ballCandidate.x, ballCandidate.y, Drawings::black, Drawings::orange);
00236 ballSpecialist.searchBall(image, colorTable, cameraMatrix, imageInfo.previousCameraMatrix,
00237 ballCandidate.x, ballCandidate.y, ballPercept);
00238
00239
00240 }
00241 DEBUG_DRAWING_FINISHED(imageProcessor_multipleBallPercepts);
00242 DEBUG_DRAWING_FINISHED(multipleBallPerceptsField);
00243 }
00244 );
00245 DEBUG_RESPONSE("gt05-ip:disable-multiple-ball-candidates",
00246 if (longestBallRun > 2)
00247 {
00248 ballSpecialist.searchBall(image, colorTable, cameraMatrix, imageInfo.previousCameraMatrix,
00249 ballCandidate.x, ballCandidate.y, ballPercept);
00250 }
00251 );
00252
00253 ballSpecialist.forwardPercept(ballPercept);
00254
00255
00256 ballPercept.multiplePercepts.calculatePanningVelocityValue(panningVelocity);
00257
00258
00259
00260 filterPercepts();
00261
00262 DEBUG_RESPONSE_NOT("gt05-ip:disable-players-perception",
00263 {
00264
00265
00266 if ((linesPercept.points[LinesPercept::redRobot].numberOfPoints != 0
00267 ||linesPercept.points[LinesPercept::blueRobot].numberOfPoints != 0)
00268 && imageInfo.horizon.direction.x != 0
00269 && imageInfo.horizon.direction.y/imageInfo.horizon.direction.x < 1)
00270 {
00271 playerSpecialist.execute();
00272 }
00273 });
00274
00275
00276 #ifdef OC_GUIDEDOG
00277 guideDogRobotSpecialist.execute();
00278 #endif //OC_GUIDEDOG
00279
00280
00281 if(imageInfo.horizonInImage)
00282 {
00283 LINE(imageProcessor_horizon,
00284 imageInfo.horizonStart.x, imageInfo.horizonStart.y, imageInfo.horizonEnd.x,
00285 imageInfo.horizonEnd.y, 1, Drawings::ps_solid, Drawings::white );
00286 }
00287 NDECLARE_DEBUGDRAWING("imageProcessor:horizon", "drawingOnImage", "shows the horizon in the image");
00288 NLINE("imageProcessor:horizon",
00289 imageInfo.horizonStart.x, imageInfo.horizonStart.y,
00290 imageInfo.horizonEnd.x, imageInfo.horizonEnd.y, 2, Drawings::ps_solid, Drawings::white );
00291
00292 NDECLARE_DEBUGDRAWING("imageProcessor:obstacle detection", "drawingOnImage", "draws debug information from the obstacle detection");
00293
00294 NDECLARE_DEBUGDRAWING("imageProcessor:robot detection", "drawingOnImage", "draws debug information from the robot detection");
00295
00296
00297
00298 DEBUG_DRAWING_FINISHED(imageProcessor_horizon);
00299 DEBUG_DRAWING_FINISHED(imageProcessor_scanLines);
00300 DEBUG_DRAWING_FINISHED(imageProcessor_general);
00301 DEBUG_DRAWING_FINISHED(imageProcessor_edges);
00302 DEBUG_DRAWING_FINISHED(imageProcessor_robot_detection);
00303
00304 SEND_DEBUG_IMAGE(imageProcessorPlayers);
00305 GENERATE_DEBUG_IMAGE(imageProcessorGeneral,
00306 Image correctedImage(image);
00307 colorCorrector.correct(correctedImage);
00308 INIT_DEBUG_IMAGE(imageProcessorGeneral, correctedImage);
00309 )
00310 SEND_DEBUG_IMAGE(imageProcessorGeneral);
00311
00312 GENERATE_DEBUG_IMAGE(segmentedImage1,
00313 Image correctedImage(image);
00314 colorCorrector.correct(correctedImage);
00315 colorTable.generateColorClassImage(correctedImage, segmentedImage1ColorClassImage);
00316 )
00317 SEND_DEBUG_COLOR_CLASS_IMAGE(segmentedImage1);
00318
00319 GENERATE_DEBUG_IMAGE(imageProcessorGradients,
00320 SUSANEdgeDetectionLite edgeDetectionU(GT2005BeaconDetector::edgeThresholdU);
00321 SUSANEdgeDetectionLite edgeDetectionV(GT2005BeaconDetector::edgeThresholdV);
00322 Image edgeDetectionImage;
00323 bool edgeY;
00324 bool edgeU;
00325 bool edgeV;
00326 edgeDetectionImage.cameraInfo = image.cameraInfo;
00327 for (int y=1; y<edgeDetectionImage.cameraInfo.resolutionHeight-1; y++)
00328 {
00329 for (int x=1; x<edgeDetectionImage.cameraInfo.resolutionWidth-1; x++)
00330 {
00331 edgeY = edgeDetectionU.isEdgePoint(image, x, y, SUSANEdgeDetectionLite::componentA);
00332 edgeU = edgeDetectionU.isEdgePoint(image, x, y, SUSANEdgeDetectionLite::componentB);
00333 edgeV = edgeDetectionV.isEdgePoint(image, x, y, SUSANEdgeDetectionLite::componentC);
00334 if (edgeU&&edgeV)
00335 {
00336 edgeDetectionImage.image[y][0][x] = 210;
00337 edgeDetectionImage.image[y][1][x] = 127;
00338 edgeDetectionImage.image[y][2][x] = 127;
00339 }
00340 else if (edgeU)
00341 {
00342 edgeDetectionImage.image[y][0][x] = 130;
00343 edgeDetectionImage.image[y][1][x] = 170;
00344 edgeDetectionImage.image[y][2][x] = 80;
00345 }
00346 else if (edgeV)
00347 {
00348 edgeDetectionImage.image[y][0][x] = 130;
00349 edgeDetectionImage.image[y][1][x] = 80;
00350 edgeDetectionImage.image[y][2][x] = 170;
00351 }
00352 else if (edgeY)
00353 {
00354 edgeDetectionImage.image[y][0][x] = 255;
00355 edgeDetectionImage.image[y][1][x] = 127;
00356 edgeDetectionImage.image[y][2][x] = 127;
00357 }
00358 else
00359 {
00360 edgeDetectionImage.image[y][0][x] = image.image[y][0][x]/2;
00361 edgeDetectionImage.image[y][1][x] = image.image[y][1][x];
00362 edgeDetectionImage.image[y][2][x] = image.image[y][2][x];
00363 }
00364 edgeDetectionImage.image[y][3][x] = 128;
00365 edgeDetectionImage.image[y][4][x] = 128;
00366 edgeDetectionImage.image[y][5][x] = 128;
00367 }
00368 }
00369 INIT_DEBUG_IMAGE(imageProcessorGradients, edgeDetectionImage);
00370 )
00371 SEND_DEBUG_IMAGE(imageProcessorGradients);
00372
00373 GENERATE_DEBUG_IMAGE(imageProcessorBall,
00374 Image correctedImage(image);
00375 colorCorrector.correct(correctedImage);
00376 for (int iPBix=0; iPBix<correctedImage.cameraInfo.resolutionWidth; iPBix++)
00377 {
00378 for (int iPBiy=0; iPBiy<correctedImage.cameraInfo.resolutionHeight; iPBiy++)
00379 {
00380 correctedImage.image[iPBiy][0][iPBix]=ballSpecialist.getSimilarityToOrange(correctedImage.image[iPBiy][0][iPBix],correctedImage.image[iPBiy][1][iPBix],correctedImage.image[iPBiy][2][iPBix]);
00381 if (correctedImage.image[iPBiy][0][iPBix]==0)
00382 {
00383 correctedImage.image[iPBiy][1][iPBix]=127;
00384 correctedImage.image[iPBiy][2][iPBix]=127;
00385 }
00386 else
00387 {
00388 if (correctedImage.image[iPBiy][0][iPBix]>30)
00389 correctedImage.image[iPBiy][1][iPBix]=0;
00390 else
00391 correctedImage.image[iPBiy][1][iPBix]=255;
00392 if (correctedImage.image[iPBiy][0][iPBix]>60)
00393 correctedImage.image[iPBiy][2][iPBix]=0;
00394 else
00395 correctedImage.image[iPBiy][2][iPBix]=255;
00396 }
00397 }
00398 }
00399 INIT_DEBUG_IMAGE(imageProcessorBall, correctedImage);
00400 )
00401 SEND_DEBUG_IMAGE(imageProcessorBall);
00402 DEBUG_DRAWING_FINISHED(imageProcessor_ball4);
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 imageInfo.previousCameraMatrix = cameraMatrix;
00418 prevCmTricot = cmTricot;
00419
00420
00421
00422
00423
00424
00425 N_GENERATE_DEBUG_IMAGE(colorCorrectedAsJpeg,
00426 colorCorrectedAsJpegImage = image;
00427 colorCorrector.correct(colorCorrectedAsJpegImage);
00428 );
00429 N_SEND_DEBUG_IMAGE_AS_JPEG(colorCorrectedAsJpeg)
00430
00431 N_GENERATE_DEBUG_IMAGE(colorCorrected,
00432 colorCorrectedImage = image;
00433 colorCorrector.correct(colorCorrectedImage);
00434 );
00435 N_SEND_DEBUG_IMAGE(colorCorrected);
00436
00437 N_GENERATE_DEBUG_IMAGE(segmented,
00438 Image colorCorrectedImage(image);
00439 colorCorrector.correct(colorCorrectedImage);
00440 colorTable.generateColorClassImage(colorCorrectedImage, segmentedImage);
00441 );
00442 N_SEND_DEBUG_COLOR_CLASS_IMAGE(segmented)
00443
00444 N_GENERATE_DEBUG_IMAGE(edgeDetection,
00445 SUSANEdgeDetectionLite edgeDetectionU(GT2005BeaconDetector::edgeThresholdU);
00446 SUSANEdgeDetectionLite edgeDetectionV(GT2005BeaconDetector::edgeThresholdV);
00447 bool edgeY;
00448 bool edgeU;
00449 bool edgeV;
00450 edgeDetectionImage.cameraInfo = image.cameraInfo;
00451 for (int y=1; y<edgeDetectionImage.cameraInfo.resolutionHeight-1; y++)
00452 {
00453 for (int x=1; x<edgeDetectionImage.cameraInfo.resolutionWidth-1; x++)
00454 {
00455 edgeY = edgeDetectionU.isEdgePoint(image, x, y, SUSANEdgeDetectionLite::componentA);
00456 edgeU = edgeDetectionU.isEdgePoint(image, x, y, SUSANEdgeDetectionLite::componentB);
00457 edgeV = edgeDetectionV.isEdgePoint(image, x, y, SUSANEdgeDetectionLite::componentC);
00458 if (edgeU&&edgeV)
00459 {
00460 edgeDetectionImage.image[y][0][x] = 210;
00461 edgeDetectionImage.image[y][1][x] = 127;
00462 edgeDetectionImage.image[y][2][x] = 127;
00463 }
00464 else if (edgeU)
00465 {
00466 edgeDetectionImage.image[y][0][x] = 130;
00467 edgeDetectionImage.image[y][1][x] = 170;
00468 edgeDetectionImage.image[y][2][x] = 80;
00469 }
00470 else if (edgeV)
00471 {
00472 edgeDetectionImage.image[y][0][x] = 130;
00473 edgeDetectionImage.image[y][1][x] = 80;
00474 edgeDetectionImage.image[y][2][x] = 170;
00475 }
00476 else if (edgeY)
00477 {
00478 edgeDetectionImage.image[y][0][x] = 255;
00479 edgeDetectionImage.image[y][1][x] = 127;
00480 edgeDetectionImage.image[y][2][x] = 127;
00481 }
00482 else
00483 {
00484 edgeDetectionImage.image[y][0][x] = image.image[y][0][x]/2;
00485 edgeDetectionImage.image[y][1][x] = image.image[y][1][x];
00486 edgeDetectionImage.image[y][2][x] = image.image[y][2][x];
00487 }
00488 edgeDetectionImage.image[y][3][x] = 128;
00489 edgeDetectionImage.image[y][4][x] = 128;
00490 edgeDetectionImage.image[y][5][x] = 128;
00491 }
00492 }
00493 );
00494 N_SEND_DEBUG_IMAGE_AS_JPEG(edgeDetection);
00495
00496 N_GENERATE_DEBUG_IMAGE(ball,
00497 ballImage = image;
00498 colorCorrector.correct(ballImage);
00499 for (int iPBix=0; iPBix<ballImage.cameraInfo.resolutionWidth; iPBix++)
00500 {
00501 for (int iPBiy=0; iPBiy<ballImage.cameraInfo.resolutionHeight; iPBiy++)
00502 {
00503 ballImage.image[iPBiy][0][iPBix]=ballSpecialist.getSimilarityToOrange(ballImage.image[iPBiy][0][iPBix],ballImage.image[iPBiy][1][iPBix],ballImage.image[iPBiy][2][iPBix]);
00504 if (ballImage.image[iPBiy][0][iPBix]==0)
00505 {
00506 ballImage.image[iPBiy][1][iPBix]=127;
00507 ballImage.image[iPBiy][2][iPBix]=127;
00508 }
00509 else
00510 {
00511 if (ballImage.image[iPBiy][0][iPBix]>30)
00512 ballImage.image[iPBiy][1][iPBix]=0;
00513 else
00514 ballImage.image[iPBiy][1][iPBix]=255;
00515 if (ballImage.image[iPBiy][0][iPBix]>60)
00516 ballImage.image[iPBiy][2][iPBix]=0;
00517 else
00518 ballImage.image[iPBiy][2][iPBix]=255;
00519 }
00520 }
00521 }
00522 );
00523 N_SEND_DEBUG_IMAGE_AS_JPEG(ball);
00524
00525 N_SEND_DEBUG_GRAY_SCALE_IMAGE(scanLines);
00526 }
00527
00528 void GT2005ImageProcessor::scanColumns()
00529 {
00530
00531
00532
00533
00534
00535 double scanLineStartHY = imageInfo.distanceTopLeftCorner - verticalScanLineTopAboveHorizon;
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 double bottomLeftHX = imageInfo.invRotation.c[1].x * static_cast<double>(imageInfo.maxImageCoordinates.y);
00551 Geometry::Line scanLine(
00552 imageInfo.rotation * Vector2<double>(min(0.0, bottomLeftHX), scanLineStartHY),
00553 imageInfo.vertLine.direction);
00554
00555
00556 Vector2<double> scanLineOffset(imageInfo.horizon.direction.x * verticalScanLineSpacing, imageInfo.horizon.direction.y * verticalScanLineSpacing);
00557
00558
00559 Vector2<double> scanLineEnd2(imageInfo.vertLine.direction.x * verticalScanLineLength2, imageInfo.vertLine.direction.y * verticalScanLineLength2);
00560 Vector2<double> scanLineEnd13(imageInfo.vertLine.direction.x * verticalScanLineLength13, imageInfo.vertLine.direction.y * verticalScanLineLength13);
00561
00562
00563
00564 bool relevantForLines;
00565 int pixelsRelevantForGoal;
00566
00567 Vector2<int> topBorderIntersection, bottomBorderIntersection;
00568 Vector2<int> topEndpoint, bottomEndpoint;
00569
00570
00571 for (int i = 0; i<=80; ++i)
00572 {
00573
00574 scanLine.base += scanLineOffset;
00575
00576
00577 if(!Geometry::getIntersectionPointsOfLineAndRectangle(Vector2<int>(0,0), imageInfo.maxImageCoordinates,
00578 scanLine, topBorderIntersection, bottomBorderIntersection))
00579 {
00580
00581 break;
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 double topBorderHY = imageInfo.invRotation.c[0].y * topBorderIntersection.x
00593 + imageInfo.invRotation.c[1].y * topBorderIntersection.y;
00594 double bottomBorderHY = imageInfo.invRotation.c[0].y * bottomBorderIntersection.x
00595 + imageInfo.invRotation.c[1].y * bottomBorderIntersection.y;
00596
00597
00598 if (bottomBorderHY < scanLineStartHY)
00599 {
00600
00601 continue;
00602 }
00603
00604
00605 if (topBorderHY > scanLineStartHY)
00606 {
00607
00608 topEndpoint = topBorderIntersection;
00609 }
00610 else
00611 {
00612
00613 topEndpoint.x = static_cast<int>(scanLine.base.x);
00614 topEndpoint.y = static_cast<int>(scanLine.base.y);
00615 ASSERT(!Geometry::clipPointInsideRectange(Vector2<int>(0,0), imageInfo.maxImageCoordinates, topEndpoint));
00616 }
00617
00618
00619
00620 switch (i & 3)
00621 {
00622
00623 case 1:
00624 case 3:
00625
00626 if (topBorderHY > scanLineStartHY + verticalScanLineLength13)
00627 continue;
00628
00629
00630 if (bottomBorderHY < scanLineStartHY + verticalScanLineLength13)
00631 {
00632
00633 bottomEndpoint = bottomBorderIntersection;
00634 }
00635 else
00636 {
00637
00638 bottomEndpoint.x = static_cast<int>(scanLine.base.x + scanLineEnd13.x);
00639 bottomEndpoint.y = static_cast<int>(scanLine.base.y + scanLineEnd13.y);
00640 ASSERT(!Geometry::clipPointInsideRectange(Vector2<int>(0,0), imageInfo.maxImageCoordinates, bottomEndpoint));
00641 }
00642
00643
00644 relevantForLines = false;
00645 break;
00646
00647
00648
00649 case 2:
00650
00651 if (topBorderHY > scanLineStartHY + verticalScanLineLength2)
00652 continue;
00653
00654
00655 if (bottomBorderHY < scanLineStartHY + verticalScanLineLength2)
00656 {
00657
00658 bottomEndpoint = bottomBorderIntersection;
00659 }
00660 else
00661 {
00662
00663 bottomEndpoint.x = static_cast<int>(scanLine.base.x + scanLineEnd2.x);
00664 bottomEndpoint.y = static_cast<int>(scanLine.base.y + scanLineEnd2.y);
00665 ASSERT(!Geometry::clipPointInsideRectange(Vector2<int>(0,0), imageInfo.maxImageCoordinates, bottomEndpoint));
00666 }
00667
00668
00669 relevantForLines = false;
00670 break;
00671
00672
00673
00674 case 0:
00675 default:
00676
00677 bottomEndpoint = bottomBorderIntersection;
00678
00679
00680 relevantForLines = true;
00681 }
00682
00683
00684
00685
00686
00687
00688 if (i & 1)
00689 {
00690
00691 pixelsRelevantForGoal = 1024;
00692 }
00693 else
00694 {
00695 if (topBorderHY > scanLineStartHY + verticalScanLineLength13)
00696 {
00697
00698 pixelsRelevantForGoal = -1;
00699 }
00700 else
00701 {
00702
00703 int goalBottomX = static_cast<int>(scanLine.base.x + scanLineEnd13.x);
00704 int goalBottomY = static_cast<int>(scanLine.base.y + scanLineEnd13.y);
00705
00706
00707 pixelsRelevantForGoal = 1 + max(abs(goalBottomX-topEndpoint.x), abs(goalBottomY-topEndpoint.y));
00708 }
00709 }
00710
00711
00712 scan(topEndpoint, bottomEndpoint, true, !relevantForLines, pixelsRelevantForGoal);
00713 }
00714 }
00715
00716
00717 void GT2005ImageProcessor::scanRows()
00718 {
00719 Geometry::Line scanLine(imageInfo.horizon);
00720 double horizontalScanLineSpacing(20.0);
00721 Vector2<double> scanOffset(imageInfo.vertLine.direction * horizontalScanLineSpacing);
00722 scanLine.base += (scanOffset*2.0);
00723 Vector2<int> startPoint,
00724 endPoint;
00725
00726 if(!Geometry::getIntersectionPointsOfLineAndRectangle(Vector2<int>(0,0),
00727 imageInfo.maxImageCoordinates,
00728 scanLine, startPoint, endPoint))
00729 {
00730 scanLine.base.x = (double)imageInfo.maxImageCoordinates.x / 2.0;
00731 scanLine.base.y = 1;
00732 }
00733 while(true)
00734 {
00735 if(Geometry::getIntersectionPointsOfLineAndRectangle(
00736 Vector2<int>(0,0),
00737 imageInfo.maxImageCoordinates,
00738 scanLine, startPoint, endPoint))
00739 {
00740 LINE(imageProcessor_general,startPoint.x,startPoint.y,endPoint.x,endPoint.y,
00741 1,Drawings::ps_solid, Drawings::green);
00742 if(rand() > RAND_MAX / 2)
00743 scan(startPoint, endPoint, false, false, -1);
00744 else
00745 scan(startPoint, endPoint, false, false, -1);
00746 scanLine.base += scanOffset;
00747 }
00748 else
00749 {
00750 return;
00751 }
00752 }
00753 }
00754
00755 void GT2005ImageProcessor::scan(const Vector2<int>& start, const Vector2<int>& end,
00756 bool vertical, bool noLines, int pixelsRelevantForGoal)
00757 {
00758
00759 if (vertical)
00760 {
00761
00762 goalSpecialistY.notifyAboutNewScanline(start);
00763 goalSpecialistB.notifyAboutNewScanline(start);
00764 }
00765
00766 DEBUG_RESPONSE("gt05-ip:enable-edge-detection",
00767 edgeSpecialist.resetLine();
00768 );
00769
00770 LinesPercept::LineType typeOfLinesPercept = LinesPercept::field;
00771 int pixelsSinceGoal = 0;
00772 int pixelsBetweenGoalAndObstacle = 0;
00773
00774 Vector2<int> actual = start,
00775 diff = end - start,
00776 step(sgn(diff.x),sgn(diff.y)),
00777 size(abs(diff.x),abs(diff.y));
00778 bool isVertical = abs(diff.y) > abs(diff.x);
00779 int count,
00780 sum;
00781 double scanAngle = diff.angle();
00782
00783 LINE(imageProcessor_scanLines,
00784 start.x, start.y, end.x, end.y,
00785 1, Drawings::ps_solid, Drawings::gray );
00786
00787
00788 if(isVertical)
00789 {
00790 count = size.y;
00791 sum = size.y / 2;
00792 }
00793 else
00794 {
00795 count = size.x;
00796 sum = size.x / 2;
00797 }
00798
00799 if(count > 7)
00800 {
00801 int numberOfPoints[LinesPercept::numberOfLineTypes],
00802 i;
00803 for(i = 0; i < LinesPercept::numberOfLineTypes; ++i)
00804 numberOfPoints[i] = linesPercept.points[i].numberOfPoints;
00805 RingBuffer<const unsigned char*,7> pixelBuffer;
00806 RingBuffer<const unsigned char*,7> pixelBufferFromUp;
00807 RingBuffer<unsigned char, 7> yBuffer;
00808 RingBuffer<unsigned char, 7> vBuffer;
00809 RingBuffer<colorClass, 7> colorClassBuffer;
00810
00811
00812 for(i = 0; i < 6; ++i)
00813 {
00814 unsigned char y,u,v;
00815 pixelBuffer.add(&image.image[actual.y][0][actual.x]);
00816 if (actual.x < 0 || actual.x >= image.cameraInfo.resolutionWidth || actual.y < 0 || actual.y >= image.cameraInfo.resolutionHeight)
00817 y = u = v = 0;
00818 else
00819 {
00820 y = colorCorrector.correct(actual.x, actual.y, 0, image.image[actual.y][0][actual.x]);
00821 u = colorCorrector.correct(actual.x, actual.y, 1, image.image[actual.y][1][actual.x]);
00822 v = colorCorrector.correct(actual.x, actual.y, 2, image.image[actual.y][2][actual.x]);
00823 }
00824 yBuffer.add(y);
00825 vBuffer.add(v);
00826 colorClass color = COLOR_CLASS(y, u, v, colorTable);
00827 colorClassBuffer.add(color);
00828
00829
00830
00831
00832 DEBUG_RESPONSE("gt05-ip:enable-edge-detection",
00833 edgeSpecialist.checkPoint(actual, color, cameraMatrix, imageInfo.previousCameraMatrix, image);
00834 );
00835
00836
00837 if (i < pixelsRelevantForGoal)
00838 {
00839 goalSpecialistY.inspectPixel(actual, color);
00840 goalSpecialistB.inspectPixel(actual, color);
00841 }
00842
00843
00844
00845 if(isVertical)
00846 {
00847 actual.y += step.y;
00848 sum += size.x;
00849 if(sum >= size.y)
00850 {
00851 sum -= size.y;
00852 actual.x += step.x;
00853 }
00854 }
00855 else
00856 {
00857 actual.x += step.x;
00858 sum += size.y;
00859 if(sum >= size.x)
00860 {
00861 sum -= size.x;
00862 actual.y += step.y;
00863 }
00864 }
00865 }
00866 lineColor = Drawings::numberOfColors;
00867
00868 int redCount = 0,
00869 blueCount = 0,
00870 greenCount = 0,
00871 noGreenCount = 100,
00872 pinkCount = 0,
00873 noPinkCount = 100,
00874 yellowCount = 0,
00875 noYellowCount = 100,
00876 skyblueCount = 0,
00877 noSkyblueCount = 100,
00878 orangeCount = 0,
00879 noOrangeCount = 100;
00880 const unsigned char* firstRed = 0,
00881 * lastRed = 0,
00882 * firstBlue = 0,
00883 * lastBlue = 0,
00884 * firstGreen = 0,
00885 * firstOrange = 0,
00886 * lastOrange = 0,
00887 * firstPink = 0,
00888 * lastPink = 0,
00889 * pFirst = pixelBuffer[2],
00890 * up = pFirst;
00891 enum{justUP, greenAndUP, down} state = justUP;
00892 bool borderFound = false;
00893
00894
00895 enum{noGroundFound, foundBeginOfGround, foundEndOfGround} groundState = noGroundFound;
00896 const int minObstacleLineLength = 75;
00897 Vector2<int> firstGround(0,0);
00898 int numberOfPixelsSinceFirstOccurrenceOfGroundColor = 0;
00899 int numberOfPixelsSinceFirstOccurrenceOfNonGroundColor = 0;
00900 int numberOfPixelsSinceLastGround = 0;
00901 int numberOfWhitePixelsSinceLastGround = 0;
00902 bool beginOfGroundIsAtTheTopOfTheImage = false;
00903 int numberOfGroundPixels = 0;
00904 int numberOfWhiteObstaclePixels = 0;
00905 int numberOfNotWhiteObstaclePixels = 0;
00906
00907 struct BorderCandidate
00908 {
00909 bool found;
00910 Vector2<int> pointOnField;
00911 Vector2<int> pointInImage;
00912 double angleOnField;
00913 double angleInImage;
00914 };
00915 BorderCandidate borderCandidate;
00916 borderCandidate.found = false;
00917
00918 for(; i <= count; ++i)
00919 {
00920 pixelsSinceGoal++;
00921 numberOfScannedPixels++;
00922 unsigned char y,u,v;
00923 pixelBuffer.add(&image.image[actual.y][0][actual.x]);
00924 if (actual.x < 0 || actual.x >= image.cameraInfo.resolutionWidth || actual.y < 0 || actual.y >= image.cameraInfo.resolutionHeight)
00925 y = u = v = 0;
00926 else
00927 {
00928 y = colorCorrector.correct(actual.x, actual.y, 0, image.image[actual.y][0][actual.x]);
00929 u = colorCorrector.correct(actual.x, actual.y, 1, image.image[actual.y][1][actual.x]);
00930 v = colorCorrector.correct(actual.x, actual.y, 2, image.image[actual.y][2][actual.x]);
00931 }
00932 yBuffer.add(y);
00933 vBuffer.add(v);
00934 colorClass color = COLOR_CLASS(y, u, v, colorTable);
00935 colorClassBuffer.add(color);
00936
00937 N_SET_COLORED_PIXEL_IN_GRAY_SCALE_IMAGE(scanLines, actual.x, actual.y, color);
00938
00939
00940 DEBUG_RESPONSE("gt05-ip:enable-edge-detection",
00941 edgeSpecialist.checkPoint(actual, color, cameraMatrix, imageInfo.previousCameraMatrix, image);
00942 );
00943
00944
00945 if (i < pixelsRelevantForGoal)
00946 {
00947 goalSpecialistY.inspectPixel(actual, color);
00948 goalSpecialistB.inspectPixel(actual, color);
00949 }
00950
00951
00952
00953 const unsigned char* p3 = pixelBuffer[3];
00954
00955 if(yBuffer[3] > yBuffer[4] + yThreshold)
00956 {
00957 up = p3;
00958
00959 if(colorClassBuffer[6] == green
00960 || colorClassBuffer[5] == green
00961 || colorClassBuffer[4] == green)
00962 {
00963 Vector2<int> coords = getCoords(p3),
00964 pointOnField;
00965 pixelBufferFromUp.init();
00966 if(Geometry::calculatePointOnField(coords.x, coords.y, cameraMatrix, imageInfo.previousCameraMatrix, image.cameraInfo, pointOnField))
00967 for(int k = pixelBuffer.getNumberOfEntries() - 1; k >= 0; --k)
00968 pixelBufferFromUp.add(pixelBuffer.getEntry(k));
00969 state = greenAndUP;
00970 }
00971 else
00972 state = justUP;
00973 }
00974
00975
00976 else if(yBuffer[3] <
00977 yBuffer[4] - yThreshold ||
00978 vBuffer[3] <
00979 vBuffer[4] - vThreshold)
00980 {
00981
00982 if(state != down &&
00983 (colorClassBuffer[0] == green
00984 || colorClassBuffer[1] == green
00985 || colorClassBuffer[2] == green))
00986 {
00987 colorClass c = colorClassBuffer[6];
00988 if(!noLines || c == skyblue || c == yellow)
00989 {
00990 Vector2<int> coords = getCoords(p3),
00991 pointOnField;
00992
00993 if(Geometry::calculatePointOnField(coords.x, coords.y, cameraMatrix, imageInfo.previousCameraMatrix, image.cameraInfo, pointOnField))
00994 {
00995 Vector2<int> upCoords = getCoords(up);
00996 int height = (coords - upCoords).abs();
00997 int distance = (int) sqrt(sqr(cameraMatrix.translation.z) + sqr(pointOnField.abs())),
00998 lineHeight = (int) Geometry::getSizeByDistance(image.cameraInfo, 25, distance);
00999
01000
01001 if(state == greenAndUP &&
01002 (colorClassBuffer[5] == white ||
01003 colorClassBuffer[4] == white))
01004 {
01005 double edgeAngleImage, edgeAngleField;
01006 Vector2<int> pointOnField2;
01007 bool edgeCalculated, isPointOnField;
01008 edgeCalculated = calcEdgeAngle(edgeAngleImage, edgeAngleField, coords, pointOnField, scanAngle, pixelBuffer);
01009 isPointOnField = Geometry::calculatePointOnField(upCoords.x, upCoords.y, cameraMatrix, imageInfo.previousCameraMatrix, image.cameraInfo, pointOnField2);
01010 if (height < 3 * lineHeight)
01011 {
01012 if(pixelBufferFromUp.getNumberOfEntries() > 0 && edgeCalculated && isPointOnField)
01013 {
01014 double upAngleImage, upAngleField;
01015 if(calcEdgeAngle(upAngleImage, upAngleField, upCoords, pointOnField2, scanAngle, pixelBufferFromUp, true))
01016 {
01017
01018 linesPercept.points[LinesPercept::field].numberOfPoints = numberOfPoints[LinesPercept::field];
01019 linesPercept.add(LinesPercept::field, pointOnField2, upCoords, upAngleField, upAngleImage);
01020 linesPercept.add(LinesPercept::field, pointOnField, coords, edgeAngleField, edgeAngleImage);
01021 }
01022 }
01023 }
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079 }
01080 else if(height >= 3 && !borderFound)
01081 {
01082 switch(c)
01083 {
01084 case skyblue:
01085 if(vertical)
01086 {
01087 borderFound = true;
01088 if(getPlayer().getTeamColor() == Player::red && !linesPercept.points[LinesPercept::skyblueGoal].numberOfPoints)
01089 goalAtBorder = pointOnField.abs() < closestBottom;
01090 closestBottom = 40000;
01091 double edgeAngleField, edgeAngleImage;
01092 if(calcEdgeAngle(edgeAngleImage, edgeAngleField, coords, pointOnField, scanAngle, pixelBuffer, false, false, 2))
01093 linesPercept.add(LinesPercept::skyblueGoal, pointOnField, coords, edgeAngleField, edgeAngleImage);
01094 typeOfLinesPercept = LinesPercept::skyblueGoal;
01095 pixelsSinceGoal = 0;
01096
01097 lastRed = lastBlue = 0;
01098 redCount = blueCount = 0;
01099 }
01100 break;
01101 case yellow:
01102 if(vertical)
01103 {
01104 borderFound = true;
01105 if(getPlayer().getTeamColor() == Player::blue && !linesPercept.points[LinesPercept::yellowGoal].numberOfPoints)
01106 goalAtBorder = pointOnField.abs() < closestBottom;
01107 closestBottom = 40000;
01108 double edgeAngleField, edgeAngleImage;
01109 if(calcEdgeAngle(edgeAngleImage, edgeAngleField, coords, pointOnField, scanAngle, pixelBuffer, false, false))
01110 linesPercept.add(LinesPercept::yellowGoal, pointOnField, coords, edgeAngleField, edgeAngleImage);
01111 typeOfLinesPercept = LinesPercept::yellowGoal;
01112 pixelsSinceGoal = 0;
01113
01114 lastRed = lastBlue = 0;
01115 redCount = blueCount = 0;
01116 }
01117 break;
01118 case white:
01119 if(height > lineHeight * 3 && vertical)
01120 {
01121
01122 double edgeAngleField, edgeAngleImage;
01123 if(calcEdgeAngle(edgeAngleImage, edgeAngleField, coords, pointOnField, scanAngle, pixelBuffer))
01124 {
01125
01126 borderCandidate.found = true;
01127 borderCandidate.pointOnField = pointOnField;
01128 borderCandidate.pointInImage = coords;
01129 borderCandidate.angleOnField = edgeAngleField;
01130 borderCandidate.angleInImage = edgeAngleImage;
01131 }
01132 typeOfLinesPercept = LinesPercept::border;
01133 lastRed = lastBlue = 0;
01134 redCount = blueCount = 0;
01135 }
01136 break;
01137 }
01138 }
01139 }
01140 }
01141 state = down;
01142 }
01143 }
01144
01145 colorClass c3 = colorClassBuffer[3];
01146 ++noOrangeCount;
01147 if (c3 == orange)
01148 {
01149 if(noOrangeCount > 1)
01150 {
01151 if (orangeCount > longestBallRun)
01152 {
01153 longestBallRun = orangeCount;
01154 ballCandidate = (getCoords(firstOrange) + getCoords(lastOrange)) / 2;
01155 }
01156 DEBUG_RESPONSE_NOT("gt05-ip:disable-multiple-ball-candidates",
01157 if (orangeCount>2)
01158 {
01159 ballClustering.addLine(getCoords(firstOrange), getCoords(lastOrange), orangeCount);
01160 }
01161 );
01162 orangeCount = 1;
01163 firstOrange = p3;
01164 lastOrange = p3;
01165 }
01166 else
01167 {
01168 ++orangeCount;
01169 if(orangeCount > 2)
01170 {
01171 lastRed = lastBlue = 0;
01172 redCount = blueCount = 0;
01173 }
01174 lastOrange = p3;
01175 }
01176 firstGreen = 0;
01177 noOrangeCount = 0;
01178 }
01179 if(vertical)
01180 {
01181
01182 ++noGreenCount;
01183 ++noPinkCount;
01184 ++noYellowCount;
01185 ++noSkyblueCount;
01186 switch(c3)
01187 {
01188 case blue:
01189 if(blueCount == 3)
01190 firstBlue = pixelBuffer[6];
01191 ++blueCount;
01192 lastBlue = p3;
01193 firstGreen = 0;
01194 break;
01195 case gray:
01196 if(firstGreen && noGreenCount < 8)
01197 firstGreen = 0;
01198 break;
01199 case green:
01200 if(!firstGreen)
01201 {
01202 firstGreen = p3;
01203 }
01204 if(noGreenCount > 6)
01205 greenCount = 1;
01206 else
01207 ++greenCount;
01208 noGreenCount = 0;
01209 break;
01210 case red:
01211 if(orangeCount < 6 || noOrangeCount > 4 || redCount > orangeCount)
01212 {
01213 if(redCount == 3)
01214 firstRed = pixelBuffer[6];
01215 ++redCount;
01216 lastRed = p3;
01217 firstGreen = 0;
01218 break;
01219 }
01220
01221 case pink:
01222 if(noPinkCount > 6)
01223 {
01224 pinkCount = 1;
01225 firstPink = p3;
01226 }
01227 else
01228 {
01229 ++pinkCount;
01230 }
01231 lastPink = p3;
01232 noPinkCount = 0;
01233 break;
01234 case yellow:
01235 if(noYellowCount > 6)
01236 yellowCount = 1;
01237 else
01238 ++yellowCount;
01239 noYellowCount = 0;
01240 break;
01241 case skyblue:
01242 if(noSkyblueCount > 6)
01243 skyblueCount = 1;
01244 else
01245 ++skyblueCount;
01246 noSkyblueCount = 0;
01247 break;
01248 default:
01249 break;
01250
01251 }
01252
01253
01254 if(count > minObstacleLineLength && cameraMatrix.isValid)
01255 {
01256 DEBUG_IMAGE_SET_PIXEL_BLACK(imageProcessorPlayers, getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y);
01257 NDOT("imageProcessor:obstacle detection",
01258 getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y,
01259 Drawings::orange, Drawings::orange);
01260 colorClass color = colorClassBuffer[0];
01261 if(groundState == noGroundFound)
01262 {
01263 DEBUG_IMAGE_SET_PIXEL_YELLOW(imageProcessorPlayers, getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y);
01264 NDOT("imageProcessor:obstacle detection",
01265 getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y,
01266 Drawings::yellow, Drawings::yellow);
01267 if(color == green || color == orange)
01268 {
01269 if(numberOfPixelsSinceFirstOccurrenceOfGroundColor == 0)
01270 {
01271 firstGround = getCoords(pixelBuffer[0]);
01272 }
01273 numberOfPixelsSinceFirstOccurrenceOfGroundColor++;
01274 if(numberOfPixelsSinceFirstOccurrenceOfGroundColor > 3 || color == orange)
01275 {
01276 Vector2<int> coords = getCoords(pixelBuffer[0]);
01277 int lineHeight = Geometry::calculateLineSize(coords, cameraMatrix, image.cameraInfo);
01278 if(i < lineHeight * 4) beginOfGroundIsAtTheTopOfTheImage = true;
01279 groundState = foundBeginOfGround;
01280 pixelsBetweenGoalAndObstacle = pixelsSinceGoal;
01281 numberOfPixelsSinceFirstOccurrenceOfNonGroundColor = 0;
01282 }
01283 }
01284 else if (color != noColor)
01285 {
01286 numberOfPixelsSinceFirstOccurrenceOfGroundColor = 0;
01287 if(color == white) numberOfWhiteObstaclePixels++;
01288 else numberOfNotWhiteObstaclePixels++;
01289 }
01290 }
01291 else if(groundState == foundBeginOfGround)
01292 {
01293 DEBUG_IMAGE_SET_PIXEL_GREEN(imageProcessorPlayers, getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y);
01294 NDOT("imageProcessor:obstacle detection",
01295 getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y,
01296 Drawings::dark_gray, Drawings::dark_gray);
01297 if(color != green && color != orange && color != noColor)
01298 {
01299 numberOfPixelsSinceFirstOccurrenceOfNonGroundColor++;
01300 if(numberOfPixelsSinceFirstOccurrenceOfNonGroundColor > 3)
01301 {
01302 groundState = foundEndOfGround;
01303 numberOfPixelsSinceLastGround = 0;
01304 numberOfWhitePixelsSinceLastGround = 0;
01305 numberOfPixelsSinceFirstOccurrenceOfGroundColor = 0;
01306 }
01307 }
01308 else if (color != noColor)
01309 {
01310 numberOfGroundPixels++;
01311 numberOfPixelsSinceFirstOccurrenceOfNonGroundColor = 0;
01312 }
01313 }
01314 else if(groundState == foundEndOfGround)
01315 {
01316 numberOfPixelsSinceLastGround++;
01317 if(color == white) numberOfWhitePixelsSinceLastGround++;
01318 DEBUG_IMAGE_SET_PIXEL_RED(imageProcessorPlayers, getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y);
01319 NDOT("imageProcessor:obstacle detection",
01320 getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y,
01321 Drawings::red, Drawings::red);
01322
01323 if(color == green || color == orange)
01324 {
01325 numberOfPixelsSinceFirstOccurrenceOfGroundColor++;
01326 if(numberOfPixelsSinceFirstOccurrenceOfGroundColor > 3 || color == orange)
01327 {
01328 numberOfPixelsSinceFirstOccurrenceOfNonGroundColor = 0;
01329 groundState = foundBeginOfGround;
01330 Vector2<int> coords = getCoords(pixelBuffer[0]),
01331 pointOnField;
01332 int lineHeight = Geometry::calculateLineSize(coords, cameraMatrix, image.cameraInfo);
01333
01334 if(numberOfPixelsSinceLastGround > lineHeight * (numberOfPixelsSinceLastGround * 4 < numberOfWhitePixelsSinceLastGround * 5 ? 5 : 2.0))
01335 {
01336 DEBUG_IMAGE_SET_PIXEL_PINK(imageProcessorPlayers, getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y);
01337 NDOT("imageProcessor:obstacle detection",
01338 getCoords(pixelBuffer[0]).x, getCoords(pixelBuffer[0]).y,
01339 Drawings::blue, Drawings::blue);
01340
01341 firstGround = getCoords(pixelBuffer[0]);
01342 numberOfGroundPixels = 0;
01343 beginOfGroundIsAtTheTopOfTheImage = false;
01344 }
01345 }
01346 }
01347 else if (color != noColor)
01348 {
01349 numberOfPixelsSinceFirstOccurrenceOfGroundColor = 0;
01350 if(color == white)
01351 numberOfWhiteObstaclePixels++;
01352 else
01353 numberOfNotWhiteObstaclePixels++;
01354 }
01355 }
01356 }
01357
01358 }
01359
01360 PLOT(p3,ColorClasses::colorClassToDrawingsColor(c3));
01361
01362
01363 if(isVertical)
01364 {
01365 actual.y += step.y;
01366 sum += size.x;
01367 if(sum >= size.y)
01368 {
01369 sum -= size.y;
01370 actual.x += step.x;
01371 }
01372 }
01373 else
01374 {
01375 actual.x += step.x;
01376 sum += size.y;
01377 if(sum >= size.x)
01378 {
01379 sum -= size.x;
01380 actual.y += step.y;
01381 }
01382 }
01383 }
01384
01385 if(!borderFound && borderCandidate.found)
01386 {
01387 linesPercept.add(LinesPercept::border,borderCandidate.pointOnField, borderCandidate.pointInImage, borderCandidate.angleOnField, borderCandidate.angleInImage);
01388 }
01389
01390 if (orangeCount > longestBallRun)
01391 {
01392 longestBallRun = orangeCount;
01393 ballCandidate = (getCoords(firstOrange) + getCoords(lastOrange)) / 2;
01394 }
01395 DEBUG_RESPONSE_NOT("gt05-ip:disable-multiple-ball-candidates",
01396 if (orangeCount>2)
01397 {
01398 ballClustering.addLine(getCoords(firstOrange), getCoords(lastOrange), orangeCount);
01399 }
01400 );
01401
01402 const unsigned char* pLast = pixelBuffer[3];
01403 PLOT(pLast,Drawings::numberOfColors);
01404
01405 if(vertical)
01406 {
01407 int goal = getPlayer().getTeamColor() == Player::red ? LinesPercept::skyblueGoal
01408 : LinesPercept::yellowGoal;
01409 if(linesPercept.points[goal].numberOfPoints == numberOfPoints[goal])
01410 {
01411 Vector2<int> coords = getCoords(pLast),
01412 pointOnField;
01413 if(Geometry::calculatePointOnField(coords.x, coords.y, cameraMatrix, imageInfo.previousCameraMatrix, image.cameraInfo, pointOnField))
01414 {
01415 int dist = pointOnField.abs();
01416 if(dist < closestBottom)
01417 closestBottom = dist;
01418 }
01419 }
01420
01421
01422 bool redFound = false,
01423 blueFound = false;
01424
01425
01426
01427
01428 if(redCount > blueCount && redCount > 4)
01429 {
01430
01431 Vector2<int> coordsFirstRed = getCoords(firstRed),
01432 coordsLastRed = getCoords(lastRed),
01433 coordsFirstGreen= getCoords(firstGreen),
01434 midPoint,
01435 pointOnField;
01436 double distance;
01437 pixelBelowHorizon(coordsFirstRed,distance);
01438
01439
01440
01441 if(firstRed && distance >= -15)
01442 {
01443
01444 midPoint = coordsFirstRed + ((coordsLastRed - coordsFirstRed) / 2);
01445
01446 DOT(imageProcessor_robot_detection, coordsFirstRed.x, coordsFirstRed.y, Drawings::white, Drawings::red);
01447 DOT(imageProcessor_robot_detection, coordsFirstRed.x, coordsLastRed.y, Drawings::white, Drawings::red);
01448 NDOT("imageProcessor:robot detection", coordsFirstRed.x, coordsFirstRed.y, Drawings::white, Drawings::red);
01449 NDOT("imageProcessor:robot detection", coordsFirstRed.x, coordsLastRed.y, Drawings::white, Drawings::red);
01450
01451 if (lastRedMidPoint.x != 1000)
01452 {
01453 LINE(imageProcessor_robot_detection,midPoint.x,midPoint.y,lastRedMidPoint.x,lastRedMidPoint.y,0,Drawings::ps_solid,Drawings::white);
01454 NLINE("imageProcessor:robot detection",midPoint.x,midPoint.y,lastRedMidPoint.x,lastRedMidPoint.y,0,Drawings::ps_solid,Drawings::white);
01455 }
01456 lastRedMidPoint = midPoint;
01457 Geometry::calculatePointOnField(midPoint.x, midPoint.y, cmTricot, prevCmTricot, image.cameraInfo, pointOnField);
01458 linesPercept.add(LinesPercept::redRobot, pointOnField, midPoint);
01459 redFound = true;
01460 }
01461 }
01462
01463
01464
01465
01466 else if(blueCount > redCount && blueCount > 4)
01467 {
01468
01469 Vector2<int> coordsFirstBlue = getCoords(firstBlue),
01470 coordsLastBlue = getCoords(lastBlue),
01471 coordsFirstGreen= getCoords(firstGreen),
01472 midPoint,
01473 pointOnField;
01474 double distance;
01475 pixelBelowHorizon(coordsFirstBlue,distance);
01476
01477
01478
01479 if(firstBlue && distance >= -15)
01480 {
01481
01482 midPoint = coordsFirstBlue + ((coordsLastBlue - coordsFirstBlue) / 2);
01483
01484 DOT(imageProcessor_robot_detection, coordsFirstBlue.x, coordsFirstBlue.y, Drawings::white, Drawings::blue);
01485 DOT(imageProcessor_robot_detection, coordsFirstBlue.x, coordsLastBlue.y, Drawings::white, Drawings::blue);
01486 NDOT("imageProcessor:robot detection", coordsFirstBlue.x, coordsFirstBlue.y, Drawings::white, Drawings::blue);
01487 NDOT("imageProcessor:robot detection", coordsFirstBlue.x, coordsLastBlue.y, Drawings::white, Drawings::blue);
01488
01489 if (lastBlueMidPoint.x != 1000){
01490 LINE(imageProcessor_robot_detection,midPoint.x,midPoint.y,lastBlueMidPoint.x,lastBlueMidPoint.y,0,Drawings::ps_solid,Drawings::white);
01491 NLINE("imageProcessor:robot detection",midPoint.x,midPoint.y,lastBlueMidPoint.x,lastBlueMidPoint.y,0,Drawings::ps_solid,Drawings::white);
01492 }
01493 lastBlueMidPoint = midPoint;
01494 Geometry::calculatePointOnField(midPoint.x, midPoint.y, cmTricot, prevCmTricot, image.cameraInfo, pointOnField);
01495 linesPercept.add(LinesPercept::blueRobot, pointOnField, midPoint);
01496 blueFound = true;
01497 }
01498 }
01499
01500 bool addObstaclesPoint = false;
01501 ObstaclesPercept::Segment s;
01502 if(count > minObstacleLineLength && cameraMatrix.isValid)
01503 {
01504 Vector2<int> firstGroundOnField;
01505 bool firstGroundOnFieldIsOnField =
01506 Geometry::calculatePointOnField(firstGround.x, firstGround.y, cameraMatrix, imageInfo.previousCameraMatrix, image.cameraInfo, firstGroundOnField);
01507
01508 Vector2<int> imageBottom = getCoords(pixelBuffer[0]);
01509 Vector2<int> imageBottomOnField;
01510 bool imageBottomIsOnField =
01511 Geometry::calculatePointOnField(imageBottom.x, imageBottom.y, cameraMatrix, imageInfo.previousCameraMatrix, image.cameraInfo, imageBottomOnField);
01512
01513 if(groundState == foundBeginOfGround)
01514 {
01515 if(firstGroundOnFieldIsOnField)
01516 {
01517 NDOT("imageProcessor:obstacle detection",
01518 imageBottom.x, imageBottom.y,
01519 Drawings::black, Drawings::red);
01520 NDOT("imageProcessor:obstacle detection",
01521 firstGround.x, firstGround.y,
01522 Drawings::red, Drawings::black);
01523
01524 addObstaclesPoint = true;
01525 s.nearPointOnField = Vector2<double>(imageBottomOnField.x, imageBottomOnField.y);
01526 s.farPointOnField = Vector2<double>(firstGroundOnField.x, firstGroundOnField.y);
01527 s.nearPointInImage = Vector2<double>(imageBottom.x, imageBottom.y);
01528 s.farPointInImage = Vector2<double>(firstGround.x, firstGround.y);
01529 s.farPointIsOnImageBorder = beginOfGroundIsAtTheTopOfTheImage;
01530 }
01531 }
01532 else if(groundState == foundEndOfGround)
01533 {
01534 int lineHeight = Geometry::calculateLineSize(imageBottom, cameraMatrix, image.cameraInfo);
01535 if(numberOfPixelsSinceLastGround < lineHeight * 4)
01536 {
01537 if(firstGroundOnFieldIsOnField)
01538 {
01539 NDOT("imageProcessor:obstacle detection",
01540 imageBottom.x, imageBottom.y,
01541 Drawings::black, Drawings::blue);
01542 NDOT("imageProcessor:obstacle detection",
01543 firstGround.x, firstGround.y,
01544 Drawings::blue, Drawings::black);
01545 addObstaclesPoint = true;
01546 s.nearPointOnField = Vector2<double>(imageBottomOnField.x, imageBottomOnField.y);
01547 s.farPointOnField = Vector2<double>(firstGroundOnField.x, firstGroundOnField.y);
01548 s.nearPointInImage = Vector2<double>(imageBottom.x, imageBottom.y);
01549 s.farPointInImage = Vector2<double>(firstGround.x, firstGround.y);
01550 s.farPointIsOnImageBorder = beginOfGroundIsAtTheTopOfTheImage;
01551 }
01552 }
01553 else if(imageBottomIsOnField)
01554 {
01555 addObstaclesPoint = true;
01556 s.nearPointOnField = s.farPointOnField = Vector2<double>(imageBottomOnField.x, imageBottomOnField.y);
01557 s.nearPointInImage = s.farPointInImage = Vector2<double>(imageBottom.x, imageBottom.y);
01558 NDOT("imageProcessor:obstacle detection",
01559 imageBottom.x, imageBottom.y,
01560 Drawings::black, Drawings::yellow);
01561 }
01562 }
01563 else if(groundState == noGroundFound)
01564 {
01565 if(imageBottomIsOnField &&
01566
01567 imageBottomOnField.abs() > 150)
01568 {
01569 addObstaclesPoint = true;
01570 s.nearPointOnField = s.farPointOnField = Vector2<double>(imageBottomOnField.x, imageBottomOnField.y);
01571 s.nearPointInImage = s.farPointInImage = Vector2<double>(imageBottom.x, imageBottom.y);
01572 NDOT("imageProcessor:obstacle detection",
01573 imageBottom.x, imageBottom.y,
01574 Drawings::black, Drawings::pink);
01575 }
01576 }
01577 }
01578 if(addObstaclesPoint)
01579 {
01580 if(
01581 angleBetweenDirectionOfViewAndGround > -80.0 &&
01582 !(s.farPointOnField.x == 0 && s.farPointOnField.y == 0)
01583 )
01584
01585 {
01586 switch(typeOfLinesPercept)
01587 {
01588 case LinesPercept::skyblueGoal:
01589 if(pixelsBetweenGoalAndObstacle < 15)
01590 s.obstacleType = ObstaclesPercept::goal;
01591 obstaclesPercept.add(s);
01592 break;
01593 case LinesPercept::yellowGoal:
01594 if(pixelsBetweenGoalAndObstacle < 15)
01595 s.obstacleType = ObstaclesPercept::goal;
01596 obstaclesPercept.add(s);
01597 break;
01598 case LinesPercept::blueRobot:
01599 if(getPlayer().getTeamColor() == Player::blue)
01600 s.obstacleType = ObstaclesPercept::teammate;
01601 else
01602 s.obstacleType = ObstaclesPercept::opponent;
01603 obstaclesPercept.add(s);
01604 break;
01605 case LinesPercept::redRobot:
01606 if(getPlayer().getTeamColor() == Player::red)
01607 s.obstacleType = ObstaclesPercept::teammate;
01608 else
01609 s.obstacleType = ObstaclesPercept::opponent;
01610 obstaclesPercept.add(s);
01611 break;
01612 case LinesPercept::border:
01613 break;
01614 }
01615 }
01616 }
01617 }
01618 }
01619 }
01620
01621
01622 bool GT2005ImageProcessor::pixelBelowHorizon(Vector2<int> point, double &distance)
01623 {
01624
01625 if (!imageInfo.horizonInImage)
01626 {
01627
01628 return true;
01629 }
01630 else
01631 {
01632 Vector3<double> point3d((double)point.x,(double)point.y,0);
01633
01634 point3d.x -= imageInfo.horizon.base.x;
01635 point3d.y -= imageInfo.horizon.base.y;
01636
01637 if (0.99 > (imageInfo.horizon.direction.x + imageInfo.horizon.direction.y)
01638 || (imageInfo.horizon.direction.x + imageInfo.horizon.direction.y) > 1.01)
01639 imageInfo.horizon.normalizeDirection();
01640
01641 RotationMatrix rot;
01642 rot.rotateZ(-sgn(imageInfo.horizon.direction.x) * asin(imageInfo.horizon.direction.y));
01643 point3d = rot * point3d;
01644 distance = point3d.y;
01645 if (distance<0)
01646 return false;
01647 return true;
01648 }
01649 }
01650 void GT2005ImageProcessor::filterPercepts()
01651 {
01652
01653 for(int i = 0; i < LinesPercept::numberOfLineTypes; ++i)
01654 if(linesPercept.points[i].numberOfPoints < 3)
01655 linesPercept.points[i].numberOfPoints = 0;
01656
01657
01658 filterLinesPercept(linesPercept, LinesPercept::border, image);
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687 filterLinesPercept(linesPercept, LinesPercept::field, image);
01688
01689 #ifdef PERCEPT_FILTER
01690
01691 char numberOfFreePartsOfGoals = 0;
01692
01693 if (obstaclesPercept.angleToFreePartOfGoalWasDetermined[0]) numberOfFreePartsOfGoals++;
01694 if (obstaclesPercept.angleToFreePartOfGoalWasDetermined[1]) numberOfFreePartsOfGoals++;
01695
01696
01697 if (landmarksPercept.numberOfGoals == 2)
01698 {
01699 landmarksPercept.numberOfGoals = 0;
01700 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01701 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01702
01703 }
01704
01705 if (numberOfFreePartsOfGoals > landmarksPercept.numberOfGoals)
01706 {
01707 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01708 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01709 }
01710
01711
01712 if (landmarksPercept.numberOfFlags > 2)
01713 {
01714 landmarksPercept.numberOfFlags = 0;
01715
01716 }
01717
01718 if (landmarksPercept.numberOfFlags > 0)
01719 {
01720
01721 if (landmarksPercept.numberOfGoals == 1)
01722 {
01723 if (landmarksPercept.goals[0].color == skyblue)
01724 {
01725 for (unsigned char i = 0;i<landmarksPercept.numberOfFlags;i++)
01726 if ((landmarksPercept.flags[i].type == Flag::pinkAboveYellow) ||
01727 (landmarksPercept.flags[i].type == Flag::yellowAbovePink))
01728 {
01729
01730 landmarksPercept.numberOfGoals = 0;
01731 landmarksPercept.numberOfFlags = 0;
01732 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01733 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01734 }
01735 }
01736 else
01737 {
01738 for (unsigned char i = 0;i<landmarksPercept.numberOfFlags;i++)
01739 if ((landmarksPercept.flags[i].type == Flag::pinkAboveSkyblue) ||
01740 (landmarksPercept.flags[i].type == Flag::skyblueAbovePink))
01741 {
01742
01743 landmarksPercept.numberOfGoals = 0;
01744 landmarksPercept.numberOfFlags = 0;
01745 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01746 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01747 }
01748 }
01749 }
01750
01751
01752 if (landmarksPercept.numberOfFlags == 2)
01753 {
01754 switch(landmarksPercept.flags[0].type)
01755 {
01756 case Flag::pinkAboveSkyblue:
01757 switch(landmarksPercept.flags[1].type)
01758 {
01759 case Flag::yellowAbovePink:
01760
01761 landmarksPercept.numberOfFlags = 0;
01762 break;
01763 case Flag::skyblueAbovePink:
01764 if (landmarksPercept.flags[0].angle > landmarksPercept.flags[1].angle)
01765 {
01766
01767 landmarksPercept.numberOfFlags = 0;
01768 }
01769 break;
01770 case Flag::pinkAboveYellow:
01771 if (landmarksPercept.flags[0].angle < landmarksPercept.flags[1].angle)
01772 {
01773
01774 landmarksPercept.numberOfFlags = 0;
01775 }
01776 break;
01777 }
01778 break;
01779 case Flag::skyblueAbovePink:
01780 switch(landmarksPercept.flags[1].type)
01781 {
01782 case Flag::pinkAboveYellow:
01783
01784 landmarksPercept.numberOfFlags = 0;
01785 case Flag::yellowAbovePink:
01786 if (landmarksPercept.flags[0].angle > landmarksPercept.flags[1].angle)
01787 {
01788
01789 landmarksPercept.numberOfFlags = 0;
01790 }
01791 break;
01792 case Flag::pinkAboveSkyblue:
01793 if (landmarksPercept.flags[0].angle < landmarksPercept.flags[1].angle)
01794 {
01795
01796 landmarksPercept.numberOfFlags = 0;
01797 }
01798 break;
01799 }
01800 break;
01801 case Flag::yellowAbovePink:
01802 switch(landmarksPercept.flags[1].type)
01803 {
01804 case Flag::pinkAboveSkyblue:
01805
01806 landmarksPercept.numberOfFlags = 0;
01807 break;
01808 case Flag::pinkAboveYellow:
01809 if (landmarksPercept.flags[0].angle > landmarksPercept.flags[1].angle)
01810 {
01811
01812 landmarksPercept.numberOfFlags = 0;
01813 }
01814 break;
01815 case Flag::skyblueAbovePink:
01816 if (landmarksPercept.flags[0].angle < landmarksPercept.flags[1].angle)
01817 {
01818
01819 landmarksPercept.numberOfFlags = 0;
01820 }
01821 break;
01822 }
01823 break;
01824 case Flag::pinkAboveYellow:
01825 switch(landmarksPercept.flags[1].type)
01826 {
01827 case Flag::skyblueAbovePink:
01828
01829 landmarksPercept.numberOfFlags = 0;
01830 break;
01831 case Flag::pinkAboveSkyblue:
01832 if (landmarksPercept.flags[0].angle > landmarksPercept.flags[1].angle)
01833 {
01834
01835 landmarksPercept.numberOfFlags = 0;
01836 }
01837 break;
01838 case Flag::yellowAbovePink:
01839 if (landmarksPercept.flags[0].angle < landmarksPercept.flags[1].angle)
01840 {
01841
01842 landmarksPercept.numberOfFlags = 0;
01843 }
01844 break;
01845 }
01846 break;
01847 }
01848 }
01849 }
01850
01851
01852 if (landmarksPercept.numberOfFlags != 0)
01853 if (landmarksPercept.numberOfGoals == 1)
01854 {
01855 for (int i = 0;i<landmarksPercept.numberOfFlags;i++)
01856 if (landmarksPercept.goals[0].color == skyblue)
01857 {
01858
01859 if (landmarksPercept.flags[i].type == Flag::skyblueAbovePink)
01860 {
01861 if (landmarksPercept.flags[i].angle < (landmarksPercept.goals[0].angle + minAngleBetweenFlagAndGoal))
01862 {
01863
01864 landmarksPercept.numberOfFlags = 0;
01865 landmarksPercept.numberOfGoals = 0;
01866 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01867 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01868 return;
01869 }
01870 }
01871 else
01872 {
01873
01874 if ((landmarksPercept.flags[i].angle + minAngleBetweenFlagAndGoal) > landmarksPercept.goals[0].angle)
01875 {
01876
01877 landmarksPercept.numberOfFlags = 0;
01878 landmarksPercept.numberOfGoals = 0;
01879 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01880 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01881 return;
01882 }
01883 }
01884 }
01885 else
01886 {
01887
01888 if (landmarksPercept.flags[i].type == Flag::yellowAbovePink)
01889 {
01890 if ((landmarksPercept.flags[i].angle + minAngleBetweenFlagAndGoal) > landmarksPercept.goals[0].angle)
01891 {
01892
01893 landmarksPercept.numberOfFlags = 0;
01894 landmarksPercept.numberOfGoals = 0;
01895 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01896 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01897 return;
01898 }
01899 }
01900 else
01901 {
01902
01903 if (landmarksPercept.flags[i].angle < (landmarksPercept.goals[0].angle + minAngleBetweenFlagAndGoal))
01904 {
01905
01906 landmarksPercept.numberOfFlags = 0;
01907 landmarksPercept.numberOfGoals = 0;
01908 obstaclesPercept.angleToFreePartOfGoalWasDetermined[0] = false;
01909 obstaclesPercept.angleToFreePartOfGoalWasDetermined[1] = false;
01910 return;
01911 }
01912 }
01913 }
01914 }
01915 #endif
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946 }
01947
01948 bool GT2005ImageProcessor::calcEdgeAngle(
01949 double& angleInImage,
01950 double& angleOnField,
01951 const Vector2<int>& pointInImage,
01952 const Vector2<int>& pointOnField,
01953 double scanAngle,
01954 const RingBuffer<const unsigned char*,7>& pixelBuffer,
01955 const bool againstScanline,
01956 const bool borderOrLine,
01957 int channel)
01958 {
01959
01960 int indices[] = {3, 4, 2, 5, 1};
01961 Vector2<double> maxGrad;
01962 double maxLength = -1;
01963 for(unsigned int i = 0; i < sizeof(indices) / sizeof(indices[0]); ++i)
01964 {
01965 Vector2<int> point = getCoords(pixelBuffer[indices[i]]);
01966 Vector2<double> grad = Vector2<double>(double(image.image[point.y][channel][point.x]) - image.image[point.y + 1][channel][point.x - 1] ,
01967 double(image.image[point.y + 1][channel][point.x]) - image.image[point.y][channel][point.x - 1]);
01968 double length = grad.abs();
01969
01970 if(length > maxLength)
01971 {
01972 Vector2<double> gradRotated = (rotation2x2 * Vector2<double>(grad.x, -grad.y)).normalize();
01973 gradRotated.y *= -1;
01974
01975 double angle = gradRotated.angle();
01976 bool similarDirection = (angle > scanAngle && angle < scanAngle + pi) || (angle < scanAngle - pi && angle > scanAngle - pi2);
01977 if(againstScanline != similarDirection)
01978 {
01979 maxGrad = grad;
01980 maxLength = length;
01981 }
01982 }
01983 }
01984
01985 if(maxLength > 0)
01986 {
01987 Vector2<double> gradRotated = (rotation2x2 * Vector2<double>(maxGrad.x, -maxGrad.y)).normalize();
01988 gradRotated.y *= -1;
01989
01990
01991 double diff = fabs(scanAngle - gradRotated.angle());
01992 if(diff > pi)
01993 diff = pi2 - diff;
01994 if(diff < pi / 6 || diff > 5 * pi / 6)
01995 {
01996 angleInImage = angleOnField = LinesPercept::UNDEF;
01997 return false;
01998 }
01999 Vector2<int> endPoint(int(pointInImage.x + gradRotated.x * 10), int(pointInImage.y + gradRotated.y * 10));
02000 ARROW(imageProcessor_edges,
02001 pointInImage.x,
02002 pointInImage.y,
02003 endPoint.x,
02004 endPoint.y,
02005 1, 1, (againstScanline ? Drawings::red : Drawings::pink)
02006 );
02007
02008 if (borderOrLine)
02009 {
02010
02011
02012
02013 Vector2<double> normalToLine = gradRotated;
02014 normalToLine = normalToLine.rotateLeft();
02015 Vector2<int> pointOnLine = pointInImage;
02016 lineFinder.considerLinePoint(pointOnLine, normalToLine);
02017 }
02018
02019 Vector2<int> point;
02020 if(Geometry::calculatePointOnField(endPoint.x, endPoint.y, cameraMatrix, imageInfo.previousCameraMatrix, image.cameraInfo, point))
02021 {
02022 angleInImage = normalize((endPoint - pointInImage).angle() - pi_2);
02023 angleOnField = normalize((point - pointOnField).angle() + pi_2);
02024 return true;
02025 }
02026 }
02027 angleInImage = angleOnField = LinesPercept::UNDEF;
02028 return false;
02029 }
02030
02031 void GT2005ImageProcessor::plot(const unsigned char* p,Drawings::Color color)
02032 {
02033 if(lineColor == Drawings::numberOfColors)
02034 {
02035 last = p;
02036 lineColor = color;
02037 }
02038 else if(color != lineColor)
02039 {
02040 Vector2<int> p1 = getCoords(last),
02041 p2 = getCoords(p);
02042 LINE(imageProcessor_general,p1.x,p1.y,p2.x,p2.y,0,Drawings::ps_solid,lineColor);
02043 last = p;
02044 lineColor = color;
02045 }
02046 }
02047
02048 bool GT2005ImageProcessor::handleMessage(InMessage& message)
02049 {
02050 switch(message.getMessageID())
02051 {
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061
02062
02063 case idColorTable64: beaconDetector.analyzeColorTable();
02064 return true;
02065 }
02066 return false;
02067 }
02068
02069 void GT2005ImageProcessor::filterLinesPercept(LinesPercept& percept, int type, const Image& image)
02070 {
02071 const int maxNumberOfEdgePoints = 200;
02072 double maxAngle = 0.25;
02073 double maxDist = 0.187;
02074
02075 int i, j;
02076
02077
02078 bool similar[maxNumberOfEdgePoints][maxNumberOfEdgePoints];
02079 for(i = 0; i < percept.points[type].numberOfPoints; i++)
02080 {
02081 Vector2<double> dir1 = Vector2<double>(cos(percept.points[type].pointsOnField[i].angle),sin(percept.points[type].pointsOnField[i].angle));
02082
02083
02084 for(j = i + 1; j < percept.points[type].numberOfPoints; j++)
02085 {
02086
02087 bool sim = false;
02088
02089 double angleDiff = fabs(normalize(percept.points[type].pointsOnField[i].angle - percept.points[type].pointsOnField[j].angle));
02090 if(angleDiff < maxAngle)
02091 {
02092
02093
02094
02095 Vector2<double> v1 = Vector2<double>((double)(percept.points[type].pointsOnField[j] - percept.points[type].pointsOnField[i]).x,(double)(percept.points[type].pointsOnField[j] - percept.points[type].pointsOnField[i]).y).normalize();
02096 double distance1 = fabs(v1 * dir1);
02097 if(distance1 < maxDist)
02098 {
02099 Vector2<double> dir2 = Vector2<double>(cos(percept.points[type].pointsOnField[j].angle),sin(percept.points[type].pointsOnField[j].angle));
02100 double distance2 = fabs(-v1 * dir2);
02101 sim = (distance2 < maxDist);
02102 }
02103 }
02104 similar[i][j] = sim;
02105 similar[j][i] = sim;
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117 }
02118 }
02119
02120
02121 int nextFree = 0;
02122
02123
02124 for(i = 0; i < percept.points[type].numberOfPoints; i++)
02125 {
02126 int countSim = 0;
02127
02128 for (j = 0; j < percept.points[type].numberOfPoints; j++)
02129 {
02130
02131 if(similar[i][j])
02132 {
02133 countSim++;
02134 }
02135 }
02136 if(countSim >= 2)
02137 {
02138 percept.points[type].pointsInImage[nextFree] = percept.points[type].pointsInImage[i];
02139 percept.points[type].pointsOnField[nextFree++] = percept.points[type].pointsOnField[i];
02140 }
02141 }
02142 percept.points[type].numberOfPoints = nextFree;
02143 }