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}