Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SiftTekkotsu.cc

Go to the documentation of this file.
00001 #include "SiftTekkotsu.h"
00002 #include "DualCoding/Sketch.h"
00003 #include "Shared/newmat/newmat.h"
00004 #include "Shared/mathutils.h" // for isnan fix
00005 
00006 #include "SiftMatch.h"
00007 #include "Vision/SIFT/SIFTDatabase/keypoint.h"
00008 #include "Vision/SIFT/SIFTDatabase/keypointpair.h"
00009 #include "Vision/SIFT/SIFTDatabase/model.h"
00010 #include "Vision/SIFT/SIFTDatabase/object.h"
00011 #include "Vision/SIFT/SIFTPP/sift.hpp"
00012 #include "Vision/SIFT/SIFTPP/sift-driver.hpp"
00013 
00014 #include <cstring>
00015 
00016 using namespace std;
00017 using namespace DualCoding;
00018 
00019 SiftTekkotsu::SiftTekkotsu() : kb(), imageDatabase(), testSIFTImage(), siftImageMaxID(0),
00020              argv(new char*[20]), argvCopy(argv), argc(7) {
00021   argv[0] = new char[1024];
00022   argv[1] = new char[1024];
00023   argv[2] = new char[1024];
00024   argv[3] = new char[1024];
00025   argv[4] = new char[1024];
00026   argv[5] = new char[1024];
00027   argv[6] = new char[1024];
00028 }
00029 
00030 SiftTekkotsu::~SiftTekkotsu(){
00031   argv = argvCopy;
00032   for (int i = 0; i < argc; i++)
00033     delete [] argv[i];
00034   //  free(argv);
00035   delete [] argv;
00036   
00037   for (unsigned int i = 0; i < imageDatabase.size(); i++){
00038     imageDatabase[i]->clearImage();
00039     delete imageDatabase[i];
00040   }
00041   
00042   clearTestState();
00043 }
00044 
00045 void SiftTekkotsu::detectKeypoints(ImageBuffer buffer, vector<keypoint*>& keys, vector< vector< vector<int> > >& gaussianSpace){
00046   // Call SIFT++ detection
00047   
00048   vector<double> keyValues;
00049   int numKeypoints;
00050   
00051   numKeypoints = 0;
00052   
00053   strcpy(argv[0], "siftpp");
00054   //strcpy(argv[1], PGMFileName.c_str());
00055   strcpy(argv[1], "bogusImage");
00056   strcpy(argv[2], "-o");
00057   strcpy(argv[3], "/tmp/siftTekkotsu.key");
00058   strcpy(argv[4], "--image-provided");
00059   strcpy(argv[5], "--verbose");
00060   strcpy(argv[6], "--save-gss");
00061   
00062   VL::pixel_t* tempPixelArray = (VL::pixel_t*)malloc(sizeof(float) * buffer.width * buffer.height);
00063   int tempPixelArrayPtr = 0;
00064   for (int i = 0; i < buffer.height; i++){
00065     for (int j = 0; j < buffer.width; j++){
00066       tempPixelArray[tempPixelArrayPtr] = buffer.byteArray[tempPixelArrayPtr] / 255.f;
00067       tempPixelArrayPtr++;
00068     }
00069   }
00070   VL::Sift* sift =  siftdriver(5, argv, &numKeypoints, &keyValues, gaussianSpace, tempPixelArray, buffer.width, buffer.height);
00071   free(tempPixelArray);
00072   
00073   delete sift;
00074   
00075   
00076   // Convert raw values into keypoints
00077   for (int i = 0; i < numKeypoints; i++){
00078     int j = i * (128+6);
00079     keypoint* key = new keypoint();
00080     //    key->valid = true;
00081     key->imageX           = key->modelX           = keyValues[j++];
00082     key->imageY           = key->modelY           = keyValues[j++];
00083     key->imageScale       = key->modelScale       = keyValues[j++];
00084     key->imageOrientation = key->modelOrientation = keyValues[j++];
00085     key->imageIntScale = (int)keyValues[j++];
00086     key->imageIntOctave = (int)keyValues[j++];
00087     for (int jj = 0; jj < 128; jj++){
00088       key->desc.push_back(keyValues[j+jj]);
00089     }
00090     keys.push_back(key);
00091   }
00092   
00093 }
00094 
00095 void SiftTekkotsu::findInImage(ImageBuffer buffer, vector<SiftMatch*>& matchesFound, bool objectSpecified, int wantedObjectID){
00096   clearTestState();
00097   testSIFTImage.buffer.width = buffer.width;
00098   testSIFTImage.buffer.height = buffer.height;
00099   testSIFTImage.buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00100   memcpy(testSIFTImage.buffer.byteArray, buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00101   detectKeypoints(buffer, testSIFTImage.keypoints, testSIFTImage.gaussianSpace);
00102   findInImage(testSIFTImage.keypoints, matchesFound, objectSpecified, wantedObjectID);
00103 }
00104 
00105 void SiftTekkotsu::findInImage(vector<keypoint*>& keys, vector<SiftMatch*>& matchesFound, bool objectSpecified, int wantedObjectID){
00106   // Match keypoints
00107   size_t objectsSize = kb.objects.size();
00108   size_t maxNumModels1 = kb.maxNumModels+1;
00109   vector< vector< vector<keypoint*> > > matches;
00110   matches.resize(objectsSize);
00111   for (size_t i = 0; i < objectsSize; i++){
00112     matches[i].resize(maxNumModels1);
00113   }
00114   vector< vector< vector<keypoint*> > > imageKey;
00115   imageKey.resize(objectsSize);
00116   for (size_t i = 0; i < objectsSize; i++){
00117     imageKey[i].resize(maxNumModels1);
00118   }
00119   kb.keypointMatching(&keys, matches, imageKey, objectSpecified, wantedObjectID);
00120   
00121   // Match to models
00122   vector<KnowledgeBase::modelMatchingInfo*> mminfo;
00123   kb.modelMatching(keys.size(), matches, imageKey, mminfo);
00124   
00125   if (mminfo.size() > 0){
00126     for (int i = 0; i < (int)mminfo[0]->inliers->size(); i++){
00127       (*(mminfo[0]->inliers))[i]->getKey1()->finalMatch = (*(mminfo[0]->inliers))[i]->getKey2();
00128       if ((*(mminfo[0]->inliers))[i]->getKey2() != NULL) (*(mminfo[0]->inliers))[i]->getKey2()->matches.push_back((*(mminfo[0]->inliers))[i]->getKey1());
00129     }
00130   }
00131   
00132   // Convert mminfo to SiftMatch
00133   for (unsigned int i = 0; i < mminfo.size(); i++){
00134     SiftMatch *sMatch = new SiftMatch;
00135     convertSiftMatchFromModelMatchingInfo(*sMatch, *(mminfo[i]));
00136     matchesFound.push_back(sMatch);
00137   }
00138   
00139   // Previously, used to clean up keys here
00140   // But now leave this to clearTestState() instead
00141   // Clean up keys
00142   //  for (unsigned int i = 0; i < keys.size(); i++){
00143   //    delete keys[i];
00144   //  }
00145   
00146   // Clean up mminfo
00147   for (unsigned int i = 0; i < mminfo.size(); i++){
00148     delete mminfo[i];
00149   }
00150   
00151 }
00152 
00153 void SiftTekkotsu::clearTestState(){
00154   testSIFTImage.clearImage();
00155   for (unsigned int i = 0; i < testSIFTImage.keypoints.size(); i++){
00156     if (testSIFTImage.keypoints[i]->finalMatch != NULL){
00157       for (vector<keypoint*>::iterator iter = testSIFTImage.keypoints[i]->finalMatch->matches.begin(); iter != testSIFTImage.keypoints[i]->finalMatch->matches.end(); iter++){
00158   if (*iter == testSIFTImage.keypoints[i]){
00159     testSIFTImage.keypoints[i]->finalMatch->matches.erase(iter);
00160     break;
00161   }
00162       }
00163     }
00164     delete testSIFTImage.keypoints[i];
00165   }
00166   testSIFTImage.keypoints.clear();
00167   testSIFTImage.gaussianSpace.clear();
00168   testSIFTImage.clearImage();
00169 }
00170 
00171 void SiftTekkotsu::convertSiftMatchFromModelMatchingInfo(SiftMatch& sMatch, KnowledgeBase::modelMatchingInfo& mminfo){
00172   NEWMAT::Matrix* transform = mminfo.solution;
00173   // recover theta from the rotation components of the transform,
00174   // using the fact that sin^2 + cos^2 = 1
00175   double scale = sqrt((*transform)(1,1) * (*transform)(1,1) + (*transform)(2,1) * (*transform)(2,1));
00176   double recoveredCos = (*transform)(1,1) / scale;
00177   double theta = acos(max(-1.0, min(1.0, recoveredCos)));
00178   double tx = (*transform)(3,1);
00179   double ty = (*transform)(4,1);
00180       
00181   if (isnan(theta)) theta = 0.0;
00182   if ((*transform)(2,1) / scale < 0.0) theta = -theta;
00183   
00184   //  cout << "Conversion in progress\n";
00185   //  cout << mminfo.matchedModel << endl;
00186   //  cout << mminfo.matchedModel->O << endl;
00187   
00188   sMatch.objectID          = mminfo.matchedModel->O->getID();
00189   sMatch.objectName        = mminfo.matchedModel->O->getName();
00190   sMatch.modelID           = mminfo.matchedModel->getID();
00191   sMatch.modelName         = mminfo.matchedModel->getName();
00192   sMatch.probOfMatch       = mminfo.probOfMatch;
00193   sMatch.error             = mminfo.error;
00194   sMatch.scale             = scale;
00195   sMatch.orientation       = theta;
00196   sMatch.columnTranslation = tx;
00197   sMatch.rowTranslation    = ty;
00198   for (vector<keypointPair*>::const_iterator it = mminfo.inliers->begin();
00199        it != mminfo.inliers->end(); it++ )
00200     sMatch.inliers.push_back(*(*it));
00201   
00202   sMatch.computeBoundingBox();
00203 }
00204 
00205 
00206 
00207 
00208 /// Training API calls
00209 
00210 // Create a new object
00211 // Returns object ID
00212 int SiftTekkotsu::train_addNewObject(string PGMFileName){
00213   unsigned int siftImageID;
00214   return train_addNewObject(PGMFileName, siftImageID);
00215 }
00216 int SiftTekkotsu::train_removeObject(string PGMFileName, int oID){
00217   unsigned int siftImageID;
00218   return train_removeObject(PGMFileName, siftImageID, oID);
00219 }
00220 int SiftTekkotsu::train_addNewObject(string PGMFileName, unsigned int& siftImageID){
00221   ImageBuffer buffer;
00222   PGMImg pgmImg;
00223   pgmImg.fromFile(PGMFileName);
00224   convertPGMImgToImageBuffer(pgmImg, buffer);
00225   
00226   int returnVal = train_addNewObject(buffer, siftImageID);
00227   free(buffer.byteArray);
00228   return returnVal;
00229 }
00230 int SiftTekkotsu::train_removeObject(string PGMFileName, unsigned int& siftImageID, int oID){
00231   ImageBuffer buffer;
00232   PGMImg pgmImg;
00233   pgmImg.fromFile(PGMFileName);
00234   convertPGMImgToImageBuffer(pgmImg, buffer);
00235   
00236   int returnVal = train_removeObject(buffer, siftImageID, oID);
00237   free(buffer.byteArray);
00238   return returnVal;
00239 }
00240 int SiftTekkotsu::train_addNewObject(ImageBuffer buffer){
00241   unsigned int siftImageID;
00242   return train_addNewObject(buffer, siftImageID);
00243 }
00244 int SiftTekkotsu::train_removeObject(ImageBuffer buffer, int oID){
00245   unsigned int siftImageID;
00246   return train_removeObject(buffer, siftImageID, oID);
00247 }
00248 //void KnowledgeBase::unlearn_fromModel(vector<keypoint*>* newKeys, model* bestModel, NEWMAT::Matrix* transform, double& s, double& theta, double& tx, double& ty)
00249 int SiftTekkotsu::train_addNewObject(ImageBuffer buffer, unsigned int& siftImageID){
00250   // Detect keypoints from image
00251   SIFTImage* sImage = new SIFTImage(siftImageMaxID++);
00252   
00253   siftImageID = siftImageMaxID-1;
00254   imageDatabase.push_back(sImage);
00255   sImage->buffer.width = buffer.width;
00256   sImage->buffer.height = buffer.height;
00257   sImage->buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00258   memcpy(sImage->buffer.byteArray, buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00259   detectKeypoints(buffer, sImage->keypoints, sImage->gaussianSpace);
00260   return train_addNewObject(sImage->keypoints);
00261 }
00262 int SiftTekkotsu::train_removeObject(ImageBuffer buffer, unsigned int& siftImageID, int oID){
00263   // Detect keypoints from image
00264   SIFTImage* sImage = new SIFTImage(siftImageMaxID++);
00265   
00266   siftImageID = siftImageMaxID-1;
00267   imageDatabase.push_back(sImage);
00268   sImage->buffer.width = buffer.width;
00269   sImage->buffer.height = buffer.height;
00270   sImage->buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00271   memcpy(sImage->buffer.byteArray, buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00272   detectKeypoints(buffer, sImage->keypoints, sImage->gaussianSpace);
00273   return train_removeObject(sImage->keypoints, oID);
00274 }
00275 int SiftTekkotsu::train_addNewObject(vector<keypoint*>& keys){
00276   return (kb.learn_newObject(&keys))->getID();
00277 }
00278 int SiftTekkotsu::train_removeObject(vector<keypoint*>& keys, int oID){
00279   return (kb.unlearn_Object(&keys, oID))->getID();
00280 }
00281 
00282 // Specify object to add image to
00283 // Return model ID
00284 int SiftTekkotsu::train_addToObject(int objectID, string PGMFileName){
00285   unsigned int siftImageID;
00286   SiftMatch matchFound;
00287   return train_addToObject(objectID, PGMFileName, siftImageID, matchFound);
00288 }
00289 int SiftTekkotsu::train_removefromObject(int objectID, string PGMFileName) {
00290   cout << "Call recieved by siftTekkotsu..."; 
00291   unsigned int siftImageID;
00292   SiftMatch matchFound;
00293   return train_removefromObject(objectID, PGMFileName, siftImageID, matchFound);
00294 } 
00295 int SiftTekkotsu::train_addToObject(int objectID, string PGMFileName, unsigned int& siftImageID, SiftMatch& matchFound){
00296   ImageBuffer buffer;
00297   PGMImg pgmImg;
00298   pgmImg.fromFile(PGMFileName);
00299   convertPGMImgToImageBuffer(pgmImg, buffer);
00300   
00301   int returnVal = train_addToObject(objectID, buffer, siftImageID, matchFound);
00302   free(buffer.byteArray); return returnVal;
00303 }
00304 int SiftTekkotsu::train_removefromObject(int objectID, string PGMFileName, unsigned int& siftImageID, SiftMatch& matchFound){
00305   ImageBuffer buffer;
00306   PGMImg pgmImg;
00307   pgmImg.fromFile(PGMFileName);
00308   convertPGMImgToImageBuffer(pgmImg, buffer);
00309   
00310   int returnVal = train_removefromObject(objectID, buffer, siftImageID, matchFound);
00311   free(buffer.byteArray); return returnVal;
00312 }
00313 int SiftTekkotsu::train_addToObject(int objectID, ImageBuffer buffer){
00314   unsigned int siftImageID;
00315   SiftMatch matchFound;
00316   return train_addToObject(objectID, buffer, siftImageID, matchFound);
00317 }
00318 int SiftTekkotsu::train_removefromObject(int objectID, ImageBuffer buffer){
00319   unsigned int siftImageID;
00320   SiftMatch matchFound;
00321   return train_removefromObject(objectID, buffer, siftImageID, matchFound);
00322 }
00323 
00324 int SiftTekkotsu::train_addToObject(int objectID, ImageBuffer buffer, unsigned int& siftImageID, SiftMatch& matchFound){
00325   object* wantedObject = kb.objectExists(objectID);
00326   if (!wantedObject) return -1;
00327   
00328   // Detect keypoints from image
00329   SIFTImage* sImage = new SIFTImage(siftImageMaxID++);
00330   
00331   siftImageID = siftImageMaxID-1;
00332   imageDatabase.push_back(sImage);
00333   sImage->buffer.width = buffer.width;
00334   sImage->buffer.height = buffer.height;
00335   sImage->buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00336   memcpy(sImage->buffer.byteArray, buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00337   detectKeypoints(buffer, sImage->keypoints, sImage->gaussianSpace);
00338   return train_addToObject(objectID, sImage->keypoints, wantedObject, matchFound);
00339 }
00340 int SiftTekkotsu::train_removefromObject(int objectID, ImageBuffer buffer, unsigned int& siftImageID, SiftMatch& matchFound){
00341   object* wantedObject = kb.objectExists(objectID);
00342   if (!wantedObject) return -1;
00343   
00344   // Detect keypoints from image
00345   SIFTImage* sImage = new SIFTImage(siftImageMaxID++);
00346   
00347   siftImageID = siftImageMaxID-1;
00348   imageDatabase.push_back(sImage);
00349   sImage->buffer.width = buffer.width;
00350   sImage->buffer.height = buffer.height;
00351   sImage->buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00352   memcpy(sImage->buffer.byteArray, buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00353   detectKeypoints(buffer, sImage->keypoints, sImage->gaussianSpace);
00354   return train_removefromObject(objectID, sImage->keypoints, wantedObject, matchFound);;
00355 }
00356 int SiftTekkotsu::train_addToObject(int /*objectID*/, vector<keypoint*>& keys, object* wantedObject, SiftMatch& matchFound){
00357   // Match keypoints
00358   size_t objectsSize = kb.objects.size();
00359   size_t maxNumModels1 = kb.maxNumModels+1;
00360   vector< vector< vector<keypoint*> > > matches;
00361   matches.resize(objectsSize);
00362   for (size_t i = 0; i < objectsSize; i++){
00363     matches[i].resize(maxNumModels1);
00364   }
00365   vector< vector< vector<keypoint*> > > imageKey;
00366   imageKey.resize(objectsSize);
00367   for (size_t i = 0; i < objectsSize; i++){
00368     imageKey[i].resize(maxNumModels1);
00369   }
00370   kb.keypointMatching(&keys, matches, imageKey, false, -1);
00371   
00372   // Match to models
00373   vector<KnowledgeBase::modelMatchingInfo*> mminfo;
00374   kb.modelMatching(keys.size(), matches, imageKey, mminfo);
00375 
00376   // Find best match to given object
00377   int bestModelIndex = -1;
00378   model* bestModel = NULL;
00379   double bestError = numeric_limits<double>::infinity();
00380   for (unsigned int i = 0; i < mminfo.size(); i++){
00381     if (mminfo[i]->matchedModel->O == wantedObject){
00382       bestModelIndex = (int)i;
00383       bestModel = mminfo[i]->matchedModel;
00384       bestError = mminfo[i]->error;
00385       break;
00386     }
00387   }
00388   if (bestModelIndex != -1){
00389     for (int i = 0; i < (int)mminfo[bestModelIndex]->inliers->size(); i++){
00390       (*(mminfo[bestModelIndex]->inliers))[i]->getKey1()->finalMatch = (*(mminfo[bestModelIndex]->inliers))[i]->getKey2();
00391       if ((*(mminfo[bestModelIndex]->inliers))[i]->getKey2() != NULL) (*(mminfo[bestModelIndex]->inliers))[i]->getKey2()->matches.push_back((*(mminfo[bestModelIndex]->inliers))[i]->getKey1());
00392     }
00393   }
00394   
00395   double threshold = 0.01 * MAXIMAGEDIM;
00396   
00397   if (bestModel == NULL || bestError > threshold ){
00398     // Create new model
00399     bestModel = kb.learn_newModel(&keys, wantedObject, mminfo);
00400     matchFound.objectID          = bestModel->O->getID();
00401     matchFound.modelID           = bestModel->getID();
00402     matchFound.probOfMatch       = 1.0;
00403     matchFound.error             = 0;
00404     matchFound.scale             = 1.0;
00405     matchFound.orientation       = 0;
00406     matchFound.columnTranslation = 0;
00407     matchFound.rowTranslation    = 0;
00408   }else{
00409     // Add to old model
00410     kb.learn_toModel(&keys, bestModel, mminfo[bestModelIndex]->solution);
00411     // Copy information to SiftMatch
00412     convertSiftMatchFromModelMatchingInfo(matchFound, *(mminfo[bestModelIndex]));
00413   }
00414   
00415   // Clean up
00416   for (unsigned int i = 0; i < mminfo.size(); i++){
00417     delete mminfo[i];
00418   }
00419   
00420   return bestModel->getID();
00421 }
00422 int SiftTekkotsu::train_removefromObject(int /*objectID*/, vector<keypoint*>& keys, object* wantedObject, SiftMatch& matchFound){
00423   // Match keypoints
00424   cout << "Final siftTekkotsu function called... \n"; 
00425   size_t objectsSize = kb.objects.size();
00426   size_t maxNumModels1 = kb.maxNumModels+1;
00427   vector< vector< vector<keypoint*> > > matches;
00428   matches.resize(objectsSize);
00429   for (size_t i = 0; i < objectsSize; i++){
00430     matches[i].resize(maxNumModels1);
00431   }
00432   vector< vector< vector<keypoint*> > > imageKey;
00433   imageKey.resize(objectsSize);
00434   for (size_t i = 0; i < objectsSize; i++){
00435     imageKey[i].resize(maxNumModels1);
00436   }
00437   kb.keypointMatching(&keys, matches, imageKey, false, -1);
00438   
00439   // Match to models
00440   vector<KnowledgeBase::modelMatchingInfo*> mminfo;
00441   kb.modelMatching(keys.size(), matches, imageKey, mminfo);
00442 
00443   // Find best match to given object
00444   int bestModelIndex = -1;
00445   model* bestModel = NULL;
00446   double bestError = numeric_limits<double>::infinity();
00447   for (unsigned int i = 0; i < mminfo.size(); i++){
00448     if (mminfo[i]->matchedModel->O == wantedObject){
00449       bestModelIndex = (int)i;
00450       bestModel = mminfo[i]->matchedModel;
00451       bestError = mminfo[i]->error;
00452       break;
00453     }
00454   }
00455   if (bestModelIndex != -1){
00456     for (int i = 0; i < (int)mminfo[bestModelIndex]->inliers->size(); i++){
00457       (*(mminfo[bestModelIndex]->inliers))[i]->getKey1()->finalMatch = (*(mminfo[bestModelIndex]->inliers))[i]->getKey2();
00458       if ((*(mminfo[bestModelIndex]->inliers))[i]->getKey2() != NULL) (*(mminfo[bestModelIndex]->inliers))[i]->getKey2()->matches.push_back((*(mminfo[bestModelIndex]->inliers))[i]->getKey1());
00459     }
00460   }
00461   
00462   double threshold = 0.01 * MAXIMAGEDIM;
00463   
00464   if (bestModel == NULL || bestError > threshold ){
00465     /* Create new model
00466        bestModel = kb.learn_newModel(&keys, wantedObject, mminfo);
00467        matchFound.objectID          = bestModel->O->getID();
00468        matchFound.modelID           = bestModel->getID();
00469        matchFound.probOfMatch       = 1.0;
00470        matchFound.error             = 0;
00471        matchFound.scale             = 1.0;
00472        matchFound.orientation       = 0;
00473        matchFound.columnTranslation = 0;
00474        matchFound.rowTranslation    = 0;  */
00475   }else{
00476     // Add to old model
00477     cout << "Calling unlearn in Knowledge Base \n";
00478     kb.unlearn_fromModel(&keys, bestModel, mminfo[bestModelIndex]->solution);
00479     // Copy information to SiftMatch
00480     convertSiftMatchFromModelMatchingInfo(matchFound, *(mminfo[bestModelIndex]));
00481   }
00482   
00483   // Clean up
00484   for (unsigned int i = 0; i < mminfo.size(); i++){
00485     delete mminfo[i];
00486   }
00487   return 0; 
00488   
00489 }
00490 
00491 
00492 // Explicitly create new model for a given object
00493 // Returns model ID
00494 int SiftTekkotsu::train_addNewModel(int objectID, string PGMFileName){
00495   unsigned int siftImageID;
00496   return train_addNewModel(objectID, PGMFileName, siftImageID);
00497 }
00498 int SiftTekkotsu::train_removeModel(int objectID, string PGMFileName, int mID){
00499   unsigned int siftImageID;
00500   return train_removeModel(objectID, PGMFileName, siftImageID, mID);
00501 }
00502 int SiftTekkotsu::train_addNewModel(int objectID, string PGMFileName, unsigned int& siftImageID){
00503   ImageBuffer buffer;
00504   PGMImg pgmImg;
00505   pgmImg.fromFile(PGMFileName);
00506   convertPGMImgToImageBuffer(pgmImg, buffer);
00507   
00508   int returnVal = train_addNewModel(objectID, buffer, siftImageID);
00509   free(buffer.byteArray);
00510   return returnVal;
00511 }
00512 int SiftTekkotsu::train_removeModel(int objectID, string PGMFileName, unsigned int& siftImageID, int mID){
00513   ImageBuffer buffer;
00514   PGMImg pgmImg;
00515   pgmImg.fromFile(PGMFileName);
00516   convertPGMImgToImageBuffer(pgmImg, buffer);
00517   
00518   int returnVal = train_removeModel(objectID, buffer, siftImageID, mID);
00519   free(buffer.byteArray);
00520   return returnVal;
00521 }
00522 int SiftTekkotsu::train_addNewModel(int objectID, ImageBuffer buffer){
00523   unsigned int siftImageID;
00524   return train_addNewModel(objectID, buffer, siftImageID);
00525 }
00526 int SiftTekkotsu::train_removeModel(int objectID, ImageBuffer buffer, int mID){
00527   unsigned int siftImageID;
00528   return train_removeModel(objectID, buffer, siftImageID, mID);
00529 }
00530 int SiftTekkotsu::train_addNewModel(int objectID, ImageBuffer buffer, unsigned int& siftImageID){
00531   object* wantedObject = kb.objectExists(objectID);
00532   if (!wantedObject) return -1;
00533   
00534   // Detect keypoints from image
00535   SIFTImage* sImage = new SIFTImage(siftImageMaxID++);
00536   
00537   siftImageID = siftImageMaxID-1;
00538   imageDatabase.push_back(sImage);
00539   sImage->buffer.width = buffer.width;
00540   sImage->buffer.height = buffer.height;
00541   sImage->buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00542   memcpy(sImage->buffer.byteArray, buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00543   detectKeypoints(buffer, sImage->keypoints, sImage->gaussianSpace);
00544   return train_addNewModel(objectID, sImage->keypoints, wantedObject);
00545 }
00546 int SiftTekkotsu::train_removeModel(int objectID, ImageBuffer buffer, unsigned int& siftImageID, int mID){
00547   object* wantedObject = kb.objectExists(objectID);
00548   if (!wantedObject) return -1;
00549   
00550   // Detect keypoints from image
00551   SIFTImage* sImage = new SIFTImage(siftImageMaxID++);
00552   
00553   siftImageID = siftImageMaxID-1;
00554   imageDatabase.push_back(sImage);
00555   sImage->buffer.width = buffer.width;
00556   sImage->buffer.height = buffer.height;
00557   sImage->buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00558   memcpy(sImage->buffer.byteArray, buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00559   detectKeypoints(buffer, sImage->keypoints, sImage->gaussianSpace);
00560   return train_removeModel(objectID, sImage->keypoints, wantedObject, mID);
00561 }
00562 int SiftTekkotsu::train_addNewModel(int /*objectID*/, vector<keypoint*>& keys, object* wantedObject){
00563   // Match keypoints
00564   size_t objectsSize = kb.objects.size();
00565   size_t maxNumModels1 = kb.maxNumModels+1;
00566   vector< vector< vector<keypoint*> > > matches;
00567   matches.resize(objectsSize);
00568   for (size_t i = 0; i < objectsSize; i++){
00569     matches[i].resize(maxNumModels1);
00570   }
00571   vector< vector< vector<keypoint*> > > imageKey;
00572   imageKey.resize(objectsSize);
00573   for (size_t i = 0; i < objectsSize; i++){
00574     imageKey[i].resize(maxNumModels1);
00575   }
00576   kb.keypointMatching(&keys, matches, imageKey, false, -1);
00577   
00578   // Match to models
00579   // This step is necessary to get best matches so that we can create keygroups
00580   vector<KnowledgeBase::modelMatchingInfo*> mminfo;
00581   kb.modelMatching(keys.size(), matches, imageKey, mminfo);
00582   
00583   // Ignore matching, create new model
00584   int modelID = (kb.learn_newModel(&keys, wantedObject, mminfo))->getID();
00585   
00586   // Clean up
00587   for (unsigned int i = 0; i < mminfo.size(); i++){
00588     delete mminfo[i];
00589   }
00590   
00591   return modelID;
00592   
00593 }
00594 int SiftTekkotsu::train_removeModel(int /*objectID*/, vector<keypoint*>& keys, object* wantedObject, int mID){
00595   // Match keypoints
00596   cout << "kill me \n"; 
00597   size_t objectsSize = kb.objects.size();
00598   size_t maxNumModels1 = kb.maxNumModels+1;
00599   vector< vector< vector<keypoint*> > > matches;
00600   matches.resize(objectsSize);
00601   for (size_t i = 0; i < objectsSize; i++){
00602     matches[i].resize(maxNumModels1);
00603   }
00604   vector< vector< vector<keypoint*> > > imageKey;
00605   imageKey.resize(objectsSize);
00606   for (size_t i = 0; i < objectsSize; i++){
00607     imageKey[i].resize(maxNumModels1);
00608   }
00609   kb.keypointMatching(&keys, matches, imageKey, false, -1);
00610   
00611   // Match to models
00612   // This step is necessary to get best matches so that we can create keygroups
00613   vector<KnowledgeBase::modelMatchingInfo*> mminfo;
00614   kb.modelMatching(keys.size(), matches, imageKey, mminfo);
00615   
00616   // Ignore matching, create new model
00617   cout << "Removing model...";  
00618   int modelID = (kb.unlearn_Model(&keys, wantedObject, mminfo, mID))->getID();
00619   
00620   // Clean up
00621   for (unsigned int i = 0; i < mminfo.size(); i++){
00622     delete mminfo[i];
00623   }
00624   
00625   return modelID;
00626   
00627 }
00628 
00629 
00630 /// Testing API calls
00631 
00632 // Detects all instances of a given known object in image
00633 void SiftTekkotsu::findObjectInImage(int objectID, string PGMFileName, vector<SiftMatch*>& matchesFound){
00634   ImageBuffer buffer;
00635   PGMImg pgmImg;
00636   pgmImg.fromFile(PGMFileName);
00637   convertPGMImgToImageBuffer(pgmImg, buffer);
00638   
00639   findObjectInImage(objectID, buffer, matchesFound);
00640   free(buffer.byteArray);
00641 }
00642 void SiftTekkotsu::findObjectInImage(int objectID, ImageBuffer buffer, vector<SiftMatch*>& matchesFound){
00643   if (!kb.objectExists(objectID)) return;
00644   
00645   findInImage(buffer, matchesFound, true, objectID);
00646 }
00647 
00648 
00649 // Detects all instances of all known objects in image
00650 void SiftTekkotsu::findAllObjectsInImage(string PGMFileName, vector<SiftMatch*>& matchesFound){
00651   ImageBuffer buffer;
00652   PGMImg pgmImg;
00653   pgmImg.fromFile(PGMFileName);
00654   convertPGMImgToImageBuffer(pgmImg, buffer);
00655   
00656   findAllObjectsInImage(buffer, matchesFound);
00657   free(buffer.byteArray);
00658 }
00659 
00660 void SiftTekkotsu::findAllObjectsInImage(ImageBuffer buffer, vector<SiftMatch*>& matchesFound){
00661   findInImage(buffer, matchesFound, false, -1);
00662 }
00663 
00664 
00665 
00666 /// Naming calls
00667 
00668 // Object name
00669 bool SiftTekkotsu::setObjectName(int objectID, string Name){
00670   // Find object
00671   object* O = kb.objectExists(objectID);
00672   if (!O) return false;
00673   
00674   // Ensure uniqueness
00675   if (getObjectID(Name) != -1) return false;
00676   
00677   O->setName(Name);
00678   
00679   return true;
00680 }
00681 
00682 string SiftTekkotsu::getObjectName(int objectID){
00683   // Find object
00684   object* O = kb.objectExists(objectID);
00685   if (!O) {
00686     return "";
00687   }
00688   
00689   return O->getName();
00690 }
00691 
00692 int SiftTekkotsu::getObjectID(string Name){
00693   for (unsigned int i = 0; i < kb.objects.size(); i++){
00694     if (kb.objects[i]->getName().compare(Name) == 0){
00695       return (int)i;
00696     }
00697   }
00698   return -1;
00699 }
00700 
00701 // Model name
00702 bool SiftTekkotsu::setModelName(int objectID, int modelID, string Name){
00703   // Find object
00704   object* O = kb.objectExists(objectID);
00705   if (!O) return false;
00706   
00707   // Find model
00708   model* M = O->modelExists(modelID);
00709   if (!M) return false;
00710   
00711   // Ensure uniqueness
00712   if (getModelID(objectID, Name) != -1) return false;
00713   
00714   M->setName(Name);
00715   
00716   return true;
00717 }
00718 
00719 string SiftTekkotsu::getModelName(int objectID, int modelID){
00720   // Find object
00721   object* O = kb.objectExists(objectID);
00722   if (!O) {
00723     return "";
00724   }
00725   
00726   // Find model
00727   model* M = O->modelExists(modelID);
00728   if (!M){
00729     return "" ;
00730   }
00731   
00732   return M->getName();
00733 }
00734 
00735 int SiftTekkotsu::getModelID(int objectID, string Name){
00736   // Find object
00737   object* O = kb.objectExists(objectID);
00738   if (!O) {
00739     return -1;
00740   }
00741   
00742   for (unsigned int i = 0; i < O->models.size(); i++){
00743     if (O->models[i]->getName().compare(Name) == 0){
00744       return (int)i;
00745     }
00746   }
00747   
00748   return -1;
00749 }
00750 
00751 
00752 
00753 /// Parameter calls
00754 
00755 void  SiftTekkotsu::setParameter(const char* paramName, double paramVal){
00756   kb.setParameter(paramName, paramVal);
00757 }
00758 
00759 double SiftTekkotsu::getParameter(const char* paramName){
00760   return kb.getParameter(paramName);
00761 }
00762 
00763 void SiftTekkotsu::saveToFile(const std::string &filename, bool saveImages){
00764   clearTestState();
00765   
00766   ofstream outfile;
00767   outfile.open(filename.c_str());
00768   outfile.precision(8);
00769   outfile.setf(ios::fixed);
00770   outfile.setf(ios::showpoint);
00771   
00772   outfile << saveImages << endl;
00773   
00774   if (saveImages){
00775     // Save siftImageMaxID
00776     outfile << siftImageMaxID << endl;
00777     // Save imageDatabase
00778     outfile << imageDatabase.size() << endl;
00779     for (unsigned int i = 0; i < imageDatabase.size(); i++){
00780       // Save id
00781       outfile << imageDatabase[i]->id << endl;
00782       // Save ImageBuffer
00783       outfile << imageDatabase[i]->buffer.width << " " << imageDatabase[i]->buffer.height << endl;
00784       for (int j = 0; j < imageDatabase[i]->buffer.width*imageDatabase[i]->buffer.height; j++){
00785   outfile << (unsigned int)(imageDatabase[i]->buffer.byteArray[j]) << " ";
00786       }
00787       outfile << endl;
00788       // Save Gaussian Space
00789       outfile << imageDatabase[i]->gaussianSpace.size() << endl;
00790       for (int ii = 0; ii < (int)imageDatabase[i]->gaussianSpace.size(); ii++){
00791   outfile << imageDatabase[i]->gaussianSpace[ii].size() << endl;
00792   for (int j = 0; j < (int)imageDatabase[i]->gaussianSpace[ii].size(); j++){
00793     outfile << imageDatabase[i]->gaussianSpace[ii][j].size() << endl;
00794     for (int k = 0; k < (int)imageDatabase[i]->gaussianSpace[ii][j].size(); k++){
00795       outfile << imageDatabase[i]->gaussianSpace[ii][j][k] << " ";
00796     }
00797   }
00798   outfile << endl;
00799       }
00800       // Save keypoint IDs
00801       outfile << imageDatabase[i]->keypoints.size() << endl;
00802       for (unsigned int j = 0; j < imageDatabase[i]->keypoints.size(); j++){
00803   outfile << imageDatabase[i]->keypoints[j]->getID() << " ";
00804       }
00805       outfile << endl;
00806     }
00807   }
00808   
00809   // Save kb
00810   kb.saveToFile(outfile);
00811   
00812   outfile.close();
00813 }
00814 
00815 void SiftTekkotsu::loadFile(const std::string &filename){
00816   bool verbose = true;
00817   
00818   if (verbose) cout << "Loading SiftTekkotsu database from " << filename << endl;
00819   
00820   // Clean up state
00821   for (unsigned int i = 0; i < imageDatabase.size(); i++){
00822     imageDatabase[i]->clearImage();
00823     delete imageDatabase[i];
00824   }
00825   imageDatabase.clear();
00826   clearTestState();
00827   
00828   ifstream infile;
00829   infile.open(filename.c_str());
00830   
00831   // Read saveImages
00832   bool saveImages;
00833   infile >> saveImages;
00834   
00835   vector< vector<int> > keypointIDs;
00836   unsigned int imageDatabaseSize;
00837   if (saveImages){
00838     infile >> siftImageMaxID;
00839     // Read imageDatabase
00840     infile >> imageDatabaseSize;
00841     if (verbose) cout << "Number of images: " << imageDatabaseSize << endl;
00842     for (unsigned int i = 0; i < imageDatabaseSize; i++){
00843       if (verbose) cout << "Reading SIFTImage #" << i << endl;
00844       int id;
00845       infile >> id;
00846       SIFTImage* sImage = new SIFTImage(id);
00847       if (verbose) cout << "\tReading ImageBuffer\n";
00848       // Read ImageBuffer
00849       infile >> sImage->buffer.width >> sImage->buffer.height;
00850       if (verbose) cout << "\t\t" << sImage->buffer.height << "x" << sImage->buffer.width << endl;
00851       sImage->buffer.byteArray = (unsigned char*)malloc(sImage->buffer.width * sImage->buffer.height * sizeof(unsigned char));
00852       for (int j = 0; j < sImage->buffer.width*sImage->buffer.height; j++){
00853   unsigned int temp;
00854   infile >> temp;
00855   sImage->buffer.byteArray[j] = (unsigned char)temp;
00856       }
00857       if (verbose) cout << "\tReading Gaussian Space\n";
00858       // Read Gaussian Space
00859       int numOctaves;
00860       infile >> numOctaves;
00861       if (verbose) cout << "\t\tnumOctaves = " << numOctaves << endl;
00862       for (int ii = 0; ii < numOctaves; ii++){
00863   vector< vector<int> > octaveGaussianSpace;
00864   int numLevels;
00865   infile >> numLevels;
00866   //      if (verbose) cout << "\t\t\tnumLevels = " << numLevels << endl;
00867   for (int j = 0; j < numLevels; j++){
00868     vector<int> levelSpace;
00869     int numVals;
00870     infile >> numVals;
00871     //        if (verbose) cout << "\t\t\tnumVals = " << numVals << endl;
00872     for (int k = 0; k < numVals; k++){
00873       int val;
00874       infile >> val;
00875       levelSpace.push_back(val);
00876     }
00877     octaveGaussianSpace.push_back(levelSpace);
00878   }
00879   sImage->gaussianSpace.push_back(octaveGaussianSpace);
00880       }
00881       if (verbose) cout << "\tReading keypoint IDs\n";
00882       // Read keypoint IDs
00883       int numKeys;
00884       infile >> numKeys;
00885       vector<int> keys;
00886       for (int j = 0; j < numKeys; j++){
00887   int keyID;
00888   infile >> keyID;
00889   keys.push_back(keyID);
00890       }
00891       keypointIDs.push_back(keys);
00892       imageDatabase.push_back(sImage);
00893     }
00894   }
00895   
00896   // Read kb
00897   if (verbose) cout << "Reading Knowledgebase\n";
00898   kb.readFromFile(infile);
00899   
00900   if (verbose) cout << "Check: imageDatabase.size() == " << imageDatabase.size() << "; keypointIDs.size() == " << keypointIDs.size() << endl;
00901   
00902   // Link imageDatabase keypoints back to kb
00903   for (unsigned int i = 0; i < imageDatabase.size(); i++){
00904     if (verbose) cout << "Linking imageDatabase[" << i << "]\n";
00905     for (unsigned int j = 0; j < keypointIDs[i].size(); j++){
00906       for (unsigned int k = 0; k < kb.keys.size(); k++){
00907   if (keypointIDs[i][j] == kb.keys[k]->getID()){
00908     //          if (verbose) cout << "Success! " << keypointIDs[i][j] << "\n";
00909     imageDatabase[i]->keypoints.push_back(kb.keys[k]);
00910     break;
00911   }
00912       }
00913     }
00914   }
00915   
00916   infile.close();
00917   
00918 }
00919 
00920 /**
00921    Advanced image database functions
00922    SiftTekkotsu maintains a database of all the training images and of the most recent testing image.
00923    The information stored for each image include:
00924    1. the image itself (stored as ImageBuffer)
00925    2. Gaussian space generated by SIFT++
00926    3. keypoints detected in the image by SIFT++, and used for matching by KnowledgeBase
00927    The below set of functions allow the user to access the information in the image database.
00928 **/
00929 
00930 int SiftTekkotsu::convertSiftImageIDToIndex(int siftImageID){
00931   for (unsigned int i = 0; i < imageDatabase.size(); i++){
00932     if (imageDatabase[i]->id == siftImageID) return (int)i;
00933   }
00934   return -1;
00935 }
00936 
00937 /// Retrieve training image information
00938 
00939 // getImageBuffer assumes buffer.byteArray is not allocated, and will allocate memory that callee should free
00940 bool SiftTekkotsu::trainImage_getImageBuffer(  unsigned int siftImageID, ImageBuffer& buffer){
00941   int index = convertSiftImageIDToIndex(siftImageID);
00942   if (index == -1) return false;
00943   
00944   buffer.width  = imageDatabase[index]->buffer.width;
00945   buffer.height = imageDatabase[index]->buffer.height;
00946   buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00947   memcpy(buffer.byteArray, imageDatabase[index]->buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00948   
00949   return true;
00950 }
00951 
00952 bool SiftTekkotsu::trainImage_getGaussianSpace(unsigned int siftImageID, vector< vector< vector<int> > >& gaussianSpace){
00953   int index = convertSiftImageIDToIndex(siftImageID);
00954   if (index == -1) return false;
00955   
00956   gaussianSpace.clear();
00957   for (unsigned int i = 0; i < imageDatabase[index]->gaussianSpace.size(); i++){
00958     vector< vector<int> > octaveSpace;
00959     for (unsigned int j = 0; j < imageDatabase[index]->gaussianSpace[i].size(); j++){
00960       vector<int> levelSpace;
00961       for (unsigned int k = 0; k < imageDatabase[index]->gaussianSpace[i][j].size(); k++){
00962   levelSpace.push_back(imageDatabase[index]->gaussianSpace[i][j][k]);
00963       }
00964       octaveSpace.push_back(levelSpace);
00965     }
00966     gaussianSpace.push_back(octaveSpace);
00967   }
00968   
00969   return true;
00970 }
00971 
00972 bool SiftTekkotsu::trainImage_getKeypoints(    unsigned int siftImageID, vector<keypoint*>& keypoints){
00973   int index = convertSiftImageIDToIndex(siftImageID);
00974   if (index == -1) return false;
00975   
00976   keypoints.clear();
00977   for (unsigned int i = 0; i < imageDatabase[index]->keypoints.size(); i++){
00978     keypoints.push_back(imageDatabase[index]->keypoints[i]);
00979   }
00980   
00981   return true;
00982 }
00983 
00984 /// Retrieve testing image information
00985 // getImageBuffer assumes buffer.byteArray is not allocated, and will allocate memory that callee should free
00986 void SiftTekkotsu::testImage_getImageBuffer(  ImageBuffer& buffer){
00987   buffer.width  = testSIFTImage.buffer.width;
00988   buffer.height = testSIFTImage.buffer.height;
00989   buffer.byteArray = (unsigned char*)malloc(buffer.width*buffer.height*sizeof(unsigned char));
00990   memcpy(buffer.byteArray, testSIFTImage.buffer.byteArray, buffer.width*buffer.height*sizeof(unsigned char));
00991 }
00992 
00993 void SiftTekkotsu::testImage_getGaussianSpace(vector< vector< vector<int> > >& gaussianSpace){
00994   gaussianSpace.clear();
00995   for (unsigned int i = 0; i < testSIFTImage.gaussianSpace.size(); i++){
00996     vector< vector<int> > octaveSpace;
00997     for (unsigned int j = 0; j < testSIFTImage.gaussianSpace[i].size(); j++){
00998       vector<int> levelSpace;
00999       for (unsigned int k = 0; k < testSIFTImage.gaussianSpace[i][j].size(); k++){
01000   levelSpace.push_back(testSIFTImage.gaussianSpace[i][j][k]);
01001       }
01002       octaveSpace.push_back(levelSpace);
01003     }
01004     gaussianSpace.push_back(octaveSpace);
01005   }
01006 }
01007 
01008 void SiftTekkotsu::testImage_getKeypoints(    vector<keypoint*>& keypoints){
01009   keypoints.clear();
01010   for (unsigned int i = 0; i < testSIFTImage.keypoints.size(); i++){
01011     keypoints.push_back(testSIFTImage.keypoints[i]);
01012   }
01013 }
01014 
01015 ImageBuffer SiftTekkotsu::sketchToBuffer(const DualCoding::Sketch<DualCoding::uchar>& sk) {
01016   ImageBuffer buffer;
01017   buffer.height = sk.height;
01018   buffer.width = sk.width;
01019   size_t buffsize = sizeof(unsigned char)*buffer.height*buffer.width;
01020   cout << "buffsize = " << buffsize << endl;
01021   unsigned char *imgBuf = (unsigned char *)malloc(buffsize);
01022   sk->savePixels((char *)imgBuf,buffsize);
01023   buffer.byteArray = imgBuf;
01024   return buffer;
01025 }

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:51 2016 by Doxygen 1.6.3