NNClassifier.h
Go to the documentation of this file.
00001 /* Copyright (C) 2012 Christian Lutz, Thorsten Engesser
00002  * 
00003  * This file is part of motld
00004  * 
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #ifndef NNCLASSIFIER_H
00020 #define NNCLASSIFIER_H
00021 
00022 //#include <iostream>
00023 //#include <fstream>
00024 #include <vector>
00025 #include "Matrix.h"
00026 #include "Histogram.h"
00027 
00028 namespace motld {
00030   class NNPatch
00031   {
00032   public:
00034     Matrix patch;
00036     float avg;
00038     float norm2;
00040     float* histogram;
00042   NNPatch() : patch(), avg(0), norm2(1), histogram(NULL){}
00044     NNPatch(const NNPatch& copyFrom);
00046     NNPatch(const Matrix& curPatch);  
00048     NNPatch(const Matrix& curPatch, const ObjectBox& bbox, 
00049             const unsigned char * rgb = NULL, const int w = 0, const int h = 0);
00051     NNPatch(const ObjectBox& bbox, const Matrix& curImage, const int patchSize,
00052             const unsigned char * rgb = NULL, const int w = 0, const int h = 0);
00054     NNPatch(std::ifstream & inputStream, const int patchSize);
00056     ~NNPatch();
00058     NNPatch& operator=(const NNPatch& copyFrom);
00060     void saveToStream(std::ofstream & outputStream) const;
00061   };
00062 
00065   class NNClassifier
00066   {
00067   public:
00069     NNClassifier(int width, int height, int patchSize, bool useColor = true, bool allowFastChange = false);
00071     NNClassifier(std::ifstream & inputStream);
00073     double getConf(const NNPatch& patch, int objId = 0, bool conservative = false) const;
00075     double getConf(NNPatch& patch, int objId, bool conservative,
00076                    const ObjectBox& bbox, const unsigned char * rgb, int w, int h) const;
00078     bool trainNN(const NNPatch& patch, int objId = 0, bool positive = true, bool tmp = false);
00080     void addObject(const NNPatch& patch);
00082     const std::vector<std::vector<NNPatch> > * getPosPatches() const;
00084     const std::vector<NNPatch> * getNegPatches() const;
00086     void removeWarps();
00088     void saveToStream(std::ofstream & outputStream) const;
00089   
00090   private:
00091     int ivWidth;
00092     int ivHeight;
00093     int ivPatchSize;
00094     static Histogram * ivHistogram;
00095     std::vector<std::vector<NNPatch> > ivPosPatches;
00096     std::vector<NNPatch> ivNegPatches;
00097     std::vector<char> ivWarpIndices;
00098     bool ivUseColor, ivAllowFastChange;
00099     double getConf(const float* patch, float norm2 = 1.0f, int objId = 0, bool conservative = false) const;
00100     double crossCorr(const float* patchA, const float* patchB, float denom = 1) const;
00101     double cmpHistograms(const float* h1, const float* h2) const;
00102   };
00103 
00104 
00105 /**************************************************************************************************
00106  * IMPLEMENTATION                                                                                 *
00107  **************************************************************************************************/
00108  
00110 // NNPatch
00111  
00112   NNPatch::NNPatch(const NNPatch& copyFrom)
00113   {
00114     patch = Matrix(copyFrom.patch);
00115     avg = copyFrom.avg;
00116     norm2 = copyFrom.norm2;
00117     if(copyFrom.histogram != NULL)
00118     {
00119       histogram = new float[NUM_BINS];
00120       memcpy(histogram, copyFrom.histogram, NUM_BINS * sizeof(float));
00121       //for(int i = 0; i < NUM_BINS; i++)
00122       //  histogram[i] = copyFrom.histogram[i];
00123     }else
00124       histogram = NULL;
00125   }
00126   
00127   NNPatch::NNPatch(const Matrix& curPatch)
00128   {
00129     patch = curPatch;
00130     avg = patch.avg();
00131     patch += -avg;
00132     norm2 = patch.norm2();
00133     histogram = NULL;
00134   }  
00135 
00136   NNPatch::NNPatch(const Matrix& curPatch, const ObjectBox& bbox, 
00137                    const unsigned char * rgb, const int w, const int h)
00138   {
00139     patch = curPatch;
00140     avg = patch.avg();
00141     patch += -avg;
00142     norm2 = patch.norm2();
00143     histogram = (rgb == NULL ? NULL 
00144                  : Histogram::getInstance()->getColorDistribution(rgb, w, h, bbox));
00145   }
00146 
00147   NNPatch::NNPatch(const ObjectBox& bbox, const Matrix& curImage, const int patchSize, 
00148                    const unsigned char * rgb, const int w, const int h)
00149   {
00150     patch = curImage.getRectSubPix(bbox.x + 0.5 * bbox.width, bbox.y + 0.5 * bbox.height, 
00151                                    round(bbox.width), round(bbox.height));
00152     patch.rescale(patchSize, patchSize);
00153     avg = patch.avg();
00154     patch += -avg;
00155     norm2 = patch.norm2();
00156     histogram = (rgb == NULL ? NULL 
00157                  : Histogram::getInstance()->getColorDistribution(rgb, w, h, bbox));
00158   }
00159 
00160   NNPatch::NNPatch(std::ifstream & inputStream, const int patchSize)
00161   {
00162     patch = Matrix(patchSize, patchSize);
00163     inputStream.read((char*)patch.data(), patchSize*patchSize*sizeof(float));  
00164     inputStream.read((char*)&avg, sizeof(float));  
00165     inputStream.read((char*)&norm2, sizeof(float));  
00166     bool hist;
00167     inputStream.read((char*)&hist, sizeof(bool));  
00168     if(hist){
00169       histogram = new float[NUM_BINS];
00170       inputStream.read((char*)histogram, NUM_BINS*sizeof(float));  
00171     }else
00172       histogram = NULL;
00173   }
00174 
00175   void NNPatch::saveToStream(std::ofstream & outputStream) const
00176   {
00177     outputStream.write((char*)patch.data(), patch.size()*sizeof(float));  
00178     outputStream.write((char*)&avg, sizeof(float));  
00179     outputStream.write((char*)&norm2, sizeof(float));  
00180     bool hist = histogram != NULL;
00181     outputStream.write((char*)&hist, sizeof(bool));  
00182     if(hist)
00183       outputStream.write((char*)histogram, NUM_BINS*sizeof(float));  
00184   }
00185 
00186   NNPatch::~NNPatch()
00187   {
00188     if(histogram != NULL)
00189       delete [] histogram;
00190     histogram = NULL;
00191   }
00192 
00193   NNPatch& NNPatch::operator=(const NNPatch& copyFrom)
00194     {
00195       if (this != &copyFrom) {
00196         patch = Matrix(copyFrom.patch);
00197         avg = copyFrom.avg;
00198         norm2 = copyFrom.norm2;
00199         if(copyFrom.histogram != NULL)
00200         {
00201           if(histogram != NULL)
00202             delete [] histogram;
00203           histogram = new float[NUM_BINS];
00204           memcpy(histogram, copyFrom.histogram, NUM_BINS * sizeof(float));
00205         }else
00206           histogram = NULL;
00207       }
00208       return *this;
00209     }
00210 
00212 // NNClassifier
00213 
00214   Histogram * NNClassifier::ivHistogram = Histogram::getInstance();
00215 
00216   NNClassifier::NNClassifier(int width, int height, int patchSize, bool useColor, bool allowFastChange) 
00217     : ivWidth(width), ivHeight(height), ivPatchSize(patchSize),
00218     ivUseColor(useColor), ivAllowFastChange(allowFastChange) {}
00219 
00220   NNClassifier::NNClassifier(std::ifstream & inputStream)
00221   {
00222     inputStream.read((char*)&ivWidth, sizeof(int));
00223     inputStream.read((char*)&ivHeight, sizeof(int));
00224     inputStream.read((char*)&ivPatchSize, sizeof(int));
00225     inputStream.read((char*)&ivUseColor, sizeof(bool));
00226     inputStream.read((char*)&ivAllowFastChange, sizeof(bool));
00227     int nNeg, nObs, nPos;
00228     inputStream.read((char*)&nNeg, sizeof(int));
00229     for(int i = 0; i < nNeg; ++i)
00230       ivNegPatches.push_back(NNPatch(inputStream, ivPatchSize));
00231     inputStream.read((char*)&nObs, sizeof(int));
00232     ivPosPatches = std::vector<std::vector<NNPatch> >(nObs);
00233     for(int i = 0; i < nObs; ++i)
00234     {
00235       inputStream.read((char*)&nPos, sizeof(int));
00236       for(int j = 0; j < nPos; ++j)
00237         ivPosPatches[i].push_back(NNPatch(inputStream, ivPatchSize));  
00238     }
00239   }
00240 
00241   const std::vector<std::vector<NNPatch> > * NNClassifier::getPosPatches() const
00242   {
00243     return &ivPosPatches;
00244   }
00245   const std::vector<NNPatch> * NNClassifier::getNegPatches() const
00246   {
00247     return &ivNegPatches;
00248   }
00249 
00250   void NNClassifier::removeWarps()
00251   {
00252     for(unsigned int p = 0; p < ivPosPatches.size(); p++)
00253       if(ivWarpIndices[p] > 0)
00254       {
00255         ivPosPatches[p].erase(ivPosPatches[p].end() - ivWarpIndices[p], ivPosPatches[p].end());
00256         ivWarpIndices[p] = 0;
00257       }
00258   }
00259 
00260   void NNClassifier::addObject(const NNPatch& patch)
00261   {
00262     ivPosPatches.push_back(std::vector<NNPatch>());
00263     ivPosPatches[ivPosPatches.size() - 1].push_back(patch);
00264     ivWarpIndices.push_back(0);
00265     // remove negative patches that are too similar to this new object
00266     for(int i = ivNegPatches.size() - 1; i >= 0; i--)
00267     {  
00268       double ncc = crossCorr(ivNegPatches[i].patch.data(), patch.patch.data(), 
00269                              ivNegPatches[i].norm2 * patch.norm2);
00270       if(ncc > 0.8){
00271         ivNegPatches.erase(ivNegPatches.begin() + i);    
00272 #if DEBUG
00273         std::cout << "removed negative patch " << i << " (ncc = " << ncc << ")" << std::endl;
00274 #endif
00275       }
00276     }
00277   }
00278 
00284   bool NNClassifier::trainNN(const NNPatch& patch, int objId, bool positive, bool tmp)
00285   {
00286     double conf = getConf(patch, positive ? objId : -1, false);
00287     if(positive)
00288     {
00289       if(conf < 0.75)
00290       {
00291         ivPosPatches[objId].push_back(patch);    
00292         if(tmp)
00293           ivWarpIndices[objId]++;
00294         return true;
00295       }
00296     }
00297     else if(conf < 0.85)
00298     {
00299       ivNegPatches.push_back(patch);
00300       return true;
00301     }
00302     return false;
00303   }
00304 
00308   double NNClassifier::getConf(const NNPatch& patch, int objId, bool conservative) const
00309   {
00310     if(ivUseColor)
00311     {
00312       double conf = getConf(patch.patch.data(), patch.norm2, objId, conservative);
00313       if(objId < 0 || conf < 0.58 || patch.histogram == NULL || ivPosPatches[objId][0].histogram == NULL)
00314         return conf;
00315       double colorCons = cmpHistograms(ivPosPatches[objId][0].histogram, patch.histogram);
00316       //Histogram::compareColorDistribution(ivPosPatches[objId][0].histogram, patch.histogram);
00317       //return std::min(colorCons, conf);
00318       if(colorCons < 0.75)
00319         return conf * 0.8;
00320       return conf + (1-conf) * 0.4;
00321     } //else
00322     return getConf(patch.patch.data(), patch.norm2, objId, conservative);
00323   }
00324 
00326   double NNClassifier::getConf(NNPatch& patch, int objId, bool conservative,
00327                                const ObjectBox& bbox, const unsigned char * rgb, int w, int h) const
00328   {
00329     if(ivUseColor)
00330     {
00331       double conf = getConf(patch.patch.data(), patch.norm2, objId, conservative);
00332       if(objId < 0 || conf < 0.58 || ivPosPatches[objId][0].histogram == NULL)
00333         return conf;
00334       else{
00335         if(patch.histogram == NULL && rgb != NULL)
00336           patch.histogram = Histogram::getInstance()->getColorDistribution(rgb, w, h, bbox);
00337         if(patch.histogram != NULL)
00338         {
00339           double colorCons = cmpHistograms(ivPosPatches[objId][0].histogram, patch.histogram);
00340           //Histogram::compareColorDistribution(ivPosPatches[objId][0].histogram, patch.histogram);
00341           //return std::min(colorCons, conf);
00342           if(colorCons < 0.75)
00343             return conf * 0.8;
00344           return conf + (1-conf) * 0.4;
00345         }
00346         return conf;
00347       }
00348     } //else
00349     return getConf(patch.patch.data(), patch.norm2, objId, conservative);
00350   }
00351 
00352   double NNClassifier::getConf(const float* patch, float norm2, int objId, bool conservative) const
00353   {
00354     //max NCC with positive examples
00355     double posNCC = 0;
00356     if (objId >= 0)
00357     {
00358       int nPos = ivPosPatches[objId].size();
00359       double* posNCCs = new double[nPos];
00360 #pragma omp parallel for
00361       for (int i = 0; i < nPos; i++)
00362       {
00363         posNCCs[i] = crossCorr(ivPosPatches[objId][i].patch.data(), patch, (ivPosPatches[objId][i].norm2 * norm2));
00364         if (!ivAllowFastChange && conservative && i > nPos/2)
00365           posNCCs[i] *= 1.0 - 0.05 * (i-nPos/2) / (double)nPos;  
00366       }
00367       for (int i = 0; i < nPos; i++)
00368         if (posNCCs[i] > posNCC)
00369           posNCC = posNCCs[i]; 
00370       delete[] posNCCs;
00371     }
00372     //max NCC with negative examples
00373     double negNCC = 0;
00374     int nNeg = ivNegPatches.size();
00375     if (nNeg)
00376     {
00377       double* negNCCs = new double[nNeg];
00378 #pragma omp parallel for
00379       for (int i = 0; i < nNeg; i++)
00380         negNCCs[i] = crossCorr(ivNegPatches[i].patch.data(), patch, (ivNegPatches[i].norm2 * norm2));
00381       for (int i = 0; i < nNeg; i++)
00382         if (negNCCs[i] > negNCC)
00383           negNCC = negNCCs[i];
00384       delete[] negNCCs;
00385     }else
00386       negNCC = 0.3; //hack! there should always be a negative example from initialization
00387     
00388     if(objId < 0)
00389       return negNCC;
00390     return (1 - negNCC) / (2 - negNCC - posNCC);
00391   }
00392 
00393   double NNClassifier::crossCorr(const float* patchA, const float* patchB, float denom) const
00394   {
00395     double sumDiff = 0;
00396     for (int i = 0; i < ivPatchSize*ivPatchSize; ++i)
00397       sumDiff += patchA[i] * patchB[i];
00398     if (denom <= 0)
00399       return sumDiff;
00400     return (sumDiff/sqrt(denom) + 1) / 2.0;
00401   }
00402 
00403 #define INVBINS (1.0/NUM_BINS)
00404   double NNClassifier::cmpHistograms(const float* h1, const float* h2) const
00405   {
00406     double corr = 0;
00407     double norm1 = 0;
00408     double norm2 = 0;
00409     for (int i = 0; i < NUM_BINS; ++i) 
00410     {
00411       corr  += (h1[i]-INVBINS) * (h2[i]-INVBINS);
00412       norm1 += (h1[i]-INVBINS) * (h1[i]-INVBINS);
00413       norm2 += (h2[i]-INVBINS) * (h2[i]-INVBINS);
00414     }
00415     return (corr / sqrt(norm1*norm2) + 1) / 2.0;
00416   }
00417 
00418   void NNClassifier::saveToStream(std::ofstream & outputStream) const
00419   {
00420     outputStream.write((char*)&ivWidth, sizeof(int));
00421     outputStream.write((char*)&ivHeight, sizeof(int));
00422     outputStream.write((char*)&ivPatchSize, sizeof(int));
00423     outputStream.write((char*)&ivUseColor, sizeof(bool));
00424     outputStream.write((char*)&ivAllowFastChange, sizeof(bool));
00425     // negative patches
00426     int nNeg = ivNegPatches.size();
00427     outputStream.write((char*)&nNeg, sizeof(int));
00428     for(std::vector<NNPatch>::const_iterator it = ivNegPatches.begin(); it != ivNegPatches.end(); ++it)
00429       it->saveToStream(outputStream);
00430     // positive patches
00431     int nObs = ivPosPatches.size();
00432     outputStream.write((char*)&nObs, sizeof(int));
00433     for(std::vector<std::vector<NNPatch> >::const_iterator oit = ivPosPatches.begin(); oit != ivPosPatches.end(); ++oit)
00434     {
00435       int nPos = oit->size();
00436       outputStream.write((char*)&nPos, sizeof(int));
00437       for(std::vector<NNPatch>::const_iterator it = oit->begin(); it != oit->end(); ++it)
00438         it->saveToStream(outputStream);
00439     }
00440   }
00441 
00442 }
00443 
00444 #endif //NNCLASSIFIER_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


motld
Author(s): Jost Tobias Springenberg, Jan Wuelfing
autogenerated on Wed Dec 26 2012 16:24:49