train-faceParts.C

Go to the documentation of this file.
00001 /*!@file Gist/train-faceParts.C testing Feed Forward Network class
00002   for use to train any mapping */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // 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: Christian Siagian <siagian@usc.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Gist/train-faceParts.C $
00036 // $Id: train-faceParts.C 14376 2011-01-11 02:44:34Z pez $
00037 //
00038 
00039 // ######################################################################
00040 /*! This class test implementation a simple feedforward network
00041  with backpropagation. */
00042 
00043 #include "Channels/OrientationChannel.H"
00044 #include "Component/ModelManager.H"
00045 #include "GUI/XWinManaged.H"
00046 #include "Image/CutPaste.H"
00047 #include "Image/DrawOps.H"
00048 #include "Image/ImageSet.H"
00049 #include "Image/MathOps.H"
00050 #include "Image/PyramidOps.H"
00051 #include "Image/ShapeOps.H"
00052 #include "Image/Transforms.H"
00053 #include "Neuro/StdBrain.H"
00054 #include "Neuro/VisualCortex.H"
00055 #include "Raster/Raster.H"
00056 
00057 
00058 #include "Gist/FFN.H"
00059 #include "Gist/ModelFace.H"
00060 
00061 #define LEARN_RATE                 0.5
00062 #define TRAIN_START_INDEX          277
00063 #define NUM_TRAIN_SAMPLE           200
00064 #define TEST_START_INDEX           234
00065 #define NUM_TEST_SAMPLE            100
00066 
00067 CloseButtonListener wList; XWinManaged *imgWin;
00068 Image<byte> targetmask;
00069 
00070 Image<float> getPartImage(char* iName, Rectangle pr);
00071 Image<float> getPartImage(Image<float> img, Rectangle pr);
00072 
00073 Rectangle getPartRect(char* iName, char* dName, FacePart part, int opp);
00074 Rectangle getPartRect(Image<float> img, char* dName, FacePart part, int opp);
00075 
00076 void getFeature(Rectangle r, FacePart part, Image<double> features);
00077 void getEyeFeature  (Rectangle r, Image<double> features);
00078 void getNoseFeature (Rectangle r, Image<double> features);
00079 void getMouthFeature(Rectangle r, Image<double> features);
00080 
00081 void train
00082 (FeedForwardNetwork* ffn, FacePart part, nub::soft_ref<StdBrain> brain);
00083 void fillEyeData
00084 ( int start, std::vector<Image<double> > pData,
00085   std::vector<Image<double> >nData, int *pCt, int *nCt);
00086 void fillNoseData
00087 ( int start, std::vector<Image<double> > pData,
00088   std::vector<Image<double> > nData, int *pCt, int *nCt);
00089 void fillMouthData
00090 ( int start, std::vector<Image<double> > pData,
00091   std::vector<Image<double> > nData, int *pCt, int *nCt);
00092 
00093 bool within(Rectangle r, int x, int y);
00094 
00095 nub::soft_ref<OrientationChannel> oriChan;
00096 
00097 // CURRENT IMAGE BEING PROCESS - MINIMIZING PROCESSING
00098 // IN REAL APPLICATION A BRAIN WOULD DO THIS
00099 Image<float> currImg;
00100 ImageSet<float> currGaPyr[NUM_DIR];
00101 
00102 void printRegion(Image<float> img,int sX,int eX,int dX, int sY,int eY, int dY);
00103 
00104 // testing feed forward network to teach a network to detect an object
00105 int main(const int argc, const char **argv)
00106 {
00107 
00108   // Instantiate a ModelManager:
00109   ModelManager manager("Face Recognition Model");
00110 
00111   // Instantiate our various ModelComponents:
00112   nub::soft_ref<StdBrain> brain(new StdBrain(manager));
00113   manager.addSubComponent(brain);
00114 
00115   // Parse command-line:
00116   if (manager.parseCommandLine(argc, argv,"", 0, 0) == false)
00117     return(1);
00118 
00119   // let's get all our ModelComponent instances started:
00120   manager.start();
00121   LFATAL("fixme");
00122   nub::soft_ref<VisualCortex> vc;////// = brain->getVC();
00123   ///////  dynCastWeakToFrom(oriChan, vc->subChan("orientation"));
00124 
00125   // seed the random number generator
00126   srand((unsigned)time(0));
00127 
00128   // instantiate a feed forward network for each face part
00129   FeedForwardNetwork *ffn_e = new FeedForwardNetwork();
00130   FeedForwardNetwork *ffn_n = new FeedForwardNetwork();
00131   FeedForwardNetwork *ffn_m = new FeedForwardNetwork();
00132 
00133   // get the weight values for each part
00134   char h1EName[200],h2EName[200],oEName[200];
00135   sprintf(h1EName,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"hidden1EYE.dat");
00136   sprintf(h2EName,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"hidden2EYE.dat");
00137   sprintf(oEName ,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"outEYE.dat");
00138 
00139   char h1NName[200],h2NName[200],oNName[200];
00140   sprintf(h1NName,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"hidden1NOSE.dat");
00141   sprintf(h2NName,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"hidden2NOSE.dat");
00142   sprintf(oNName ,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"outNOSE.dat");
00143 
00144   char h1MName[200],h2MName[200],oMName[200];
00145   sprintf(h1MName,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"hidden1MOUTH.dat");
00146   sprintf(h2MName,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"hidden2MOUTH.dat");
00147   sprintf(oMName ,"%s%s%s",WEIGHT_DATA_FOLDER,FILE_TAGNAME,"outMOUTH.dat");
00148 
00149   // initialize the size of network
00150   // use 3-weight layer network
00151   ffn_e->init3L(h1EName, h2EName, oEName,
00152                 RE_INPUT, RE_HIDDEN_1, RE_HIDDEN_2, 1, LEARN_RATE, 0.0);
00153   ffn_n->init3L(h1NName, h2NName, oNName,
00154                 N_INPUT,   N_HIDDEN_1,  N_HIDDEN_2, 1, LEARN_RATE, 0.0);
00155   ffn_m->init3L(h1MName, h2MName, oMName,
00156                 M_INPUT,   M_HIDDEN_1,  M_HIDDEN_2, 1, LEARN_RATE, 0.0);
00157 
00158   // train each individual face parts
00159   train(ffn_e, EYE, brain);
00160   train(ffn_n, NOSE, brain);
00161   train(ffn_m, MOUTH, brain);
00162 
00163   // save the weight values
00164   //ffn_e->write3L(h1EName, h2EName, oEName);
00165   //ffn_n->write3L(h1NName, h2NName, oNName);
00166   //ffn_m->write3L(h1MName, h2MName, oMName);
00167 }
00168 
00169 // ######################################################################
00170 // train the FFN for the part
00171 void train(FeedForwardNetwork *ffn, FacePart part, nub::soft_ref<StdBrain> brain)
00172 {
00173   // set the appropriate storage size for the specified part
00174   int pW = 0, pH = 0;
00175   switch(part)
00176     {
00177     case EYE:
00178       pW = MODEL_EYE_WIDTH;
00179       pH = MODEL_EYE_HEIGHT;
00180     break;
00181     case NOSE:
00182       pW = MODEL_NOSE_WIDTH;
00183       pH = MODEL_NOSE_HEIGHT;
00184     break;
00185     case MOUTH:
00186       pW = MODEL_MOUTH_WIDTH;
00187       pH = MODEL_MOUTH_HEIGHT;
00188     break;
00189     default:
00190       LFATAL("Unknown face part");
00191     }
00192 
00193   // store positive training samples
00194   // negative training samples will be generated randomly every 10 epoch
00195   std::vector<Image<double> > pData(NUM_TRAIN_SAMPLE);
00196   std::vector<Image<double> > nData(NUM_TRAIN_SAMPLE);
00197 
00198   // the success of the neural net lies in the set of training samples
00199   // knowing what the boudaries we are looking for
00200 //   int  start = TRAIN_START_INDEX;
00201   int pCount = 0, nCount = 0;
00202 
00203   // setup the test cases for each part
00204 //   switch(part)
00205 //   {
00206 //   case EYE:
00207 //     fillEyeData  (start, pData, nData, &pCount, &nCount);   break;
00208 //   case NOSE:
00209 //     fillNoseData (start, pData, nData, &pCount, &nCount);   break;
00210 //   case MOUTH:
00211 //     fillMouthData(start, pData, nData, &pCount, &nCount);   break;
00212 //   default:
00213 //     LFATAL("Unknown face part");
00214 //   }
00215 
00216   // train the network
00217   printf("Start Training\n");
00218   int nfc = NUM_TRAIN_SAMPLE;
00219   Image<double> trueout(1,1,ZEROS);
00220   double errSum = double(2*NUM_TRAIN_SAMPLE);
00221   int nTrials = 0;
00222   Image<double> ffnOut;
00223   while(nTrials < 0) // change to a positive number to train
00224   {
00225     errSum = 0.0; nfc = 0; int i = 0;
00226     while (i < pCount || i < nCount)
00227     {
00228       // run the positive sample image
00229       if(i < pCount)
00230       {
00231         ffn->run3L(pData[i]);
00232         ffnOut = ffn->getOutput();
00233         errSum += fabs(1.0 - ffnOut[0]);
00234         if(ffnOut[0] < .5)
00235         {
00236           nfc++;
00237           printf("falsePOS o: %f, err: %f\n",ffnOut[0], 1.0-ffnOut[0]);
00238         }
00239         trueout[0] = 1.0; ffn->backprop3L(trueout);
00240       }
00241 
00242       // run the negative sample image
00243       if(i < nCount)
00244       {
00245         ffn->run3L(nData[i]);
00246         ffnOut = ffn->getOutput();
00247         errSum += fabs(ffnOut[0]);
00248         if(ffnOut[0] > .5)
00249         {
00250           nfc++;
00251           printf("falseNEG: out: %f, err: %f\n",ffnOut[0],ffnOut[0]);
00252         }
00253         trueout[0] = 0.0; ffn->backprop3L(trueout);
00254       }
00255       i++;
00256     }
00257     nTrials++;
00258 
00259     // periodically report progress
00260     if(nTrials %10 == 0)
00261       printf("Trial_%04d_Err: %f, nfc: %d \n",
00262              nTrials,errSum/double(pCount+nCount),nfc);
00263   }
00264 
00265   // final error count
00266   printf("Final Trial_%04d_Err: %f, nfc: %d \n",
00267          nTrials,errSum/double(pCount+nCount),nfc);
00268 
00269   // test the current network on test images.
00270   printf("Testing Phase\n");
00271 
00272   // traverse through the test cases
00273 //   start = TEST_START_INDEX; errSum = 0.0; nfc = 0;
00274 //   for(int i = start; i < start+NUM_TEST_SAMPLE; i++)
00275 //   {
00276 //     double testData[pSize];
00277 //     char iName[200],dName[200];
00278 //     sprintf(iName, "%s%s%04d%s",IMAGE_FOLDER,FILE_TAGNAME,i,IMAGE_FILE_EXT);
00279 //     sprintf(dName, "%s%s%04d%s",DATA_FOLDER, FILE_TAGNAME,i,DATA_FILE_EXT );
00280 
00281 //     // get the part from the image
00282 //     Rectangle pr = getPartRect(iName, dName, part,0);
00283 //     Image<float> *pImg = getPartImage(iName,pr);
00284 //     getFeature(pImg, testData);
00285 
00286 //     // run the positive sample image
00287 //     ffn->run3L(testData);
00288 //     errSum += fabs(1.0 - ffn->out[0]);
00289 //     if(ffn->out[0] < .5) nfc++;
00290 
00291 //     // get random images from the same file (for negative cases)
00292 //     pr = getPartRect(iName, dName, part,1);
00293 //     pImg = getPartImage(iName,pr);
00294 //     getFeature(pImg,testData);
00295 
00296 //     // run the negative sample image
00297 //     ffn->run3L(testData);
00298 //     errSum += fabs(ffn->out[0]);
00299 //     if(ffn->out[0] > .5) nfc++;
00300 
00301 //    XWinManaged *eWin = new XWinManaged(Dims(MODEL_EYE_WIDTH*4,MODEL_EYE_WIDTH*4),
00302 //                                        1000,0,"False eye");
00303 //    wList.add(*eWin);
00304 //    XWinManaged *neWin = new XWinManaged(Dims(MODEL_EYE_WIDTH*4,MODEL_EYE_WIDTH*4),
00305 //                                         1000,0,"False non-eye");
00306 //    wList.add(*neWin);
00307 //    eWin->drawImage(zoomXY(eImg[i], 4,-1),0,0);
00308 //    neWin->drawImage(zoomXY(neImg[i], 4,-1),0,0);
00309 //    Raster::waitForKey();
00310 //  }
00311 //  printf("Test_Err: %f, nfc: %d \n", errSum/NUM_TEST_SAMPLE/2.0,nfc);
00312 
00313   // test on an image:
00314   int tNum = 333;
00315   char tName[200];
00316   sprintf(tName, "%s%s%04d%s",IMAGE_FOLDER,FILE_TAGNAME,tNum,IMAGE_FILE_EXT);
00317   Image<float> tImg = Raster::ReadGray(tName);
00318 
00319     currImg = tImg;
00320     float cMean  = float(mean(currImg));
00321     float cStdev = float(stdev(currImg));
00322     currImg -= cMean;
00323     currImg /= cStdev;
00324     for(int i = 0; i< NUM_DIR; i++)
00325       currGaPyr[i] = buildPyrGabor(currImg,0,4,i*45,7,1,9,0);
00326 
00327   ImageSet<float> tImgPyr = buildPyrGaussian(currImg, 0, 9, 3);
00328   Image<double> tData;
00329   Image<float> apa;
00330 
00331   Image<float> res(tImgPyr[1].getWidth(), tImgPyr[1].getHeight(), ZEROS);
00332   for(int i = 0; i < tImgPyr[1].getWidth() - pW; i++)
00333     for(int j = 0; j < tImgPyr[1].getHeight() - pH; j++)
00334     {
00335       Rectangle a = Rectangle::tlbrI(j,i,j+pH-1,i+pW-1);
00336       getFeature(a, part, tData);
00337       ffn->run3L(tData);
00338       Image<double> ffnOut = ffn->getOutput();
00339       res.setVal(i+pW/2,j+pH/2,ffnOut[0]);
00340 //       if(ffnOut[0] >.7 & i == 42 && j == 61)
00341 //       {
00342 
00343 //         Rectangle r2(a.top()/2, a.left()/2, a.bottom()/2, a.right()/2);
00344 //         printf("t: %d, b: %d, l: %d, r: %d\n",
00345 //        a.top(),a.bottom(),a.left(),a.right());
00346 //         printf("t: %d, b: %d, l: %d, r: %d\n",
00347 //        r2.top(),r2.bottom(),r2.left(),r2.right());
00348 
00349 //         printRegion(currGaPyr[0][1],i,i+11,1,j,j+13,1);
00350 //         for(int t = 0; t < 61*4; t++)
00351 //           printf("%2d - %f \n",t, tData[t]);
00352 //         printf("i: %d j: %d out: %f\n",i,j,ffnOut[0]);
00353 //         apa = getPartImage(tImg,a);
00354 //         Raster::waitForKey();
00355 //       }
00356     }
00357   XWinManaged *eWin = new XWinManaged(Dims(2*2*tImgPyr[1].getWidth(),
00358                                            2*tImgPyr[1].getHeight()),
00359                                       700,0,"TestImage");
00360   wList.add(*eWin);
00361   eWin->drawImage(tImg+(zoomXY(res, 2,-1)*255),0,0);
00362   eWin->drawImage(zoomXY(res, 2,-1),2*tImgPyr[1].getWidth(),0);
00363   Raster::waitForKey();
00364 }
00365 
00366 // ######################################################################
00367 void fillEyeData
00368 (int start,
00369  std::vector<Image<double> > pData,
00370  std::vector<Image<double> > nData,
00371  int *pCt, int  *nCt)
00372 {
00373   int pW = MODEL_EYE_WIDTH, pH = MODEL_EYE_HEIGHT;
00374   char iName[200],dName[200];
00375   int pCount = 0; int nCount = 0;
00376 
00377   // get positive samples of eyes(left and right) from the files
00378   for(int s = 0; s < NUM_TRAIN_SAMPLE/2; s++)
00379   {
00380     sprintf(iName, "%s%s%04d%s",
00381             IMAGE_FOLDER,FILE_TAGNAME,start+s,IMAGE_FILE_EXT);
00382     sprintf(dName, "%s%s%04d%s",
00383             DATA_FOLDER, FILE_TAGNAME,start+s,DATA_FILE_EXT );
00384     if(s%10 == 0)
00385       printf("setting up positive image %d\n",s);
00386 
00387     currImg = Raster::ReadGray(iName);
00388     float cMean  = float(mean(currImg));
00389     float cStdev = float(stdev(currImg));
00390     currImg -= cMean;
00391     currImg /= cStdev;
00392 
00393     for(int i = 0; i< NUM_DIR; i++)
00394       currGaPyr[i] = buildPyrGabor(currImg,0,4,i*45,7,1,9,0);
00395 
00396     // get the left eye from the image
00397     getEyeFeature(getPartRect(currImg, dName, L_EYE, 0),
00398                    pData[pCount]);
00399     pCount++;
00400 
00401     // get the right eye from the image
00402     getEyeFeature(getPartRect(currImg, dName, R_EYE, 0),
00403                    pData[pCount]);
00404     pCount++;
00405   }
00406 
00407   // get negative-case images from the last file
00408   Rectangle ler = getPartRect(currImg, dName, L_EYE, 0);
00409   Rectangle rer = getPartRect(currImg, dName, R_EYE, 0);
00410   int w = currImg.getWidth(), h = currImg.getHeight();
00411 
00412   // This code is changed over and over - samples are provided by user
00413   // from area above the eye
00414   for (int i = w/5/2+5; i < 2*w/5-10; i+= pW/2)
00415     for(int j = 15; j < std::min(ler.top(),rer.top())-10;j+= pH)
00416     {
00417       getEyeFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00418                      nData[nCount]); nCount++;
00419     }
00420 
00421   // from the area below the eyes
00422   for (int i = w/5/2; i < 2*w/5-10; i+= pW/2)
00423     for(int j = std::max(ler.bottomI(),rer.bottomI())+5; j < h/2-pH; j+= pH)
00424     {
00425       getEyeFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00426                      nData[nCount]); nCount++;
00427     }
00428 
00429   *nCt = nCount;
00430   *pCt = pCount;
00431   printf("pCount: %d, nCount: %d \n", pCount, nCount);
00432 }
00433 
00434 // ######################################################################
00435 void fillNoseData
00436 (int start,
00437  std::vector<Image<double> > pData,
00438  std::vector<Image<double> > nData,
00439  int *pCt, int  *nCt)
00440 {
00441   int pW = MODEL_NOSE_WIDTH, pH = MODEL_NOSE_HEIGHT;
00442   char iName[200],dName[200];
00443   int pCount = 0; int nCount = 0;
00444 
00445   // get positive samples of noses from the files
00446   for(int s = 0; s < NUM_TRAIN_SAMPLE; s++)
00447   {
00448     sprintf(iName, "%s%s%04d%s",
00449             IMAGE_FOLDER,FILE_TAGNAME,start+s,IMAGE_FILE_EXT);
00450     sprintf(dName, "%s%s%04d%s",
00451             DATA_FOLDER, FILE_TAGNAME,start+s,DATA_FILE_EXT );
00452     if(s%10 == 0)
00453       printf("setting up positive image %d\n",s);
00454 
00455     currImg = Raster::ReadGray(iName);
00456     float cMean  = float(mean(currImg));
00457     float cStdev = float(stdev(currImg));
00458     currImg -= cMean;
00459     currImg /= cStdev;
00460     for(int i = 0; i< NUM_DIR; i++)
00461       currGaPyr[i] = buildPyrGabor(currImg,0,4,i*45,7,1,9,0);
00462 
00463     // get the nose from the image
00464     getNoseFeature(getPartRect(currImg, dName, NOSE, 0),
00465                     pData[pCount]);
00466     pCount++;
00467   }
00468 
00469   // get negative-case images from the last file
00470   Rectangle nr = getPartRect(currImg, dName, NOSE, 0);
00471   int w = currImg.getWidth(), h = currImg.getHeight();
00472 
00473   // from the area above the nose
00474   for (int i = w/5/2; i < 2*w/5; i+= pW/3)
00475     for(int j = 0; j < nr.top()-pH;j+= pH/2)
00476     {
00477       getNoseFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00478                       nData[nCount]); nCount++;
00479     }
00480 
00481   // from the area below the nose
00482   for (int i = w/5/2; i < 2*w/5; i+= pW/2)
00483     for(int j = nr.bottomI(); j < h/2-pH; j+= pH/2)
00484     {
00485       getNoseFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00486                       nData[nCount]); nCount++;
00487     }
00488 
00489   // from the area on the left side of the nose
00490   for (int i = w/5/2; i < nr.left()-10; i+= pW/2)
00491     for(int j = nr.top()-pH; j < nr.bottomI()+pH; j+= pH/2)
00492     {
00493       getNoseFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00494                       nData[nCount]); nCount++;
00495     }
00496 
00497   // from the area on the right side of the nose
00498   for (int i = nr.rightI() + 5; i < 2*w/5; i+= pW/2)
00499     for(int j = nr.top()-pH; j < nr.bottomI()+pH; j+= pH/2)
00500     {
00501       getNoseFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00502                       nData[nCount]); nCount++;
00503     }
00504   *nCt = nCount;
00505   *pCt = pCount;
00506   printf("pCount: %d, nCount: %d \n",pCount,nCount);
00507 }
00508 
00509 // ######################################################################
00510 void fillMouthData
00511 ( int start,
00512   std::vector<Image<double> > pData,
00513   std::vector<Image<double> > nData,
00514   int *pCt, int  *nCt)
00515 {
00516   int pW = MODEL_MOUTH_WIDTH, pH = MODEL_MOUTH_HEIGHT;
00517   char iName[200],dName[200];
00518   int pCount = 0; int nCount = 0;
00519 
00520   // get positive samples of mouths from the files
00521   for(int s = 0; s < NUM_TRAIN_SAMPLE; s++)
00522   {
00523     sprintf(iName, "%s%s%04d%s",
00524             IMAGE_FOLDER,FILE_TAGNAME,start+s,IMAGE_FILE_EXT);
00525     sprintf(dName, "%s%s%04d%s",
00526             DATA_FOLDER, FILE_TAGNAME,start+s,DATA_FILE_EXT );
00527     if(s%10 == 0)
00528       printf("setting up positive image %d\n",s);
00529 
00530     currImg = Raster::ReadGray(iName);
00531     float cMean  = float(mean(currImg));
00532     float cStdev = float(stdev(currImg));
00533     currImg -= cMean;
00534     currImg /= cStdev;
00535     for(int i = 0; i< NUM_DIR; i++)
00536       currGaPyr[i] = buildPyrGabor(currImg,0,4,i*45,7,1,9,0);
00537 
00538     // get the Mouth from the image
00539      getMouthFeature(getPartRect(currImg, dName, MOUTH, 0),
00540                      pData[pCount]);
00541     pCount++;
00542   }
00543 
00544   // get negative-case images from the last file
00545   Rectangle mr = getPartRect(currImg, dName, MOUTH, 0);
00546   int w = currImg.getWidth(), h = currImg.getHeight();
00547 
00548   // from the area above the mouth
00549   for (int i = w/5/2; i < 2*w/5; i+= pW/2)
00550     for(int j = 0; j < mr.top()-pH;j+= pH/2)
00551     {
00552       getMouthFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00553                       nData[nCount]); nCount++;
00554     }
00555 
00556   // from the area below the mouth
00557   for (int i = w/5/2; i < 2*w/5; i+= pW/2)
00558     for(int j = mr.bottomI(); j < h/2-pH; j+= pH/2)
00559     {
00560       getMouthFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00561                       nData[nCount]); nCount++;
00562     }
00563 
00564   // from the area on the left side of the mouth
00565   for (int i = w/5/2; i < mr.left()-10; i+= pW/2)
00566     for(int j = mr.top(); j < mr.bottomI(); j+= pH/2)
00567     {
00568       getMouthFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00569                        nData[nCount]); nCount++;
00570     }
00571 
00572   // from the area on the right side of the mouth
00573   for (int i = mr.rightI() + 5; i < 2*w/5; i+= pW/2)
00574     for(int j = mr.top(); j < mr.bottomI(); j+= pH/2)
00575     {
00576       getMouthFeature(Rectangle(Point2D<int>(i,j), Dims(pW, pH)),
00577                       nData[nCount]); nCount++;
00578     }
00579 
00580   *nCt = nCount;
00581   *pCt = pCount;
00582   printf("pCount: %d, nCount: %d \n",pCount,nCount);
00583 }
00584 
00585 // ######################################################################
00586 // get nose features
00587 void getFeature(Rectangle r, FacePart part, Image<double> features)
00588 {
00589   switch(part)
00590     {
00591     case EYE:   getEyeFeature  (r, features);     break;
00592     case NOSE:  getNoseFeature (r, features);     break;
00593     case MOUTH: getMouthFeature(r, features);     break;
00594     default:
00595       LFATAL("Unknown face part");
00596     }
00597 }
00598 
00599 // ######################################################################
00600 // get nose features
00601 void getEyeFeature(Rectangle r, Image<double> features)
00602 {
00603   //getPartImage(currImg,r);
00604   // image -> array to be inputted
00605   int k = 0;
00606   Rectangle r2 =
00607     Rectangle::tlbrI(r.top()/2               , r.left()/2              ,
00608                      r.top()/2+r.height()/2-1, r.left()/2+r.width()/2-1 );
00609 
00610 
00611   // the eye model is 12 by 6
00612   // we will extract information from specific points only
00613   // so as to reduce the input numbers
00614 
00615   // for level 1
00616   // ______________
00617   // |    XXXX    |
00618   // |X  X    X  X|
00619   // |X  X    X  X|
00620   // |X  X    X  X|
00621   // |X  X    X   |
00622   // |____XXXX____|
00623 
00624   int totalF1 = 24;
00625   int xF1[24] = { 4, 5, 6, 7, 4, 5, 6, 7, 0, 3, 8,11,
00626                   0, 3, 8,11, 0, 3, 8,11, 0, 3, 8,11 };
00627   int yF1[24] = { 0, 0, 0, 0, 5, 5, 5, 5, 1, 1, 1, 1,
00628                   2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
00629 
00630   // for level 2
00631   // ________
00632   // |  XX  |
00633   // |X XX X|
00634   // |__XX__|
00635 
00636   int totalF2 = 8;
00637   int xF2[8]  = { 2, 3, 0, 2, 3, 5, 2, 3 };
00638   int yF2[8]  = { 0, 0, 1, 1, 1, 1, 2, 2 };
00639 
00640   // get feature from all angle of gabor response
00641   for(int n = 0; n < NUM_DIR; n++)
00642   {
00643     for(int i = 0; i< totalF1; i++)
00644     {
00645         features[k] = double(currGaPyr[n][1].getVal(
00646                         r.left()+xF1[i], r.top()+yF1[i]));
00647         k++;
00648     }
00649 
00650     for(int i = 0; i< totalF2; i++)
00651     {
00652         features[k] = double(currGaPyr[n][2].getVal(
00653                         r2.left()+xF2[i], r2.top()+yF2[i]));
00654         k++;
00655     }
00656   }
00657 }
00658 
00659 // ######################################################################
00660 // get nose features
00661 void getNoseFeature(Rectangle r, Image<double> features)
00662 {
00663   //getPartImage(currImg,r);
00664   // image -> array to be inputted
00665   int k = 0;
00666   Rectangle r2 =
00667     Rectangle::tlbrI(r.top()/2               , r.left()/2              ,
00668                     r.top()/2+r.height()/2-1, r.left()/2+r.width()/2-1 );
00669 
00670   // the Nose model is 20 by 10
00671   // we will extract information from specific points only
00672   // so as to reduce the number of inputs
00673 
00674   // for level 1
00675   // ________________
00676   // |              |
00677   // |              |
00678   // |      XX      |
00679   // |      XX      |
00680   // |      XX      |
00681   // |      XX      |
00682   // |      XX      |
00683   // |      XX      |
00684   // |      XX      |
00685   // |      XX      |
00686   // |      XX      |
00687   // |      XX      |
00688   // |      XX      |
00689   // |   XXXXXXXX   |
00690   // |   X      X   |
00691   // |   X      X   |
00692   // |   X      X   |
00693   // |   X      X   |
00694   // |   XXXXXXXX   |
00695   // |              |
00696   // |______________|
00697 
00698   int totalF1 = 44;
00699   int xF1[44] = { 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7,
00700                   3, 4, 5, 6, 7, 8, 9,10, 3,10, 3,10, 3,10, 3,10, 3, 4, 5, 6,
00701                   7, 8, 9,10 };
00702   int yF1[44] = { 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,
00703                  12,12,12,12,12,12,12,12,13,13,14,14,15,15,16,16,17,17,17,17,
00704                  17,17,17,17 };
00705 
00706   // for level 2
00707   // _________
00708   // |       |
00709   // |   X   |
00710   // |   X   |
00711   // |   X   |
00712   // |   X   |
00713   // |   X   |
00714   // | XXXXX |
00715   // | X   X |
00716   // | XXXXX |
00717   // |_______|
00718 
00719   int totalF2 = 17;
00720   int xF2[17]  = { 3, 3, 3, 3, 3, 1, 2, 3, 4, 5, 1, 5, 1, 2, 3, 4, 5 };
00721   int yF2[17]  = { 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8 };
00722 
00723   // get feature from all angle of gabor response
00724   for(int n = 0; n < NUM_DIR; n++)
00725   {
00726     for(int i = 0; i< totalF1; i++)
00727     {
00728         features[k] = double(currGaPyr[n][1].getVal(
00729                         r.left()+xF1[i], r.top()+yF1[i]));
00730         k++;
00731     }
00732 
00733     for(int i = 0; i< totalF2; i++)
00734     {
00735         features[k] = double(currGaPyr[n][2].getVal(
00736                         r2.left()+xF2[i], r2.top()+yF2[i]));
00737         k++;
00738     }
00739   }
00740 }
00741 
00742 // ######################################################################
00743 // get mouth features
00744 void getMouthFeature(Rectangle r, Image<double> features)
00745 {
00746   //getPartImage(currImg,r);
00747   // image -> array to be inputted
00748   int k = 0;
00749   Rectangle r2 =
00750     Rectangle::tlbrI(r.top()/2               , r.left()/2              ,
00751                     r.top()/2+r.height()/2-1, r.left()/2+r.width()/2-1 );
00752 
00753   // the Mouth model is 20 by 10
00754   // we will extract information from specific points only
00755   // so as to reduce the number of inputs
00756 
00757   // for level 1
00758   // ______________________
00759   // |                    |
00760   // |                    |
00761   // |  X    XXXXXX   X   |
00762   // |  X      XX     X   |
00763   // |  X      XX     X   |
00764   // |  X      XX     X   |
00765   // |  X      XX     X   |
00766   // |  X    XXXXXX   X   |
00767   // |                    |
00768   // |____________________|
00769 
00770   int totalF1 = 32;
00771   int xF1[32] = { 2, 7, 8, 9,10,11,12,17, 2, 9,10,17, 2, 9,10,17,
00772                   2, 9,10,17, 2, 9,10,17, 2, 7, 8, 9,10,11,12,17 };
00773   int yF1[32] = { 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
00774                   5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7 };
00775 
00776   // for level 2
00777   // ____________
00778   // |          |
00779   // | X XXXX X |
00780   // | X  XX  X |
00781   // | X XXXX X |
00782   // |__________|
00783 
00784   int totalF2 = 16;
00785   int xF2[16]  = { 1, 3, 4, 5, 6, 8, 1, 4, 5, 8, 1, 3, 4, 5, 6, 8 };
00786   int yF2[16]  = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3 };
00787 
00788   // get feature from all angle of gabor response
00789   for(int n = 0; n < NUM_DIR; n++)
00790   {
00791     for(int i = 0; i< totalF1; i++)
00792     {
00793         features[k] = double(currGaPyr[n][1].getVal(
00794                         r.left()+xF1[i], r.top()+yF1[i]));
00795         k++;
00796     }
00797 
00798     for(int i = 0; i< totalF2; i++)
00799     {
00800         features[k] = double(currGaPyr[n][2].getVal(
00801                         r2.left()+xF2[i], r2.top()+yF2[i]));
00802         k++;
00803     }
00804   }
00805 }
00806 
00807 // ######################################################################
00808 Rectangle getPartRect(char* iName, char* dName, FacePart part, int opp)
00809 {
00810   Image<float> img = Raster::ReadGray(iName);
00811   return getPartRect(img, dName, part, opp);
00812 }
00813 
00814 // ######################################################################
00815 Rectangle getPartRect(Image <float> img, char* dName, FacePart part, int opp)
00816 {
00817   int top = 0, bot = 0, left = 0, right = 0, width = 0, height = 0;
00818   // set the appropriate index for the specified part
00819   switch(part)
00820     {
00821     case EYE:
00822       top    = NUM_HEADER_LINE + RE_TOP;
00823       bot    = NUM_HEADER_LINE + RE_BOTTOM;
00824       left   = NUM_HEADER_LINE + RE_LEFT;
00825       right  = NUM_HEADER_LINE + RE_RIGHT;
00826       width  = MODEL_EYE_WIDTH;
00827       height = MODEL_EYE_HEIGHT;
00828       break;
00829     case NOSE:
00830       top    = NUM_HEADER_LINE + N_TOP;
00831       bot    = NUM_HEADER_LINE + N_BOTTOM;
00832       left   = NUM_HEADER_LINE + N_LEFT;
00833       right  = NUM_HEADER_LINE + N_RIGHT;
00834       width  = MODEL_NOSE_WIDTH;
00835       height = MODEL_NOSE_HEIGHT;
00836       break;
00837     case MOUTH:
00838       top    = NUM_HEADER_LINE + M_TOP;
00839       bot    = NUM_HEADER_LINE + M_BOTTOM;
00840       left   = NUM_HEADER_LINE + M_LEFT;
00841       right  = NUM_HEADER_LINE + M_RIGHT;
00842       width  = MODEL_MOUTH_WIDTH;
00843       height = MODEL_MOUTH_HEIGHT;
00844       break;
00845     case L_EYE:
00846       top    = NUM_HEADER_LINE + LE_TOP;
00847       bot    = NUM_HEADER_LINE + LE_BOTTOM;
00848       left   = NUM_HEADER_LINE + LE_LEFT;
00849       right  = NUM_HEADER_LINE + LE_RIGHT;
00850       width  = MODEL_EYE_WIDTH;
00851       height = MODEL_EYE_HEIGHT;
00852       break;
00853     case R_EYE:
00854       top    = NUM_HEADER_LINE + RE_TOP;
00855       bot    = NUM_HEADER_LINE + RE_BOTTOM;
00856       left   = NUM_HEADER_LINE + RE_LEFT;
00857       right  = NUM_HEADER_LINE + RE_RIGHT;
00858       width  = MODEL_EYE_WIDTH;
00859       height = MODEL_EYE_HEIGHT;
00860       break;
00861     default:
00862       LFATAL("Unknown face part");
00863     }
00864 
00865   // get the size of the image
00866   if(img.getWidth() == 0)
00867     LFATAL("Image not found");
00868   int w = img.getWidth(), h = img.getHeight();
00869 
00870   // parse the data file to get part
00871   FILE *fp;  char input[100];
00872 
00873   // if data not found assuming to ask for negative sample
00874   // size still as specified above
00875   if((fp = fopen(dName,"rb")) == NULL)
00876     LFATAL("data file not found");
00877 
00878   int temp, temp2, xT, yT;  int xL, yL;  int xB, yB;  int xR, yR;
00879 
00880   // get the coordinate of top of the part
00881   fseek (fp, 0, SEEK_SET);
00882   for(int i = 0; i<= top; i++) if (fgets(input, 1000, fp) == NULL) LFATAL("fgets failed");
00883   sscanf(input, "point %d = [ %d, %d], index = %d", &temp, &xT, &yT, &temp2);
00884 
00885   // get the coordinate of left of the part
00886   fseek (fp, 0, SEEK_SET);
00887   for(int i = 0; i<= left; i++) if (fgets(input, 1000, fp) == NULL) LFATAL("fgets failed");
00888   sscanf(input, "point %d = [ %d, %d], index = %d", &temp, &xL, &yL, &temp2);
00889 
00890   // get the coordinate of bottom of the part
00891   fseek (fp, 0, SEEK_SET);
00892   for(int i = 0; i<= bot; i++) if (fgets(input, 1000, fp) == NULL) LFATAL("fgets failed");
00893   sscanf(input, "point %d = [ %d, %d], index = %d", &temp, &xB, &yB, &temp2);
00894 
00895   // get the coordinate of right of the part
00896   fseek (fp, 0, SEEK_SET);
00897   for(int i = 0; i<= right; i++) if (fgets(input, 1000, fp) == NULL) LFATAL("fgets failed");
00898   sscanf(input, "point %d = [ %d, %d], index = %d", &temp, &xR, &yR, &temp2);
00899 
00900   fclose(fp);
00901 
00902   // adjust coordinates for nose boundary
00903   switch(part)
00904     {
00905     case EYE: case MOUTH: case L_EYE: case R_EYE:break;
00906     case NOSE:
00907       if(xB > xL) xL = xB;
00908       if(xB < xR) xR = xB;
00909       if(yB > std::min(yL,yR)) yB = std::min(yL,yR);
00910       break;
00911     default:
00912       LFATAL("Unknown face part");
00913     }
00914   //     // for debugging
00915   //     imgWin = new XWinManaged(img.getDims(),1000,700,"Image"); wList.add(*imgWin);
00916   //     drawCircle(img, Point2D<int>(xT,h-yT),2,255,2);
00917   //     drawCircle(img, Point2D<int>(xL,h-yL),2,255,1);
00918   //     drawCircle(img, Point2D<int>(xR,h-yR),2,255,1);
00919   //     drawCircle(img, Point2D<int>(xB,h-yB),2,255,1);
00920   //     imgWin->drawImage(zoomXY(img, 1,-1),0,0);
00921   //     Raster::waitForKey();
00922 
00923   // set the appropriate bounding rectangle for the specified part
00924   int t = 0, b = 0, l = 0, r = 0;
00925   t = (h - yT + h - yB)/4 - height/2    ;
00926   l = (xL + xR)/4         - width/2     ;
00927   b = (h - yT + h - yB)/4 + height/2 - 1;
00928   r = (xL + xR)/4         + width/2  - 1;
00929 
00930   // if actually want part that excludes this rectangle
00931   if(opp)
00932   {
00933     Rectangle box =
00934       Rectangle::tlbrI(t - height/2, l - width/2, b + height/2, r + width/2);
00935 
00936     // get a random coordinate in range:
00937     // width : [0 ... w/2 - MODEL_EYE_WIDTH  - 1]
00938     // height: [0 ... h/2 - MODEL_EYE_HEIGHT - 1]
00939     // but not close to the eyes
00940     int xRand, yRand;
00941     xRand = int(rand()/(RAND_MAX + 1.0) * (w/2 - width  - 1));
00942     yRand = int(rand()/(RAND_MAX + 1.0) * (h/2 - height - 1));
00943 
00944     Rectangle lFace =
00945       Rectangle::tlbrI(0,0      ,h/2,w/5/2);
00946     Rectangle rFace =
00947       Rectangle::tlbrI(0,4*w/5/2,h/2,w/2  );
00948 
00949     while(within(box  , xRand, yRand)||
00950           within(lFace, xRand, yRand)||
00951           within(rFace, xRand, yRand)  )
00952     {
00953       xRand = int(rand()/(RAND_MAX + 1.0) * (w/2 - width  - 1));
00954       yRand = int(rand()/(RAND_MAX + 1.0) * (h/2 - height - 1));
00955 
00956     }
00957 
00958     Rectangle res =
00959       Rectangle::tlbrI(yRand, xRand, yRand+height - 1, xRand+width - 1);
00960 
00961 //     printf("bad case:(%d,%d)\n",xRand,yRand);
00962 //     XWinManaged *gfWin = new XWinManaged(img.getDims(),
00963 //                                          1000,0,"GetFeaures:Img");
00964 //     wList.add(*gfWin);
00965 //     drawRect(img, res,255,1);
00966 //     gfWin->drawImage(zoomXY(img, 1,-1),0,0);
00967 //     Raster::waitForKey();
00968 
00969     return res;
00970   }
00971 
00972   Rectangle res = Rectangle::tlbrI(t,l,b,r);
00973 
00974 //     printf("good case\n");
00975 //     XWinManaged *gfWin = new XWinManaged(img.getDims(),
00976 //                                          1000,0,"GetFeature:Img");
00977 //     wList.add(*gfWin);
00978 //     drawRect(img, res,255,1);
00979 //     gfWin->drawImage(zoomXY(img, 1,-1),0,0);
00980 //     Raster::waitForKey();
00981 
00982 
00983   return res;
00984 
00985 }
00986 
00987 // ######################################################################
00988 bool within(Rectangle r, int x, int y)
00989 {
00990   //printf("t: %d, b: %d, l: %d, r: %d\n",
00991   //       r.top(),r.bottom(),r.left(),r.right());
00992   return (x >= r.left() && x <= r.rightI() &&
00993           y >= r.top()  && y <= r.bottomI()  );
00994 }
00995 
00996 // ######################################################################
00997 Image<float> getPartImage(char* iName, Rectangle pr)
00998 {
00999   Image<float> img = Raster::ReadGray(iName);
01000   return getPartImage(img,pr);
01001 }
01002 
01003 // ######################################################################
01004 //   XWinManaged *gM[4];
01005 //   XWinManaged *fM[4];
01006   XWinManaged *iWin;
01007   XWinManaged *gaWin[NUM_DIR][3];
01008 int start_win = 1;
01009 Image<float> getPartImage(Image<float> img, Rectangle pr)
01010 {
01011   int w = img.getWidth(), h = img.getHeight();
01012   ImageSet<float> gPyr = buildPyrGaussian(img, 0, 9, 3);
01013   Image<float> resMap;
01014   resMap = crop(gPyr[1],pr);
01015   // resMap = crop(imgPyr[0][1],pr);
01016 
01017   // for debugging
01018   if(start_win == 1)
01019     {
01020       iWin = new XWinManaged(Dims(w*2,h),700,700,"Image");     wList.add(*iWin);
01021       //start_win = 0;
01022     }
01023 
01024   float min, max;
01025   getMinMax(gPyr[1], min,max);
01026   drawRect(gPyr[1], pr, max, 1);
01027   iWin->drawImage(zoomXY(gPyr[1], 2,-1),0,0);
01028   iWin->drawImage(zoomXY(resMap,8,-1),w,0);
01029   //Raster::waitForKey();
01030 
01031   // Gabor filter debug
01032   Image<float> temp;
01033   for(int i = 0; i < NUM_DIR; i++)
01034     for(int j = 1; j < 4; j++)
01035     {
01036       if(start_win == 1)
01037         gaWin[i][j-1] = new XWinManaged(img.getDims(),i*w,j*h,"imgL");
01038       temp = zoomXY(currGaPyr[i][j],int(pow(2.0,j-1)),-1);
01039       temp = crop(temp,pr);
01040         //drawRect(temp, pr,100,1);
01041       gaWin[i][j-1]->drawImage(zoomXY(temp,8,-1),0,0);
01042     }
01043   start_win = 0;
01044   Raster::waitForKey();
01045 
01046 
01047 //    printf("t: %d, b: %d, l: %d, r: %d\n",
01048 //           pr.top(),pr.bottom(),pr.left(),pr.right());
01049 //   printf("w: %d, h: %d\n",w,h);
01050 
01051 //     ImageSet<float> imgPyr[NUM_DIR];
01052 //     for(int i = 0; i < NUM_DIR; i++)
01053 //     imgPyr[i] = buildPyrOriented(img, 0, 2, 9, i*45.0, 10.0);
01054 
01055 //   Image<float> tempMap[NUM_DIR];
01056 //   Image<float> resMap2[NUM_DIR];
01057 
01058 //   //   tempMap = squared(imgPyr[0][1]);
01059 //   for(int i = 0; i < NUM_DIR; i++)
01060 //     {
01061 //       tempMap[i] = imgPyr[i][1];
01062 //       resMap2[i] = crop(tempMap[i],pr);
01063 //       tempMap[i].drawRect(pr, 100, 1);
01064 
01065 //       if(start_win == 1)
01066 //      {
01067 //        gM[i] = new XWinManaged(Dims(w,h),i*w,0,"imgL");     wList.add(*gM[i]);
01068 //        fM[i] = new XWinManaged(Dims(w,h),i*w,h,"imgL");     wList.add(*fM[i]);
01069 //      }
01070 //       gM[i]->drawImage(zoomXY(resMap2[i],4,-1),0,0);
01071 //       fM[i]->drawImage(zoomXY(tempMap[i],2,-1),0,0);
01072 
01073 //     }
01074 
01075   return resMap;
01076 }
01077 
01078 // ######################################################################
01079 // simple image printing procedure
01080 void printRegion(Image<float> img,int sX,int eX,int dX, int sY,int eY, int dY)
01081 {
01082   for(int j = sY; j<=eY; j+=dY)
01083   {
01084     for(int i = sX; i<=eX; i+=dX)
01085       printf("%8.3f ", img.getVal(i,j));
01086     printf(" \n");
01087   }
01088   printf("\n");
01089 }
01090 
01091 // ######################################################################
01092 /* So things look consistent in everyone's emacs... */
01093 /* Local Variables: */
01094 /* indent-tabs-mode: nil */
01095 /* End: */
Generated on Sun May 8 08:40:39 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3