1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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.image.processing.transform.RemapProcessor;
55
56 import Jama.Matrix;
57
58
59
60
61
62
63
64 public class PAW {
65 static {
66 Tracker.init();
67 }
68
69
70 int _nPix;
71
72
73 double _xmin;
74
75
76 double _ymin;
77
78
79 Matrix _src;
80
81
82 Matrix _dst;
83
84
85 int[][] _tri;
86
87
88 int[][] _tridx;
89
90
91 FImage _mask;
92
93
94 Matrix _coeff;
95
96
97 Matrix _alpha;
98
99
100 Matrix _beta;
101
102
103 FImage _mapx;
104
105
106 FImage _mapy;
107
108 boolean sameSide(double x0, double y0, double x1, double y1, double x2,
109 double y2, double x3, double y3)
110 {
111 final double x = (x3 - x2) * (y0 - y2) - (x0 - x2) * (y3 - y2);
112 final double y = (x3 - x2) * (y1 - y2) - (x1 - x2) * (y3 - y2);
113
114 if (x * y >= 0)
115 return true;
116 return false;
117 }
118
119 int isWithinTri(double x, double y, int[][] tri, Matrix shape) {
120 final int n = tri.length;
121 final int p = shape.getRowDimension() / 2;
122
123 for (int t = 0; t < n; t++) {
124 final int i = tri[t][0];
125 final int j = tri[t][1];
126 final int k = tri[t][2];
127
128 final double s11 = shape.get(i, 0);
129 final double s21 = shape.get(j, 0);
130 final double s31 = shape.get(k, 0);
131 final double s12 = shape.get(i + p, 0);
132 final double s22 = shape.get(j + p, 0);
133 final double s32 = shape.get(k + p, 0);
134
135 if (sameSide(x, y, s11, s12, s21, s22, s31, s32)
136 && sameSide(x, y, s21, s22, s11, s12, s31, s32)
137 && sameSide(x, y, s31, s32, s11, s12, s21, s22))
138 return t;
139 }
140 return -1;
141 }
142
143 static PAW load(final String fname) throws FileNotFoundException {
144 BufferedReader br = null;
145 try {
146 br = new BufferedReader(new FileReader(fname));
147 final Scanner sc = new Scanner(br);
148 return read(sc, true);
149 } finally {
150 try {
151 br.close();
152 } catch (final IOException e) {
153 }
154 }
155 }
156
157 void save(final String fname) throws IOException {
158 BufferedWriter bw = null;
159 try {
160 bw = new BufferedWriter(new FileWriter(fname));
161
162 write(bw);
163 } finally {
164 try {
165 if (bw != null)
166 bw.close();
167 } catch (final IOException e) {
168 }
169 }
170 }
171
172 void write(BufferedWriter s) throws IOException {
173 s.write(IO.Types.PAW.ordinal() + " " + _nPix + " " + _xmin + " "
174 + _ymin + " ");
175
176 IO.writeMat(s, _src);
177 IO.writeIntArray(s, _tri);
178 IO.writeIntArray(s, _tridx);
179 IO.writeImg(s, _mask);
180 IO.writeMat(s, _alpha);
181 IO.writeMat(s, _beta);
182 }
183
184 static PAW read(Scanner s, boolean readType) {
185 if (readType) {
186 final int type = s.nextInt();
187 assert (type == IO.Types.PAW.ordinal());
188 }
189
190 final PAW paw = new PAW();
191 paw._nPix = s.nextInt();
192 paw._xmin = s.nextDouble();
193 paw._ymin = s.nextDouble();
194
195 paw._src = IO.readMat(s);
196 paw._tri = IO.readIntArray(s);
197 paw._tridx = IO.readIntArray(s);
198 paw._mask = IO.readImgByte(s);
199 paw._alpha = IO.readMat(s);
200 paw._beta = IO.readMat(s);
201
202 paw._mapx = new FImage(paw._mask.width, paw._mask.height);
203 paw._mapy = new FImage(paw._mask.width, paw._mask.height);
204
205 paw._coeff = new Matrix(paw.nTri(), 6);
206 paw._dst = paw._src;
207
208 return paw;
209 }
210
211 int nPoints() {
212 return _src.getRowDimension() / 2;
213 }
214
215 int nTri() {
216 return _tri.length;
217 }
218
219 int width() {
220 return _mask.width;
221 }
222
223 int height() {
224 return _mask.height;
225 }
226
227 PAW(Matrix src, int[][] tri) {
228 assert (src.getColumnDimension() == 1);
229 assert (tri[0].length == 3);
230
231 _src = src.copy();
232 _tri = tri.clone();
233
234 final int n = nPoints();
235
236 _alpha = new Matrix(nTri(), 3);
237 _beta = new Matrix(nTri(), 3);
238
239 for (int i = 0; i < nTri(); i++) {
240 final int j = _tri[i][0];
241 final int k = _tri[i][1];
242 final int l = _tri[i][2];
243
244 final double c1 = _src.get(l + n, 0) - _src.get(j + n, 0);
245 final double c2 = _src.get(l, 0) - _src.get(j, 0);
246 final double c4 = _src.get(k + n, 0) - _src.get(j + n, 0);
247 final double c3 = _src.get(k, 0) - _src.get(j, 0);
248 final double c5 = c3 * c1 - c2 * c4;
249
250 _alpha.set(i, 0, (_src.get(j + n, 0) * c2 - _src.get(j, 0) * c1)
251 / c5);
252 _alpha.set(i, 1, c1 / c5);
253 _alpha.set(i, 2, -c2 / c5);
254
255 _beta.set(i, 0, (_src.get(j, 0) * c4 - _src.get(j + n, 0) * c3)
256 / c5);
257 _beta.set(i, 1, -c4 / c5);
258 _beta.set(i, 2, c3 / c5);
259 }
260
261 double xmax, ymax, xmin, ymin;
262 xmax = xmin = _src.get(0, 0);
263 ymax = ymin = _src.get(n, 0);
264
265 for (int i = 0; i < n; i++) {
266 final double vx = _src.get(i, 0);
267 final double vy = _src.get(i + n, 0);
268
269 xmax = Math.max(xmax, vx);
270 ymax = Math.max(ymax, vy);
271 xmin = Math.min(xmin, vx);
272 ymin = Math.min(ymin, vy);
273 }
274
275 final int w = (int) (xmax - xmin + 1.0);
276 final int h = (int) (ymax - ymin + 1.0);
277 _mask = new FImage(w, h);
278 _tridx = new int[h][w];
279
280 for (int i = 0; i < h; i++) {
281 for (int j = 0; j < w; j++) {
282 if ((_tridx[i][j] = isWithinTri(j + xmin, i + ymin, tri, _src)) == -1) {
283 _mask.pixels[i][j] = 0;
284 } else {
285 _mask.pixels[i][j] = 0;
286 }
287 }
288 }
289
290 _mapx = new FImage(_mask.width, _mask.height);
291 _mapy = new FImage(_mask.width, _mask.height);
292 _coeff = new Matrix(nTri(), 6);
293
294 _dst = _src;
295 _xmin = xmin;
296 _ymin = ymin;
297 }
298
299 PAW() {
300 }
301
302 void crop(FImage src, FImage dst, Matrix s) {
303 assert ((s.getRowDimension() == _src.getRowDimension()) && (s
304 .getColumnDimension() == 1));
305
306 _dst = s;
307
308 calcCoeff();
309
310 warpRegion(_mapx, _mapy);
311
312 RemapProcessor.remap(src, dst, _mapx, _mapy);
313 }
314
315 void calcCoeff() {
316 final int p = nPoints();
317
318 for (int l = 0; l < nTri(); l++) {
319 final int i = _tri[l][0];
320 final int j = _tri[l][1];
321 final int k = _tri[l][2];
322
323 final double c1 = _dst.get(i, 0);
324 final double c2 = _dst.get(j, 0) - c1;
325 final double c3 = _dst.get(k, 0) - c1;
326 final double c4 = _dst.get(i + p, 0);
327 final double c5 = _dst.get(j + p, 0) - c4;
328 final double c6 = _dst.get(k + p, 0) - c4;
329
330 final double[] coeff = _coeff.getArray()[l];
331 final double[] alpha = _alpha.getArray()[l];
332 final double[] beta = _beta.getArray()[l];
333
334 coeff[0] = c1 + c2 * alpha[0] + c3 * beta[0];
335 coeff[1] = c2 * alpha[1] + c3 * beta[1];
336 coeff[2] = c2 * alpha[2] + c3 * beta[2];
337 coeff[3] = c4 + c5 * alpha[0] + c6 * beta[0];
338 coeff[4] = c5 * alpha[1] + c6 * beta[1];
339 coeff[5] = c5 * alpha[2] + c6 * beta[2];
340 }
341 }
342
343 void warpRegion(FImage mapx, FImage mapy) {
344 if ((mapx.height != _mask.height) || (mapx.width != _mask.width))
345 _mapx.internalAssign(new FImage(_mask.width, _mask.height));
346
347 if ((mapy.height != _mask.height) || (mapy.width != _mask.width))
348 _mapy.internalAssign(new FImage(_mask.width, _mask.height));
349
350 int k = -1;
351 double[] a = null, ap;
352
353 final float[][] xp = mapx.pixels;
354 final float[][] yp = mapy.pixels;
355 final float[][] mp = _mask.pixels;
356
357 for (int y = 0; y < _mask.height; y++) {
358 final double yi = y + _ymin;
359
360 for (int x = 0; x < _mask.width; x++) {
361 final double xi = x + _xmin;
362
363 if (mp[y][x] == 0) {
364 xp[y][x] = -1;
365 yp[y][x] = -1;
366 } else {
367 final int j = _tridx[y][x];
368
369 if (j != k) {
370 a = _coeff.getArray()[j];
371 k = j;
372 }
373 ap = a;
374 double xo = ap[0];
375 xo += ap[1] * xi;
376 xp[y][x] = (float) (xo + ap[2] * yi);
377
378 double yo = ap[3];
379 yo += ap[4] * xi;
380 yp[y][x] = (float) (yo + ap[5] * yi);
381 }
382 }
383 }
384 }
385 }