00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
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
00078 LocalBinaryPatterns::~LocalBinaryPatterns()
00079 {
00080 }
00081
00082
00083
00084
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
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
00097 itsTempLBP[id].push_back(lbp);
00098 itsTempColor[id].push_back(col);
00099
00100 std::vector<float> svar = var;
00101 std::sort(svar.begin(),svar.end());
00102
00103 itsTempVariance[id].push_back(svar);
00104
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;
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
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
00145
00146
00147
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
00157 sumEntries++;
00158 if(uniform<=2) lbps[diff]++;
00159 else lbps[itsLBPPixels+1]++;
00160
00161 if(itsVarBins > 0)
00162 vars.push_back(var / itsLBPPixels);
00163 }
00164 }
00165
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
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
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
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
00251 int bin = getVarIndex<std::vector<float> >(itsVarBinThresholds,vars[i],binHint);
00252 varHist[bin]++;
00253 binHint=bin;
00254 }
00255
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
00288 MapModelVector::const_iterator imitr=incompleteModels.begin(), imstop = incompleteModels.end();
00289
00290 for(;imitr!=imstop;imitr++)
00291 {
00292
00293 for(uint i=0;i<imitr->second.size();i++)
00294 {
00295 std::vector<float> combinedHist = imitr->second[i];
00296
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
00311 for(;imitr!=imstop;imitr++)
00312 {
00313
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
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
00341 for(;sitr!=sstop;sitr++)
00342 {
00343
00344 for(uint i=0;i<sitr->second.size();i++)
00345 {
00346 ASSERT(dst[sitr->first].size() <= sitr->second.size());
00347
00348 if(dst[sitr->first].size() < sitr->second.size())
00349 dst[sitr->first].resize(sitr->second.size());
00350
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
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
00365
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
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
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
00410 float step = totalDist.size()/float(itsVarBins);
00411
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
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
00448 hist.insert(hist.end(),col.begin(),col.end());
00449
00450 if(itsVarBins > 0)
00451 hist.insert(hist.end(),varHist[tmitr->first][i].begin(),varHist[tmitr->first][i].end());
00452
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
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
00483 bool binFound=false;
00484 const int endBin = thresh.size();
00485
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
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
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
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);