/Users/lyon/j4p/src/face/EigenFaceCreator.java

1    package face; 
2     
3    import java.io.*; 
4    import java.util.Collections; 
5    import java.util.Vector; 
6     
7     
8    /** 
9     * Creates the FaceBundle's from the list of images and tries to 
10    * match against submitted image. 
11    * 
12    * 
13    * @author Konrad Rzeszutek 
14    * @version 1.0 
15    */ 
16   public class EigenFaceCreator { 
17    
18       private File root_dir; 
19       private static final int MAGIC_SETNR = 16; 
20       private FaceBundle[] b = null; 
21       /** 
22        * Our threshold for accepting the matched image. Anything above this 
23        * number is considered as not found in any of the face-spaces. 
24        */ 
25       public static double THRESHOLD = 3.0; 
26    
27       /** 
28        * Our minimum distance observed for the submitted image in the 
29        * face-spaces. 
30        * 
31        */ 
32       public double DISTANCE = Double.MAX_VALUE; 
33    
34       /** 
35        * This determines if caching of face-spaces should be activated. 
36        * Anything above zero means yes. Anything else means no. 
37        */ 
38       public int USE_CACHE = 1; 
39    
40       /** 
41        * Match against the given file. 
42        * 
43        * @return  The Identifier of the image in the face-space. If image not 
44        * found (based on THRESHOLD) null is returned. 
45        */ 
46       public String checkAgainst(String f) throws FileNotFoundException, IOException { 
47    
48           String id = null; 
49           if (b != null) { 
50               double small = Double.MAX_VALUE; 
51               int idx = -1; 
52               double[] img = readImage(f); 
53    
54               for (int i = 0; i < b.length; i++) { 
55                   b[i].submitFace(img); 
56                   if (small > b[i].distance()) { 
57                       small = b[i].distance(); 
58                       idx = i; 
59                   } 
60               } 
61               DISTANCE = small; 
62               if (small < THRESHOLD) 
63                   id = b[idx].getID(); 
64           } 
65           return id; 
66       } 
67    
68       /** 
69        * Construct the face-spaces from the given directory. There 
70        * must be at least sixteen images in that directory and each image 
71        * must have the same dimensions. The face-space bundles are also 
72        * cached in that directory for speeding up further initialization. 
73        * 
74        * @param n The directory where the training images are located. 
75        * 
76        * @throws  FileNotFoundException The <code>n</code> directory does not exist. 
77        * @throws  IOException Problems reading images from the given directory or saving 
78        * the cache file (if caching is enabled) 
79        * @throws  IllegalArgumentException The arguments submitted are wrong. 
80        * @throws  ClassNotFoundException The cached objects are out-of-date or are 
81        *  not this version&#39;s face-space objects 
82        * 
83        */ 
84       public void readFaceBundles(String n) throws FileNotFoundException, 
85               IOException, IllegalArgumentException, ClassNotFoundException { 
86    
87           root_dir = new File(n); 
88    
89           File[] files = root_dir.listFiles(new face.ImageFilter()); 
90           Vector filenames = new Vector(); 
91    
92           String[] set = new String[MAGIC_SETNR]; 
93    
94           int i = 0; 
95    
96           // Sort the list of filenames. 
97           for (i = 0; i < files.length; i++) { 
98               filenames.addElement(files[i].getName()); 
99           } 
100          Collections.sort(filenames); 
101   
102          b = new FaceBundle[(files.length / MAGIC_SETNR) + 1]; 
103   
104          // Read each set of 16 images. 
105          for (i = 0; i < b.length; i++) { 
106              for (int j = 0; j < MAGIC_SETNR; j++) { 
107                  if (filenames.size() > j + MAGIC_SETNR * i) { 
108                      set[j] = (String) filenames.get(j + MAGIC_SETNR * i); 
109                      //System.out.println(" - "+set[j]); 
110                  } 
111              } 
112              b[i] = submitSet(root_dir.getAbsolutePath() + "/", set); 
113              // Call something here to notify? 
114          } 
115      } 
116   
117      /** 
118       * Submit a set of sixteen images in the <code>dir</code> directory and 
119       * construct a face-space object. This can be done either by reading the 
120       * cached objects (if there are any) or computing the {@link face.FaceBundle}. 
121       * 
122       * @param dir Directory where the images reside 
123       * @param files String array of the names of the files (ie: "image01.jpg") 
124       * @throws  FileNotFoundException The <code>dir</code> directory does not exist. Or the <code>files</code> are nonexistent 
125       * @throws  IOException Problems reading images from the given directory or saving 
126       * the cache file (if caching is enabled) 
127       * @throws  IllegalArgumentException The arguments submitted are wrong. 
128       * @throws  ClassNotFoundException The cached objects are out-of-date or are 
129       *  not this version's face-space objects 
130       * 
131       */ 
132      private FaceBundle submitSet(String dir, String[] files) throws FileNotFoundException, 
133              IOException, IllegalArgumentException, ClassNotFoundException { 
134   
135          if (files.length != MAGIC_SETNR) 
136              throw new IllegalArgumentException("Can only accept a set of " + MAGIC_SETNR + " files."); 
137   
138          FaceBundle bundle = null; 
139          int i = 0; 
140          String name = "cache"; 
141          // The names are all sorted, we presume. 
142   
143          for (i = 0; i < files.length; i++) { 
144              System.out.println("files[i]=" + files[i]); 
145              if (files[i] == null) continue; 
146              int endIndex = files[i].indexOf('.'); 
147              System.out.println("endIndex=" + endIndex); 
148              name = name + files[i].substring(0, endIndex); 
149              // Construct the cache name 
150          } 
151          // Check to see if a FaceBundle cache has been saved. 
152   
153          File f = new File(dir + name + ".cache"); 
154   
155          if (f.exists() && (USE_CACHE > 0)) /* it's cached */ 
156              bundle = readBundle(f); 
157          else { 
158   
159              bundle = computeBundle(dir, files); 
160              if (USE_CACHE > 0) 
161                  saveBundle(f, bundle); 
162          } 
163   
164          return bundle; 
165      } 
166   
167      /** 
168       * Caches the face-space object in <code>f</code> file. 
169       * 
170       * @param f File where to save it 
171       * @param bundle  The face-space object. 
172       * @throws  FileNotFoundException The <code>f</code> is invalid. 
173       * @throws  IOException Problems reading the data. 
174       * 
175       */ 
176      private void saveBundle(File f, FaceBundle bundle) throws FileNotFoundException, IOException { 
177   
178   
179          f.createNewFile(); 
180          FileOutputStream out = new FileOutputStream(f.getAbsolutePath()); 
181          ObjectOutputStream fos = new ObjectOutputStream(out); 
182          fos.writeObject(bundle); 
183          fos.close(); 
184          //System.out.println("saved bundle ... "f.getAbsolutePath()); 
185   
186   
187      } 
188   
189      /** 
190       * Read the cache object from file. 
191       * 
192       * @param f File where to read from. 
193       * @throws  ClassNotFoundException The cached objects are out-of-date or are 
194       *  not this version's face-space objects 
195       * @throws  FileNotFoundException The <code>f</code> is invalid. 
196       * @throws  IOException Problems reading the data. 
197       */ 
198      private FaceBundle readBundle(File f) throws FileNotFoundException, IOException, ClassNotFoundException { 
199   
200          FileInputStream in = new FileInputStream(f); 
201          ObjectInputStream fo = new ObjectInputStream(in); 
202          FaceBundle bundle = (FaceBundle) fo.readObject(); 
203          fo.close(); 
204          //System.out.println("read cached bundle.."); 
205   
206          return bundle; 
207      } 
208   
209      /** 
210       * Construct the face-spaces from the given directory. 
211       * 
212       * @param dir The directory where to read from. 
213       * @param id  The names of the files which to read from. 
214       * @throws  IllegalArgumentException The image files  are either wrong format or there is an image with the wrong dimensions. 
215   
216       */ 
217      private FaceBundle computeBundle(String dir, String[] id) throws 
218              IllegalArgumentException { 
219   
220          ImageFileFormat[] files = new ImageFileFormat[MAGIC_SETNR]; 
221          ImageFileFormat file = null; 
222          String temp = null; 
223          int width = 0; 
224          int height = 0; 
225          int i = 0; 
226   
227          for (i = 0; i < files.length; i++) { 
228              temp = id[i].toLowerCase(); 
229              temp = temp.substring(temp.lastIndexOf('.') + 1, temp.length()); 
230              try { 
231                  if (temp.equals("jpg") || temp.equals("jpeg")) 
232                      file = new JPGFile(dir + id[i]); 
233                  else if (temp.equals("ppm") || temp.equals("pnm")) file = new PPMFile(dir + id[i]); 
234              } catch (IOException e) { 
235                  e.printStackTrace();  //To change body of catch statement use Options | File Templates. 
236              } 
237              if (file == null) 
238                  throw new IllegalArgumentException(id[i] + " is not an image file!"); 
239   
240              files[i] = file; 
241   
242              if (i == 0) { 
243                  width = files[i].getWidth(); 
244                  height = files[i].getHeight(); 
245              } 
246              if ((width != files[i].getWidth()) || (height != files[i].getHeight())) 
247                  throw new IllegalArgumentException( 
248                          "All image files must have the same" 
249                          + "width and height!"); 
250          } 
251   
252          // Then construct our big double[][] array - MxN^2 
253          double[][] face_v = new double[MAGIC_SETNR][width * height]; 
254          //System.out.println("Generating bundle of ("+face_v.length+" x "+face_v[0].length+"), h:"+height+" w:"+width); 
255   
256          for (i = 0; i < files.length; i++) { 
257              //System.arraycopy(files[i].getDouble(),0,face_v[i],0,face_v[i].length); 
258              face_v[i] = files[i].getDouble(); 
259          } 
260   
261          // Do the computation! 
262   
263          return EigenFaceComputation.submit(face_v, width, height, id); 
264   
265      } 
266   
267      public double[] readImage(String f) throws FileNotFoundException, 
268              IllegalArgumentException, IOException { 
269   
270          ImageFileFormat file = null; 
271          String temp = f.toLowerCase(); 
272          temp = temp.substring(temp.lastIndexOf('.') + 1, temp.length()); 
273          if (temp.equals("jpg")) 
274              file = new JPGFile(f); 
275          else if (temp.equals("ppm") || temp.equals("pnm")) file = new PPMFile(f); 
276          if (file == null) 
277              throw new IllegalArgumentException(f + " is not an image file!"); 
278          return file.getDouble(); 
279      } 
280   
281  } 
282   
283  class ImageFilter implements FileFilter { 
284   
285      public boolean accept(File f) { 
286   
287          if (f.isDirectory()) { 
288              return true; 
289          } 
290   
291          String extension = f.getName(); 
292          int i = extension.lastIndexOf('.'); 
293   
294          if (i > 0 && i < extension.length() - 1) { 
295              extension = extension.substring(i + 1).toLowerCase(); 
296          } 
297   
298          if (extension != null) { 
299              if ((extension.equals("ppm")) || 
300                      (extension.equals("pnm")) || 
301                      (extension.equals("jpg")) || 
302                      (extension.equals("jpeg"))) { 
303                  return true; 
304              } else { 
305                  return false; 
306              } 
307          } 
308   
309          return false; 
310      } 
311  } 
312