00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "LFLineFitter.h"
00029
00030
00031 LFLineFitter::LFLineFitter()
00032 {
00033 localWindSize_ = 50;
00034 smallLocalWindowSize_ = max(localWindSize_/10,5);
00035 nMinEdges_ = 2;
00036 nMaxWindPoints_ = 4*(localWindSize_+1)*(localWindSize_+1);
00037 minLength_ = 2;
00038
00039 nLinesToFitInStage_[0] = 300;
00040 nLinesToFitInStage_[1] = 2000;
00041 nTrialsPerLineInStage_[0] = 300;
00042 nTrialsPerLineInStage_[1] = 1;
00043 sigmaFitALine_ = 0.75;
00044 sigmaFindSupport_ = 0.75;
00045 maxGap_ = 1.5;
00046
00047 outEdgeMap_ = NULL;
00048 rpoints_ = NULL;
00049 rProjection_ = NULL;
00050 absRProjection_ = NULL;
00051 idx_ = NULL;
00052 }
00053
00054 void LFLineFitter::Configure(double sigmaFitALine,double sigmaFindSupport, double maxGap,
00055 int nLayer,int *nLinesToFitInStage,int *nTrialsPerLineInStage)
00056 {
00057 sigmaFitALine_ = sigmaFitALine;
00058 sigmaFindSupport_ = sigmaFindSupport;
00059 maxGap_ = maxGap;
00060 for(int i=0;i<nLayer;i++)
00061 {
00062 nLinesToFitInStage_[i] = nLinesToFitInStage[i];
00063 nTrialsPerLineInStage_[i] = nTrialsPerLineInStage[i];
00064 }
00065 }
00066
00067 void LFLineFitter::Configure(const char *fileName)
00068 {
00069
00070 for(int i=0;i<50;i++)
00071 cout<<"*";
00072 cout<<endl;
00073
00074 cout<<" LFLineFitting"<<endl;
00075
00076 for(int i=0;i<50;i++)
00077 cout<<"*";
00078 cout<<endl;
00079
00080
00081 char str[256];
00082 FILE *fp=NULL;
00083 fp = fopen(fileName,"rt");
00084 if(fp==NULL)
00085 {
00086 cerr<<"[ERROR] Cannot read file "<<fileName<<"\n!!!";
00087 exit(0);
00088 }
00089
00090 cout<<"Load Configuration from "<<fileName<<endl;
00091
00092 int ret=0;
00093 ret=fscanf(fp,"%s\n",str);
00094 cout<<str<<" = ";
00095 ret=fscanf(fp,"%s\n",str);
00096 sigmaFitALine_ = atof(str);
00097 cout<<sigmaFitALine_<<endl;
00098
00099 ret=fscanf(fp,"%s\n",str);
00100 cout<<str<<" = ";
00101 ret=fscanf(fp,"%s\n",str);
00102 sigmaFindSupport_ = atof(str);
00103 cout<<sigmaFindSupport_<<endl;
00104
00105 ret=fscanf(fp,"%s\n",str);
00106 cout<<str<<" = ";
00107 ret=fscanf(fp,"%s\n",str);
00108 maxGap_ = atof(str);
00109 cout<<maxGap_<<endl;
00110
00111 for(int i=0;i<2;i++)
00112 {
00113 ret=fscanf(fp,"%s\n",str);
00114 cout<<str<<" = ";
00115 ret=fscanf(fp,"%s\n",str);
00116 nLinesToFitInStage_[i] = (int)atof(str);
00117 cout<<nLinesToFitInStage_[i]<<endl;
00118
00119 ret=fscanf(fp,"%s\n",str);
00120 cout<<str<<" = ";
00121 ret=fscanf(fp,"%s\n",str);
00122 nTrialsPerLineInStage_[i] = (int)atof(str);
00123 cout<<nTrialsPerLineInStage_[i]<<endl;
00124 }
00125
00126 fclose(fp);
00127 cout<<endl<<endl;
00128 }
00129
00130
00131 LFLineFitter::~LFLineFitter()
00132 {
00133 SafeRelease();
00134 }
00135
00136 void LFLineFitter::SafeRelease()
00137 {
00138 if(outEdgeMap_)
00139 delete [] outEdgeMap_;
00140 if(rpoints_)
00141 delete [] rpoints_;
00142 if(rProjection_)
00143 delete [] rProjection_;
00144 if(absRProjection_)
00145 delete [] absRProjection_;
00146 if(idx_)
00147 delete [] idx_;
00148 outEdgeMap_ = NULL;
00149 rpoints_ = NULL;
00150 rProjection_ = NULL;
00151 absRProjection_ = NULL;
00152 idx_ = NULL;
00153
00154
00155 }
00156
00157 void LFLineFitter::Init()
00158 {
00159 outEdgeMap_ = new LFLineSegment[nLinesToFitInStage_[0]+nLinesToFitInStage_[1]];
00160 rpoints_ = new CvPoint [nMaxWindPoints_];
00161 rProjection_ = new double [nMaxWindPoints_];
00162 absRProjection_ = new double [nMaxWindPoints_];
00163 idx_ = new int [nMaxWindPoints_];
00164
00165 }
00166
00167 void LFLineFitter::FitLine(IplImage *inputImage)
00168 {
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 width_ = inputImage->width;
00179 height_ = inputImage->height;
00180
00181 map<int,CvPoint> edgeMap;
00182
00183 int i,j,k;
00184 int x0,y0;
00185 int width,height;
00186 int index=0;
00187 int nPixels=0;
00188 int nEdges=0;
00189 int maxSupport=0;
00190 LFLineSegment tmpLs,bestLs;
00191 CvPoint2D64f lnormal;
00192 int nWindPoints=0,nWaitingKillingList=0,nProposedKillingList=0;
00193 CvPoint *windPoints,*waitingKillingList,*proposedKillingList;
00194 windPoints = new CvPoint [nMaxWindPoints_];
00195 waitingKillingList = new CvPoint[nMaxWindPoints_];
00196 proposedKillingList = new CvPoint[nMaxWindPoints_];
00197
00198 width = inputImage->width;
00199 height = inputImage->height;
00200 nPixels = width*height;
00201
00202 for(int y=0;y<height;y++)
00203 {
00204 for(int x=0;x<width;x++)
00205 {
00206 i = x + y*width;
00207 if(cvGetReal1D(inputImage,i)!=0)
00208 {
00209 edgeMap.insert(pair<int,CvPoint>(i,cvPoint(x,y)));
00210 nEdges++;
00211 }
00212 }
00213 }
00214
00215
00216 nInputEdges_ = nEdges;
00217 nLineSegments_=0;
00218 for(k=0;k<2;k++)
00219 {
00220 if(nEdges<nMinEdges_)
00221 break;
00222 for(i=0;i<nLinesToFitInStage_[k];i++)
00223 {
00224 maxSupport = 0;
00225 for(j=0;j<nTrialsPerLineInStage_[k];j++)
00226 {
00227
00228 index = SampleAPixel(&edgeMap,inputImage,nPixels);
00229 y0 = index/width;
00230 x0 = index - y0*width;
00231
00232
00233 Find(x0,y0,windPoints,nWindPoints,inputImage,smallLocalWindowSize_);
00234
00235
00236 FitALine(nWindPoints,windPoints,sigmaFitALine_,lnormal);
00237
00238
00239 Find(&edgeMap,x0,y0,windPoints,nWindPoints,inputImage,localWindSize_);
00240
00241
00242 FindSupport(nWindPoints,windPoints,lnormal,sigmaFindSupport_,maxGap_,
00243 tmpLs,proposedKillingList,nProposedKillingList,x0,y0);
00244
00245
00246 if(tmpLs.nSupport_ > maxSupport)
00247 {
00248 maxSupport = tmpLs.nSupport_;
00249 nWaitingKillingList = nProposedKillingList;
00250 memcpy(waitingKillingList,proposedKillingList,sizeof(CvPoint)*nWaitingKillingList);
00251 bestLs = tmpLs;
00252 }
00253 }
00254
00255
00256 for(j=0;j<maxSupport;j++)
00257 {
00258 cvSetReal2D(inputImage,waitingKillingList[j].y,waitingKillingList[j].x,0.0);
00259
00260 edgeMap.erase(waitingKillingList[j].y*width+waitingKillingList[j].x);
00261 }
00262 nEdges -= bestLs.nSupport_;
00263 bestLs.len_ = sqrt( (bestLs.sx_-bestLs.ex_)*(bestLs.sx_-bestLs.ex_) + (bestLs.sy_-bestLs.ey_)*(bestLs.sy_-bestLs.ey_));
00264 outEdgeMap_[nLineSegments_] = bestLs;
00265 nLineSegments_++;
00266
00267 if(nEdges<nMinEdges_)
00268 break;
00269 }
00270 }
00271
00272
00273 qsort(outEdgeMap_,nLineSegments_,sizeof(LFLineSegment),LFLineSegment::Compare);
00274 std::cout<<"Num. lines in test image = "<<nLineSegments_<<std::endl;
00275
00276
00277 delete [] windPoints;
00278 delete [] waitingKillingList;
00279 delete [] proposedKillingList;
00280 edgeMap.clear();
00281
00282 std::cout<<"Line Ftting Done"<<std::endl;
00283
00284
00285 }
00286
00287 void LFLineFitter::SaveEdgeMap(const char *filename)
00288 {
00289 FILE *fp;
00290 qsort(outEdgeMap_,nLineSegments_,sizeof(LFLineSegment),LFLineSegment::Compare);
00291 fp = fopen(filename,"wt");
00292
00293 fprintf(fp,"%d %d\n",width_,height_);
00294 fprintf(fp,"%d\n",nLineSegments_);
00295
00296 double ratio=0;
00297 double count=0;
00298 for(int i=0;i<nLineSegments_;i++)
00299 {
00300 count += (double)outEdgeMap_[i].nSupport_;
00301 ratio = count/nInputEdges_;
00302 fprintf(fp,"%d %d %d %d\n",(int)outEdgeMap_[i].sx_,(int)outEdgeMap_[i].sy_,(int)outEdgeMap_[i].ex_,(int)outEdgeMap_[i].ey_);
00303 }
00304
00305 fclose(fp);
00306
00307
00308 }
00309
00310
00311 void LFLineFitter::DisplayEdgeMap(IplImage *inputImage,const char *outputImageName)
00312 {
00313
00314 IplImage *debugImage = cvCreateImage( cvSize(inputImage->width,inputImage->height), IPL_DEPTH_8U,1);
00315 cvZero(debugImage);
00316
00317 for(int i=0;i<nLineSegments_;i++)
00318 {
00319 cvLine(debugImage,cvPoint((int)outEdgeMap_[i].sx_,(int)outEdgeMap_[i].sy_),
00320 cvPoint((int)outEdgeMap_[i].ex_,(int)outEdgeMap_[i].ey_),cvScalar(255));
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 cvReleaseImage(&debugImage);
00336 }
00337
00338 void LFLineFitter::FindSupport(const int nWindPoints,CvPoint *windPoints,CvPoint2D64f &lnormal,
00339 double sigmaFindSupport,double maxGap,LFLineSegment &ls,
00340 CvPoint *proposedKillingList,int &nProposedKillingList,int x0,int y0)
00341 {
00342 int i,j;
00343 int nRindices = 0;
00344 int zeroIndex=0;
00345 double residuals;
00346 CvPoint2D64f ldirection;
00347
00348
00349 for(i=0;i<nWindPoints;i++)
00350 {
00351 residuals = fabs( windPoints[i].x*lnormal.x + windPoints[i].y*lnormal.y );
00352 if(residuals<sigmaFindSupport)
00353 {
00354 rpoints_[nRindices] = windPoints[i];
00355 nRindices++;
00356 }
00357 }
00358 ldirection.x = -lnormal.y;
00359 ldirection.y = lnormal.x;
00360
00361
00362 if(nRindices<minLength_)
00363 {
00364 ls.nSupport_ = -1;
00365 return;
00366 }
00367
00368
00369
00370 for(i=0;i<nRindices;i++)
00371 {
00372 rProjection_[i] = rpoints_[i].x*ldirection.x+ rpoints_[i].y*ldirection.y;
00373 idx_[i] = i;
00374 }
00375
00376
00377 ISort(rProjection_,nRindices,idx_);
00378
00379 for(i=0;i<nRindices;i++)
00380 absRProjection_[i] = fabs(rProjection_[i]);
00381
00382 for(i=0;i<nRindices;i++)
00383 {
00384 if(absRProjection_[i]==0)
00385 {
00386 zeroIndex = i;
00387 break;
00388 }
00389 }
00390
00391 int maxIndex = nRindices-1;
00392 for( i=zeroIndex; i<(nRindices-1); i++)
00393 {
00394 if((rProjection_[i+1]-rProjection_[i])>maxGap)
00395 {
00396 maxIndex = i;
00397 break;
00398 }
00399 }
00400
00401 int minIndex = 0;
00402 for( i=zeroIndex; i>0; i--)
00403 {
00404 if((rProjection_[i]-rProjection_[i-1])>maxGap)
00405 {
00406 minIndex = i;
00407 break;
00408 }
00409 }
00410
00411 ls.nSupport_ = maxIndex-minIndex+1;
00412 ls.sx_ = (double)rpoints_[ idx_[minIndex] ].x+x0;
00413 ls.sy_ = (double)rpoints_[ idx_[minIndex] ].y+y0;
00414 ls.ex_ = (double)rpoints_[ idx_[maxIndex] ].x+x0;
00415 ls.ey_ = (double)rpoints_[ idx_[maxIndex] ].y+y0;
00416
00417 j = 0;
00418 for(i=minIndex;i<=maxIndex;i++)
00419 {
00420 proposedKillingList[j].x = rpoints_[ idx_[i] ].x + x0;
00421 proposedKillingList[j].y = rpoints_[ idx_[i] ].y + y0;
00422 j++;
00423 }
00424 nProposedKillingList = j;
00425
00426 ls.normal_ = lnormal;
00427 }
00428
00429
00430 int LFLineFitter::FitALine(const int nWindPoints,CvPoint *windPoints,const double sigmaFitALine,CvPoint2D64f &lnormal)
00431 {
00432 double inlierRatio = 0.9;
00433 double outlierRatio = 0.9;
00434 double gamma = 0.05;
00435 int nMaxTry = 29;
00436
00437 int i=0,j=0,index=0;
00438 int cscore;
00439 double tmpScore;
00440 double norm;
00441 int bestscore = -1;
00442 CvPoint2D64f cdirection,cnormal;
00443
00444 while(i<nMaxTry)
00445 {
00446 index = (int)floor(rand()/(double)RAND_MAX*(double)nWindPoints);
00447 norm = sqrt( 1.0*windPoints[index].x*windPoints[index].x + windPoints[index].y*windPoints[index].y );
00448
00449 if(norm>0)
00450 {
00451 cdirection.x = windPoints[index].x/norm;
00452 cdirection.y = windPoints[index].y/norm;
00453
00454 cnormal.x = -cdirection.y;
00455 cnormal.y = cdirection.x;
00456
00457 cscore = 0;
00458 for(j=0;j<nWindPoints;j++)
00459 {
00460 tmpScore = fabs(windPoints[j].x*cnormal.x+windPoints[j].y*cnormal.y);
00461 if(tmpScore<sigmaFitALine)
00462 cscore++;
00463 }
00464
00465 if( ((double)cscore)/nWindPoints > inlierRatio)
00466 {
00467 bestscore = cscore;
00468 lnormal = cnormal;
00469 return bestscore;
00470 }
00471
00472 if( (1.0-((double)cscore)/nWindPoints) < outlierRatio)
00473 {
00474 outlierRatio = 1.0-((double)cscore)/nWindPoints;
00475 nMaxTry = (int)ceil(log(gamma)/log(outlierRatio));
00476 }
00477
00478 if(cscore>bestscore)
00479 {
00480 bestscore = cscore;
00481 lnormal = cnormal;
00482 }
00483 }
00484 i = i+1;
00485 }
00486
00487 return bestscore;
00488 }
00489
00490
00491
00492
00493 void LFLineFitter::Find(int x0,int y0,CvPoint *windPoints,int &nWindPoints,IplImage *inputImage,int localWindSize)
00494 {
00495 int x,y;
00496 nWindPoints = 0;
00497
00498 for(y=max(y0-localWindSize,0);y<min(y0+localWindSize,inputImage->height);y++)
00499 for(x=max(x0-localWindSize,0);x<min(x0+localWindSize,inputImage->width);x++)
00500 {
00501 if(cvGetReal2D(inputImage,y,x)!=0)
00502 {
00503 windPoints[nWindPoints].x = x - x0;
00504 windPoints[nWindPoints].y = y - y0;
00505 nWindPoints++;
00506 }
00507 }
00508 }
00509
00510
00511 void LFLineFitter::Find(map<int,CvPoint> *edgeMap,int x0,int y0,CvPoint *windPoints,int &nWindPoints,IplImage *inputImage,int localWindSize)
00512 {
00513 nWindPoints = 0;
00514 map<int,CvPoint>::iterator it;
00515
00516 int left = max(x0-localWindSize,0);
00517 int right = min(x0+localWindSize,inputImage->width);
00518 int top = max(y0-localWindSize,0);
00519 int bottom = min(y0+localWindSize,inputImage->height);
00520
00521 for(it = edgeMap->begin();it!=edgeMap->end();++it)
00522 {
00523 if( it->second.x > left && it->second.x < right &&
00524 it->second.y > top && it->second.y < bottom )
00525 {
00526 windPoints[nWindPoints].x = it->second.x - x0;
00527 windPoints[nWindPoints].y = it->second.y - y0;
00528 nWindPoints++;
00529 }
00530 }
00531 }
00532
00533
00534 int LFLineFitter::SampleAPixel(map<int,CvPoint> *edgeMap,IplImage *inputImage,int nPixels)
00535 {
00536 int index = (int)(floor(rand()/(double)RAND_MAX*(double)(edgeMap->size()-1)));
00537 map<int,CvPoint>::iterator it;
00538 it=edgeMap->begin();
00539 for(int i=0;i<index;i++)
00540 it++;
00541 return (*it).first;
00542 }
00543
00544 void LFLineFitter::ISort(double* ra, int nVec, int* ira)
00545 {
00546 unsigned long n, l, ir, i, j;
00547 n = nVec;
00548 double rra;
00549 int irra;
00550
00551 if (n<2)
00552 return;
00553 l = (n>>1)+1;
00554 ir = n;
00555 for (;;)
00556 {
00557 if (l>1)
00558 {
00559 irra = ira[(--l)-1];
00560 rra = ra[l-1];
00561 }
00562 else
00563 {
00564 irra = ira[ir-1];
00565 rra = ra[ir-1];
00566
00567 ira[ir-1] = ira[1-1];
00568 ra[ir-1] = ra[1-1];
00569
00570 if (--ir==1)
00571 {
00572 ira[1-1] = irra;
00573 ra[1-1] = rra;
00574 break;
00575 }
00576 }
00577 i = l;
00578 j = l+l;
00579 while (j<=ir)
00580 {
00581 if (j<ir && ra[j-1]<ra[j+1-1])
00582 j++;
00583 if (rra<ra[j-1])
00584 {
00585 ira[i-1] = ira[j-1];
00586 ra[i-1] = ra[j-1];
00587
00588 i = j;
00589 j <<= 1;
00590 }
00591 else
00592 j = ir+1;
00593 }
00594 ira[i-1] = irra;
00595 ra[i-1] = rra;
00596 }
00597
00598 }