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