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: */