001/** 002 * FaceTracker Licence 003 * ------------------- 004 * (Academic, non-commercial, not-for-profit licence) 005 * 006 * Copyright (c) 2010 Jason Mora Saragih 007 * All rights reserved. 008 * 009 * Redistribution and use in source and binary forms, with or without 010 * modification, are permitted provided that the following conditions are met: 011 * 012 * * The software is provided under the terms of this licence stricly for 013 * academic, non-commercial, not-for-profit purposes. 014 * * Redistributions of source code must retain the above copyright notice, 015 * this list of conditions (licence) and the following disclaimer. 016 * * Redistributions in binary form must reproduce the above copyright 017 * notice, this list of conditions (licence) and the following disclaimer 018 * in the documentation and/or other materials provided with the 019 * distribution. 020 * * The name of the author may not be used to endorse or promote products 021 * derived from this software without specific prior written permission. 022 * * As this software depends on other libraries, the user must adhere to and 023 * keep in place any licencing terms of those libraries. 024 * * Any publications arising from the use of this software, including but 025 * not limited to academic journal and conference publications, technical 026 * reports and manuals, must cite the following work: 027 * 028 * J. M. Saragih, S. Lucey, and J. F. Cohn. Face Alignment through Subspace 029 * Constrained Mean-Shifts. International Journal of Computer Vision 030 * (ICCV), September, 2009. 031 * 032 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 033 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 034 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 035 * EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 036 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 037 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 038 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 039 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 040 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 041 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 042 */ 043package com.jsaragih; 044 045import java.io.BufferedReader; 046import java.io.BufferedWriter; 047import java.io.FileNotFoundException; 048import java.io.FileReader; 049import java.io.FileWriter; 050import java.io.IOException; 051import java.util.Scanner; 052 053import org.openimaj.image.FImage; 054 055/** 056 * Multiple patches 057 * 058 * @author Jason Mora Saragih 059 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 060 */ 061public class MPatch { 062 static { Tracker.init(); } 063 064 /** Width of patch */ 065 public int _w; 066 067 /** Height of patch */ 068 public int _h; 069 070 /** List of patches */ 071 public Patch[] _p; 072 073 private FImage res_; 074 075 MPatch(Patch[] p) { 076 _w = p[0].matcher.getTemplate().width; 077 _h = p[0].matcher.getTemplate().height; 078 079 for (int i = 1; i < p.length; i++) { 080 if ((p[i].matcher.getTemplate().width != _w) 081 || (p[i].matcher.getTemplate().height != _h)) { 082 throw new IllegalArgumentException( 083 "Patches must all have the same size"); 084 } 085 } 086 087 _p = p; 088 res_ = new FImage(0, 0); 089 } 090 091 MPatch() { 092 } 093 094 static MPatch load(final String fname) throws FileNotFoundException { 095 BufferedReader br = null; 096 try { 097 br = new BufferedReader(new FileReader(fname)); 098 Scanner sc = new Scanner(br); 099 return read(sc, true); 100 } finally { 101 try { 102 br.close(); 103 } catch (IOException e) { 104 } 105 } 106 } 107 108 void save(final String fname) throws IOException { 109 BufferedWriter bw = null; 110 try { 111 bw = new BufferedWriter(new FileWriter(fname)); 112 113 write(bw); 114 } finally { 115 try { 116 if (bw != null) 117 bw.close(); 118 } catch (IOException e) { 119 } 120 } 121 } 122 123 void write(BufferedWriter s) throws IOException { 124 s.write(IO.Types.MPATCH.ordinal() + " " + _w + " " + _h + " " 125 + _p.length + " "); 126 127 for (int i = 0; i < _p.length; i++) 128 _p[i].write(s); 129 } 130 131 static MPatch read(Scanner s, boolean readType) { 132 if (readType) { 133 int type = s.nextInt(); 134 assert (type == IO.Types.MPATCH.ordinal()); 135 } 136 137 MPatch mpatch = new MPatch(); 138 139 mpatch._w = s.nextInt(); 140 mpatch._h = s.nextInt(); 141 int n = s.nextInt(); 142 143 mpatch._p = new Patch[n]; 144 for (int i = 0; i < n; i++) 145 mpatch._p[i] = Patch.read(s, true); 146 147 return mpatch; 148 } 149 150 final void sum2one(FImage M) { 151 M.divideInplace(M.sum()); 152 } 153 154 void response(FImage im, FImage resp) { 155 assert ((im.height >= _h) && (im.width >= _w)); 156 157 int h = im.height - _h + 1, w = im.width - _w + 1; 158 159 if (resp.height != h || resp.width != w) 160 resp.internalAssign(new FImage(w, h)); 161 162 if (res_ == null) 163 res_ = new FImage(w, h); 164 if (res_.height != h || res_.width != w) 165 res_.internalAssign(new FImage(w, h)); 166 167 if (_p.length == 1) { 168 _p[0].response(im, resp); 169 sum2one(resp); 170 } else { 171 resp.fill(1); 172 173 for (int i = 0; i < _p.length; i++) { 174 _p[i].response(im, res_); 175 sum2one(res_); 176 resp.multiplyInplace(res_); 177 } 178 179 sum2one(resp); 180 } 181 } 182 183 /** 184 * Returns a copy of this MPatch 185 * 186 * @return A copy of this object 187 */ 188 public MPatch copy() { 189 MPatch m = new MPatch(); 190 m._w = _w; 191 m._h = _h; 192 m.res_ = res_; 193 m._p = new Patch[_p.length]; 194 for (int i = 0; i < _p.length; i++) 195 m._p[i] = _p[i].copy(); 196 return m; 197 } 198}