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

Modules/ImageProcessor/GT2005ImageProcessor/GT2005EdgeSpecialist.cpp

Go to the documentation of this file.
00001 /**
00002 * @file GT2005EdgeSpecialist.cpp
00003 * This file contains a class for Image Processing.
00004 * @author Dirk Thomas
00005 */
00006 
00007 #include "GT2005EdgeSpecialist.h"
00008 #include "Representations/Perception/Image.h"
00009 #include "Representations/Perception/EdgesPercept.h"
00010 #include "GT2005ImageProcessorTools.h"
00011 #include <list>
00012 #include "Tools/Math/Common.h"
00013 
00014 GT2005EdgeSpecialist::GT2005EdgeSpecialist
00015 (
00016 )
00017 {
00018   // used in checkPoint
00019   greenBefore = false;
00020   whiteBefore = false;
00021   numberOfContinuousNoColor = 0;
00022 
00023   // used in addCandidate
00024   gradientThreshold = 8;
00025   double c = cos(3*pi/4);
00026   double s = sin(3*pi/4);
00027   const Matrix2x2<double> rotation(
00028     Vector2<double>(c,s),
00029     Vector2<double>(-s,c)
00030   );
00031   const Matrix2x2<double> invertY(
00032     Vector2<double>(1,0),
00033     Vector2<double>(0,-1)
00034   );
00035   referenceChange = invertY*rotation;
00036   // used in getEdgesPercept
00037   normDistance = 1.0;
00038   normProjection = 0.98;
00039   multipleAverageDistance = 2.0;
00040 }
00041 
00042 void GT2005EdgeSpecialist::reset()
00043 {
00044   numOfEdgePoints = 0;
00045 }
00046 
00047 void GT2005EdgeSpecialist::resetLine()
00048 {
00049   greenBefore = false;
00050   whiteBefore = false;
00051   numberOfContinuousNoColor = 0;
00052 }
00053 
00054 void GT2005EdgeSpecialist::checkPoint(const Vector2<int> point, const colorClass color, const CameraMatrix& cameraMatrix, const CameraMatrix& prevCameraMatrix, const Image& image)
00055 {
00056   Vector2<int> pointOnField; // position on field, relative to robot
00057   if(Geometry::calculatePointOnField(point.x, point.y, cameraMatrix, image.cameraInfo, pointOnField))
00058   {
00059     switch(color)
00060     {
00061       case green:
00062         lastGreen = point;
00063         lastGreenField = pointOnField;
00064         if(whiteBefore)
00065         {
00066           // trigger specialist (white2green)
00067           addCandidate(lastGreen, image);
00068         }
00069         greenBefore = true;
00070         whiteBefore = false;
00071         numberOfContinuousNoColor = 0;
00072         break;
00073       case white:
00074         lastWhite = pointOnField;
00075         if(greenBefore)
00076         {
00077           // trigger specialist (green2white)
00078           addCandidate(lastGreen, image);
00079         }
00080         greenBefore = false;
00081         whiteBefore = true;
00082         numberOfContinuousNoColor = 0;
00083         break;
00084       case noColor:
00085         numberOfContinuousNoColor++;
00086         break;
00087       default:
00088         greenBefore = false;
00089         whiteBefore = false;
00090         numberOfContinuousNoColor = 0;
00091         break;
00092     } // end switch
00093   } // end if
00094 
00095 }
00096 
00097 void GT2005EdgeSpecialist::addCandidate(const Vector2<int> point, const Image& image)
00098 {
00099   gradientThreshold = 3;
00100 
00101   // 2x2 pixel gradient
00102   Vector2<double> grad = Vector2<double>(image.image[point.y][0][point.x] - image.image[(point.y)-1][0][(point.x)-1] ,
00103     image.image[(point.y)-1][0][point.x] - image.image[point.y][0][(point.x)-1]);
00104   /*
00105   // 3x3 pixel gradient - not better than 2x2
00106   double grad = Vector2<double>(
00107     image.image[point.y-1][0][point.x-1]
00108     + 2*image.image[point.y][0][point.x-1]
00109     + image.image[point.y+1][0][point.x-1]
00110     - image.image[point.y-1][0][point.x+1]
00111     - 2*image.image[point.y][0][point.x+1]
00112     - image.image[point.y+1][0][point.x+1],
00113     image.image[point.y-1][0][point.x-1]
00114     + 2*image.image[point.y-1][0][point.x]
00115     + image.image[point.y-1][0][point.x+1]
00116     - image.image[point.y+1][0][point.x-1]
00117     - 2*image.image[point.y+1][0][point.x]
00118     - image.image[point.y+1][0][point.x+1]
00119   );
00120   gradientThreshold *= 2;
00121   */
00122 
00123   if (grad.abs() > gradientThreshold)
00124   {
00125     if (numOfEdgePoints < maxNumberOfEdgePoints)
00126     {
00127       edgePoints[numOfEdgePoints].offset = point;
00128       Vector2<double> gradRotated = referenceChange * grad;
00129       edgePoints[numOfEdgePoints].line = Geometry::Line(point, gradRotated.normalize());
00130       edgePoints[numOfEdgePoints].weight = 0;
00131       edgePoints[numOfEdgePoints].belongsToLineNo = -1;
00132       DOT(imageProcessor_edges, point.x, point.y, 0, 1);
00133       NDOT("gt05ip:edges-candidate-points", point.x, point.y, 0, 1);
00134       numOfEdgePoints++;
00135     }
00136     else
00137     {
00138       OUTPUT(idText,text,"EdgeSpecialist: candidate-point drop (raise maxNumberOfEdgePoints)");
00139     }
00140   }
00141 }
00142 
00143 void GT2005EdgeSpecialist::getEdgesPercept(EdgesPercept& percept, const CameraMatrix& cameraMatrix, const CameraMatrix& prevCameraMatrix, const Image& image)
00144 {
00145   int i, j;
00146 
00147   NDECLARE_DEBUGDRAWING( "gt05ip:edges-candidate-points" , "drawingOnImage" , "show candidate edge points" );
00148   NDECLARE_DEBUGDRAWING( "gt05ip:edges-points" , "drawingOnImage" , "show selected edge points" );
00149   NDECLARE_DEBUGDRAWING( "gt05ip:edges" , "drawingOnImage" , "show detected edges" );
00150 
00151   // for all lines, calculate how many other lines are similar/near in sense of this special norm
00152   bool similar[maxNumberOfEdgePoints][maxNumberOfEdgePoints];
00153   int lineHeight[maxNumberOfEdgePoints];
00154   for(i = 1; i < numOfEdgePoints; i++)
00155   {
00156     lineHeight[i] = Geometry::calculateLineSize(edgePoints[i].offset, cameraMatrix, image.cameraInfo);
00157     for(j = 0; j < i; j++)
00158     {
00159       // similar/near if distance is small and normal is in the same direction
00160       bool sim = false;
00161       // test projection first - to remove unneeded calculations of "expensive" distance
00162       double projection = edgePoints[i].line.direction * edgePoints[j].line.direction;
00163       if(projection > normProjection)
00164       {
00165         // distance point to line:
00166         // http://mo.mathematik.uni-stuttgart.de/kurse/kurs8/seite44.html
00167         // NOTE: this is because in fact, the line.direction is here the *normal* to the real line
00168         double distance1 = (edgePoints[j].line.base - edgePoints[i].line.base) * edgePoints[i].line.direction;
00169         distance1 = distance1 * distance1;
00170         if(distance1 < normDistance * lineHeight[i])
00171         {
00172           double distance2 = (edgePoints[i].line.base - edgePoints[j].line.base) * edgePoints[j].line.direction;
00173           distance2 = distance2 * distance2;
00174           sim = (distance2 < normDistance * lineHeight[j]);
00175         }
00176       }
00177       similar[i][j] = sim;
00178       similar[j][i] = sim;
00179       // draw similarity-lines
00180       /*if(sim) LINE(imageProcessor_edges, 
00181         edgePoints[i].offset.x, 
00182         edgePoints[i].offset.y, 
00183         edgePoints[j].offset.x, 
00184         edgePoints[j].offset.y,
00185         0, 0, 2
00186       );*/
00187     }
00188   }
00189 
00190   // analyse detected points and extract edges
00191   int maxWeight = 0;
00192   int colorArrow = 0;
00193   int colorEdge = 0;
00194   for(int m = 0; m < 10; m++)
00195   {
00196     int edgePointWithHighestWeight = -1;
00197     maxWeight = 0;
00198 
00199     // for all points, calculate how many other are similar
00200     for(i = 0; i < numOfEdgePoints; i++)
00201     {
00202       if(edgePoints[i].belongsToLineNo == -1) // only if point is not yet matched to an edge
00203       for (j = i + 1; j < numOfEdgePoints; j++)
00204       {
00205         if(edgePoints[j].belongsToLineNo == -1) // only if point is not yet matched to an edge
00206         if(similar[i][j])
00207         {
00208           // weight added to both points because of reflexivity of distance-norm
00209           edgePoints[i].weight++;
00210           edgePoints[j].weight++;
00211 
00212           if(edgePoints[i].weight > maxWeight)
00213           {
00214             maxWeight = edgePoints[i].weight;
00215             edgePointWithHighestWeight = i;
00216           }
00217           if(edgePoints[j].weight > maxWeight)
00218           {
00219             maxWeight = edgePoints[j].weight;
00220             edgePointWithHighestWeight = j;
00221           }
00222         }
00223       }
00224     }
00225 
00226     // break detection if no more highest is found
00227     if(maxWeight<1) break;
00228 
00229     // draw point with highest weight
00230     DOT(imageProcessor_edges, edgePoints[edgePointWithHighestWeight].offset.x, edgePoints[edgePointWithHighestWeight].offset.y, colorArrow, colorArrow);
00231     NDOT("gt05ip:edges-points", edgePoints[edgePointWithHighestWeight].offset.x, edgePoints[edgePointWithHighestWeight].offset.y, colorArrow, colorArrow);
00232 
00233     // store points which belong to the current line
00234     Vector2<int>start, end;
00235     int numberOfEdges = 0;
00236     double averageDistance;
00237     struct Edge
00238     {
00239       //int numberOfEdgePoints;
00240       std::list <int> pointIndices;
00241     };
00242     std::list <int>::iterator it;
00243     Edge edges[30];
00244     for(i = 0; i < 30; i++) edges[i].pointIndices.clear();
00245 
00246     // show lines that belong to the line with highest weight
00247     for(i = 0; i < numOfEdgePoints; i++)
00248     {
00249       if(edgePoints[i].belongsToLineNo == -1)
00250       {
00251         if(similar[i][edgePointWithHighestWeight])
00252         {
00253           ARROW(imageProcessor_edges, 
00254             edgePoints[i].line.base.x,
00255             edgePoints[i].line.base.y,
00256             edgePoints[i].line.base.x + edgePoints[i].line.direction.x * 10,
00257             edgePoints[i].line.base.y + edgePoints[i].line.direction.y * 10, 1, 1, colorArrow
00258           );
00259           NARROW("gt05ip:edges-points",
00260             edgePoints[i].line.base.x,
00261             edgePoints[i].line.base.y,
00262             edgePoints[i].line.base.x + edgePoints[i].line.direction.x * 10,
00263             edgePoints[i].line.base.y + edgePoints[i].line.direction.y * 10, 1, 1, colorArrow
00264           );
00265           // store points in ordered collection based on x- or y-values
00266           for(it = edges[numberOfEdges].pointIndices.begin( ); it != edges[numberOfEdges].pointIndices.end( ); it++)
00267           {
00268             if(edgePoints[*it].offset.x > edgePoints[i].offset.x) break;
00269           }
00270           edges[numberOfEdges].pointIndices.insert(it, i);
00271         }
00272       }
00273     }
00274     colorArrow++;
00275     numberOfEdges++;
00276 
00277     // check points on the single edge and filter outsiders and/or split in multiple parts
00278 
00279     // compute avg-distance
00280     if(edges[0].pointIndices.size() <= 1) continue;
00281     start = edgePoints[edges[0].pointIndices.front()].offset;
00282     end = edgePoints[edges[0].pointIndices.back()].offset;
00283     //if(edges[0].numberOfEdgePoints > 0) averageDistance = Geometry::distance(start, end) / edges[0].numberOfEdgePoints;
00284     averageDistance = Geometry::distance(start, end) / edges[0].pointIndices.size();
00285     // split edge in multple parts if distance of two neighboured points is much bigger than avg-distance
00286     int current, last, size;
00287     
00288     it = edges[numberOfEdges-1].pointIndices.begin();
00289     bool finished = (it != edges[numberOfEdges-1].pointIndices.end());
00290     while(finished)
00291     {
00292       size = edges[numberOfEdges-1].pointIndices.size();
00293       last = *it;
00294       it++;
00295       if(it != edges[numberOfEdges-1].pointIndices.end())
00296       {
00297         current = *it;
00298         int x1 = edgePoints[last].offset.x;
00299         int x2 = edgePoints[current].offset.x;
00300         if(x1 + multipleAverageDistance * averageDistance < x2)
00301         {
00302           // split of *it and following points into next edge
00303           edges[numberOfEdges].pointIndices.splice(
00304             edges[numberOfEdges].pointIndices.begin(),
00305             edges[numberOfEdges-1].pointIndices,
00306             it,
00307             edges[numberOfEdges-1].pointIndices.end()
00308           );
00309           it = std::list <int>::iterator(edges[numberOfEdges].pointIndices.begin());
00310           numberOfEdges++;
00311         }
00312       }
00313       finished = (it != edges[numberOfEdges-1].pointIndices.end());
00314     }
00315 
00316 
00317     // for each resulting edge check size, draw and generate percept
00318     for(int j = 0; j < numberOfEdges; j++)
00319     {
00320       // draw edge (and generate edge-percept) if based on a couple of points
00321       if(edges[j].pointIndices.size() > 4)
00322       {
00323         // generate edge-point-percept, "disable" all points for any further computation
00324         for(it = edges[j].pointIndices.begin(); it != edges[j].pointIndices.end(); it++)
00325         {
00326           i = *it;
00327           Vector2<double> pointOnField; //position on field, relative to robot
00328           if(Geometry::calculatePointOnField(edgePoints[i].offset.x, edgePoints[i].offset.y, cameraMatrix, prevCameraMatrix, image.cameraInfo, pointOnField))
00329           {
00330             edgePoints[i].belongsToLineNo = edgePointWithHighestWeight;
00331             edgePoints[i].weight = 0;
00332           }
00333         }
00334         start = edgePoints[edges[j].pointIndices.front()].offset;
00335         end = edgePoints[edges[j].pointIndices.back()].offset;
00336         LINE(imageProcessor_edges, 
00337           start.x, 
00338           start.y, 
00339           end.x, 
00340           end.y,
00341           1, 1, colorEdge
00342         );
00343         NLINE("gt05ip:edges",
00344           start.x, 
00345           start.y, 
00346           end.x, 
00347           end.y,
00348           1, 1, colorEdge
00349         );
00350         Vector2<double> point1OnField, point2OnField;
00351         Geometry::calculatePointOnField(start.x, start.y, cameraMatrix, prevCameraMatrix, image.cameraInfo, point1OnField);
00352         Geometry::calculatePointOnField(end.x, end.y, cameraMatrix, prevCameraMatrix, image.cameraInfo, point2OnField);
00353         Vector2<double> grad = edgePoints[edges[j].pointIndices.front()].line.direction;
00354         Vector2<double> dir(grad.y, -grad.x);
00355         if ((edgePoints[edges[j].pointIndices.back()].line.base - edgePoints[edges[j].pointIndices.front()].line.base) * dir > 0)
00356           percept.add(point2OnField, point1OnField, end, start);
00357         else
00358           percept.add(point1OnField, point2OnField, start, end);
00359       }
00360     }
00361     colorEdge++;
00362     if(edgePoints[edgePointWithHighestWeight].belongsToLineNo == -1) edgePoints[edgePointWithHighestWeight].belongsToLineNo = -2;
00363   }
00364 }

Generated on Mon Mar 20 21:59:46 2006 for GT2005 by doxygen 1.3.6