LocalBinaryPatterns.C

Go to the documentation of this file.
00001 /*!@file Features/LocalBinaryPatterns.C Multiclass LocalBinaryPatterns Classifier module */
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Dan Parks <danielfp@usc.edu>
00033 // $HeadURL$
00034 // $Id$
00035 //
00036 
00037 #include <fstream>
00038 #include <iostream>
00039 #include <iomanip>
00040 #include <string>
00041 #include <cstdlib>
00042 #include <map>
00043 
00044 #include "LocalBinaryPatterns.H"
00045 #include "Component/ModelComponent.H"
00046 #include "Component/ModelParam.H"
00047 #include "Component/OptionManager.H"
00048 #include "Image/ColorOps.H"
00049 #include "Image/CutPaste.H"
00050 
00051 #define LOG_OFFSET 1.0F
00052 
00053 namespace
00054 {
00055 inline int lbpsign(int x)
00056 {
00057   return (((x)<0) ? 0 : 1);
00058 }
00059 
00060 };
00061 
00062 
00063 //! Constructor
00064 LocalBinaryPatterns::LocalBinaryPatterns(int LBPRadius, int LBPPixels, int varBins, bool useColor, bool normalize) :
00065   itsLBPRadius(LBPRadius),
00066   itsLBPPixels(LBPPixels),
00067   itsVarBins(varBins),
00068   itsUseColor(useColor),
00069   itsNormalize(normalize)
00070 {
00071   if(itsUseColor)
00072     itsColorBins = 2;
00073   else
00074     itsColorBins = 0;
00075 }
00076 
00077 //! Destructor
00078 LocalBinaryPatterns::~LocalBinaryPatterns()
00079 {
00080 }
00081 
00082 
00083 
00084 //! Add model to
00085 
00086 void LocalBinaryPatterns::addModel(const Image<PixRGB<byte> >& texture, const int id)
00087 {
00088   std::vector<float> lbp,col,var;
00089   createRawHistogram(texture,lbp,col,var);
00090   // Bin LBP in a temp list until we are ready to build the complete histogram
00091   addModel(lbp,col,var,id);
00092 }
00093  
00094 void LocalBinaryPatterns::addModel(const std::vector<float>& lbp, const std::vector<float> &col, const std::vector<float>& var, const int id)
00095 {
00096   // Store LBP and color bins 
00097   itsTempLBP[id].push_back(lbp);
00098   itsTempColor[id].push_back(col);
00099   // Sort variance, to speed up build process
00100   std::vector<float> svar = var;
00101   std::sort(svar.begin(),svar.end());
00102   // Store Variance values temporarily until we can get the total distribution of variances
00103   itsTempVariance[id].push_back(svar);
00104   //LINFO("Number of models is now %Zu, for id %d, num exemplars %Zu ",itsTempLBP.size(),id,itsTempLBP[id].size());
00105 }
00106 
00107 std::vector<float> LocalBinaryPatterns::createHistogram(const Image<PixRGB<byte> >& texture)
00108 {
00109   std::vector<float> lbp,col,var;
00110   createRawHistogram(texture,lbp,col,var);
00111   std::vector<float> varHist = convertVariance(var);
00112   std::vector<float> hist = lbp;
00113   hist.insert(hist.end(),col.begin(),col.end());
00114   hist.insert(hist.end(),varHist.begin(),varHist.end());
00115   return hist;
00116 }
00117 
00118 
00119 void LocalBinaryPatterns::createRawHistogram(const Image<PixRGB<byte> >& colTexture, std::vector<float>& lbps, std::vector<float>& col, std::vector<float>& vars)
00120 {
00121   Image<float> texture = luminance(colTexture);
00122   int w = texture.getWidth(), h = texture.getHeight();
00123   lbps.resize(itsLBPPixels+2);
00124   float step = 1;//itsLBPPixels*2+1;
00125   ASSERT(2*itsLBPRadius < std::min(w,h));
00126   float *g = new float[itsLBPPixels];
00127   int *sg = new int[itsLBPPixels];
00128   int sumEntries=0;
00129   for (float y = itsLBPRadius; y < h-itsLBPRadius; y+=step)
00130     {
00131       for (float x = itsLBPRadius; x < w-itsLBPRadius; x+=step)
00132         {
00133           float var=0;
00134           //float lbp=0;
00135           uint diff=0;
00136           float uniform=0;
00137           float mu=0;
00138           float gc = texture.getValInterp(x,y);
00139           for(int p=0;p<itsLBPPixels;p++)
00140             {
00141               g[p] = texture.getValInterp(x-itsLBPRadius*sin(2.0*M_PI*p/itsLBPPixels),y+itsLBPRadius*cos(2.0*M_PI*p/itsLBPPixels));
00142               mu += g[p];
00143               sg[p] = lbpsign(g[p]-gc);
00144               // If want to calculate full LBP, need to do
00145               //lbp += lbpsign(g[p])*pow(2,p);
00146               // then circular bit shift until minimum value is found
00147               // Here we will just bin the "uniform" patterns in addition to the variance
00148               diff += sg[p];          
00149             }
00150           for(int p=0;p<itsLBPPixels;p++)
00151             {
00152               if(p==0) uniform += abs(sg[itsLBPPixels-1]-sg[0]);
00153               else uniform += abs(sg[p]-sg[p-1]);
00154               var += (sg[p]-mu)*(sg[p]-mu);
00155             }
00156           // Bin into one of the uniform bins or into the "other" bin
00157           sumEntries++;
00158           if(uniform<=2) lbps[diff]++;
00159           else lbps[itsLBPPixels+1]++;
00160           // Normalize and add to list of variances (have to wait to bin variances until a total distribution is determined)
00161           if(itsVarBins > 0)
00162             vars.push_back(var / itsLBPPixels);
00163         }
00164     }
00165   // Normalize values in lbps histogram
00166   if(itsNormalize)
00167     {
00168       for(uint b=0;b<lbps.size();b++)
00169         {
00170           lbps[b]=lbps[b]/float(sumEntries)+LOG_OFFSET;
00171         }
00172     }
00173   delete[] g;
00174   delete[] sg;
00175 
00176   // If using color, add color
00177 
00178   if(itsUseColor)
00179     {
00180       float rg,by,rgbysum;
00181       colorSum(colTexture,colTexture.getBounds(),rg,by);
00182       if(itsNormalize)
00183         {
00184           rgbysum = rg+by;
00185           col.push_back(rg/rgbysum+LOG_OFFSET);
00186           col.push_back(by/rgbysum+LOG_OFFSET);
00187         }
00188       else
00189         {
00190           col.push_back(rg);
00191           col.push_back(by);
00192         }
00193     }
00194 }
00195 
00196 
00197 void LocalBinaryPatterns::getLabeledData(const MapModelVector& models, std::vector<std::vector<float> >& data, std::vector<float>& labels)
00198 {
00199   data.clear();
00200   labels.clear();
00201   MapModelVector::const_iterator mitr=models.begin(), mstop = models.end();  
00202   int idx=0;
00203   for(;mitr!=mstop;mitr++)
00204     {
00205       // Iterate through model exemplars
00206       for(uint i=0;i<mitr->second.size();i++)
00207         {
00208           labels.push_back(mitr->first);
00209           data.push_back(std::vector<float>());
00210           data[idx] = mitr->second[i];
00211           idx++;
00212         }
00213     }
00214 
00215 }
00216 
00217 void LocalBinaryPatterns::colorSum(Image<PixRGB<byte> >img, Rectangle rec, float& rg, float& by)
00218 {
00219   ASSERT(img.rectangleOk(rec));
00220   const Image<PixRGB<byte> > subImg = crop(img,rec);
00221   Image<float> l,a,b;
00222   getLAB(subImg,l,a,b);
00223   rg=0; by=0;
00224   Dims dims = subImg.getDims();
00225 
00226   for (int y = 0; y < dims.h(); ++y)
00227     {
00228       for (int x = 0; x < dims.w(); ++x)
00229         {
00230           rg+=(a.getVal(x,y)+128);
00231           by+=(b.getVal(x,y)+128);
00232         }
00233     }
00234 
00235 }
00236 
00237 
00238 
00239 std::vector<float> LocalBinaryPatterns::convertVariance(const std::vector<float>& vars)
00240 {
00241   std::vector<float> varHist = std::vector<float>(vars.size());
00242   // Convert the variance values into a histogram based on the bin break points
00243   varHist.resize(itsVarBins);
00244   if(itsVarBins == 0)
00245     return varHist;
00246   int sumEntries=vars.size();
00247   int binHint = -1;
00248   for(uint i=0;i<vars.size();i++)
00249     {
00250       // Optimized version
00251       int bin = getVarIndex<std::vector<float> >(itsVarBinThresholds,vars[i],binHint);
00252       varHist[bin]++;
00253       binHint=bin;
00254     }
00255   // Normalize values in var histogram
00256   for(uint b=0;b<varHist.size();b++)
00257     {
00258       varHist[b]=varHist[b]/float(sumEntries)+LOG_OFFSET;
00259     }
00260   return varHist;
00261 }
00262 
00263 LocalBinaryPatterns::MapModelVector LocalBinaryPatterns::getModels()
00264 {
00265   return itsModels;
00266 }
00267 
00268 void LocalBinaryPatterns::setModels(const MapModelVector& models)
00269 {
00270   itsModels=models;
00271 }
00272 
00273 std::vector<float> LocalBinaryPatterns::getVarThresholds()
00274 {
00275   return itsVarBinThresholds;
00276 }
00277 
00278 void LocalBinaryPatterns::setVarThresholds(std::vector<float> thresholds)
00279 {
00280   ASSERT(thresholds.size()==(uint)std::max(0,itsVarBins-1));
00281   itsVarBinThresholds = thresholds;
00282 }
00283 
00284 
00285 void LocalBinaryPatterns::setIncompleteModels(const MapModelVector& incompleteModels)
00286 {
00287   // Need to split the vectors into an LBP operator and a variance list based on the size of the LBP operator histogram
00288   MapModelVector::const_iterator imitr=incompleteModels.begin(), imstop = incompleteModels.end();
00289   // Iterate through model ids
00290   for(;imitr!=imstop;imitr++)
00291     {
00292       // Iterate through model exemplars
00293       for(uint i=0;i<imitr->second.size();i++)
00294         {
00295           std::vector<float> combinedHist = imitr->second[i];
00296           // Split according to length of LBP histogram
00297           std::vector<float> lbp,col,tmpVar;
00298           lbp.insert(lbp.begin(),combinedHist.begin(),combinedHist.begin()+itsLBPPixels+2);
00299           col.insert(col.begin(),combinedHist.begin()+itsLBPPixels+2,combinedHist.begin()+itsLBPPixels+2+itsColorBins);
00300           tmpVar.insert(tmpVar.begin(),combinedHist.begin()+itsLBPPixels+2+itsColorBins,combinedHist.end());
00301           addModel(lbp,col,tmpVar,imitr->first);
00302         }
00303     }
00304 }
00305 
00306 LocalBinaryPatterns::MapModelVector LocalBinaryPatterns::getIncompleteModels()
00307 {
00308   MapModelVector models;
00309   MapModelVector::const_iterator imitr=itsTempLBP.begin(), imstop = itsTempLBP.end();
00310   // Iterate through model ids
00311   for(;imitr!=imstop;imitr++)
00312     {
00313       // Iterate through model exemplars
00314       for(uint i=0;i<imitr->second.size();i++)
00315         {
00316           std::vector<float> lbp = imitr->second[i];
00317           std::vector<float> col = itsTempColor[imitr->first][i];
00318           std::vector<float> tmpVar = itsTempVariance[imitr->first][i];
00319           // Combined lbp, col, and var
00320           std::vector<float> combinedHist = lbp;
00321           combinedHist.insert(combinedHist.end(),col.begin(),col.end());
00322           combinedHist.insert(combinedHist.end(),tmpVar.begin(),tmpVar.end());
00323           models[imitr->first].push_back(combinedHist);
00324         }
00325     }
00326   return models;
00327 }
00328 
00329 void LocalBinaryPatterns::combineModels(const std::vector< MapModelVector >& allModels, MapModelVector& combined)
00330 {
00331   for(uint i=0;i<allModels.size();i++)
00332     {
00333       appendMap(combined,allModels[i]);
00334     }
00335 }
00336 
00337 void LocalBinaryPatterns::appendMap(MapModelVector& dst, const MapModelVector& src)
00338 {
00339   MapModelVector::const_iterator sitr=src.begin(), sstop = src.end();
00340   // Iterate through model ids
00341   for(;sitr!=sstop;sitr++)
00342     {
00343       // Iterate through model exemplars
00344       for(uint i=0;i<sitr->second.size();i++)
00345         {
00346           ASSERT(dst[sitr->first].size() <= sitr->second.size());
00347           // Allocate space if needed
00348           if(dst[sitr->first].size() < sitr->second.size())
00349             dst[sitr->first].resize(sitr->second.size());
00350           // Append map exemplar to end of original exemplar
00351           dst[sitr->first][i].insert(dst[sitr->first][i].end(),sitr->second[i].begin(),sitr->second[i].end());
00352         }
00353     }
00354 }
00355 
00356 std::vector<float> LocalBinaryPatterns::merge(const std::vector<float>& left, const std::vector<float>& right)
00357 {
00358     // Fill the resultant vector with sorted results from both vectors
00359     std::vector<float> result;
00360     unsigned left_it = 0, right_it = 0;
00361  
00362     while(left_it < left.size() && right_it < right.size())
00363     {
00364         // If the left value is smaller than the right it goes next
00365         // into the resultant vector
00366         if(left[left_it] < right[right_it])
00367         {
00368             result.push_back(left[left_it]);
00369             left_it++;
00370         }
00371         else
00372         {
00373             result.push_back(right[right_it]);
00374             right_it++;
00375         }
00376     }
00377  
00378     // Push the remaining data from both vectors onto the resultant
00379     while(left_it < left.size())
00380     {
00381         result.push_back(left[left_it]);
00382         left_it++;
00383     }
00384  
00385     while(right_it < right.size())
00386     {
00387         result.push_back(right[right_it]);
00388         right_it++;
00389     }
00390  
00391     return result;
00392 }
00393 
00394 void LocalBinaryPatterns::buildModels()
00395 {
00396   itsVarBinThresholds.clear();
00397   if(itsVarBins > 0)
00398     {
00399       // Build total variance distribution, note this assumes that individual variance vectors were presorted
00400       std::vector<float> totalDist;
00401       MapModelVector::const_iterator tvitr=itsTempVariance.begin(), tvstop = itsTempVariance.end();
00402       for(;tvitr!=tvstop;tvitr++)
00403         {
00404           for(uint i=0;i<tvitr->second.size();i++)
00405             {
00406               totalDist = merge(totalDist,tvitr->second[i]);
00407             }
00408         }
00409       // Determine number of elements to skip to collect thresholds
00410       float step = totalDist.size()/float(itsVarBins);
00411       // Grab thresholds (might want to interpolate them)
00412       for(int s=1;s<itsVarBins;s++)
00413         {
00414           float thresh=totalDist[floor(step*s)];
00415           itsVarBinThresholds.push_back(thresh);
00416         }
00417     }
00418   itsModels.clear();
00419   convertIncompleteModels();
00420 }
00421 
00422 void LocalBinaryPatterns::convertIncompleteModels()
00423 {
00424   MapModelVector varHist; 
00425   MapModelVector::const_iterator tvitr=itsTempVariance.begin(), tvstop = itsTempVariance.end();
00426   if(itsVarBins > 0)
00427     {
00428       // Convert model variance data to histograms
00429       for(tvitr=itsTempVariance.begin();tvitr!=tvstop;tvitr++)   
00430         {
00431           std::vector<std::vector<float> > bins = std::vector<std::vector<float> > ((*tvitr).second.size());
00432           for(uint i=0;i<tvitr->second.size();i++)
00433             {
00434               bins[i] = convertVariance(tvitr->second[i]);
00435             }
00436           varHist[tvitr->first] = bins;
00437         }
00438     }
00439   
00440   MapModelVector::const_iterator tmitr=itsTempLBP.begin(), tmstop = itsTempLBP.end();
00441   for(;tmitr!=tmstop;tmitr++)
00442     {
00443       for(uint i=0;i<tmitr->second.size();i++)
00444         {
00445           std::vector<float> hist = tmitr->second[i];
00446           std::vector<float> col = itsTempColor[tmitr->first][i];
00447           // Add color
00448           hist.insert(hist.end(),col.begin(),col.end());
00449           // Add variance if valid
00450           if(itsVarBins > 0)
00451             hist.insert(hist.end(),varHist[tmitr->first][i].begin(),varHist[tmitr->first][i].end());
00452           // Initialize if no key is present
00453           if(itsModels.find(tmitr->first) == itsModels.end())
00454             itsModels[tmitr->first] = std::vector<std::vector<float> >();
00455           itsModels[tmitr->first].push_back(hist);
00456         }
00457     }
00458 
00459 }
00460 
00461 
00462 template<class T> int LocalBinaryPatterns::getVarIndex(const T& thresh, float var, int binHint)
00463 {
00464   // Optimization, if variance is pre-sorted
00465   if(binHint >=0)
00466     {
00467       if(binHint < int(thresh.size()) )
00468         {
00469           if(var < thresh[binHint])
00470             {
00471               if(binHint == 0)
00472                 return binHint;
00473               else if(var > thresh[binHint-1])
00474                 return binHint;
00475             }
00476         }
00477       else if(var > thresh[binHint-1])
00478         {
00479           return binHint;
00480         }
00481     }
00482   // Binary search to find correct bin
00483   bool binFound=false;
00484   const int endBin = thresh.size();
00485   // Check if only one bin
00486   if(endBin==0)
00487     return 0;
00488   int lowBin = 0, highBin = endBin;
00489   int curBin = (lowBin+highBin)/2;
00490   while(!binFound)
00491     {
00492       
00493       if(var > thresh[curBin])
00494         lowBin = curBin+1;
00495       else 
00496         highBin = curBin;
00497       curBin = (lowBin+highBin)/2;
00498       if( highBin - lowBin <= 1)
00499         {
00500           binFound=true;
00501         }
00502     }
00503   if(var > thresh[lowBin])
00504     curBin = highBin;
00505   else
00506     curBin = std::min(lowBin,endBin);
00507   return curBin;
00508 }
00509 
00510 //! Get number of models
00511 uint LocalBinaryPatterns::getTotalModelExemplars(MapModelVector models)
00512 {
00513   MapModelVector::const_iterator mmitr = models.begin(), mmstop = models.end();
00514   uint cnt=0;
00515   for(;mmitr!=mmstop;mmitr++)
00516     {
00517       cnt += mmitr->second.size();
00518     }
00519   return cnt;
00520 }
00521 
00522 
00523 LocalBinaryPatterns::MapModelVector LocalBinaryPatterns::readModelsFile(std::string modelsFile)
00524 {
00525   FILE *fmodel;
00526   int numEntries, numColumns;
00527   MapModelVector models;
00528 
00529   fmodel = fopen(modelsFile.c_str(),"r");
00530   if(fmodel == NULL)
00531     {
00532       LFATAL("Unable to open LBP models file");
00533     }
00534   numEntries=0;
00535   while(1)
00536     {
00537       int id;
00538       if(fscanf(fmodel, "%d %d ", &id,&numColumns)!= 2) 
00539         {
00540           LINFO("Read %d samples in model file %s",numEntries,modelsFile.c_str());
00541           break;
00542         }
00543       std::vector<float> hist;
00544       for(int c=0;c<numColumns;c++)
00545         {
00546           float tmp;
00547           if(fscanf(fmodel, "%f ", &tmp)!= 1) LFATAL("Failed to load column %d in row %d of file: %s",c,numEntries,modelsFile.c_str());
00548           hist.push_back(tmp);
00549         }
00550       if(fscanf(fmodel,"\n")!= 0) LFATAL("Failed to parse newline at end of row %d of file: %s",numEntries,modelsFile.c_str());
00551       // Initialize if no key is present
00552       if(models.find(id) == models.end())
00553         models[id] = std::vector<std::vector<float> >();
00554       models[id].push_back(hist);
00555       numEntries++;
00556     }
00557   fclose(fmodel);
00558   return models;
00559 }
00560 
00561 void LocalBinaryPatterns::writeModelsFile(std::string modelsFile, MapModelVector models)
00562 {
00563   std::ofstream outfile;
00564   outfile.open(modelsFile.c_str(),std::ios::out);
00565   if (outfile.is_open()) 
00566     {
00567       MapModelVector::const_iterator mmitr = models.begin(), mmstop = models.end();
00568       for(;mmitr!=mmstop;mmitr++)    
00569         {
00570           for(uint i=0;i<mmitr->second.size();i++) 
00571             {
00572               outfile << mmitr->first << " " << mmitr->second[i].size() << " ";
00573               for(uint j=0;j<mmitr->second[i].size();j++) 
00574                 {
00575                   outfile << std::setiosflags(std::ios::fixed) << std::setprecision(4) << mmitr->second[i][j] << " ";
00576                 }
00577               outfile << std::endl;
00578             }
00579         }
00580       outfile.close();
00581     }
00582   else 
00583     {
00584       LFATAL("Could not open LBP Models output file");
00585     }
00586 }
00587 
00588 
00589 std::vector<float> LocalBinaryPatterns::readThresholdsFile(std::string thresholdsFile)
00590 {
00591   FILE *fthresh;
00592   int numEntries;
00593   std::vector<float> thresholds;
00594 
00595   fthresh = fopen(thresholdsFile.c_str(),"r");
00596   if(fthresh == NULL)
00597     {
00598       LFATAL("Unable to open Bin Thresholds input file");
00599     }
00600 
00601   if(fscanf(fthresh, "%d\n", &numEntries) != 1) LFATAL("Failed to load number of entries from: %s", thresholdsFile.c_str());
00602   for(int i=0;i<numEntries;i++)
00603     {
00604       float tmp;
00605       if(fscanf(fthresh, "%f ", &tmp)!= 1) LFATAL("Failed to load threshold for bin %d in file: %s",i,thresholdsFile.c_str());
00606       thresholds.push_back(tmp);
00607     }
00608   if(fscanf(fthresh,"\n")!= 0) LFATAL("Failed to parse newline at end of bin thresholds in file: %s",thresholdsFile.c_str());
00609   fclose(fthresh);
00610   return thresholds;
00611 }
00612 
00613 void LocalBinaryPatterns::writeThresholdsFile(std::string thresholdsFile, std::vector<float> thresholds)
00614 {
00615   std::ofstream outfile;
00616   outfile.open(thresholdsFile.c_str(),std::ios::out);
00617   if (outfile.is_open()) 
00618     {
00619       outfile << thresholds.size() << " ";
00620       outfile << std::endl;
00621       for(uint i=0;i<thresholds.size();i++) 
00622         {
00623           outfile << std::setiosflags(std::ios::fixed) << std::setprecision(4) << thresholds[i] << " ";
00624         }
00625       outfile << std::endl;
00626       outfile.close();
00627     }
00628   else 
00629     {
00630       LFATAL("Could not open Bin Thresholds output file");
00631     }
00632 }
00633 
00634 
00635 // Template instantiations for getVarIndex
00636 template int LocalBinaryPatterns::getVarIndex(const std::vector<float> &thresh, float var, int binHint);
00637 
00638 template int LocalBinaryPatterns::getVarIndex(const std::deque<float> &thresh, float var, int binHint);
Generated on Sun May 8 08:40:38 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3