1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.geometry.estimators;
17
18 import com.irurueta.geometry.CoordinatesType;
19 import com.irurueta.geometry.PinholeCamera;
20 import com.irurueta.geometry.Point2D;
21 import com.irurueta.geometry.Point3D;
22 import com.irurueta.numerical.robust.MSACRobustEstimator;
23 import com.irurueta.numerical.robust.MSACRobustEstimatorListener;
24 import com.irurueta.numerical.robust.RobustEstimator;
25 import com.irurueta.numerical.robust.RobustEstimatorException;
26 import com.irurueta.numerical.robust.RobustEstimatorMethod;
27
28 import java.util.ArrayList;
29 import java.util.List;
30
31
32
33
34
35 @SuppressWarnings("DuplicatedCode")
36 public class MSACUPnPPointCorrespondencePinholeCameraRobustEstimator extends
37 UPnPPointCorrespondencePinholeCameraRobustEstimator {
38
39
40
41
42
43
44
45 public static final double DEFAULT_THRESHOLD = 1.0;
46
47
48
49
50
51 public static final double MIN_THRESHOLD = 0.0;
52
53
54
55
56
57
58
59 private double threshold;
60
61
62
63
64 public MSACUPnPPointCorrespondencePinholeCameraRobustEstimator() {
65 super();
66 threshold = DEFAULT_THRESHOLD;
67 }
68
69
70
71
72
73
74
75 public MSACUPnPPointCorrespondencePinholeCameraRobustEstimator(
76 final PinholeCameraRobustEstimatorListener listener) {
77 super(listener);
78 threshold = DEFAULT_THRESHOLD;
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public MSACUPnPPointCorrespondencePinholeCameraRobustEstimator(
95 final List<Point3D> points3D, final List<Point2D> points2D) {
96 super(points3D, points2D);
97 threshold = DEFAULT_THRESHOLD;
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public MSACUPnPPointCorrespondencePinholeCameraRobustEstimator(
117 final PinholeCameraRobustEstimatorListener listener,
118 final List<Point3D> points3D, final List<Point2D> points2D) {
119 super(listener, points3D, points2D);
120 threshold = DEFAULT_THRESHOLD;
121 }
122
123
124
125
126
127
128
129
130
131
132 public double getThreshold() {
133 return threshold;
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148 public void setThreshold(final double threshold) throws LockedException {
149 if (isLocked()) {
150 throw new LockedException();
151 }
152 if (threshold <= MIN_THRESHOLD) {
153 throw new IllegalArgumentException();
154 }
155 this.threshold = threshold;
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 @Override
172 public PinholeCamera estimate() throws LockedException, NotReadyException, RobustEstimatorException {
173 if (isLocked()) {
174 throw new LockedException();
175 }
176 if (!isReady()) {
177 throw new NotReadyException();
178 }
179
180
181 final var nonRobustEstimator = new UPnPPointCorrespondencePinholeCameraEstimator();
182
183 nonRobustEstimator.setPlanarConfigurationAllowed(planarConfigurationAllowed);
184 nonRobustEstimator.setNullspaceDimension2Allowed(nullspaceDimension2Allowed);
185 nonRobustEstimator.setPlanarThreshold(planarThreshold);
186 nonRobustEstimator.setSkewness(skewness);
187 nonRobustEstimator.setHorizontalPrincipalPoint(horizontalPrincipalPoint);
188 nonRobustEstimator.setVerticalPrincipalPoint(verticalPrincipalPoint);
189
190
191 nonRobustEstimator.setSuggestSkewnessValueEnabled(isSuggestSkewnessValueEnabled());
192 nonRobustEstimator.setSuggestedSkewnessValue(getSuggestedSkewnessValue());
193 nonRobustEstimator.setSuggestHorizontalFocalLengthEnabled(isSuggestHorizontalFocalLengthEnabled());
194 nonRobustEstimator.setSuggestedHorizontalFocalLengthValue(getSuggestedHorizontalFocalLengthValue());
195 nonRobustEstimator.setSuggestVerticalFocalLengthEnabled(isSuggestVerticalFocalLengthEnabled());
196 nonRobustEstimator.setSuggestedVerticalFocalLengthValue(getSuggestedVerticalFocalLengthValue());
197 nonRobustEstimator.setSuggestAspectRatioEnabled(isSuggestAspectRatioEnabled());
198 nonRobustEstimator.setSuggestedAspectRatioValue(getSuggestedAspectRatioValue());
199 nonRobustEstimator.setSuggestPrincipalPointEnabled(isSuggestPrincipalPointEnabled());
200 nonRobustEstimator.setSuggestedPrincipalPointValue(getSuggestedPrincipalPointValue());
201 nonRobustEstimator.setSuggestRotationEnabled(isSuggestRotationEnabled());
202 nonRobustEstimator.setSuggestedRotationValue(getSuggestedRotationValue());
203 nonRobustEstimator.setSuggestCenterEnabled(isSuggestCenterEnabled());
204 nonRobustEstimator.setSuggestedCenterValue(getSuggestedCenterValue());
205
206 final var innerEstimator = new MSACRobustEstimator<>(new MSACRobustEstimatorListener<PinholeCamera>() {
207
208
209 private final Point2D testPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
210
211
212 private final List<Point3D> subset3D = new ArrayList<>();
213
214
215 private final List<Point2D> subset2D = new ArrayList<>();
216
217 @Override
218 public double getThreshold() {
219 return threshold;
220 }
221
222 @Override
223 public int getTotalSamples() {
224 return points3D.size();
225 }
226
227 @Override
228 public int getSubsetSize() {
229 return PointCorrespondencePinholeCameraEstimator.MIN_NUMBER_OF_POINT_CORRESPONDENCES;
230 }
231
232 @Override
233 public void estimatePreliminarSolutions(final int[] samplesIndices, final List<PinholeCamera> solutions) {
234 subset3D.clear();
235 subset3D.add(points3D.get(samplesIndices[0]));
236 subset3D.add(points3D.get(samplesIndices[1]));
237 subset3D.add(points3D.get(samplesIndices[2]));
238 subset3D.add(points3D.get(samplesIndices[3]));
239 subset3D.add(points3D.get(samplesIndices[4]));
240 subset3D.add(points3D.get(samplesIndices[5]));
241
242 subset2D.clear();
243 subset2D.add(points2D.get(samplesIndices[0]));
244 subset2D.add(points2D.get(samplesIndices[1]));
245 subset2D.add(points2D.get(samplesIndices[2]));
246 subset2D.add(points2D.get(samplesIndices[3]));
247 subset2D.add(points2D.get(samplesIndices[4]));
248 subset2D.add(points2D.get(samplesIndices[5]));
249
250 try {
251 nonRobustEstimator.setLists(subset3D, subset2D);
252
253 final var cam = nonRobustEstimator.estimate();
254 solutions.add(cam);
255 } catch (final Exception e) {
256
257
258 }
259 }
260
261 @Override
262 public double computeResidual(final PinholeCamera currentEstimation, final int i) {
263
264 final var point3D = points3D.get(i);
265 final var point2D = points2D.get(i);
266
267
268 currentEstimation.project(point3D, testPoint);
269
270
271 return testPoint.distanceTo(point2D);
272 }
273
274 @Override
275 public boolean isReady() {
276 return MSACUPnPPointCorrespondencePinholeCameraRobustEstimator.this.isReady();
277 }
278
279 @Override
280 public void onEstimateStart(final RobustEstimator<PinholeCamera> estimator) {
281 if (listener != null) {
282 listener.onEstimateStart(MSACUPnPPointCorrespondencePinholeCameraRobustEstimator.this);
283 }
284 }
285
286 @Override
287 public void onEstimateEnd(final RobustEstimator<PinholeCamera> estimator) {
288 if (listener != null) {
289 listener.onEstimateEnd(MSACUPnPPointCorrespondencePinholeCameraRobustEstimator.this);
290 }
291 }
292
293 @Override
294 public void onEstimateNextIteration(final RobustEstimator<PinholeCamera> estimator, int iteration) {
295 if (listener != null) {
296 listener.onEstimateNextIteration(
297 MSACUPnPPointCorrespondencePinholeCameraRobustEstimator.this, iteration);
298 }
299 }
300
301 @Override
302 public void onEstimateProgressChange(final RobustEstimator<PinholeCamera> estimator, float progress) {
303 if (listener != null) {
304 listener.onEstimateProgressChange(
305 MSACUPnPPointCorrespondencePinholeCameraRobustEstimator.this, progress);
306 }
307 }
308 });
309
310 try {
311 locked = true;
312 inliersData = null;
313 innerEstimator.setConfidence(confidence);
314 innerEstimator.setMaxIterations(maxIterations);
315 innerEstimator.setProgressDelta(progressDelta);
316 final var result = innerEstimator.estimate();
317 inliersData = innerEstimator.getInliersData();
318 return attemptRefine(result, nonRobustEstimator.getMaxSuggestionWeight());
319 } catch (final com.irurueta.numerical.LockedException e) {
320 throw new LockedException(e);
321 } catch (final com.irurueta.numerical.NotReadyException e) {
322 throw new NotReadyException(e);
323 } finally {
324 locked = false;
325 }
326 }
327
328
329
330
331
332
333 @Override
334 public RobustEstimatorMethod getMethod() {
335 return RobustEstimatorMethod.MSAC;
336 }
337
338
339
340
341
342
343
344
345
346
347
348
349 @Override
350 protected double getRefinementStandardDeviation() {
351 return threshold;
352 }
353 }