00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "Representations/Perception/Image.h"
00012 #ifdef CT32K_LAYOUT
00013 #include "Representations/Perception/ColorTable32K.h"
00014 #else
00015 #include "Representations/Perception/ColorTable64.h"
00016 #endif
00017 #include "Representations/Perception/CameraMatrix.h"
00018 #include "Representations/Perception/LandmarksPercept.h"
00019 #include "Tools/FieldDimensions.h"
00020 #include "Tools/RingBuffer.h"
00021 #include "Tools/Math/Vector2.h"
00022 #include "Modules/ImageProcessor/ImageProcessorTools/ColorCorrector.h"
00023 #include "VLCImageProcessorTools.h"
00024 #include "VLCBeaconDetector.h"
00025
00026
00027 const int Y(0),
00028 U(cameraResolutionWidth_ERS7),
00029 V(2 * cameraResolutionWidth_ERS7);
00030
00031
00032 VLCBeaconDetector::VLCBeaconDetector(const Image& image,
00033 const CameraMatrix& cameraMatrix,
00034 const CameraMatrix& prevCameraMatrix,
00035 const ImageInfo& imageInf,
00036 const ColorTable& colorTable,
00037 const ColorCorrector& colorCorrector,
00038 LandmarksPercept& landmarksPercept):
00039 image(image), cameraMatrix(cameraMatrix),
00040 prevCameraMatrix(prevCameraMatrix),
00041 imageInf(imageInf), colorTable(colorTable),
00042 colorCorrector(colorCorrector),
00043 landmarksPercept(landmarksPercept),
00044 flagSpecialist(colorCorrector),
00045 horizontalBaseOffset(1.6),
00046 numOfHorizontalScanLineAbove(10),
00047 numOfHorizontalScanLineBelow(3),
00048 horizontalOffsetModifier(0.9),
00049 clusteringDistanceTolerance(6),
00050 minPinkRunLength(2),
00051 clusteringAspectRatio(1.5),
00052 projectionAspectRatio(0.4),
00053 minFlagConfidence(0.5),
00054 edgeScanDepth(6),
00055 edgeDetectionU(edgeThresholdU),
00056 edgeDetectionV(edgeThresholdV)
00057 {}
00058
00059
00060 void VLCBeaconDetector::execute()
00061 {
00062 flagSpecialist.init(image);
00063 numOfBeaconCandidates = 0;
00064 double dist(horizontalBaseOffset);
00065 Geometry::Line scanLine;
00066 scanLine.direction = imageInf.horizon.direction;
00067 scanLine.base = imageInf.horizon.base;
00068 int i;
00069 for(i=0; i < numOfHorizontalScanLineBelow; i++)
00070 {
00071 scanLine.base += imageInf.vertLine.direction*dist;
00072 dist += horizontalOffsetModifier;
00073 Vector2<int> startPoint, endPoint;
00074 if(Geometry::getIntersectionPointsOfLineAndRectangle(
00075 Vector2<int>(0,0), imageInf.maxImageCoordinates, scanLine, startPoint, endPoint))
00076 {
00077 LINE(imageProcessor_general, startPoint.x, startPoint.y, endPoint.x, endPoint.y, 1, Drawings::ps_dash, Drawings::gray);
00078 scanForPink(startPoint, endPoint);
00079 }
00080 else
00081 {
00082 break;
00083 }
00084 }
00085 dist = horizontalBaseOffset;
00086 scanLine.base = imageInf.horizon.base;
00087 for(i=0; i < numOfHorizontalScanLineAbove; i++)
00088 {
00089 scanLine.base -= imageInf.vertLine.direction*dist;
00090 dist += horizontalOffsetModifier;
00091 Vector2<int> startPoint, endPoint;
00092 if(Geometry::getIntersectionPointsOfLineAndRectangle(
00093 Vector2<int>(0,0), imageInf.maxImageCoordinates, scanLine, startPoint, endPoint))
00094 {
00095 LINE(imageProcessor_general, startPoint.x, startPoint.y, endPoint.x, endPoint.y, 1, Drawings::ps_dash, Drawings::yellow);
00096 scanForPink(startPoint, endPoint);
00097 }
00098 else
00099 {
00100 break;
00101 }
00102 }
00103 if(numOfBeaconCandidates)
00104 {
00105 clusterPinkBeaconParts();
00106 }
00107 flagSpecialist.getFlagPercept(cameraMatrix, prevCameraMatrix, image.cameraInfo, imageInf.horizon, landmarksPercept);
00108 }
00109
00110
00111 void VLCBeaconDetector::scanForPink(const Vector2<int>& start,
00112 const Vector2<int>& end)
00113 {
00114 BresenhamLineScan bresenham(start, end);
00115 bresenham.init();
00116 Vector2<int> pixel(start), lastPixel(start);
00117 int Y(0),U(0),V(0),lastY(0),lastU(0),lastV(0);
00118 Run currentRun;
00119 bool isPinkRun(false);
00120 bool currentPixelPink(false);
00121 for(int i=0; i<bresenham.numberOfPixels; i++)
00122 {
00123 U = image.image[pixel.y][1][pixel.x];
00124
00125 U = colorCorrector.correct(pixel.x, pixel.y, 1, U);
00126 if(U > minPinkUValue)
00127 {
00128 Y = image.image[pixel.y][0][pixel.x];
00129 Y = colorCorrector.correct(pixel.x, pixel.y, 0, Y);
00130 V = image.image[pixel.y][2][pixel.x];
00131 V = colorCorrector.correct(pixel.x, pixel.y, 2, V);
00132 currentPixelPink = (COLOR_CLASS(Y,U,V,(*bestColorTable)) == pink);
00133 }
00134 else
00135 {
00136 currentPixelPink = false;
00137 }
00138 if(!isPinkRun)
00139 {
00140 if(currentPixelPink)
00141 {
00142 currentRun.scanLineStart = start;
00143 currentRun.start = pixel;
00144 currentRun.length = 1;
00145 isPinkRun = true;
00146 }
00147 }
00148 else
00149 {
00150 if(currentPixelPink)
00151 {
00152 currentRun.length++;
00153 lastY = Y;
00154 lastU = U;
00155 lastV = V;
00156 }
00157 else
00158 {
00159 isPinkRun = false;
00160 if(currentRun.length >= minPinkRunLength)
00161 {
00162 currentRun.end = lastPixel;
00163 if(!addCandidate(currentRun)) break;
00164 LINE(imageProcessor_general, currentRun.start.x, currentRun.start.y,
00165 currentRun.end.x, currentRun.end.y, 1, Drawings::ps_solid, Drawings::pink);
00166 }
00167 }
00168 }
00169
00170 lastPixel = pixel;
00171 bresenham.getNext(pixel);
00172 }
00173
00174 if(isPinkRun)
00175 {
00176 currentRun.end = pixel;
00177 addCandidate(currentRun);
00178 LINE(imageProcessor_general, currentRun.start.x, currentRun.start.y,
00179 currentRun.end.x, currentRun.end.y, 1, Drawings::ps_solid, Drawings::pink);
00180 }
00181 }
00182
00183
00184 bool VLCBeaconDetector::addCandidate(const Run& pinkRun)
00185 {
00186 bool returnValue(numOfBeaconCandidates<MAX_NUMBER_OF_PINK_RUNS);
00187 if(returnValue)
00188 {
00189 if((numOfBeaconCandidates>0) &&
00190 (pinkRun.scanLineStart == beaconCandidates[numOfBeaconCandidates-1].scanLineStart) &&
00191 ((beaconCandidates[numOfBeaconCandidates-1].end - pinkRun.start).abs()<4))
00192 {
00193 beaconCandidates[numOfBeaconCandidates-1].end = pinkRun.end;
00194 }
00195 else
00196 {
00197 beaconCandidates[numOfBeaconCandidates++] = pinkRun;
00198 }
00199 }
00200 return returnValue;
00201 }
00202
00203
00204 void VLCBeaconDetector::clusterPinkBeaconParts()
00205 {
00206
00207 double rotation(imageInf.horizon.direction.angle());
00208 double ca(cos(-rotation));
00209 double sa(sin(-rotation));
00210 Matrix2x2<double> rotMat(Vector2<double>(ca,sa),Vector2<double>(-sa,ca));
00211 Matrix2x2<double> invRotMat = rotMat.transpose();
00212 for(int i=0; i<numOfBeaconCandidates; i++)
00213 {
00214 transformedCandidates[i].transform(beaconCandidates[i], rotMat, i);
00215 }
00216
00217 for(int j=0; j<numOfBeaconCandidates; j++)
00218 {
00219 int leftest(j);
00220 for(int k=j; k<numOfBeaconCandidates; k++)
00221 {
00222 if(transformedCandidates[k].start.x<transformedCandidates[leftest].start.x)
00223 {
00224 leftest = k;
00225 }
00226 }
00227 if(leftest != j)
00228 {
00229 TransformedRun help(transformedCandidates[j]);
00230 transformedCandidates[j] = transformedCandidates[leftest];
00231 transformedCandidates[leftest] = help;
00232 }
00233 }
00234
00235 int beginOfBeacon(0), endOfBeacon(0);
00236 double xRight(transformedCandidates[0].end.x);
00237 double xLeft(transformedCandidates[0].start.x);
00238 double yRight(transformedCandidates[0].end.y);
00239 double yLeft(transformedCandidates[0].start.y);
00240 double runLength(xRight-xLeft);
00241 double yMax, yMin;
00242 double originMinY, originMaxY;
00243 if (yRight > yLeft)
00244 {
00245 yMax = yRight;
00246 yMin = yLeft;
00247 }
00248 else
00249 {
00250 yMax = yLeft;
00251 yMin = yRight;
00252 }
00253 originMinY = beaconCandidates[0].scanLineStart.y;
00254 originMaxY = beaconCandidates[0].scanLineStart.y;
00255 for(int l=1; l<numOfBeaconCandidates; l++)
00256 {
00257 if(transformedCandidates[l].start.x < xRight + (double)clusteringDistanceTolerance)
00258 {
00259 if(transformedCandidates[l].end.x > xRight)
00260 {
00261 double candidateLength = transformedCandidates[l].end.x-xLeft;
00262 bool newRunHigher = (transformedCandidates[l].end.y-yLeft > 0.0);
00263 double candidateHeight = newRunHigher ? (transformedCandidates[l].end.y-yLeft) : (yLeft-transformedCandidates[l].end.y);
00264 if (candidateHeight < candidateLength*clusteringAspectRatio)
00265 {
00266 xRight = transformedCandidates[l].end.x;
00267 yRight = transformedCandidates[l].end.y;
00268 endOfBeacon = l;
00269 if (transformedCandidates[l].end.y-yMax > 0.0)
00270 {
00271 yMax = transformedCandidates[l].end.y;
00272 originMaxY = beaconCandidates[l].scanLineStart.y;
00273 }
00274 else if (yMin - transformedCandidates[l].end.y > 0.0)
00275 {
00276 yMin = transformedCandidates[l].end.y;
00277 originMinY = beaconCandidates[l].scanLineStart.y;
00278 }
00279 }
00280 else
00281 {
00282 double newLength = transformedCandidates[l].end.x - transformedCandidates[l].start.x;
00283 if (newLength > runLength)
00284 {
00285 xRight = transformedCandidates[l].end.x;
00286 xLeft = transformedCandidates[l].start.x;
00287 yRight = transformedCandidates[l].end.y;
00288 yLeft = transformedCandidates[l].start.y;
00289 endOfBeacon = l;
00290 beginOfBeacon = l;
00291 runLength = newLength;
00292 if (yRight > yLeft)
00293 {
00294 yMax = yRight;
00295 yMin = yLeft;
00296 }
00297 else
00298 {
00299 yMax = yLeft;
00300 yMin = yRight;
00301 }
00302 originMinY = beaconCandidates[l].scanLineStart.y;
00303 originMaxY = beaconCandidates[l].scanLineStart.y;
00304 }
00305 }
00306 }
00307 else
00308 {
00309 double newRunHeight = (transformedCandidates[l].end.y + transformedCandidates[l].start.y)/2.0;
00310 bool candidateMax = (newRunHeight-yMax > 0.0);
00311 bool candidateMin = (yMin - newRunHeight > 0.0);
00312 if (candidateMax)
00313 {
00314 double candidateHeight = newRunHeight - yMin;
00315 double candidateLength = xRight-xLeft;
00316 if (candidateHeight < candidateLength*clusteringAspectRatio)
00317 {
00318 yMax = newRunHeight;
00319 originMaxY = beaconCandidates[l].scanLineStart.y;
00320 }
00321 }
00322 else if (candidateMin)
00323 {
00324 double candidateHeight = yMax - newRunHeight;
00325 double candidateLength = xRight-xLeft;
00326 if (candidateHeight < candidateLength*clusteringAspectRatio)
00327 {
00328 yMin = newRunHeight;
00329 originMinY = beaconCandidates[l].scanLineStart.y;
00330 }
00331 }
00332 }
00333 }
00334 else
00335 {
00336 double originX = (beaconCandidates[beginOfBeacon].scanLineStart.x + beaconCandidates[endOfBeacon].scanLineStart.x)/2.0;
00337
00338 double originY = (originMinY + originMaxY)/2;
00339 double mergedScanLineLength = xRight-xLeft;
00340 Vector2<double> leftOfBeacon, rightOfBeacon;
00341 leftOfBeacon.x = xLeft - originX;
00342 rightOfBeacon.x = xRight - originX;
00343 leftOfBeacon.y = (yMax+yMin)/2.0 - originY;
00344 rightOfBeacon.y = leftOfBeacon.y;
00345 leftOfBeacon = (invRotMat*leftOfBeacon);
00346 rightOfBeacon = (invRotMat*rightOfBeacon);
00347 leftOfBeacon.x += originX;
00348 leftOfBeacon.y += originY;
00349 rightOfBeacon.x += originX;
00350 rightOfBeacon.y += originY;
00351 Geometry::clipPointInsideRectange(Vector2<int>(0,0), Vector2<int>(image.cameraInfo.resolutionWidth,image.cameraInfo.resolutionHeight), leftOfBeacon);
00352 Geometry::clipPointInsideRectange(Vector2<int>(0,0), Vector2<int>(image.cameraInfo.resolutionWidth,image.cameraInfo.resolutionHeight), rightOfBeacon);
00353 LINE(imageProcessor_general, int(leftOfBeacon.x+0.5), int(leftOfBeacon.y+0.5),
00354 int(rightOfBeacon.x+0.5), int(rightOfBeacon.y+0.5), 1, Drawings::ps_dash, Drawings::red);
00355 analyzeBeacon(leftOfBeacon, mergedScanLineLength);
00356 beginOfBeacon = l;
00357 endOfBeacon = l;
00358 xRight = transformedCandidates[l].end.x;
00359 yRight = transformedCandidates[l].end.y;
00360 xLeft = transformedCandidates[l].start.x;
00361 yLeft = transformedCandidates[l].start.y;
00362 if (yRight > yLeft)
00363 {
00364 yMax = yRight;
00365 yMin = yLeft;
00366 }
00367 else
00368 {
00369 yMax = yLeft;
00370 yMin = yRight;
00371 }
00372 originMinY = beaconCandidates[l].scanLineStart.y;
00373 originMaxY = beaconCandidates[l].scanLineStart.y;
00374 }
00375 }
00376 double originX = (beaconCandidates[beginOfBeacon].scanLineStart.x + beaconCandidates[endOfBeacon].scanLineStart.x)/2.0;
00377
00378 double originY = (originMinY + originMaxY)/2;
00379 double mergedScanLineLength = xRight-xLeft;
00380 Vector2<double> leftOfBeacon, rightOfBeacon;
00381 leftOfBeacon.x = xLeft - originX;
00382 rightOfBeacon.x = xRight - originX;
00383 leftOfBeacon.y = (yMax+yMin)/2.0 - originY;
00384 rightOfBeacon.y = leftOfBeacon.y;
00385 leftOfBeacon = (invRotMat*leftOfBeacon);
00386 rightOfBeacon = (invRotMat*rightOfBeacon);
00387 leftOfBeacon.x += originX;
00388 leftOfBeacon.y += originY;
00389 rightOfBeacon.x += originX;
00390 rightOfBeacon.y += originY;
00391 Geometry::clipPointInsideRectange(Vector2<int>(0,0), Vector2<int>(image.cameraInfo.resolutionWidth,image.cameraInfo.resolutionHeight), leftOfBeacon);
00392 Geometry::clipPointInsideRectange(Vector2<int>(0,0), Vector2<int>(image.cameraInfo.resolutionWidth,image.cameraInfo.resolutionHeight), rightOfBeacon);
00393 LINE(imageProcessor_general, int(leftOfBeacon.x+0.5), int(leftOfBeacon.y+0.5),
00394 int(rightOfBeacon.x+0.5), int(rightOfBeacon.y+0.5), 1, Drawings::ps_dash, Drawings::red);
00395 analyzeBeacon(leftOfBeacon, mergedScanLineLength);
00396 }
00397
00398 void VLCBeaconDetector::analyzeBeacon(const Vector2<double>& left, const double pinkRunWidth)
00399 {
00400 if (pinkRunWidth >= 3.0)
00401 {
00402 double rotation(imageInf.horizon.direction.angle());
00403 double ca(cos(rotation));
00404 double sa(sin(rotation));
00405 Matrix2x2<double> rotMat(Vector2<double>(ca,sa),Vector2<double>(-sa,ca));
00406 int flagReliability[4] = {0, 0, 0, 0};
00407 Flag::FlagType flagFound;
00408 Vector2<int> topEdge[4];
00409 Vector2<int> bottomEdge[4];
00410 int i;
00411 int totalWeight = 0;
00412 int highestReliability = 0;
00413 int mostReliableFlag = -1;
00414 for (i=0; i<4; i++)
00415 {
00416 topEdge[i].x = 0;
00417 topEdge[i].y = 0;
00418 bottomEdge[i].x = 0;
00419 bottomEdge[i].y = 0;
00420 }
00421 Vector2<double> currentPos;
00422 Vector2<double> step;
00423 int numberOfScanCol;
00424 if (pinkRunWidth <= 8.0)
00425 {
00426 Vector2<double> displacement((pinkRunWidth-3.0)/2.0, 0);
00427 Vector2<double> init(1.0, 0.0);
00428 displacement = rotMat*displacement;
00429 init = rotMat*init;
00430 step = displacement;
00431 currentPos = left+init;
00432 numberOfScanCol = 3;
00433 }
00434 else
00435 {
00436 Vector2<double> displacement((pinkRunWidth-5.0)/3.0, 0);
00437 Vector2<double> init(2.0, 0.0);
00438 displacement = rotMat*displacement;
00439 init = rotMat*init;
00440 step = displacement;
00441 currentPos = left+init;
00442 numberOfScanCol = 4;
00443 }
00444 for (i=0; i<numberOfScanCol; i++)
00445 {
00446 Vector2<int> top, bottom;
00447 int reliability = scanForBeaconEdges(Vector2<int>(int(currentPos.x+0.5), int(currentPos.y+0.5)),
00448 pinkRunWidth, flagFound, top, bottom);
00449 if (reliability != 0)
00450 {
00451 flagReliability[(int)flagFound] += reliability;
00452 topEdge[(int)flagFound] += top;
00453 bottomEdge[(int)flagFound] += bottom;
00454 }
00455 currentPos += step;
00456 }
00457 for (i=0; i<4; i++)
00458 {
00459 totalWeight += flagReliability[i];
00460 if (flagReliability[i] > highestReliability)
00461 {
00462 highestReliability = flagReliability[i];
00463 mostReliableFlag = i;
00464 }
00465 }
00466 if (mostReliableFlag != -1)
00467 {
00468 double confidence = highestReliability/totalWeight;
00469 if (confidence >= minFlagConfidence)
00470 {
00471 int posX = (int)((topEdge[mostReliableFlag].x + bottomEdge[mostReliableFlag].x)/(2*flagReliability[mostReliableFlag]) + 0.5);
00472 int posY = (int)((topEdge[mostReliableFlag].y + bottomEdge[mostReliableFlag].y)/(2*flagReliability[mostReliableFlag]) + 0.5);
00473 Vector2<int> center(posX, posY);
00474 const Vector2<int> border(0,0);
00475 Geometry::clipPointInsideRectange(border, imageInf.maxImageCoordinates-border, center);
00476 DOT(imageProcessor_ball4, center.x, center.y, Drawings::black, Drawings::blue);
00477 switch ((Flag::FlagType)mostReliableFlag)
00478 {
00479 case Flag::pinkAboveYellow:
00480 flagSpecialist.searchFlags(image, colorTable, cameraMatrix, yellow, true, imageInf.horizon, center.x, center.y);
00481 break;
00482 case Flag::pinkAboveSkyblue:
00483 flagSpecialist.searchFlags(image, colorTable, cameraMatrix, skyblue, true, imageInf.horizon, center.x, center.y);
00484 break;
00485 case Flag::yellowAbovePink:
00486 flagSpecialist.searchFlags(image, colorTable, cameraMatrix, yellow, false, imageInf.horizon, center.x, center.y);
00487 break;
00488 case Flag::skyblueAbovePink:
00489 flagSpecialist.searchFlags(image, colorTable, cameraMatrix, skyblue, false, imageInf.horizon, center.x, center.y);
00490 break;
00491 }
00492 }
00493 }
00494 }
00495 }
00496
00497 int VLCBeaconDetector::scanForBeaconEdges(const Vector2<int>& position, const double pinkRunWidth,
00498 Flag::FlagType& flagType, Vector2<int>& topEdge, Vector2<int>& bottomEdge)
00499 {
00500 Vector2<int> beaconCenter(position);
00501 Vector2<int> start, end;
00502 Geometry::Line vertLine;
00503 vertLine.direction = imageInf.vertLine.direction;
00504 vertLine.base.x = (double)beaconCenter.x;
00505 vertLine.base.y = (double)beaconCenter.y;
00506 Geometry::getIntersectionPointsOfLineAndRectangle(Vector2<int>(1,1),
00507 imageInf.maxImageCoordinates-Vector2<int>(1,1), vertLine, start, end);
00508 Vector2<int> pos, pos2, pinkBottomEdge, pinkTopEdge, colorBottomEdge, colorTopEdge;
00509 colorClass bottomColor(noColor),topColor(noColor), baseColor(noColor), dontCare(noColor);
00510 bool topColorEdgeFound(false), pinkTopFound(false);
00511 bool unreliable(false);
00512 Flag::FlagType beaconType(Flag::pinkAboveYellow);
00513 int reliability;
00514
00515 if(scanForBeaconPart(beaconCenter, end, pos, pinkBottomEdge, bottomColor))
00516 {
00517 if(bottomColor == white || bottomColor == gray)
00518 {
00519
00520 if(scanForBeaconPart(beaconCenter, start, pos, pinkTopEdge, topColor))
00521 {
00522 if(topColor == skyblue)
00523 {
00524 beaconType = Flag::skyblueAbovePink;
00525 topColorEdgeFound = scanForBeaconPart(pos, start, pos2, colorTopEdge, dontCare);
00526 }
00527 else if(topColor == yellow)
00528 {
00529 beaconType = Flag::yellowAbovePink;
00530 topColorEdgeFound = scanForBeaconPart(pos, start, pos2, colorTopEdge, dontCare);
00531 }
00532 else
00533 {
00534 return 0;
00535 }
00536 }
00537 else
00538 {
00539 return 0;
00540 }
00541 }
00542 else if((bottomColor == skyblue) || (bottomColor == yellow))
00543 {
00544 if(scanForBeaconPart(pos, end, pos2, colorBottomEdge, baseColor))
00545 {
00546 if(baseColor == white || baseColor == gray)
00547 {
00548 if(bottomColor == skyblue)
00549 {
00550 beaconType = Flag::pinkAboveSkyblue;
00551 pinkTopFound = scanForBeaconPart(beaconCenter, start, pos, pinkTopEdge, topColor);
00552 }
00553 else
00554 {
00555 beaconType = Flag::pinkAboveYellow;
00556 pinkTopFound = scanForBeaconPart(beaconCenter, start, pos, pinkTopEdge, topColor);
00557 }
00558 }
00559 else
00560 {
00561 if (scanForBeaconPart(beaconCenter, start, pos, pinkTopEdge, topColor))
00562 {
00563 Vector2<int> toPink(pinkTopEdge - pinkBottomEdge);
00564 double distanceToPink = toPink.abs();
00565 double similarityPink;
00566 if (distanceToPink > pinkRunWidth)
00567 similarityPink = (pinkRunWidth/distanceToPink);
00568 else
00569 similarityPink = (distanceToPink/pinkRunWidth);
00570 if (similarityPink > projectionAspectRatio)
00571 {
00572 colorBottomEdge = pinkBottomEdge + (pinkBottomEdge - pinkTopEdge);
00573 pinkTopFound = true;
00574 if(bottomColor == skyblue)
00575 beaconType = Flag::pinkAboveSkyblue;
00576 else
00577 beaconType = Flag::pinkAboveYellow;
00578 }
00579 else
00580 return 0;
00581 }
00582 else
00583 return 0;
00584 }
00585 }
00586 else
00587 {
00588
00589 if (scanForBeaconPart(beaconCenter, start, pos, pinkTopEdge, topColor))
00590 {
00591 Vector2<int> toPink(pinkTopEdge - pinkBottomEdge);
00592 double distanceToPink = toPink.abs();
00593 double similarityPink;
00594 if (distanceToPink > pinkRunWidth)
00595 similarityPink = (pinkRunWidth/distanceToPink);
00596 else
00597 similarityPink = (distanceToPink/pinkRunWidth);
00598 if (similarityPink > projectionAspectRatio)
00599 {
00600 colorBottomEdge = pinkBottomEdge + (pinkBottomEdge - pinkTopEdge);
00601 pinkTopFound = true;
00602 if(bottomColor == skyblue)
00603 beaconType = Flag::pinkAboveSkyblue;
00604 else
00605 beaconType = Flag::pinkAboveYellow;
00606 }
00607 else
00608 return 0;
00609 }
00610 else
00611 return 0;
00612 }
00613 }
00614 else
00615 {
00616 return 0;
00617 }
00618 }
00619 else
00620 {
00621 if(scanForBeaconPart(beaconCenter, start, pos, pinkTopEdge, topColor))
00622 {
00623 DOT(imageProcessor_ball4, pinkTopEdge.x, pinkTopEdge.y, Drawings::black, Drawings::pink);
00624 if(topColor == skyblue)
00625 {
00626 beaconType = Flag::skyblueAbovePink;
00627 topColorEdgeFound = scanForBeaconPart(pos, start, pos2, colorTopEdge, dontCare);
00628 if (!topColorEdgeFound)
00629 return 0;
00630 DOT(imageProcessor_ball4, colorTopEdge.x, colorTopEdge.y, Drawings::black, Drawings::red);
00631 }
00632 else if(topColor == yellow)
00633 {
00634 beaconType = Flag::yellowAbovePink;
00635 topColorEdgeFound = scanForBeaconPart(pos, start, pos2, colorTopEdge, dontCare);
00636 if (!topColorEdgeFound)
00637 return 0;
00638 DOT(imageProcessor_ball4, colorTopEdge.x, colorTopEdge.y, Drawings::black, Drawings::red);
00639 }
00640 else
00641 {
00642 Vector2<double> projectedLenght(0, pinkRunWidth+3.0);
00643 double rotation(imageInf.horizon.direction.angle());
00644 double ca(cos(rotation));
00645 double sa(sin(rotation));
00646 Matrix2x2<double> rotMat(Vector2<double>(ca,sa),Vector2<double>(-sa,ca));
00647 Vector2<double> topToBottomDisplacement = rotMat*projectedLenght;
00648 Vector2<int> displacement((int)(topToBottomDisplacement.x+0.5), (int)(topToBottomDisplacement.y+0.5));
00649 pinkBottomEdge = pinkTopEdge + displacement;
00650 const Vector2<int> border(0,0);
00651 Geometry::clipPointInsideRectange(border, imageInf.maxImageCoordinates-border, pinkBottomEdge);
00652 unsigned char colorY(colorCorrector.correct(pinkBottomEdge.x,pinkBottomEdge.y,0,image.image[pinkBottomEdge.y][0][pinkBottomEdge.x]));
00653 unsigned char colorU(colorCorrector.correct(pinkBottomEdge.x,pinkBottomEdge.y,1,image.image[pinkBottomEdge.y][1][pinkBottomEdge.x]));
00654 unsigned char colorV(colorCorrector.correct(pinkBottomEdge.x,pinkBottomEdge.y,2,image.image[pinkBottomEdge.y][2][pinkBottomEdge.x]));
00655 bottomColor = COLOR_CLASS(colorY,colorU,colorV,(*bestColorTable));
00656 DOT(imageProcessor_ball4, pinkBottomEdge.x, pinkBottomEdge.y, Drawings::gray, ColorClasses::colorClassToDrawingsColor(bottomColor));
00657 if((bottomColor == skyblue) || (bottomColor == yellow))
00658 {
00659 colorBottomEdge = pinkBottomEdge + displacement;
00660 Geometry::clipPointInsideRectange(border, imageInf.maxImageCoordinates-border, colorBottomEdge);
00661 colorY = colorCorrector.correct(colorBottomEdge.x,colorBottomEdge.y,0,image.image[colorBottomEdge.y][0][colorBottomEdge.x]);
00662 colorU = colorCorrector.correct(colorBottomEdge.x,colorBottomEdge.y,1,image.image[colorBottomEdge.y][1][colorBottomEdge.x]);
00663 colorV = colorCorrector.correct(colorBottomEdge.x,colorBottomEdge.y,2,image.image[colorBottomEdge.y][2][colorBottomEdge.x]);
00664 baseColor = COLOR_CLASS(colorY,colorU,colorV,(*bestColorTable));
00665 DOT(imageProcessor_ball4, colorBottomEdge.x, colorBottomEdge.y, Drawings::white, ColorClasses::colorClassToDrawingsColor(baseColor));
00666 if (baseColor == white || baseColor == gray)
00667 {
00668 if (bottomColor == skyblue)
00669 {
00670 beaconType = Flag::pinkAboveSkyblue;
00671 pinkTopFound = true;
00672 unreliable = true;
00673 }
00674 else if (bottomColor == yellow)
00675 {
00676 beaconType = Flag::pinkAboveYellow;
00677 pinkTopFound = true;
00678 unreliable = true;
00679 }
00680 else
00681 return 0;
00682 }
00683 else if (baseColor == pink)
00684 {
00685 if (bottomColor == skyblue)
00686 {
00687 beaconType = Flag::skyblueAbovePink;
00688 pinkTopEdge = pinkBottomEdge;
00689 pinkBottomEdge = colorBottomEdge;
00690 topColor = skyblue;
00691 bottomColor = pink;
00692 unreliable = true;
00693 }
00694 else if (bottomColor == yellow)
00695 {
00696 beaconType = Flag::yellowAbovePink;
00697 pinkTopEdge = pinkBottomEdge;
00698 pinkBottomEdge = colorBottomEdge;
00699 topColor = yellow;
00700 bottomColor = pink;
00701 unreliable = true;
00702 }
00703 else
00704 return 0;
00705 }
00706 else
00707 return 0;
00708 }
00709 else
00710 {
00711 return 0;
00712 }
00713 }
00714 }
00715 else
00716 {
00717 return 0;
00718 }
00719 }
00720
00721
00722
00723
00724 if(beaconType == Flag::pinkAboveYellow || beaconType == Flag::pinkAboveSkyblue)
00725 {
00726 if(pinkTopFound)
00727 {
00728
00729
00730
00731 Vector2<int> topPosition(pinkBottomEdge);
00732 Vector2<int> toColor(pinkBottomEdge - colorBottomEdge);
00733 Vector2<int> toPink(pinkTopEdge - pinkBottomEdge);
00734 double distanceToColor = toColor.abs();
00735 double distanceToPink = toPink.abs();
00736 double similarityColor, similarityPink;
00737 if (distanceToColor > pinkRunWidth)
00738 similarityColor = (pinkRunWidth/distanceToColor);
00739 else
00740 similarityColor = (distanceToColor/pinkRunWidth);
00741 if (distanceToPink > pinkRunWidth)
00742 similarityPink = (pinkRunWidth/distanceToPink);
00743 else
00744 similarityPink = (distanceToPink/pinkRunWidth);
00745 if (similarityColor > similarityPink)
00746 topPosition += toColor;
00747 else
00748 topPosition += toPink;
00749
00750
00751 if (unreliable)
00752 reliability = lowReliability;
00753 else
00754 reliability = highReliability;
00755 flagType = beaconType;
00756 topEdge = topPosition*reliability;
00757 bottomEdge = pinkBottomEdge*reliability;
00758 return reliability;
00759 }
00760 else
00761 {
00762
00763 Vector2<int> topPosition(pinkBottomEdge);
00764 Vector2<int> relVec(pinkBottomEdge - colorBottomEdge);
00765 topPosition += relVec;
00766
00767
00768
00769 reliability = mediumReliability;
00770 flagType = beaconType;
00771 topEdge = topPosition*reliability;
00772 bottomEdge = pinkBottomEdge*reliability;
00773 return reliability;
00774 }
00775 }
00776 else
00777 {
00778 if (bottomColor == noColor && topColorEdgeFound)
00779 {
00780 Vector2<int> bottomPosition(pinkTopEdge);
00781 Vector2<int> relVec(pinkTopEdge - colorTopEdge);
00782 bottomPosition += relVec;
00783 flagSpecialist.searchFlags(image, colorTable, cameraMatrix, topColor, false,
00784 imageInf.horizon, (int)((pinkTopEdge.x+bottomPosition.x+1.0)/2), (int)((pinkTopEdge.y+bottomPosition.y+1.0)/2));
00785 DOT(imageProcessor_ball4, pinkTopEdge.x, pinkTopEdge.y, Drawings::white, Drawings::black);
00786 DOT(imageProcessor_ball4, bottomPosition.x, bottomPosition.y, Drawings::black, Drawings::yellow);
00787 DOT(imageProcessor_ball4, (int)((pinkTopEdge.x+bottomPosition.x+1.0)/2), (int)((pinkTopEdge.y+bottomPosition.y+1.0)/2), Drawings::black, Drawings::blue);
00788 reliability = mediumReliability;
00789 flagType = beaconType;
00790 topEdge = pinkTopEdge*reliability;
00791 bottomEdge = bottomPosition*reliability;
00792 return reliability;
00793 }
00794 else{
00795 Vector2<int> bottomPosition;
00796 if (topColorEdgeFound)
00797 {
00798 bottomPosition = pinkTopEdge;
00799 Vector2<int> toColor(pinkTopEdge - colorTopEdge);
00800 Vector2<int> toPink(pinkBottomEdge - pinkTopEdge);
00801 double distanceToColor = toColor.abs();
00802 double distanceToPink = toPink.abs();
00803 double similarityColor, similarityPink;
00804 if (distanceToColor > pinkRunWidth)
00805 similarityColor = (pinkRunWidth/distanceToColor);
00806 else
00807 similarityColor = (distanceToColor/pinkRunWidth);
00808 if (distanceToPink > pinkRunWidth)
00809 similarityPink = (pinkRunWidth/distanceToPink);
00810 else
00811 similarityPink = (distanceToPink/pinkRunWidth);
00812 if (similarityColor > similarityPink)
00813 bottomPosition += toColor;
00814 else
00815 bottomPosition += toPink;
00816 if (unreliable)
00817 reliability = lowReliability;
00818 else
00819 reliability = highReliability;
00820 flagType = beaconType;
00821 topEdge = pinkTopEdge*reliability;
00822 bottomEdge = bottomPosition*reliability;
00823 return reliability;
00824 }
00825 else
00826 {
00827 if (unreliable)
00828 reliability = lowReliability;
00829 else
00830 reliability = mediumReliability;
00831 flagType = beaconType;
00832 topEdge = pinkTopEdge*reliability;
00833 bottomEdge = pinkBottomEdge*reliability;
00834 return reliability;
00835 }
00836 }
00837 }
00838 return true;
00839 }
00840
00841
00842 bool VLCBeaconDetector::scanForBeaconPart(const Vector2<int>& start, const Vector2<int>& end,
00843 Vector2<int>& position, Vector2<int>& edge, colorClass& color)
00844 {
00845
00846
00847 BresenhamLineScan bresenham(start, end);
00848 bresenham.init();
00849 Vector2<int> pixel(start);
00850 for(int i=0; i<bresenham.numberOfPixels; i++)
00851 {
00852
00853 bool edgeU = edgeDetectionU.isEdgePoint(image, pixel.x, pixel.y, SUSANEdgeDetectionLite::componentB);
00854 bool edgeV = edgeDetectionV.isEdgePoint(image, pixel.x, pixel.y, SUSANEdgeDetectionLite::componentC);
00855 DOT(imageProcessor_ball4, pixel.x, pixel.y, Drawings::black, Drawings::orange);
00856
00857 if (edgeU || edgeV)
00858 {
00859 position = pixel;
00860 edge = pixel;
00861 color = noColor;
00862
00863 if (edge.x < 0)
00864 edge.x = 0;
00865
00866 if (edge.y < 0)
00867 edge.y = 0;
00868
00869 unsigned char colorY(colorCorrector.correct(edge.x,edge.y,0,image.image[edge.y][0][edge.x]));
00870 unsigned char colorU(colorCorrector.correct(edge.x,edge.y,1,image.image[edge.y][1][edge.x]));
00871 unsigned char colorV(colorCorrector.correct(edge.x,edge.y,2,image.image[edge.y][2][edge.x]));
00872 colorClass edgeColor = COLOR_CLASS(colorY,colorU,colorV,(*bestColorTable));
00873 color = edgeColor;
00874 int counter;
00875 for (counter = 0; counter < edgeScanDepth &&
00876 ((color == noColor)||(color==edgeColor)||(color==orange)||edgeU||edgeV); counter++)
00877 {
00878 bresenham.getNext(position);
00879
00880 if (position.x < 0)
00881 position.x = 0;
00882 if (position.y < 0)
00883 position.y = 0;
00884 unsigned char colorY(colorCorrector.correct(position.x,position.y,0,image.image[position.y][0][position.x]));
00885 unsigned char colorU(colorCorrector.correct(position.x,position.y,1,image.image[position.y][1][position.x]));
00886 unsigned char colorV(colorCorrector.correct(position.x,position.y,2,image.image[position.y][2][position.x]));
00887 color = COLOR_CLASS(colorY,colorU,colorV,(*bestColorTable));
00888 edgeU = edgeDetectionU.isEdgePoint(image, position.x, position.y, SUSANEdgeDetectionLite::componentB);
00889 edgeV = edgeDetectionV.isEdgePoint(image, position.x, position.y, SUSANEdgeDetectionLite::componentC);
00890 }
00891 if (counter != edgeScanDepth)
00892 return true;
00893 }
00894
00895 bresenham.getNext(pixel);
00896 }
00897 return 0;
00898 }
00899
00900 void VLCBeaconDetector::analyzeColorTable()
00901 {
00902 Vector3<int> nearPoint,farPoint;
00903 #ifdef CT32K_LAYOUT
00904 ((ColorTable32K&) colorTable).getBoxAroundColorClass(pink,nearPoint,farPoint);
00905 #else
00906 ((ColorTable64&) colorTable).getBoxAroundColorClass(pink,nearPoint,farPoint);
00907 #endif
00908 minPinkUValue = nearPoint.y;
00909 }