View Javadoc

1   /**
2    * FaceTracker Licence
3    * -------------------
4    * (Academic, non-commercial, not-for-profit licence)
5    *
6    * Copyright (c) 2010 Jason Mora Saragih
7    * All rights reserved.
8    *
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions are met:
11   *
12   *     * The software is provided under the terms of this licence stricly for
13   *       academic, non-commercial, not-for-profit purposes.
14   *     * Redistributions of source code must retain the above copyright notice,
15   *       this list of conditions (licence) and the following disclaimer.
16   *     * Redistributions in binary form must reproduce the above copyright
17   *       notice, this list of conditions (licence) and the following disclaimer
18   *       in the documentation and/or other materials provided with the
19   *       distribution.
20   *     * The name of the author may not be used to endorse or promote products
21   *       derived from this software without specific prior written permission.
22   *     * As this software depends on other libraries, the user must adhere to and
23   *       keep in place any licencing terms of those libraries.
24   *     * Any publications arising from the use of this software, including but
25   *       not limited to academic journal and conference publications, technical
26   *       reports and manuals, must cite the following work:
27   *
28   *       J. M. Saragih, S. Lucey, and J. F. Cohn. Face Alignment through Subspace
29   *       Constrained Mean-Shifts. International Journal of Computer Vision
30   *       (ICCV), September, 2009.
31   *
32   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
33   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
34   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
35   * EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
36   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
37   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
39   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
41   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  package com.jsaragih;
44  
45  import java.io.BufferedReader;
46  import java.io.BufferedWriter;
47  import java.io.FileNotFoundException;
48  import java.io.FileReader;
49  import java.io.FileWriter;
50  import java.io.IOException;
51  import java.util.Scanner;
52  
53  import org.openimaj.image.FImage;
54  import org.openimaj.math.matrix.MatrixUtils;
55  
56  import Jama.Matrix;
57  
58  /**
59   * Check whether a patch looks like a face by applying an SVM classifier
60   * 
61   * @author Jason Mora Saragih
62   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
63   */
64  public class FCheck {
65  	static { Tracker.init(); }
66  	
67  	/** < Piecewise affine warp */
68  	PAW _paw;
69  	
70  	/** < SVM bias */
71  	double _b;
72  	
73  	/** < SVM gain */
74  	Matrix _w;
75  
76  	private Matrix vec_;
77  	private FImage crop_;
78  
79  	/**
80  	 * Construct
81  	 * 
82  	 * @param b
83  	 * @param w
84  	 * @param paw
85  	 */
86  	FCheck(double b, Matrix w, PAW paw) {
87  		assert ((w.getRowDimension() == paw._nPix));
88  
89  		_b = b;
90  		_w = w.copy();
91  		_paw = paw;
92  
93  		crop_ = new FImage(_paw._mask.width, _paw._mask.height);
94  		vec_ = new Matrix(_paw._nPix, 1);
95  	}
96  
97  	protected FCheck() {
98  	}
99  
100 	static FCheck load(final String fname) throws FileNotFoundException {
101 		BufferedReader br = null;
102 		try {
103 			br = new BufferedReader(new FileReader(fname));
104 			Scanner sc = new Scanner(br);
105 			return read(sc, true);
106 		} finally {
107 			try {
108 				br.close();
109 			} catch (IOException e) {
110 			}
111 		}
112 	}
113 
114 	void save(final String fname) throws IOException {
115 		BufferedWriter bw = null;
116 		try {
117 			bw = new BufferedWriter(new FileWriter(fname));
118 
119 			write(bw);
120 		} finally {
121 			try {
122 				if (bw != null)
123 					bw.close();
124 			} catch (IOException e) {
125 			}
126 		}
127 	}
128 
129 	void write(BufferedWriter s) throws IOException {
130 		s.write(IO.Types.FCHECK.ordinal() + " " + _b + " ");
131 		IO.writeMat(s, _w);
132 		_paw.write(s);
133 	}
134 
135 	static FCheck read(Scanner s, boolean readType) {
136 		if (readType) {
137 			int type = s.nextInt();
138 			assert (type == IO.Types.FCHECK.ordinal());
139 		}
140 
141 		FCheck fcheck = new FCheck();
142 
143 		fcheck._b = s.nextDouble();
144 		fcheck._w = IO.readMat(s);
145 		fcheck._paw = PAW.read(s, true);
146 		fcheck.crop_ = new FImage(fcheck._paw._mask.width,
147 				fcheck._paw._mask.height);
148 		fcheck.vec_ = new Matrix(fcheck._paw._nPix, 1);
149 
150 		return fcheck;
151 	}
152 
153 	boolean check(FImage im, Matrix s) {
154 		assert ((s.getRowDimension() / 2 == _paw.nPoints()) && (s
155 				.getColumnDimension() == 1));
156 
157 		_paw.crop(im, crop_, s);
158 
159 		if ((vec_.getRowDimension() != _paw._nPix)
160 				|| (vec_.getColumnDimension() != 1))
161 			vec_ = new Matrix(_paw._nPix, 1);
162 
163 		final int w = crop_.width;
164 		final int h = crop_.height;
165 
166 		final double[][] vp = vec_.getArray();
167 		final float[][] cp = crop_.pixels;
168 		final float[][] mp = _paw._mask.pixels;
169 
170 		for (int i = 0, k = 0; i < h; i++) {
171 			for (int j = 0; j < w; j++) {
172 				if (mp[i][j] != 0) {
173 					vp[k][0] = cp[i][j];
174 					k++;
175 				}
176 			}
177 		}
178 
179 		double mean = MatrixUtils.sum(vec_) / vec_.getRowDimension();
180 		MatrixUtils.minus(vec_, mean);
181 
182 		double var = 0;
183 		for (int i = 0; i < _paw._nPix; i++)
184 			var += vec_.get(i, 0) * vec_.get(i, 0);
185 
186 		if (var < 1.0e-10)
187 			MatrixUtils.fill(vec_, 0);
188 		else
189 			vec_ = vec_.times(1 / Math.sqrt(var)); // FIXME inline
190 
191 		double wdv = 0;
192 		for (int i = 0; i < _paw._nPix; i++)
193 			wdv += _w.get(i, 0) * vec_.get(i, 0);
194 
195 		if ((wdv + _b) > 0)
196 			return true;
197 
198 		return false;
199 	}
200 }