00001 /*!@file SceneUnderstanding/GeometricHashing.C Shape from shading */ 00002 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00006 // by the University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/FeatureMatching/GeometricHashing.C $ 00036 // $Id: GeometricHashing.C 12962 2010-03-06 02:13:53Z irock $ 00037 // 00038 00039 #ifndef GeometricHashing_C_DEFINED 00040 #define GeometricHashing_C_DEFINED 00041 00042 #include "FeatureMatching/GeometricHashing.H" 00043 #include "Image/DrawOps.H" 00044 #include "GUI/DebugWin.H" 00045 #include <fcntl.h> 00046 00047 // ###################################################################### 00048 GeometricHashing::GeometricHashing() : 00049 itsTableWidth(0.10), 00050 itsNumFeatures(0), 00051 itsNumBinEntries(0) 00052 { 00053 itsHashTable = Image<TableEntry>(32,32,ZEROS); 00054 itsTableWidth = 1/32.0; 00055 } 00056 00057 // ###################################################################### 00058 GeometricHashing::~GeometricHashing() 00059 { 00060 00061 } 00062 00063 //void GeometricHashing::addModel(const Model& model) 00064 //{ 00065 // itsModels.push_back(model); 00066 // 00067 // //uint p1 = 0; 00068 // //uint p2 = 1; 00069 // for(uint p1 = 0; p1 < model.v.size(); p1++) 00070 // for(uint p2 = p1; p2 < model.v.size(); p2++) 00071 // { 00072 // if (p1 == p2) 00073 // continue; 00074 // //Change basis 00075 // std::vector<Point2D<float> > featureLoc = changeBasis(model.v, p1, p2); 00076 // 00077 // //Add entries to hash table 00078 // for(uint i=0; i<featureLoc.size(); i++) 00079 // { 00080 // // LINFO("%i %fx%f", 00081 // // i, featureLoc[i].i, featureLoc[i].j); 00082 // //Dont insert the basis points, since they are always at the same place 00083 // if (i != p1 && i != p2) 00084 // insertToHashTable(featureLoc[i], p1, p2, model.id, model.rot); 00085 // } 00086 // } 00087 //} 00088 00089 void GeometricHashing::addModel(const Model& model) 00090 { 00091 itsModels.push_back(model); 00092 00093 //Find the minimum bounding box 00094 Point2D<int> tl = model.v[0]; 00095 Point2D<int> br = model.v[0]; 00096 for(uint i=0; i<model.v.size(); i++) 00097 { 00098 if (br.i > model.v[i].i) 00099 br.i = model.v[i].i; 00100 if (br.j > model.v[i].j) 00101 br.j = model.v[i].j; 00102 00103 if (tl.i < model.v[i].i) 00104 tl.i = model.v[i].i; 00105 if (tl.j < model.v[i].j) 00106 tl.j = model.v[i].j; 00107 } 00108 00109 std::vector<Point2D<float> > featureLoc = changeBasis(model.v, tl, br); 00110 for(uint i=0; i<featureLoc.size(); i++) 00111 insertToHashTable(featureLoc[i], 0, 0, model.id, model.rot); 00112 00113 } 00114 00115 void GeometricHashing::insertToHashTable(const Point2D<float> loc, 00116 int p1, int p2, int modelId, 00117 Point3D<float> rot) 00118 { 00119 00120 ModelTableEntry mte; 00121 mte.modelId = modelId; 00122 mte.rot = rot; 00123 mte.featureLoc = loc; 00124 mte.basisP1 = p1; 00125 mte.basisP2 = p2; 00126 00127 Image<GeometricHashing::TableEntry>::iterator iter = findInHash(loc); 00128 if (iter != NULL) 00129 iter->modelEntries.push_back(mte); 00130 } 00131 00132 00133 Image<GeometricHashing::TableEntry>::iterator 00134 GeometricHashing::findInHash(const Point2D<float>& loc) 00135 { 00136 //Find the table location; 00137 int i = (itsHashTable.getWidth()/2) + int( floor(loc.i / itsTableWidth) ); 00138 int j = (itsHashTable.getHeight()/2) + int( floor(loc.j / itsTableWidth) ); 00139 00140 Image<GeometricHashing::TableEntry>::iterator iter = NULL; 00141 00142 if (itsHashTable.coordsOk(i,j)) 00143 { 00144 iter = itsHashTable.beginw(); 00145 iter += (i + j*itsHashTable.getWidth()); 00146 } 00147 return iter; 00148 } 00149 00150 //std::vector<GeometricHashing::Acc> GeometricHashing::getVotes(std::vector<Point2D<int> >& input) 00151 //{ 00152 // std::vector<Acc> acc; 00153 // 00154 // //Choose two points from the image to become the basis 00155 // for(uint p1 = 0; p1 < input.size(); p1++) 00156 // for(uint p2 = p1; p2 < input.size(); p2++) 00157 // { 00158 // if (p1 == p2) 00159 // continue; 00160 // //Change basis of input 00161 // std::vector<Point2D<float> > newInput = changeBasis(input, p1, p2); 00162 // 00163 // //For each input find the value in the hash table and count the votes 00164 // for(uint i=0; i<newInput.size(); i++) 00165 // { 00166 // Image<GeometricHashing::TableEntry>::iterator iter = 00167 // findInHash(newInput[i]); 00168 // if (iter != NULL) 00169 // { 00170 // for(uint j=0; j<iter->modelEntries.size(); j++) 00171 // { 00172 // ModelTableEntry mte = iter->modelEntries[j]; 00173 // 00174 // //find the acc; 00175 // bool found = false; 00176 // for(uint i=0; i<acc.size(); i++) 00177 // { 00178 // if (acc[i].P1 == mte.basisP1 && 00179 // acc[i].P2 == mte.basisP2 && 00180 // acc[i].modelId == mte.modelId && 00181 // acc[i].rot == mte.rot && 00182 // acc[i].inputP1 == p1 && 00183 // acc[i].inputP2 == p2) 00184 // { 00185 // found = true; 00186 // acc[i].inputP1 = p1; 00187 // acc[i].inputP2 = p2; 00188 // acc[i].votes++; 00189 // } 00190 // } 00191 // 00192 // if (!found) 00193 // { 00194 // Acc newAcc; 00195 // newAcc.P1 = mte.basisP1; 00196 // newAcc.P2 = mte.basisP2; 00197 // newAcc.modelId = mte.modelId; 00198 // newAcc.rot = mte.rot; 00199 // newAcc.votes = 1; 00200 // newAcc.inputP1 = p1; 00201 // newAcc.inputP2 = p2; 00202 // acc.push_back(newAcc); 00203 // } 00204 // } 00205 // } 00206 // } 00207 // } 00208 // 00209 // return acc; 00210 //} 00211 00212 std::vector<GeometricHashing::Acc> GeometricHashing::getVotes(std::vector<Point2D<int> >& input) 00213 { 00214 std::vector<Acc> acc; 00215 00216 if (input.size() <= 0) 00217 return acc; 00218 00219 //Find the minimum bounding box 00220 Point2D<int> tl = input[0]; 00221 Point2D<int> br = input[0]; 00222 for(uint i=0; i<input.size(); i++) 00223 { 00224 if (br.i > input[i].i) 00225 br.i = input[i].i; 00226 if (br.j > input[i].j) 00227 br.j = input[i].j; 00228 00229 if (tl.i < input[i].i) 00230 tl.i = input[i].i; 00231 if (tl.j < input[i].j) 00232 tl.j = input[i].j; 00233 } 00234 00235 std::vector<Point2D<float> > newInput = changeBasis(input, tl, br); 00236 00237 Point2D<float> center(tl.i+(br.i - tl.i)/2, 00238 tl.j+(br.j - tl.j)/2); 00239 00240 00241 //For each input find the value in the hash table and count the votes 00242 for(uint i=0; i<newInput.size(); i++) 00243 { 00244 Image<GeometricHashing::TableEntry>::iterator iter = 00245 findInHash(newInput[i]); 00246 if (iter != NULL) 00247 { 00248 for(uint j=0; j<iter->modelEntries.size(); j++) 00249 { 00250 ModelTableEntry mte = iter->modelEntries[j]; 00251 00252 //find the acc; 00253 bool found = false; 00254 for(uint i=0; i<acc.size(); i++) 00255 { 00256 if (acc[i].modelId == mte.modelId && 00257 acc[i].rot == mte.rot) 00258 { 00259 found = true; 00260 acc[i].votes++; 00261 } 00262 } 00263 00264 if (!found) 00265 { 00266 Acc newAcc; 00267 newAcc.modelId = mte.modelId; 00268 newAcc.rot = mte.rot; 00269 newAcc.votes = 1; 00270 newAcc.center = center; 00271 acc.push_back(newAcc); 00272 } 00273 } 00274 } 00275 } 00276 00277 return acc; 00278 } 00279 00280 Image<PixRGB<byte> > GeometricHashing::getHashTableImage() 00281 { 00282 00283 int binWidth = 10; 00284 Image<PixRGB<byte> > img(itsHashTable.getDims()*binWidth, ZEROS); 00285 drawGrid(img, binWidth, binWidth, 1, 1, PixRGB<byte>(0,0,255)); 00286 drawLine(img, Point2D<int>(0, img.getHeight()/2), 00287 Point2D<int>(img.getWidth(), img.getHeight()/2), 00288 PixRGB<byte>(0,0,255),2); 00289 drawLine(img, Point2D<int>(img.getWidth()/2, 0), 00290 Point2D<int>(img.getWidth()/2, img.getHeight()), 00291 PixRGB<byte>(0,0,255),2); 00292 00293 float scale = binWidth/itsTableWidth; 00294 for(uint i=0; i<itsHashTable.size(); i++) 00295 { 00296 TableEntry te = itsHashTable[i]; 00297 for(uint j=0; j<te.modelEntries.size(); j++) 00298 { 00299 ModelTableEntry mte = te.modelEntries[j]; 00300 int x = (img.getWidth()/2) + (int)(scale*mte.featureLoc.i); 00301 int y = (img.getHeight()/2) - (int)(scale*mte.featureLoc.j); 00302 drawCircle(img, Point2D<int>(x,y), 3, PixRGB<byte>(0,255,0)); 00303 } 00304 } 00305 00306 return img; 00307 00308 } 00309 00310 00311 std::vector<Point2D<float> > GeometricHashing::changeBasis( 00312 const std::vector<Point2D<int> >& featureLoc, 00313 int p1, int p2) 00314 { 00315 00316 std::vector<Point2D<float> > newFeatureLoc; 00317 00318 float modelScale = 1/sqrt( squareOf(featureLoc[p2].i - featureLoc[p1].i) + 00319 squareOf(featureLoc[p2].j - featureLoc[p1].j) ); 00320 00321 float ang = 0; 00322 if ((featureLoc[p2].i - featureLoc[p1].i) != 0) 00323 ang = -atan((featureLoc[p2].j - featureLoc[p1].j)/(featureLoc[p2].i - featureLoc[p1].i)); 00324 00325 //Rotate the model 00326 for(uint i=0; i<featureLoc.size(); i++) 00327 { 00328 float x = modelScale*(featureLoc[i].i); 00329 float y = modelScale*(featureLoc[i].j); 00330 00331 newFeatureLoc.push_back( 00332 Point2D<float>((x * cos(ang) - y * sin(ang)), 00333 (y * cos(ang) + x * sin(ang)))); 00334 } 00335 00336 //Offset so the midpoint is between points center 00337 Point2D<float> center(newFeatureLoc[p1].i+(newFeatureLoc[p2].i - newFeatureLoc[p1].i)/2, 00338 newFeatureLoc[p1].j+(newFeatureLoc[p2].j - newFeatureLoc[p1].j)/2); 00339 for(uint i=0; i<newFeatureLoc.size(); i++) 00340 newFeatureLoc[i] -= center; 00341 00342 00343 return newFeatureLoc; 00344 } 00345 00346 std::vector<Point2D<float> > GeometricHashing::changeBasis( 00347 const std::vector<Point2D<int> >& featureLoc, 00348 Point2D<int> tl, 00349 Point2D<int> br) 00350 { 00351 00352 std::vector<Point2D<float> > newFeatureLoc; 00353 00354 //Offset so the midpoint is between points center 00355 Point2D<float> center(tl.i+(br.i - tl.i)/2, 00356 tl.j+(br.j - tl.j)/2); 00357 00358 float modelScale = 1/sqrt( squareOf(br.i - tl.i) + 00359 squareOf(br.j - tl.j) ); 00360 00361 //Transelate the model to 0,0 and scale it 00362 float ang = 0; 00363 for(uint i=0; i<featureLoc.size(); i++) 00364 { 00365 float x = modelScale*(featureLoc[i].i - center.i); 00366 float y = modelScale*(featureLoc[i].j - center.j); 00367 00368 newFeatureLoc.push_back( 00369 Point2D<float>((x * cos(ang) - y * sin(ang)), 00370 (y * cos(ang) + x * sin(ang)))); 00371 } 00372 00373 return newFeatureLoc; 00374 } 00375 00376 void GeometricHashing::writeTable(const char* filename) 00377 { 00378 int fd; 00379 00380 if ((fd = creat(filename, 0644)) == -1) 00381 LFATAL("Can not open %s for saving\n", filename); 00382 00383 //Write the Dims of the table 00384 int ret; 00385 int width = itsHashTable.getWidth(); 00386 int height = itsHashTable.getHeight(); 00387 ret = write(fd, (char *) &width, sizeof(int)); 00388 ret = write(fd, (char *) &height, sizeof(int)); 00389 00390 //Write each entry 00391 for(int j=0; j<height; j++) 00392 for(int i=0; i<width; i++) 00393 { 00394 GeometricHashing::TableEntry te = itsHashTable.getVal(i,j); 00395 //Write the size of the model entries 00396 size_t numEntries = te.modelEntries.size(); 00397 ret = write(fd, (char *) &numEntries, sizeof(size_t)); 00398 //Write the entries 00399 for(uint idx=0; idx<numEntries; idx++) 00400 { 00401 ModelTableEntry mte = te.modelEntries[idx]; 00402 ret = write(fd, (char *) &mte, sizeof(ModelTableEntry)); 00403 } 00404 } 00405 } 00406 00407 void GeometricHashing::readTable(const char* filename) 00408 { 00409 int fd; 00410 if ((fd = open(filename, 0, 0644)) == -1) return; 00411 00412 int ret; 00413 LINFO("Reading from %s", filename); 00414 00415 //Write the Dims of the table 00416 int width; 00417 int height; 00418 ret = read(fd, (char *) &width, sizeof(int)); 00419 ret = read(fd, (char *) &height, sizeof(int)); 00420 LINFO("Width %i %i", width, height); 00421 00422 itsHashTable = Image<TableEntry>(width,height,ZEROS); 00423 00424 //Write each entry 00425 for(int j=0; j<height; j++) 00426 for(int i=0; i<width; i++) 00427 { 00428 //Write the size of the model entries 00429 size_t numEntries; 00430 ret = read(fd, (char *) &numEntries, sizeof(size_t)); 00431 00432 //Write the entries 00433 for(uint idx=0; idx<numEntries; idx++) 00434 { 00435 ModelTableEntry mte; 00436 ret = read(fd, (char *) &mte, sizeof(ModelTableEntry)); 00437 00438 Image<GeometricHashing::TableEntry>::iterator iter = NULL; 00439 iter = itsHashTable.beginw(); 00440 iter += (i + j*itsHashTable.getWidth()); 00441 iter->modelEntries.push_back(mte); 00442 } 00443 } 00444 } 00445 00446 // ###################################################################### 00447 /* So things look consistent in everyone's emacs... */ 00448 /* Local Variables: */ 00449 /* indent-tabs-mode: nil */ 00450 /* End: */ 00451 00452 #endif 00453