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

Modules/ImageProcessor/CheckerboardDetector.cpp

Go to the documentation of this file.
00001 /**
00002 * @file CheckerboardDetector.cpp
00003 * Implementation of class CheckerboardDetector.
00004 * 
00005 * @author Uwe Düffert
00006 */
00007 
00008 #include "CheckerboardDetector.h"
00009 #include "Platform/SystemCall.h"
00010 #include "Tools/RobotConfiguration.h"
00011 
00012 CheckerboardDetector::CheckerboardDetector(const ImageProcessorInterfaces& interfaces)
00013 : ImageProcessor(interfaces),minY(0),maxY(255),maxDelta(255)
00014 {
00015 }
00016 
00017 Vector2<double> CheckerboardDetector::getExactTransitionMiddle(const Geometry::PixeledLine lin, const int start, const int amount)
00018 {
00019   Vector2<double> p;
00020   int index=start;
00021   int sum=0;
00022   int oldsum=0;
00023   while (abs(2*sum)<abs(amount))
00024   {
00025     oldsum = sum;
00026     sum = image.image[lin.getPixelY(index)][0][lin.getPixelX(index)]-
00027       image.image[lin.getPixelY(start-1)][0][lin.getPixelX(start-1)];
00028     index++;
00029   }
00030   double rightWeight=(sum-0.5*amount)/(sum-oldsum);
00031   p.x=(1-rightWeight)*lin.getPixelX(index-1)+rightWeight*lin.getPixelX(index);
00032   p.y=(1-rightWeight)*lin.getPixelY(index-1)+rightWeight*lin.getPixelY(index);
00033   return p;
00034 }
00035 
00036 void CheckerboardDetector::getTransitionsOnLine(const Geometry::PixeledLine lin, v2dArray* transPos, bArray* transWhiteBlack, int& numOfTrans)
00037 {
00038   Vector2<double> p;
00039   int state=0;      //0=no change, 1=rise, 2=fall
00040   int sumDelta=0;   //only valid if state!=0
00041   int startIndex=0; //only valid if state!=0
00042   numOfTrans=0;
00043   for (int i=1;i<lin.getNumberOfPixels();i++)
00044   {
00045     int actDelta=image.image[lin.getPixelY(i)][0][lin.getPixelX(i)]-image.image[lin.getPixelY(i-1)][0][lin.getPixelX(i-1)];
00046     if (actDelta>=maxDelta/15)
00047     {
00048       if ((state==2)&&(sumDelta<=-maxDelta/2))
00049       {
00050         p=getExactTransitionMiddle(lin,startIndex,sumDelta);
00051         (*transPos)[numOfTrans]=p;
00052         (*transWhiteBlack)[numOfTrans++]=true;
00053         DEBUG_IMAGE_SET_PIXEL_BLUE(imageProcessorGeneral, (int)p.x, (int)p.y);
00054       }
00055       if (state!=1)
00056       {
00057         startIndex=i;
00058         sumDelta=actDelta;
00059         state=1;
00060       }
00061       else
00062       {
00063         sumDelta+=actDelta;
00064       }
00065     }
00066     else if (actDelta<=-maxDelta/15)
00067     {
00068       if ((state==1)&&(sumDelta>=maxDelta/2))
00069       {
00070         p=getExactTransitionMiddle(lin,startIndex,sumDelta);
00071         (*transPos)[numOfTrans]=p;
00072         (*transWhiteBlack)[numOfTrans++]=false;
00073         DEBUG_IMAGE_SET_PIXEL_RED(imageProcessorGeneral, (int)p.x, (int)p.y);
00074       }
00075       if (state!=2)
00076       {
00077         startIndex=i;
00078         sumDelta=actDelta;
00079         state=2;
00080       }
00081       else
00082       {
00083         sumDelta+=actDelta;
00084       }
00085     }
00086     else if (state!=0)
00087     {
00088       if (abs(sumDelta)>=maxDelta/2)
00089       {
00090         p=getExactTransitionMiddle(lin,startIndex,sumDelta);
00091         (*transPos)[numOfTrans]=p;
00092         (*transWhiteBlack)[numOfTrans++]=(sumDelta<0);
00093         if (sumDelta<0)
00094         {
00095           DEBUG_IMAGE_SET_PIXEL_BLUE(imageProcessorGeneral, (int)p.x, (int)p.y);
00096         }
00097         else
00098         {
00099           DEBUG_IMAGE_SET_PIXEL_RED(imageProcessorGeneral, (int)p.x, (int)p.y);
00100         }
00101       }
00102       state=0;
00103     }
00104   }
00105 }
00106 
00107 Vector2<double> CheckerboardDetector::getTransitionToWhite(const Geometry::PixeledLine lin)
00108 {
00109   if (lin.getNumberOfPixels()>0)
00110   {
00111     //check if we are really in black, otherwise its nonsense
00112     if (image.image[lin.getPixelY(0)][0][lin.getPixelX(0)]<=minY+(maxY-minY)/4)
00113     {
00114       int state=0;      //0=no change, 1=rise, 2=fall
00115       int sumDelta=0;   //only valid if state!=0
00116       int startIndex=0; //only valid if state!=0
00117       for (int i=1;i<lin.getNumberOfPixels();i++)
00118       {
00119         int actDelta=image.image[lin.getPixelY(i)][0][lin.getPixelX(i)]-image.image[lin.getPixelY(i-1)][0][lin.getPixelX(i-1)];
00120         if (actDelta>=maxDelta/10)
00121         {
00122           if (state!=1)
00123           {
00124             startIndex=i;
00125             sumDelta=actDelta;
00126             state=1;
00127           }
00128           else
00129           {
00130             sumDelta+=actDelta;
00131           }
00132         }
00133         else if (state!=0)
00134         {
00135           if (sumDelta>=maxDelta/2)
00136           {
00137             return getExactTransitionMiddle(lin,startIndex,sumDelta);
00138           }
00139           state=0;
00140         }
00141       }
00142     }
00143   }
00144   //no transitionToWhite found -> return invalid
00145   return Vector2<double>(-1,-1);
00146 }
00147 
00148 Vector2<double> CheckerboardDetector::getMiddleAndLengthOfPerpendicular(const Vector2<double> t1, const Vector2<double> t2, double& len)
00149 {
00150   double angle=atan2(t2.y-t1.y,t2.x-t1.x)+pi_2;
00151   double dx=400*cos(angle);
00152   double dy=400*sin(angle);
00153   Vector2<int> pmid((int)(t1.x+t2.x)/2,(int)(t1.y+t2.y)/2);
00154   Vector2<int> pend1((int)(t1.x+t2.x+dx)/2,(int)(t1.y+t2.y+dy)/2);
00155   Vector2<int> pend2((int)(t1.x+t2.x-dx)/2,(int)(t1.y+t2.y-dy)/2);
00156   const Vector2<int> botlef(0,0);
00157   const Vector2<int> toprig(image.cameraInfo.resolutionWidth-1,image.cameraInfo.resolutionHeight-1);
00158   Geometry::clipLineWithRectangleCohenSutherland(botlef,toprig,pmid,pend1);
00159   Geometry::clipLineWithRectangleCohenSutherland(botlef,toprig,pmid,pend2);
00160   Geometry::PixeledLine ray1(pmid.x,pend1.x,pmid.y,pend1.y);
00161   Geometry::PixeledLine ray2(pmid.x,pend2.x,pmid.y,pend2.y);
00162   Vector2<double> p1=getTransitionToWhite(ray1);
00163   Vector2<double> p2=getTransitionToWhite(ray2);
00164   Vector2<double> pm((p1.x+p2.x)/2,(p1.y+p2.y)/2);
00165   if (((p1.x==-1)&&(p1.y==-1))||((p2.x==-1)&&(p2.y==-1)))
00166   {
00167     pm.x=-1;
00168     pm.y=-1;
00169     len=0;
00170   }
00171   else
00172   {
00173     len=sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
00174   }
00175   return pm;
00176 }
00177 
00178 bool CheckerboardDetector::getLineThroughPixelsCandidate(const v2dArray* points, const int numOfPoints, double& m, double& n)
00179 {
00180   double sumXi=0;
00181   double sumYi=0;
00182   double sumXiXi=0;
00183   double sumXiXj=0;
00184   double sumXiYi=0;
00185   double sumXiYj=0;
00186   for (int i=0;i<numOfPoints;i++)
00187   {
00188     sumXi += (*points)[i].x;
00189     sumYi += (*points)[i].y;
00190     sumXiXi += (*points)[i].x * (*points)[i].x;
00191     sumXiYi += (*points)[i].x * (*points)[i].y;
00192     for (int j=0;j<numOfPoints;j++)
00193     {
00194       sumXiXj += (*points)[i].x * (*points)[j].x;
00195       sumXiYj += (*points)[i].x * (*points)[j].y;
00196     }
00197   }
00198   if (((numOfPoints*sumXiXi-sumXiXj)==0)||((numOfPoints*sumXiXi-sumXi*sumXi)==0))
00199   {
00200     return false;
00201   }
00202   m=(numOfPoints*sumXiYi-sumXiYj)/(numOfPoints*sumXiXi-sumXiXj);
00203   n=(sumXiXi*sumYi-sumXi*sumXiYi)/(numOfPoints*sumXiXi-sumXi*sumXi);
00204   return true;
00205 }
00206 
00207 bool CheckerboardDetector::getLineThroughPixels(const v2dArray* points, const int numOfPoints, Geometry::PixeledLine& lin)
00208 {
00209   //f(x)=mx+n
00210   double m;
00211   double n;
00212   if ((numOfPoints<2)||(!getLineThroughPixelsCandidate(points,numOfPoints,m,n)))
00213   {
00214     return false;
00215   }
00216   double error2[100];
00217   double sumError2=0;
00218   int i;
00219   for (i=0;i<numOfPoints;i++)
00220   {
00221     error2[i] = m * (*points)[i].x + n - (*points)[i].y;
00222     error2[i] *= error2[i];
00223     sumError2 += error2[i];
00224   }
00225   v2dArray newPoints;
00226   int newNumOfPoints=0;
00227   for (i=0;i<numOfPoints;i++)
00228   {
00229     //throw out points that are farer away from line than average and at least 1 pixel away
00230     if ((error2[i]<=sumError2/numOfPoints)||(error2[i]<1))
00231     {
00232       newPoints[newNumOfPoints++]= (*points)[i];
00233     }
00234   }
00235   if ((newNumOfPoints<2)||(!getLineThroughPixelsCandidate(&newPoints,newNumOfPoints,m,n)))
00236   {
00237     return false;
00238   }
00239   Vector2<int> p1(0,(int)(n+1));
00240   Vector2<int> p2(1000,(int)(1000*m+n+1));
00241   const Vector2<int> botlef(0,0);
00242   const Vector2<int> toprig(image.cameraInfo.resolutionWidth-1,image.cameraInfo.resolutionHeight-1);
00243   Geometry::clipLineWithRectangleCohenSutherland(botlef,toprig,p1,p2);
00244   Geometry::PixeledLine myLin(p1,p2);
00245   lin=myLin;
00246   return true;
00247 }
00248 
00249 Vector2<double> CheckerboardDetector::getPositionFromAngles(const double alpha2,const double a2,const double alpha1,const double a1)
00250 {
00251   //thanks to Mathematica :-)
00252   Vector2<double> pos;
00253   double divident = fabs((2*a1+a2)*sin(alpha2) - a2*sin(2*alpha1+alpha2));
00254   double divisor = 2 * (a1*a1 + a1*a2 + a2*a2 - a2*(a1+a2)*cos(2*alpha1) -
00255     a1*(a1+a2)*cos(2*alpha2) + a1*a2*cos(2*(alpha1+alpha2)));
00256   if (divisor>0)
00257   {
00258     double beta11=acos(divident/sqrt(divisor));
00259     double beta12=pi-beta11;
00260     double b=sin(beta11)*a1/sin(alpha1);
00261     double error1=fabs(a2/sin(alpha2)-b/sin(pi-alpha1-alpha2-beta11));
00262     double error2=fabs(a2/sin(alpha2)-b/sin(pi-alpha1-alpha2-beta12));
00263     double beta1=(error1<error2)?beta11:beta12;
00264     double c1 = sin(pi-alpha1-beta1)*a1/sin(alpha1);
00265     pos.x = -c1*sin(beta1);
00266     pos.y = -a1+c1*cos(beta1);
00267   }
00268   else
00269   {
00270     pos.x = -5000;
00271     pos.y = 0;
00272     //2do: error
00273   }
00274   return pos;
00275 }
00276 
00277 double CheckerboardDetector::getAngleBetweenScreenPoints(const Vector2<double>& p1, const Vector2<double>& p2)
00278 {
00279   //determine the arc differences in x and y direction of these 2 points:
00280   
00281   //this is the uncorrected version useful for simulator images:
00282   double xarc=
00283     atan((p2.x-image.cameraInfo.resolutionWidth/2)*
00284     tan(image.cameraInfo.openingAngleWidth/2)/(image.cameraInfo.resolutionWidth/2))
00285     -atan((p1.x-image.cameraInfo.resolutionWidth/2)*
00286     tan(image.cameraInfo.openingAngleWidth/2)/(image.cameraInfo.resolutionWidth/2));
00287   double yarc=
00288     atan((p2.y-image.cameraInfo.resolutionHeight/2)*
00289     tan(image.cameraInfo.openingAngleHeight/2)/(image.cameraInfo.resolutionHeight/2))
00290     -atan((p1.y-image.cameraInfo.resolutionHeight/2)*
00291     tan(image.cameraInfo.openingAngleHeight/2)/(image.cameraInfo.resolutionHeight/2));
00292   
00293   //this is the distortion corrected version useful for real images
00294   //but it doesnt perform better, because our heuristics like finding a line trough pixels is done on uncorrected stuff...
00295   /*
00296   double k1 = image.cameraInfo.secondOrderRadialDistortion/image.cameraInfo.focalLenPow2;
00297   double k2 = image.cameraInfo.fourthOrderRadialDistortion/image.cameraInfo.focalLenPow4;
00298   
00299   double x1 = p1.x - image.cameraInfo.opticalCenter.x;
00300   double y1 = p1.y - image.cameraInfo.opticalCenter.y;
00301   double r1sqr = x1*x1 + y1*y1;
00302   double correctedX1 = p1.x + x1*(k1*r1sqr + k2*r1sqr*r1sqr) - image.cameraInfo.opticalCenter.x;
00303   double correctedY1 = p1.y + y1*(k1*r1sqr + k2*r1sqr*r1sqr) - image.cameraInfo.opticalCenter.y;
00304   
00305   double x2 = p2.x - image.cameraInfo.opticalCenter.x;
00306   double y2 = p2.y - image.cameraInfo.opticalCenter.y;
00307   double r2sqr = x2*x2 + y2*y2;
00308   double correctedX2 = p2.x + x2*(k1*r2sqr + k2*r2sqr*r2sqr) - image.cameraInfo.opticalCenter.x;
00309   double correctedY2 = p2.y + y2*(k1*r2sqr + k2*r2sqr*r2sqr) - image.cameraInfo.opticalCenter.y;
00310   
00311   double xarc = atan2(correctedX2,image.cameraInfo.focalLength) - atan2(correctedX1,image.cameraInfo.focalLength);
00312   double yarc = atan2(correctedY2,image.cameraInfo.focalLength) - atan2(correctedY1,image.cameraInfo.focalLength);
00313   */
00314   
00315   /*
00316   //assume you have a sphere with radius 1
00317   //determine the point on the sphere that ist (xarc,yarc) away from (1,0,0):
00318   double x=cos(xarc)*cos(yarc);
00319   double y=sin(xarc)*cos(yarc);
00320   double z=sin(yarc);
00321   //determine the distance between these 2 points:
00322   double d=sqrt((x-1)*(x-1)+y*y+z*z);
00323   //determine the resulting arc between these 2 points:
00324   double arc=2*atan(d/2);
00325   */
00326   //this can be simplified to:
00327   return 2*atan(sqrt(2-2*cos(xarc)*cos(yarc))/2);
00328 }
00329 
00330 double CheckerboardDetector::yPosFromTransitionIndex(int index)
00331 {
00332   return 49.5 + 210*(-index/2) + (index<0?111:99)*(-index%2);
00333 }
00334 
00335 void CheckerboardDetector::execute()
00336 { 
00337   specialPercept.reset(image.frameNumber);
00338   double distancePanCenterToCamera = getRobotConfiguration().getRobotDimensions().distancePanCenterToCameraX;
00339   
00340   int i,x;
00341   //find minimal and maximal brigthness in scanlines
00342   minY=image.image[image.cameraInfo.resolutionHeight*16/35][0][0];
00343   maxY=minY;
00344   //it is NOT useful to increase that area: we only get stuff into sight we do not want to see:
00345   for (i=12;i<=26;i++)
00346   {
00347     int y=image.cameraInfo.resolutionHeight*i/35;
00348     for (x=0;x<image.cameraInfo.resolutionWidth;x++)
00349     {
00350       int actY=image.image[y][0][x];
00351       if (actY>maxY) maxY=actY;
00352       if (actY<minY) minY=actY;
00353     }
00354   }
00355   maxDelta=maxY-minY;
00356   
00357   INIT_DEBUG_IMAGE(imageProcessorGeneral, image);
00358   
00359   v2dArray blackBlockMiddle;
00360   int numOfBlackBlockMiddle=0;
00361   
00362   //find all relevant bw-changes on horizontal scan lines
00363   v2dArray transPos;
00364   bArray transWhiteBlack;
00365   int numOfTrans;
00366   for (i=12;i<=26;i++)
00367   {
00368     double dummyLen;
00369     numOfTrans=0;
00370     Geometry::PixeledLine lin(0,image.cameraInfo.resolutionWidth-1,image.cameraInfo.resolutionHeight*i/35,image.cameraInfo.resolutionHeight*i/35);
00371     getTransitionsOnLine(lin,&transPos,&transWhiteBlack,numOfTrans);
00372     //if we found a relevant pair of bw-changes or a bw-change near the border
00373     //mark its middle (=middle of perpendicular through black block (if it exists)) yellow
00374     if ((!transWhiteBlack[0])&&(transPos[0].x<image.cameraInfo.resolutionWidth/4))
00375     {
00376       Vector2<double> left(0,transPos[0].y);
00377       Vector2<double> m=getMiddleAndLengthOfPerpendicular(left,transPos[0],dummyLen);
00378       if ((m.x>=0)&&(m.y>=0))
00379       {
00380         DEBUG_IMAGE_SET_PIXEL_YELLOW(imageProcessorGeneral, (int)m.x, (int)m.y);
00381         blackBlockMiddle[numOfBlackBlockMiddle++]=m;
00382       }
00383     }
00384     if ((transWhiteBlack[numOfTrans-1])&&(transPos[numOfTrans-1].x>image.cameraInfo.resolutionWidth*3/4))
00385     {
00386       Vector2<double> right(image.cameraInfo.resolutionWidth-1,transPos[0].y);
00387       Vector2<double> m=getMiddleAndLengthOfPerpendicular(transPos[numOfTrans-1],right,dummyLen);
00388       if ((m.x>=0)&&(m.y>=0))
00389       {
00390         DEBUG_IMAGE_SET_PIXEL_YELLOW(imageProcessorGeneral, (int)m.x, (int)m.y);
00391         blackBlockMiddle[numOfBlackBlockMiddle++]=m;
00392       }
00393     }
00394     for (int t=0;t<numOfTrans-1;t++)
00395     {
00396       if ((transWhiteBlack[t])&&(!transWhiteBlack[t+1]))
00397       {
00398         Vector2<double> m=getMiddleAndLengthOfPerpendicular(transPos[t],transPos[t+1],dummyLen);
00399         if ((m.x>=0)&&(m.y>=0))
00400         {
00401           DEBUG_IMAGE_SET_PIXEL_YELLOW(imageProcessorGeneral, (int)m.x, (int)m.y);
00402           blackBlockMiddle[numOfBlackBlockMiddle++]=m;
00403         }
00404       }
00405     }
00406   }
00407   //2do: check blocks for useful size?
00408   
00409   //calculate a good line through the black block middles
00410   Geometry::PixeledLine lin(0,0,1,1);
00411   if (getLineThroughPixels(&blackBlockMiddle,numOfBlackBlockMiddle,lin))
00412   {
00413     for (i=0;i<lin.getNumberOfPixels();i++)
00414     {
00415       int y=image.image[lin.getPixelY(i)][0][lin.getPixelX(i)];
00416       if (y<=minY+(maxY-minY)/4)
00417       {
00418         DEBUG_IMAGE_SET_PIXEL_BLACK(imageProcessorGeneral, lin.getPixelX(i), lin.getPixelY(i));
00419       }
00420       else if (y>=maxY-(maxY-minY)/2)
00421       {
00422         DEBUG_IMAGE_SET_PIXEL_WHITE(imageProcessorGeneral, lin.getPixelX(i), lin.getPixelY(i));
00423       }
00424       else
00425       {
00426         DEBUG_IMAGE_SET_PIXEL_Y(imageProcessorGeneral, lin.getPixelX(i), lin.getPixelY(i), 128);
00427       }
00428     }
00429     
00430     //now we have a resulting line through the checkerboard.
00431     //recalibrate minY/maxY for that line
00432     minY=image.image[lin.getPixelY(0)][0][lin.getPixelX(0)];
00433     maxY=minY;
00434     for (i=0;i<lin.getNumberOfPixels();i++)
00435     {
00436       int actY=image.image[lin.getPixelY(i)][0][lin.getPixelX(i)];
00437       if (actY>maxY) maxY=actY;
00438       if (actY<minY) minY=actY;
00439     }
00440     maxDelta=maxY-minY;
00441     //Scan that line again to get all bw-changes
00442     v2dArray transPos;
00443     bArray transWhiteBlack;
00444     int numOfTrans;
00445     getTransitionsOnLine(lin,&transPos,&transWhiteBlack,numOfTrans);
00446     int numOfBlocks=0;
00447     double blockHeight[30];
00448     if (numOfTrans>2)
00449     {
00450       for (i=0;i<numOfTrans;i++)
00451       {
00452         DEBUG_IMAGE_SET_PIXEL_GREEN(imageProcessorGeneral, (int)(transPos[i].x), (int)(transPos[i].y-2));
00453         DEBUG_IMAGE_SET_PIXEL_GREEN(imageProcessorGeneral, (int)(transPos[i].x), (int)(transPos[i].y-1));
00454         DEBUG_IMAGE_SET_PIXEL_GREEN(imageProcessorGeneral, (int)(transPos[i].x), (int)(transPos[i].y));
00455         DEBUG_IMAGE_SET_PIXEL_GREEN(imageProcessorGeneral, (int)(transPos[i].x), (int)(transPos[i].y+1));
00456         DEBUG_IMAGE_SET_PIXEL_GREEN(imageProcessorGeneral, (int)(transPos[i].x), (int)(transPos[i].y+2));
00457       }
00458 
00459       //search for middle marker by scanning all senkrechte and take the longest
00460       Vector2<double> middleBlock(-1,-1);
00461       double longest=0;
00462       int middleOffset=-1;
00463       int middleBlockNum=-1;
00464       double l;
00465       Vector2<double> m;
00466       if (!transWhiteBlack[0])
00467       {
00468         Vector2<double> lBorder=Vector2<double>(lin.getPixelX(0),lin.getPixelY(0));
00469         m=getMiddleAndLengthOfPerpendicular(lBorder,transPos[0],l);
00470         if (l>0)
00471         {
00472           blockHeight[numOfBlocks++]=l;
00473         }
00474         for (int len=0;len<l;len++)
00475         {
00476           if(m.y+len <image.cameraInfo.resolutionHeight)
00477           {
00478             DEBUG_IMAGE_SET_PIXEL_RED(imageProcessorGeneral, (int)(m.x), (int)(m.y+len));
00479           }
00480         }
00481       }
00482       for (i=0;i<numOfTrans-1;i++)
00483       {
00484         if ((transWhiteBlack[i])&&(!transWhiteBlack[i+1]))
00485         {
00486           m=getMiddleAndLengthOfPerpendicular(transPos[i],transPos[i+1],l);
00487           blockHeight[numOfBlocks++]=l;
00488           if (l>longest)
00489           {
00490             longest=l;
00491             middleBlock=m;
00492             middleOffset=i;
00493             middleBlockNum=numOfBlocks-1;
00494           }
00495           for (int len=0;len<l;len++)
00496           {
00497             if(m.y+len <image.cameraInfo.resolutionHeight)
00498             {
00499               DEBUG_IMAGE_SET_PIXEL_RED(imageProcessorGeneral, (int)(m.x), (int)(m.y+len));
00500             }
00501           }
00502         }
00503       }
00504       if (transWhiteBlack[numOfTrans-1])
00505       {
00506         Vector2<double> rBorder=Vector2<double>(lin.getPixelX(lin.getNumberOfPixels()-1),lin.getPixelY(lin.getNumberOfPixels()-1));
00507         m=getMiddleAndLengthOfPerpendicular(transPos[numOfTrans-1],rBorder,l);
00508         if (l>0)
00509         {
00510           blockHeight[numOfBlocks++]=l;
00511         }
00512         for (int len=0;len<l;len++)
00513         {
00514           if(m.y+len <image.cameraInfo.resolutionHeight)
00515           {
00516             DEBUG_IMAGE_SET_PIXEL_RED(imageProcessorGeneral, (int)(m.x), (int)(m.y+len));
00517           }
00518         }
00519       }
00520       
00521       //check here whether all the gaps have similar sizes
00522       double lastDist=(transPos[1]-transPos[0]).abs();
00523       for (i=1;i<numOfTrans-1;i++)
00524       {
00525         double dist=(transPos[i]-transPos[i-1]).abs();
00526         //if we have alternating bw transitions, than missing transition mean distance 3:
00527         if ((transWhiteBlack[i]==transWhiteBlack[i-1])||
00528           (dist>2.25*lastDist)||(dist*2.25<lastDist))
00529         {
00530           //this is an invalid scan line: transitions are missing or too far from each other
00531           middleOffset=-1;
00532           middleBlockNum=-1;
00533           break;
00534         }
00535         lastDist=dist;
00536       }
00537       
00538       if (middleBlockNum>=0)
00539       {
00540         //we only found a middle marker if it is significantly larger than the markers
00541         //left and right of it and if we dont watch angular to small block only:
00542         if (((middleBlockNum>0)&&(middleBlockNum<numOfBlocks-1)&&(blockHeight[middleBlockNum-1]*1.35<blockHeight[middleBlockNum])&&(blockHeight[middleBlockNum+1]*1.35<blockHeight[middleBlockNum]))||
00543             ((middleBlockNum==0)&&(numOfBlocks>2)&&(blockHeight[middleBlockNum+1]>0)&&(blockHeight[middleBlockNum+2])&&(blockHeight[middleBlockNum+1]/blockHeight[middleBlockNum+2]*1.35<blockHeight[middleBlockNum]/blockHeight[middleBlockNum+1]))||
00544             ((middleBlockNum==numOfBlocks-1)&&(numOfBlocks>2)&&(blockHeight[middleBlockNum-1]>0)&&(blockHeight[middleBlockNum-2])&&(blockHeight[middleBlockNum-1]/blockHeight[middleBlockNum-2]*1.35<blockHeight[middleBlockNum]/blockHeight[middleBlockNum-1])))
00545         {
00546           for (int len=0;len<longest;len++)
00547           {
00548             if(middleBlock.y+len <image.cameraInfo.resolutionHeight)
00549             {
00550               DEBUG_IMAGE_SET_PIXEL_BLUE(imageProcessorGeneral, (int)(middleBlock.x), (int)(middleBlock.y+len));
00551             }
00552           }
00553           //equally divide found black white transition into 2 halves
00554           int halfIndex=(numOfTrans-1)/2;
00555           double halfYPos=yPosFromTransitionIndex(halfIndex-middleOffset);
00556           double leftAngle=getAngleBetweenScreenPoints(transPos[0],transPos[halfIndex]);
00557           double leftLength=yPosFromTransitionIndex(0-middleOffset)-halfYPos;
00558           double rightAngle=getAngleBetweenScreenPoints(transPos[numOfTrans-1],transPos[halfIndex]);
00559           double rightLength=halfYPos-yPosFromTransitionIndex(numOfTrans-1-middleOffset);
00560           Vector2<double> pos = getPositionFromAngles(leftAngle,leftLength,rightAngle,rightLength);
00561 
00562           //direction camera looks to is arc to choosen transition + arc from this to camera middle:
00563           Vector3<double> front = cameraMatrix.rotation * Vector3<double>(1,0,0);
00564           Vector3<double> vectorToPoint(
00565             (double)image.cameraInfo.resolutionWidth/2/tan(image.cameraInfo.openingAngleWidth/2),
00566             /*image.cameraInfo.focalLength,*/
00567             (double)image.cameraInfo.resolutionWidth/2 - transPos[halfIndex].x,
00568             (double)image.cameraInfo.resolutionHeight/2 - transPos[halfIndex].y);
00569           Vector3<double> vectorToPointWorld = cameraMatrix.rotation * vectorToPoint;
00570           double dir = atan2(-pos.y,-pos.x)-
00571             (atan2(vectorToPointWorld.y,vectorToPointWorld.x)-
00572              atan2(front.y,front.x));
00573           
00574           specialPercept.checkerPose.translation = pos + Vector2<double>(-cos(dir)*distancePanCenterToCamera, -sin(dir)*distancePanCenterToCamera + halfYPos);
00575 
00576           specialPercept.type=SpecialPercept::checkerboard;
00577           specialPercept.checkerPose.rotation = dir - atan2(front.y,front.x);
00578         }
00579       }
00580     }
00581   }
00582   SEND_DEBUG_IMAGE(imageProcessorGeneral);
00583 }
00584 
00585 /*
00586 * $Log: CheckerboardDetector.cpp,v $
00587 * Revision 1.1.1.1  2004/05/22 17:19:26  cvsadm
00588 * created new repository GT2004_WM
00589 *
00590 * Revision 1.23  2004/03/29 15:26:29  dueffert
00591 * missdetection of near checkerboard corrected
00592 *
00593 * Revision 1.22  2004/03/08 01:38:56  roefer
00594 * Interfaces should be const
00595 *
00596 * Revision 1.21  2004/03/05 15:48:22  dueffert
00597 * small improvements to prevent bugs
00598 *
00599 * Revision 1.20  2004/02/29 17:29:15  dueffert
00600 * finetuning to increase robustness
00601 *
00602 * Revision 1.19  2004/02/29 13:46:48  dueffert
00603 * localization in critical cases improved
00604 *
00605 * Revision 1.18  2004/02/27 16:09:12  dueffert
00606 * new ideas added, number of scan lines increased, beautified
00607 *
00608 * Revision 1.17  2004/02/23 16:42:25  dueffert
00609 * maybe I should use this corrected camera calculation stuff
00610 *
00611 * Revision 1.16  2004/02/16 18:02:27  dueffert
00612 * hypothetical crash reason removed
00613 *
00614 * Revision 1.15  2004/01/30 15:23:46  dueffert
00615 * potential crash removed
00616 *
00617 * Revision 1.14  2004/01/19 14:57:49  dueffert
00618 * specialPercept uses reset() just like other percepts now
00619 *
00620 * Revision 1.13  2004/01/13 11:56:50  dueffert
00621 * added test for middle marker
00622 *
00623 * Revision 1.12  2004/01/08 18:19:28  mkunz
00624 * distancePanCenterToCamera -> distancePanCenterToCameraX
00625 * new: distancePanCenterToCameraZ
00626 *
00627 * Revision 1.11  2004/01/01 10:58:50  roefer
00628 * RobotDimensions are in a class now
00629 *
00630 * Revision 1.10  2003/12/17 09:18:58  dueffert
00631 * another variable image size bug fixed
00632 *
00633 * Revision 1.9  2003/12/16 18:15:48  dueffert
00634 * copy'n'paste bug fixed
00635 *
00636 * Revision 1.8  2003/12/16 17:38:35  dueffert
00637 * variable image resolution bug fixed
00638 *
00639 * Revision 1.7  2003/12/16 13:54:56  roefer
00640 * cameraInfo used for offset calculation
00641 *
00642 * Revision 1.6  2003/12/15 11:46:14  juengel
00643 * Introduced CameraInfo
00644 *
00645 * Revision 1.5  2003/12/15 10:57:23  dueffert
00646 * calculation bug fixed
00647 *
00648 * Revision 1.4  2003/12/05 12:01:35  dueffert
00649 * beautified
00650 *
00651 * Revision 1.3  2003/11/14 19:02:26  goehring
00652 * frameNumber added
00653 *
00654 * Revision 1.2  2003/11/10 13:46:51  dueffert
00655 * checkerboard localization improved
00656 *
00657 * Revision 1.1  2003/10/06 14:10:13  cvsadm
00658 * Created GT2004 (M.J.)
00659 *
00660 * Revision 1.2  2003/09/01 10:20:11  juengel
00661 * DebugDrawings clean-up 2
00662 * DebugImages clean-up
00663 * MessageIDs clean-up
00664 * Stopwatch clean-up
00665 *
00666 * Revision 1.1  2003/07/30 14:50:02  dueffert
00667 * CheckerboardDetector added
00668 *
00669 * Revision 1.4  2003/02/21 14:16:12  dueffert
00670 * recognition of our checkerboard continued, see logs/special_localisator2.log
00671 *
00672 * Revision 1.3  2003/02/20 15:32:17  dueffert
00673 * work continued
00674 *
00675 * Revision 1.2  2003/02/19 15:57:34  dueffert
00676 * some checkerboard detection work
00677 *
00678 * Revision 1.1  2003/01/22 15:00:03  dueffert
00679 * checkerboard stuff added
00680 *
00681 *
00682 */

Generated on Thu Sep 23 19:57:28 2004 for GT2004 by doxygen 1.3.6