/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'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