00001 /* 00002 Copyright 2010, Ming-Yu Liu 00003 00004 All Rights Reserved 00005 00006 Permission to use, copy, modify, and distribute this software and 00007 its documentation for any non-commercial purpose is hereby granted 00008 without fee, provided that the above copyright notice appear in 00009 all copies and that both that copyright notice and this permission 00010 notice appear in supporting documentation, and that the name of 00011 the author not be used in advertising or publicity pertaining to 00012 distribution of the software without specific, written prior 00013 permission. 00014 00015 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 00016 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00017 ANY PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 00018 ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00019 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 00020 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 00021 OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00022 */ 00023 00024 00025 00026 #include "LMLineMatcher.h" 00027 00028 00029 LMLineMatcher::LMLineMatcher() 00030 { 00031 dbImages_ = NULL; 00032 distances_ = new double[5000000]; 00033 indices_ = new int[5000000]; 00034 xIndices_ = new int[5000000]; 00035 yIndices_ = new int[5000000]; 00036 sIndices_ = new double[5000000]; 00037 dIndices_ = new double[5000000]; 00038 iindices_ = new int[5000000]; 00039 wIndices_ = new int[5000000]; 00040 hIndices_ = new int[5000000]; 00041 }; 00042 00043 LMLineMatcher::~LMLineMatcher() 00044 { 00045 SafeRelease(); 00046 }; 00047 00048 void LMLineMatcher::SafeRelease() 00049 { 00050 delete [] distances_; 00051 delete [] indices_; 00052 delete [] xIndices_; 00053 delete [] yIndices_; 00054 delete [] dIndices_; 00055 delete [] iindices_; 00056 delete [] sIndices_; 00057 delete [] wIndices_; 00058 delete [] hIndices_; 00059 00060 if (dbImages_) 00061 delete[] dbImages_; 00062 dbImages_ = NULL; 00063 00064 }; 00065 00066 void LMLineMatcher::Configure(const char *fileName) 00067 { 00068 00069 for(int i=0;i<50;i++) 00070 cout<<"*"; 00071 cout<<endl; 00072 00073 cout<<" LMLineMatching"<<endl; 00074 00075 for(int i=0;i<50;i++) 00076 cout<<"*"; 00077 cout<<endl; 00078 00079 00080 char str[256]; 00081 FILE *fp=NULL; 00082 fp = fopen(fileName,"rt"); 00083 if(fp==NULL) 00084 { 00085 cerr<<"[ERROR] Cannot read file "<<fileName<<"\n!!!"; 00086 exit(0); 00087 } 00088 cout<<"Load Configuration from "<<fileName<<endl; 00089 00090 int ret=0; 00091 // nDirections 00092 ret=fscanf(fp,"%s\n",str); 00093 cout<<str<<" = "; 00094 ret=fscanf(fp,"%s\n",str); 00095 nDirections_ = atoi(str); 00096 cout<<nDirections_<<endl; 00097 00098 // direction cost 00099 ret=fscanf(fp,"%s\n",str); 00100 cout<<str<<" = "; 00101 ret=fscanf(fp,"%s\n",str); 00102 directionCost_ = (float)atof(str); 00103 cout<<directionCost_<<endl; 00104 00105 // maximum cost 00106 ret=fscanf(fp,"%s\n",str); 00107 cout<<str<<" = "; 00108 ret=fscanf(fp,"%s\n",str); 00109 maxCost_ = atof(str); 00110 cout<<maxCost_<<endl; 00111 00112 // matching Scale 00113 ret=fscanf(fp,"%s\n",str); 00114 cout<<str<<" = "; 00115 ret=fscanf(fp,"%s\n",str); 00116 scale_ = atof(str); 00117 cout<<scale_<<endl; 00118 00119 00120 // db Scale 00121 ret=fscanf(fp,"%s\n",str); 00122 cout<<str<<" = "; 00123 ret=fscanf(fp,"%s\n",str); 00124 db_scale_ = atof(str); 00125 cout<<db_scale_<<endl; 00126 00127 // Base Search Scale 00128 ret=fscanf(fp,"%s\n",str); 00129 cout<<str<<" = "; 00130 ret=fscanf(fp,"%s\n",str); 00131 baseSearchScale_ = atof(str); 00132 cout<<baseSearchScale_<<endl; 00133 00134 // Min Search Scale 00135 ret=fscanf(fp,"%s\n",str); 00136 cout<<str<<" = "; 00137 ret=fscanf(fp,"%s\n",str); 00138 minSearchScale_ = atof(str); 00139 cout<<minSearchScale_<<endl; 00140 00141 // Max Search Scale 00142 ret=fscanf(fp,"%s\n",str); 00143 cout<<str<<" = "; 00144 ret=fscanf(fp,"%s\n",str); 00145 maxSearchScale_ = atof(str); 00146 cout<<maxSearchScale_<<endl; 00147 00148 00149 // Search Step Size 00150 ret=fscanf(fp,"%s\n",str); 00151 cout<<str<<" = "; 00152 ret=fscanf(fp,"%s\n",str); 00153 searchStepSize_ = atoi(str); 00154 cout<<searchStepSize_<<endl; 00155 00156 // Search Boundary Size 00157 ret=fscanf(fp,"%s\n",str); 00158 cout<<str<<" = "; 00159 ret=fscanf(fp,"%s\n",str); 00160 searchBoundarySize_ = atoi(str); 00161 cout<<searchBoundarySize_<<endl; 00162 00163 // Min Cost Ratio 00164 ret=fscanf(fp,"%s\n",str); 00165 cout<<str<<" = "; 00166 ret=fscanf(fp,"%s\n",str); 00167 minCostRatio_ = atof(str); 00168 cout<<minCostRatio_<<endl; 00169 00170 00171 fclose(fp); 00172 cout<<endl<<endl; 00173 } 00174 00175 00176 void LMLineMatcher::Init(const char* fileName,double db_scale) 00177 { 00178 char imageName[512]; 00179 00180 db_scale_ = db_scale; 00181 00182 FILE* fin=NULL; 00183 00184 fin = fopen(fileName, "r"); 00185 if(fileName==NULL) 00186 { 00187 cerr<<"[ERROR] Cannot read file "<<fileName<<"\n!!!"; 00188 exit(0); 00189 } 00190 int ret = 0; 00191 ret=fscanf(fin, "%d", &ndbImages_); 00192 dbImages_ = new EIEdgeImage [ndbImages_]; 00193 00194 std::cout<<"Num. templates = "<<ndbImages_<<std::endl; 00195 00196 for (int i=0;i<ndbImages_ ;i++) 00197 { 00198 ret=fscanf(fin, "%s\n", (char*)imageName); 00199 dbImages_[i].SetNumDirections(nDirections_); 00200 dbImages_[i].Read(imageName); 00201 dbImages_[i].Scale(scale_*db_scale_); 00202 } 00203 00204 fclose(fin); 00205 } 00206 00207 00208 void LMLineMatcher::computeIDT3(int width, int height, int nLines, LFLineSegment* linesSegment) 00209 { 00210 00211 queryImage_.SetNumDirections(nDirections_); 00212 queryImage_.Read(width, height, nLines, linesSegment); 00213 queryImage_.Scale(scale_); 00214 queryDistanceImage_.Configure(directionCost_,maxCost_); 00215 queryDistanceImage_.SetImage(queryImage_); 00216 00217 std::cout<<"IDT3 Computation done " << std::endl; 00218 00219 } 00220 00221 00222 00223 std::vector<LMLineMatcher::Rect> LMLineMatcher::Match(int width, int height, int nLines, LFLineSegment* linesSegment) 00224 { 00225 //LARGE_INTEGER t1, t2, f; 00226 //QueryPerformanceFrequency(&f); 00227 //QueryPerformanceCounter(&t1); 00228 00229 00230 00231 queryImage_.SetNumDirections(nDirections_); 00232 queryImage_.Read(width, height, nLines, linesSegment); 00233 queryImage_.Scale(scale_); 00234 queryDistanceImage_.Configure(directionCost_,maxCost_); 00235 queryDistanceImage_.SetImage(queryImage_); 00236 00237 std::cout<<"IDT3 Computation done " << std::endl; 00238 00239 00240 double minCost = 1e+10; 00241 int counter = 0; 00242 for (int i=0 ; i<ndbImages_ ; i++) 00243 { 00244 MatchBruteForce(dbImages_[i], i, iindices_, 00245 indices_, xIndices_, yIndices_, dIndices_, sIndices_, distances_, 00246 counter, minCost); 00247 } 00248 00249 //QueryPerformanceCounter(&t2); 00250 //std::cout<<"Fast Directional Chamfer Matching Time "<<setiosflags(ios::fixed)<<setprecision(6)<<(t2.QuadPart - t1.QuadPart)/(1.0*f.QuadPart)<<std::endl; 00251 std::cout<<"Fast Directional Chamfer Matching DOne "<<std::endl; 00252 00253 ISort(distances_, counter, iindices_); 00254 00255 00256 // Display best matcher in edge map 00257 std::vector<Rect> matches; 00258 for(int i=0; i<counter; i++) 00259 { 00260 int x = (int)ceil(xIndices_[iindices_[i]]/scale_-0.5); 00261 int y = (int)ceil(yIndices_[iindices_[i]]/scale_-0.5); 00262 double scale = sIndices_[iindices_[i]]; 00263 int detWindWidth= (int)(dbImages_[indices_[iindices_[i]]].width_*scale/scale_); 00264 int detWindHeight= (int)(dbImages_[indices_[iindices_[i]]].height_*scale/scale_); 00265 //printf("MATCH: %i %f %i %i %i %i\n", i, distances_[i], 00266 // x, y, detWindWidth, detWindHeight); 00267 matches.push_back(Rect(x,y,detWindWidth, detWindHeight, distances_[i])); 00268 00269 00270 if (imageName_.size() > 0) 00271 { 00272 //IplImage *debugImage = cvLoadImage(imageName_.c_str(),1); 00273 //DrawDetWind(debugImage,x,y,detWindWidth,detWindHeight); 00274 //cvNamedWindow("output",0); 00275 //cvShowImage("output",debugImage); 00276 //cvWaitKey(0); 00277 //cvReleaseImage(&debugImage); 00278 } 00279 } 00280 return matches; 00281 } 00282 00283 void LMLineMatcher::DrawMatchTemplate(IplImage *image,EIEdgeImage &ei,int x,int y,double scale,CvScalar scalar,int thickness) 00284 { 00285 EIEdgeImage tdbImage; 00286 tdbImage = ei; 00287 tdbImage.Scale(scale); 00288 LFLineSegment line; 00289 double ltrans[2]; 00290 ltrans[0] = 1.0*x; 00291 ltrans[1] = 1.0*y; 00292 for (int k=0 ; k<tdbImage.nLines_ ; k++) 00293 { 00294 line = tdbImage.lines_[k]; 00295 line.Translate(ltrans); 00296 cvLine(image,cvPoint((int)line.sx_,(int)line.sy_),cvPoint((int)line.ex_,(int)line.ey_),scalar,thickness); 00297 } 00298 } 00299 00300 void LMLineMatcher::DrawDetWind(IplImage *image,int x,int y,int detWindWidth,int detWindHeight,CvScalar scalar,int thickness) 00301 { 00302 cvLine(image,cvPoint( x,y),cvPoint( x+detWindWidth,y),scalar,thickness); 00303 cvLine(image,cvPoint( x+detWindWidth,y),cvPoint( x+detWindWidth, y+detWindHeight),scalar,thickness); 00304 cvLine(image,cvPoint( x+detWindWidth,y+detWindHeight),cvPoint( x, y+detWindHeight),scalar,thickness); 00305 cvLine(image,cvPoint( x, y+detWindHeight),cvPoint( x, y),scalar,thickness); 00306 00307 } 00308 00309 00310 00311 double LMLineMatcher::getCost(EIEdgeImage& tdbImage, double ltrans[2], double factor, int& count) 00312 { 00313 00314 LFLineSegment line; 00315 double minCost = 1e+10; 00316 00317 double cost = 0; 00318 for (int k=0 ; k<tdbImage.nLines_ ; k++) 00319 { 00320 line = tdbImage.lines_[k]; 00321 line.Translate(ltrans); 00322 00323 //printf("Count: %f %f %i %i %i %i\n", 00324 // ltrans[0], ltrans[1], 00325 // (int)line.sx_, (int) line.sy_, 00326 // (int)line.ex_,(int) line.ey_); 00327 00328 00329 int ccount = 0; 00330 double sum = queryDistanceImage_.idtImages_[tdbImage.directionIndices_[k]].Sum((int)line.sx_,(int) line.sy_,(int) line.ex_,(int) line.ey_, ccount); 00331 count += ccount; 00332 00333 //printf("Done\n"); 00334 cost+=sum*factor; 00335 if (cost > minCost*minCostRatio_) 00336 { 00337 cost = 1e+10; 00338 break; 00339 } 00340 } 00341 00342 return cost; 00343 } 00344 00345 double LMLineMatcher::getCost(int directionIdx, int sx, int sy, int ex, int ey, int count) const 00346 { 00347 return queryDistanceImage_.idtImages_[directionIdx].Sum(sx,sy,ex,ey,count); 00348 } 00349 00350 double LMLineMatcher::MatchBruteForce(EIEdgeImage& dbImage, 00351 int index, int* iindices, 00352 int* indices, int* xIndex, int* yIndex, 00353 double* dIndex, double* sIndex, 00354 double* distances, int& counter, double& minCost) 00355 { 00356 00357 int count =0; 00358 int i = 0; 00359 //int k; 00360 00361 LFLineSegment dbLine, queryLine; 00362 00363 00364 double ltrans[2]; 00365 00366 double factor = 1.0; 00367 double cost; //, sum; 00368 double minx, miny, maxx, maxy; 00369 double scale; 00370 00371 LFLineSegment line; 00372 00373 //int currentcount; 00374 00375 for(double s = minSearchScale_ ; s< maxSearchScale_ ; s++) 00376 { 00377 scale = pow(baseSearchScale_,s); 00378 printf("Scale %f\n", scale); 00379 EIEdgeImage tdbImage; 00380 tdbImage = dbImage; 00381 tdbImage.Scale(scale); 00382 factor = 1.0/dbImage.Length(); 00383 tdbImage.Boundary(minx, miny, maxx, maxy); 00384 tdbImage.SetDirectionIndices(); 00385 00386 printf("W %i H %i\n", queryImage_.width_, queryImage_.height_); 00387 for (int x=-(int)minx ; x<queryImage_.width_-(int)minx ; x += searchStepSize_) 00388 { 00389 for (int y=-(int)miny; y<queryImage_.height_-(int)miny; y += searchStepSize_) 00390 { 00391 00392 ltrans[0] = (double)x; 00393 ltrans[1] = (double)y; 00394 cost = 0; 00395 00396 if (minx + ltrans[0] <=searchBoundarySize_ || 00397 minx + ltrans[0] >=queryImage_.width_-searchBoundarySize_ || 00398 maxx + ltrans[0] <=searchBoundarySize_ || 00399 maxx + ltrans[0] >=queryImage_.width_-searchBoundarySize_ || 00400 miny + ltrans[1] <=searchBoundarySize_ || 00401 miny + ltrans[1] >=queryImage_.height_-searchBoundarySize_ || 00402 maxy + ltrans[1] <=searchBoundarySize_ || 00403 maxy + ltrans[1] >=queryImage_.height_-searchBoundarySize_ ) 00404 { 00405 cost = 1e+10; 00406 continue; 00407 } 00408 else 00409 { 00410 count++; 00411 00412 int ccount; 00413 cost = getCost(tdbImage, ltrans, factor, ccount); 00414 //for (k=0 ; k<tdbImage.nLines_ ; k++) 00415 //{ 00416 // line = tdbImage.lines_[k]; 00417 // line.Translate(ltrans); 00418 00419 // sum = queryDistanceImage_.idtImages_[tdbImage.directionIndices_[k]].Sum((int)line.sx_,(int) line.sy_,(int) line.ex_,(int) line.ey_, currentcount); 00420 00421 // cost+=sum*factor; 00422 // if (cost > minCost*minCostRatio_) 00423 // { 00424 // cost = 1e+10; 00425 // break; 00426 // } 00427 //} 00428 } 00429 00430 00431 if (cost<minCost*minCostRatio_) 00432 { 00433 xIndex[counter] = (int)ltrans[0]; 00434 yIndex[counter] = (int)ltrans[1]; 00435 dIndex[counter] = (i*M_PI)/nDirections_; 00436 sIndex[counter] = scale; 00437 distances[counter] = cost; 00438 iindices[counter] = counter; 00439 indices[counter++] = index; 00440 00441 if (cost<minCost) 00442 minCost = cost; 00443 00444 } 00445 00446 00447 } 00448 } 00449 00450 } 00451 return minCost; 00452 } 00453 00454 00455 void LMLineMatcher::ISort(double* ra, int nVec, int* ira) 00456 { 00457 unsigned long n, l, ir, i, j; 00458 n = nVec; 00459 double rra; 00460 int irra; 00461 00462 if (n<2) 00463 return; 00464 l = (n>>1)+1; 00465 ir = n; 00466 for (;;) 00467 { 00468 if (l>1) 00469 { 00470 irra = ira[(--l)-1]; 00471 rra = ra[l-1]; 00472 } 00473 else 00474 { 00475 irra = ira[ir-1]; 00476 rra = ra[ir-1]; 00477 00478 ira[ir-1] = ira[1-1]; 00479 ra[ir-1] = ra[1-1]; 00480 00481 if (--ir==1) 00482 { 00483 ira[1-1] = irra; 00484 ra[1-1] = rra; 00485 break; 00486 } 00487 } 00488 i = l; 00489 j = l+l; 00490 while (j<=ir) 00491 { 00492 if (j<ir && ra[j-1]<ra[j+1-1]) 00493 j++; 00494 if (rra<ra[j-1]) 00495 { 00496 ira[i-1] = ira[j-1]; 00497 ra[i-1] = ra[j-1]; 00498 00499 i = j; 00500 j <<= 1; 00501 } 00502 else 00503 j = ir+1; 00504 } 00505 ira[i-1] = irra; 00506 ra[i-1] = rra; 00507 } 00508 00509 }