00001 /*!@file SIFT/Histogram.C Histogram */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: James Bonaiuto <bonaiuto@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/SIFT/Histogram.C $ 00035 // $Id: Histogram.C 14762 2011-05-03 01:13:16Z siagian $ 00036 // 00037 00038 #include "SIFT/Histogram.H" 00039 #include "Image/DrawOps.H" 00040 00041 // ####################################################################### 00042 Histogram::Histogram(const int size) : 00043 itsHistogram(size) 00044 { clear(); } 00045 00046 // ####################################################################### 00047 Histogram::Histogram(const float* input, const int size) : 00048 itsHistogram(size) 00049 { 00050 for (int i = 0; i < size; i++) itsHistogram[i] = input[i]; 00051 } 00052 00053 // ####################################################################### 00054 Histogram::Histogram(std::vector<Histogram> histograms) 00055 { 00056 for(uint i = 0; i < histograms.size(); i++) 00057 { 00058 for (uint j = 0; j < histograms[i].size(); j++) 00059 itsHistogram.push_back(histograms[i][j]); 00060 } 00061 } 00062 00063 // ####################################################################### 00064 Histogram::Histogram(const Image<byte>& img) : 00065 itsHistogram(256) 00066 { 00067 Image<float> hi1(img.getWidth(), img.getHeight(), ZEROS); 00068 00069 int count1 = 0, count2 = 0; 00070 const int w = img.getWidth(); int h = img.getHeight(); 00071 for (int i = 0; i < w; i++) 00072 for (int j = 0; j < h; j++) 00073 { 00074 if (img.getVal(i, j) < 1) 00075 { hi1.setVal(i, j, -255); ++ count1; } 00076 else if (img.getVal(i, j) > 254) 00077 { hi1.setVal(i, j, 255); ++ count2; } 00078 itsHistogram[img.getVal(i, j)] += 1.0F; 00079 } 00080 } 00081 00082 // ###################################################################### 00083 Histogram::~Histogram() 00084 { } 00085 00086 // ####################################################################### 00087 void Histogram::addValue(const uint index, const float value) 00088 { 00089 if (index < itsHistogram.size()) 00090 itsHistogram[index] += value; 00091 else 00092 LFATAL("Index %d out of range [0..%"ZU"]", 00093 index, itsHistogram.size()-1); 00094 } 00095 00096 // ####################################################################### 00097 void Histogram::addValueInterp(const float index, const float value) 00098 { 00099 ASSERT(index >= 0.0F && index < float(itsHistogram.size())); 00100 const uint i0 = uint(index); 00101 const float di = index - float(i0); 00102 uint i1 = i0 + 1; if (i1 >= itsHistogram.size()) i1 = 0; 00103 00104 itsHistogram[i0] += value * (1.0F - di); 00105 itsHistogram[i1] += value * di; 00106 } 00107 00108 // ####################################################################### 00109 void Histogram::fill(const Image<byte>& img) 00110 { 00111 // make sure the histogram has the size 256 00112 itsHistogram.clear(); 00113 itsHistogram.resize(256); 00114 00115 int w = img.getWidth(); int h = img.getHeight(); 00116 for (int i = 0; i < w; i++) 00117 for (int j = 0; j < h; j++) 00118 itsHistogram[img.getVal(i, j)] += 1.0F; 00119 } 00120 00121 // ####################################################################### 00122 Image<byte> Histogram::getHistogramImage(const int w, const int h, 00123 const float mini, const float maxi) 00124 { 00125 if (uint(w) < itsHistogram.size()) 00126 LFATAL("not enough width to display the histogram properly"); 00127 int dw = w / itsHistogram.size(); 00128 00129 Image<byte> res(w, h, ZEROS); 00130 //res.clear(255); 00131 00132 // draw lines for 10% marks: 00133 for (int j = 0; j < 10; j++) 00134 drawLine(res, Point2D<int>(0, int(j * 0.1F * h)), 00135 Point2D<int>(w-1, int(j * 0.1F * h)), byte(64)); 00136 drawLine(res, Point2D<int>(0, h-1), Point2D<int>(w-1, h-1), byte(64)); 00137 00138 float minii = mini, maxii = maxi; 00139 if (maxi == -1.0F) { minii = findMin(); maxii = findMax(); } 00140 00141 // uniform histogram 00142 if (maxii == minii) minii = maxii - 1.0F; 00143 00144 float range = maxii - minii; 00145 00146 for (uint i = 0; i < itsHistogram.size(); i++) 00147 { 00148 int t = abs(h - int((itsHistogram[i] - minii) / range * float(h))); 00149 00150 // if we have at least 1 pixel worth to draw 00151 if (t < h-1) 00152 { 00153 for (int j = 0; j < dw; j++) 00154 drawLine(res, 00155 Point2D<int>(dw * i + j, t), 00156 Point2D<int>(dw * i + j, h - 1), 00157 byte(255)); 00158 //drawRect(res, Rectangle::tlbrI(t,dw*i,h-1,dw*i+dw-1), byte(255)); 00159 } 00160 } 00161 00162 return res; 00163 } 00164 00165 00166 // ####################################################################### 00167 float Histogram::getValue(const uint index) const 00168 { 00169 if (index < itsHistogram.size()) return itsHistogram[index]; 00170 LFATAL("Index %d out of range [0..%"ZU"]", 00171 index, itsHistogram.size()); 00172 return 0.0F; 00173 } 00174 00175 // ####################################################################### 00176 float Histogram::operator[](const uint index) const 00177 { 00178 ASSERT(index < itsHistogram.size()); 00179 return itsHistogram[index]; 00180 } 00181 00182 // ####################################################################### 00183 void Histogram::smooth() 00184 { 00185 std::vector<float> vect(itsHistogram.size()); 00186 const uint siz = itsHistogram.size(); 00187 00188 for (uint n = 0 ; n < siz ; n++) 00189 { 00190 float val0 = itsHistogram[ (n-1+siz) % siz ]; 00191 float val1 = itsHistogram[ (n +siz) % siz ]; 00192 float val2 = itsHistogram[ (n+1+siz) % siz ]; 00193 00194 vect[n] = 0.25F * (val0 + 2.0F*val1 + val2); 00195 } 00196 00197 for (uint n = 0 ; n < siz ; n++) itsHistogram[n] = vect[n]; 00198 } 00199 00200 // ####################################################################### 00201 void Histogram::smooth(Image<double> kernel) 00202 { 00203 ASSERT(kernel.getWidth() == 1 || kernel.getHeight() == 1); 00204 int ksize = kernel.getSize(); 00205 int hksize = ksize/2; 00206 00207 int size = itsHistogram.size(); 00208 std::vector<float> vect(size); 00209 00210 // float fsumb = 0.0; 00211 // for (int i = 0; i < size; i++) 00212 // { 00213 // fsumb+= itsHistogram[i]; 00214 // } 00215 //LINFO("ORG: fsumb: %f hksize: %d", fsumb, hksize); 00216 00217 for (int i = 0; i < size; i++) 00218 { 00219 float total = 0.0; float tweight = 0.0; 00220 for (int j = -hksize; j <= hksize; j++) 00221 { 00222 int k = i+j; int l = j+hksize; 00223 if(k >= 0 && k < size) 00224 { 00225 float weight = kernel.getVal(l); 00226 total += itsHistogram[k]*weight; 00227 tweight += weight; 00228 } 00229 vect[i] = total;///tweight; 00230 } 00231 //LINFO("v[%3d]= %15.5f == (%15.5f/%15.5f) = %15.5f", 00232 // i, itsHistogram[i], total, tweight, vect[i]); 00233 } 00234 for (int i = 0; i < size; i++) itsHistogram[i] = vect[i]; 00235 00236 // float fsuma = 0.0; 00237 // for (int i = 0; i < size; i++) 00238 // { 00239 // fsuma += itsHistogram[i]; 00240 // } 00241 //LINFO("SMO: fsuma: %f", fsuma); 00242 } 00243 00244 // ####################################################################### 00245 float Histogram::findMax() const 00246 { 00247 float maxi = itsHistogram[0]; 00248 for (uint n = 1 ; n < itsHistogram.size() ; n++) 00249 if (itsHistogram[n] > maxi) maxi = itsHistogram[n]; 00250 return maxi; 00251 } 00252 00253 // ####################################################################### 00254 void Histogram::findMax(int &max_loc, float &max_val) 00255 { 00256 max_val = itsHistogram[0]; 00257 max_loc = 0; 00258 00259 for (uint n = 1 ; n < itsHistogram.size() ; n++) 00260 if (itsHistogram[n] > max_val){ 00261 max_val = itsHistogram[n]; 00262 max_loc = n; 00263 } 00264 } 00265 00266 // ####################################################################### 00267 float Histogram::findMin() const 00268 { 00269 float mini = itsHistogram[0]; 00270 for (uint n = 1 ; n < itsHistogram.size() ; n++) 00271 if (itsHistogram[n] < mini) mini = itsHistogram[n]; 00272 return mini; 00273 } 00274 00275 // ####################################################################### 00276 void Histogram::findMinMax(double &min, double &max) 00277 { 00278 max = itsHistogram[0]; 00279 min = max; 00280 for (uint n = 1 ; n < itsHistogram.size() ; n++) 00281 { 00282 if (itsHistogram[n] > max) max = itsHistogram[n]; 00283 if (itsHistogram[n] < min) min = itsHistogram[n]; 00284 } 00285 } 00286 00287 00288 // ####################################################################### 00289 void Histogram::clear() 00290 { 00291 int size = itsHistogram.size(); 00292 itsHistogram.clear(); 00293 itsHistogram.resize(size, 0); 00294 } 00295 00296 // ####################################################################### 00297 void Histogram::resize(uint size) 00298 { 00299 itsHistogram.clear(); 00300 itsHistogram.resize(size); 00301 } 00302 00303 // ####################################################################### 00304 int Histogram::getSize() 00305 { 00306 return itsHistogram.size(); 00307 } 00308 00309 uint Histogram::size() const 00310 { 00311 return itsHistogram.size(); 00312 } 00313 00314 // ####################################################################### 00315 void Histogram::normalize(double sum) 00316 { 00317 if (sum == -1) 00318 { 00319 sum = 0; 00320 for(uint i=0; i<itsHistogram.size(); i++) 00321 sum += itsHistogram[i]; 00322 } 00323 00324 for(uint i=0; i<itsHistogram.size(); i++) 00325 itsHistogram[i] /= sum; 00326 } 00327 00328 // ####################################################################### 00329 double Histogram::getDistance(const Histogram& hist) 00330 { 00331 if (hist.size() > itsHistogram.size()) 00332 LFATAL("Incomputable histograms"); 00333 double sum = 0; 00334 00335 for(uint i=0; i<itsHistogram.size(); i++) 00336 { 00337 //euclidean distance 00338 sum += fabs(itsHistogram[i]-hist[i]); 00339 00340 //histogram intersection 00341 //sum += std::min(itsHistogram[i],hist[i]); 00342 00343 } 00344 00345 return sum; 00346 } 00347 00348 // ###################################################################### 00349 float Histogram::getChiSqDiff(Histogram hist2) 00350 { 00351 ASSERT(itsHistogram.size() == hist2.size()); 00352 00353 // Chi-square difference 00354 float diff = 0.0; 00355 for(uint i = 0; i < hist2.size(); i++) 00356 { 00357 float dif = itsHistogram[i] - hist2[i]; 00358 float sum = itsHistogram[i] + hist2[i]; 00359 if(sum != 0.0F) diff += (dif*dif)/sum; 00360 00361 // LINFO("[%3d] %15.5f vs. %15.5f ||| dif: %f sum: %f ---> %f", 00362 // i, itsHistogram[i], hist2[i], dif, sum, diff); 00363 } 00364 diff = diff/2.0; 00365 00366 return diff; 00367 } 00368 00369 // ####################################################################### 00370 void Histogram::divide(float div) 00371 { 00372 for(uint i = 0; i < itsHistogram.size(); i++) 00373 { 00374 //LINFO("%f/%f", itsHistogram[i], div); 00375 itsHistogram[i] = itsHistogram[i]/div; 00376 //LINFO("= %f", itsHistogram[i]); 00377 } 00378 } 00379 00380 // ###################################################################### 00381 /* So things look consistent in everyone's emacs... */ 00382 /* Local Variables: */ 00383 /* indent-tabs-mode: nil */ 00384 /* End: */