HistogramOfGradients.C

Go to the documentation of this file.
00001 /*!@file Features/HistogramOfGradients.C  */
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: Daniel Parks <danielfp@usc.edu>
00035 // $HeadURL$
00036 // $Id$
00037 //
00038 
00039 #include "Features/HistogramOfGradients.H"
00040 #include "Image/DrawOps.H"
00041 #include "Image/MathOps.H"
00042 #include "Image/Kernels.H"
00043 #include "Image/CutPaste.H"
00044 #include "Image/ColorOps.H"
00045 #include "Image/FilterOps.H"
00046 #include "Image/ShapeOps.H"
00047 
00048 
00049 HistogramOfGradients::HistogramOfGradients(bool normalize, Dims cellDims, bool fixedCells, int numOrientations, bool signedOrient) :
00050 itsNormalize(normalize),
00051 itsCellDims(cellDims),
00052 itsFixedDims(fixedCells),
00053 itsOriBins(numOrientations),
00054 itsOriSigned(signedOrient),
00055 itsEpsilon(0.0001F)
00056 {
00057   
00058 }
00059 
00060 HistogramOfGradients::~HistogramOfGradients()
00061 {
00062 }
00063 
00064 std::vector<float> HistogramOfGradients::createHistogram(const Image<float>& img, const Image<float>& img2, const Image<float>& img3)
00065 {
00066   Image<float> gradmag, gradang;
00067   calculateGradient(img,img2,img3,gradmag,gradang);
00068   return createHistogramFromGradient(gradmag,gradang);
00069 }
00070 
00071 
00072 void HistogramOfGradients::calculateGradient(const Image<float>& img, const Image<float>& img2, const Image<float>& img3, Image<float>& gradmag, Image<float>&gradang)
00073 {
00074 
00075   gradientSobel(img, gradmag, gradang);
00076 
00077   if(img2.initialized())
00078     {
00079       Image<float> gradmag2, gradang2;
00080       // Calculate Sobel for image 2
00081       gradientSobel(img2,gradmag2,gradang2);
00082       // Take element-wise max of magnitudes and use that to choose angles, store into last arguments 
00083       takeLinkedMax(gradmag,gradmag2,gradang,gradang2,gradmag,gradang);
00084     }
00085 
00086   if(img3.initialized())
00087     {
00088       Image<float> gradmag3, gradang3;
00089       // Calculate Sobel for image 2
00090       gradientSobel(img3,gradmag3,gradang3);
00091       // Determine maximum filter per orientation
00092       takeLinkedMax(gradmag,gradmag3,gradang,gradang3,gradmag,gradang);
00093     }
00094   
00095 }
00096 
00097 std::vector<float> HistogramOfGradients::createHistogramFromGradient(const Image<float>& gradmag, const Image<float>& gradang)
00098 {
00099   // Determine the number of cells
00100   
00101   Dims cells;
00102   if(itsFixedDims)
00103     cells = itsCellDims;
00104   else
00105     cells = Dims(int(round(float(gradmag.getWidth())/itsCellDims.w())),int(round(float(gradmag.getHeight())/itsCellDims.h())));
00106 
00107   FeatureVector fv = FeatureVector(cells.w(),cells.h(),itsOriBins);
00108 
00109  // Scan image and we will cumulate local samples into a "cells" sized grid
00110   // of bins, with interpolation.
00111   for (int rx=1; rx<gradmag.getWidth()-1; rx++)
00112     for (int ry=1; ry<gradmag.getHeight()-1; ry++)
00113       {
00114         if(!gradmag.coordsOk(rx,ry)) // outside image
00115           continue;
00116         // Get bin fractions
00117         const float xf = float(rx)/float(gradmag.getWidth())*cells.w();
00118         const float yf = float(ry)/float(gradmag.getHeight())*cells.h();
00119 
00120       float gradMag = gradmag.getValInterp(rx, ry);
00121       float gradAng = gradang.getValInterp(rx, ry);
00122 
00123       // will be interpolated into cells.w x cells.h x itsOriBins:
00124       addToBin(xf,yf,gradAng,gradMag,itsOriSigned,fv);
00125 
00126       }
00127 
00128   std::vector<float> returnVec;
00129   // normalize bins
00130   if(itsNormalize)
00131     {
00132       LINFO("Normalizing feature vector");
00133       returnVec = normalizeFeatureVector(fv);
00134     }
00135   else
00136     returnVec = fv.getFeatureVector();
00137   LINFO("Calculated HOG of size %Zu",returnVec.size());
00138   return returnVec;
00139 
00140 }
00141 
00142 std::vector<float> HistogramOfGradients::normalizeFeatureVector(FeatureVector featureVector)
00143 {
00144   std::vector<float> fv = featureVector.getFeatureVector();
00145   const int xsize = featureVector.getXSize();
00146   const int ysize = featureVector.getYSize();
00147   const int zsize = featureVector.getZSize();
00148   // Output is shrunk by number of cells in the block used in normalization
00149   const int newxsize = xsize - 2;
00150   const int newysize = ysize - 2;
00151   // If we have too small of a histogram, we can't normalize
00152   if(newxsize < 1 || newysize < 1)
00153     return fv;
00154   std::vector<float>::const_iterator ofv=fv.begin();
00155   std::vector<float> distfv=std::vector<float>(xsize*ysize);
00156   std::vector<float>::iterator dfv=distfv.begin();
00157   // Calculate L2 Norm ||v||^2 which will be used to update vector v like so: v=sqrt(||v||^2+epsilon)
00158   for(int x=0;x<xsize;x++)
00159     for(int y=0;y<ysize;y++)
00160       {
00161         float dSq=0;
00162         for(int z=0;z<zsize;z++)
00163           {
00164             // Increment original vector
00165             dSq += *ofv * *ofv;
00166             ofv++;
00167           }
00168         *(dfv++)=dSq;
00169       }
00170   dfv=distfv.begin();
00171   ofv=fv.begin();
00172   std::vector<float> newfv=std::vector<float>(newxsize*newysize*zsize*4);
00173   std::vector<float>::iterator nfv=newfv.begin();
00174   const int h=newysize;
00175   for(int x=0;x<xsize;x++)
00176     for(int y=0;y<ysize;y++)
00177       {
00178         if(x<newxsize && y<newysize)
00179           {
00180             // Upper left normalization block
00181             float n1 = sqrt(*dfv + *(dfv+h) + *(dfv+1) + *(dfv+h+1) + itsEpsilon);
00182             // Upper right normalization block
00183             float n2 = sqrt(*(dfv+h) + *(dfv+2*h) + *(dfv+h+1) + *(dfv+2*h+1) + itsEpsilon);
00184             // Lower left normalization block
00185             float n3 = sqrt(*(dfv+1) + *(dfv+h+1) + *(dfv+2) + *(dfv+h+2) + itsEpsilon);
00186             //Lower right normalization block
00187             float n4 = sqrt(*(dfv+h+1) + *(dfv+2*h+1) + *(dfv+h+2) + *(dfv+2*h+2) + itsEpsilon);
00188             
00189             for(int z=0;z<zsize;z++)
00190               {
00191                 //Increment new vector
00192                 *(nfv++)=*ofv/n1;
00193                 *(nfv++)=*ofv/n2;
00194                 *(nfv++)=*ofv/n3;
00195                 *(nfv++)=*ofv/n4;
00196                 ofv++;
00197               }
00198             // Increment distance vector
00199             dfv++;
00200           }
00201         else
00202           {
00203             ofv+=zsize;
00204             dfv++;
00205           }
00206       }
00207   
00208   return newfv;
00209 }
00210 
00211 void HistogramOfGradients::addToBin(const float xf, const float yf, const float ang_in, const float mag, const bool oriSigned, FeatureVector &fv)
00212 {
00213   float ang=ang_in;
00214   float oriBin;
00215   int numBins = fv.getZSize();
00216   if(oriSigned)
00217     {
00218       // ensure that angle is within -2*M_PI to 2*M_PI
00219       ang=fmod(ang,2*M_PI);
00220       // convert from -2*M_PI:2*M_PI to 0:2*M_PI
00221       if (ang < 0.0)
00222         ang += 2*M_PI; 
00223       oriBin = ang / 2.0 / M_PI * float(numBins);
00224     }
00225   else
00226     {
00227       // ensure that angle is within -M_PI to M_PI
00228       ang=fmod(ang,M_PI);
00229       // convert from -M_PI:M_PI to 0:M_PI
00230       if (ang < 0.0)
00231         ang += M_PI; 
00232       oriBin = ang / M_PI * float(numBins);
00233     }
00234   fv.addValue(xf, yf, oriBin, mag);
00235 }
00236 
00237 
00238 // ######################################################################
00239 /* So things look consistent in everyone's emacs... */
00240 /* Local Variables: */
00241 /* indent-tabs-mode: nil */
00242 /* End: */
Generated on Sun May 8 08:04:46 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3