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 package org.openimaj.image.model.asm;
31
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import org.openimaj.citation.annotation.Reference;
36 import org.openimaj.citation.annotation.ReferenceType;
37 import org.openimaj.citation.annotation.References;
38 import org.openimaj.image.Image;
39 import org.openimaj.image.model.landmark.LandmarkModel;
40 import org.openimaj.image.model.landmark.LandmarkModelFactory;
41 import org.openimaj.math.geometry.point.Point2d;
42 import org.openimaj.math.geometry.point.PointList;
43 import org.openimaj.math.geometry.shape.PointDistributionModel;
44 import org.openimaj.math.geometry.shape.PointDistributionModel.Constraint;
45 import org.openimaj.math.matrix.algorithm.pca.PrincipalComponentAnalysis.ComponentSelector;
46 import org.openimaj.util.pair.IndependentPair;
47 import org.openimaj.util.pair.ObjectFloatPair;
48
49 import Jama.Matrix;
50
51
52
53
54
55
56
57
58
59
60
61 @References(references = {
62 @Reference(
63 author = { "Cootes, T. F.", "Taylor, C. J." },
64 title = "Statistical Models of Appearance for Computer Vision",
65 type = ReferenceType.Unpublished,
66 month = "October",
67 year = "2001",
68 url = "http://isbe.man.ac.uk/~bim/Models/app_model.ps.gz"
69 ),
70 @Reference(
71 type = ReferenceType.Inproceedings,
72 author = { "T. F. Cootes", "C. J. Taylor" },
73 title = "Active Shape Models",
74 year = "1992",
75 booktitle = "in Proceedings of the British Machine Vision Conference"
76 )
77 })
78 public class ActiveShapeModel<I extends Image<?, I>> {
79 private PointDistributionModel pdm;
80 private LandmarkModel<I>[] landmarkModels;
81 private int maxIter = 50;
82 private double inlierPercentage = 0.9;
83
84
85
86
87
88
89
90
91
92
93 public ActiveShapeModel(PointDistributionModel pdm, LandmarkModel<I>[] landmarkModels) {
94 this.pdm = pdm;
95 this.landmarkModels = landmarkModels;
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public static <I extends Image<?, I>> ActiveShapeModel<I> trainModel(ComponentSelector selector,
117 List<IndependentPair<PointList, I>> data, Constraint constraint, LandmarkModelFactory<I> factory)
118 {
119 final int nPoints = data.get(0).firstObject().size();
120
121 @SuppressWarnings("unchecked")
122 final LandmarkModel<I>[] ppms = new LandmarkModel[nPoints];
123
124 for (int i = 0; i < data.size(); i++) {
125 for (int j = 0; j < nPoints; j++) {
126 if (ppms[j] == null) {
127 ppms[j] = factory.createLandmarkModel();
128 }
129
130 final PointList pl = data.get(i).firstObject();
131
132 ppms[j].updateModel(data.get(i).secondObject(), pl.get(j), pl);
133 }
134 }
135
136 final List<PointList> pls = new ArrayList<PointList>();
137 for (final IndependentPair<PointList, I> i : data)
138 pls.add(i.firstObject());
139
140 final PointDistributionModel pdm = new PointDistributionModel(constraint, pls);
141 pdm.setNumComponents(selector);
142
143 return new ActiveShapeModel<I>(pdm, ppms);
144 }
145
146
147
148
149
150
151
152 public static class IterationResult {
153
154
155
156
157 public double fit;
158
159
160
161 public PointList shape;
162
163
164
165 public Matrix pose;
166
167
168
169 public double[] parameters;
170
171 protected IterationResult(Matrix pose, PointList shape, double fit, double[] parameters) {
172 this.pose = pose;
173 this.shape = shape;
174 this.fit = fit;
175 this.parameters = parameters;
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188 public IterationResult performIteration(I image, PointList currentShape) {
189 PointList newShape = new PointList();
190
191 int inliers = 0;
192 int outliers = 0;
193
194 for (int i = 0; i < landmarkModels.length; i++) {
195 final ObjectFloatPair<Point2d> newBest = landmarkModels[i].updatePosition(image, currentShape.get(i),
196 currentShape);
197 newShape.points.add(newBest.first);
198
199 final float percentageFromStart = newBest.second;
200 if (percentageFromStart < 0.5)
201 inliers++;
202 else
203 outliers++;
204 }
205 final double score = ((double) inliers) / ((double) (inliers + outliers));
206
207
208 final IndependentPair<Matrix, double[]> newModelParams = pdm.fitModel(newShape);
209
210 final Matrix pose = newModelParams.firstObject();
211 final double[] parameters = newModelParams.secondObject();
212
213
214 newShape = pdm.generateNewShape(parameters).transform(pose);
215
216 return new IterationResult(pose, newShape, score, parameters);
217 }
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 public IterationResult fit(I image, PointList initialShape) {
235 IterationResult ir = performIteration(image, initialShape);
236 int count = 0;
237
238 while (ir.fit < inlierPercentage && count < maxIter) {
239 ir = performIteration(image, ir.shape);
240 count++;
241 }
242
243 return ir;
244 }
245
246
247
248
249 public int getMaxIterations() {
250 return maxIter;
251 }
252
253
254
255
256
257
258
259 public void setMaxIterations(int maxIter) {
260 this.maxIter = maxIter;
261 }
262
263
264
265
266 public double getInlierPercentage() {
267 return inlierPercentage;
268 }
269
270
271
272
273
274
275
276
277 public void setInlierPercentage(double inlierPercentage) {
278 this.inlierPercentage = inlierPercentage;
279 }
280
281
282
283
284 public PointDistributionModel getPDM() {
285 return pdm;
286 }
287
288
289
290
291
292 public LandmarkModel<I>[] getLandmarkModels() {
293 return landmarkModels;
294 }
295 }