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.RANSACRobustEstimator;
23 import com.irurueta.numerical.robust.RANSACRobustEstimatorListener;
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 RANSACDLTPointCorrespondencePinholeCameraRobustEstimator extends
37 DLTPointCorrespondencePinholeCameraRobustEstimator {
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 public static final boolean DEFAULT_COMPUTE_AND_KEEP_INLIERS = false;
57
58
59
60
61 public static final boolean DEFAULT_COMPUTE_AND_KEEP_RESIDUALS = false;
62
63
64
65
66
67
68
69 private double threshold;
70
71
72
73
74 private boolean computeAndKeepInliers;
75
76
77
78
79 private boolean computeAndKeepResiduals;
80
81
82
83
84 public RANSACDLTPointCorrespondencePinholeCameraRobustEstimator() {
85 super();
86 threshold = DEFAULT_THRESHOLD;
87 computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
88 computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public RANSACDLTPointCorrespondencePinholeCameraRobustEstimator(
105 final List<Point3D> points3D, final List<Point2D> points2D) {
106 super(points3D, points2D);
107 threshold = DEFAULT_THRESHOLD;
108 computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
109 computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
110 }
111
112
113
114
115
116
117
118 public RANSACDLTPointCorrespondencePinholeCameraRobustEstimator(
119 final PinholeCameraRobustEstimatorListener listener) {
120 super(listener);
121 threshold = DEFAULT_THRESHOLD;
122 computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
123 computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 public RANSACDLTPointCorrespondencePinholeCameraRobustEstimator(
143 final PinholeCameraRobustEstimatorListener listener,
144 final List<Point3D> points3D, final List<Point2D> points2D) {
145 super(listener, points3D, points2D);
146 threshold = DEFAULT_THRESHOLD;
147 computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
148 computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
149 }
150
151
152
153
154
155
156
157
158
159
160 public double getThreshold() {
161 return threshold;
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176 public void setThreshold(final double threshold) throws LockedException {
177 if (isLocked()) {
178 throw new LockedException();
179 }
180 if (threshold <= MIN_THRESHOLD) {
181 throw new IllegalArgumentException();
182 }
183 this.threshold = threshold;
184 }
185
186
187
188
189
190
191
192 public boolean isComputeAndKeepInliersEnabled() {
193 return computeAndKeepInliers;
194 }
195
196
197
198
199
200
201
202
203 public void setComputeAndKeepInliersEnabled(final boolean computeAndKeepInliers) throws LockedException {
204 if (isLocked()) {
205 throw new LockedException();
206 }
207 this.computeAndKeepInliers = computeAndKeepInliers;
208 }
209
210
211
212
213
214
215
216 public boolean isComputeAndKeepResidualsEnabled() {
217 return computeAndKeepResiduals;
218 }
219
220
221
222
223
224
225
226
227 public void setComputeAndKeepResidualsEnabled(final boolean computeAndKeepResiduals) throws LockedException {
228 if (isLocked()) {
229 throw new LockedException();
230 }
231 this.computeAndKeepResiduals = computeAndKeepResiduals;
232 }
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247 @Override
248 public PinholeCamera estimate() throws LockedException, NotReadyException, RobustEstimatorException {
249 if (isLocked()) {
250 throw new LockedException();
251 }
252 if (!isReady()) {
253 throw new NotReadyException();
254 }
255
256
257 final var nonRobustEstimator = new DLTPointCorrespondencePinholeCameraEstimator();
258
259 nonRobustEstimator.setLMSESolutionAllowed(false);
260 nonRobustEstimator.setPointCorrespondencesNormalized(normalizeSubsetPointCorrespondences);
261
262
263 nonRobustEstimator.setSuggestSkewnessValueEnabled(isSuggestSkewnessValueEnabled());
264 nonRobustEstimator.setSuggestedSkewnessValue(getSuggestedSkewnessValue());
265 nonRobustEstimator.setSuggestHorizontalFocalLengthEnabled(isSuggestHorizontalFocalLengthEnabled());
266 nonRobustEstimator.setSuggestedHorizontalFocalLengthValue(getSuggestedHorizontalFocalLengthValue());
267 nonRobustEstimator.setSuggestVerticalFocalLengthEnabled(isSuggestVerticalFocalLengthEnabled());
268 nonRobustEstimator.setSuggestedVerticalFocalLengthValue(getSuggestedVerticalFocalLengthValue());
269 nonRobustEstimator.setSuggestAspectRatioEnabled(isSuggestAspectRatioEnabled());
270 nonRobustEstimator.setSuggestedAspectRatioValue(getSuggestedAspectRatioValue());
271 nonRobustEstimator.setSuggestPrincipalPointEnabled(isSuggestPrincipalPointEnabled());
272 nonRobustEstimator.setSuggestedPrincipalPointValue(getSuggestedPrincipalPointValue());
273 nonRobustEstimator.setSuggestRotationEnabled(isSuggestRotationEnabled());
274 nonRobustEstimator.setSuggestedRotationValue(getSuggestedRotationValue());
275 nonRobustEstimator.setSuggestCenterEnabled(isSuggestCenterEnabled());
276 nonRobustEstimator.setSuggestedCenterValue(getSuggestedCenterValue());
277
278 final var innerEstimator = new RANSACRobustEstimator<>(new RANSACRobustEstimatorListener<PinholeCamera>() {
279
280
281 private final Point2D testPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
282
283
284 private final List<Point3D> subset3D = new ArrayList<>();
285
286
287 private final List<Point2D> subset2D = new ArrayList<>();
288
289 @Override
290 public double getThreshold() {
291 return threshold;
292 }
293
294 @Override
295 public int getTotalSamples() {
296 return points3D.size();
297 }
298
299 @Override
300 public int getSubsetSize() {
301 return PointCorrespondencePinholeCameraRobustEstimator.MIN_NUMBER_OF_POINT_CORRESPONDENCES;
302 }
303
304 @Override
305 public void estimatePreliminarSolutions(final int[] samplesIndices, final List<PinholeCamera> solutions) {
306 subset3D.clear();
307 subset3D.add(points3D.get(samplesIndices[0]));
308 subset3D.add(points3D.get(samplesIndices[1]));
309 subset3D.add(points3D.get(samplesIndices[2]));
310 subset3D.add(points3D.get(samplesIndices[3]));
311 subset3D.add(points3D.get(samplesIndices[4]));
312 subset3D.add(points3D.get(samplesIndices[5]));
313
314 subset2D.clear();
315 subset2D.add(points2D.get(samplesIndices[0]));
316 subset2D.add(points2D.get(samplesIndices[1]));
317 subset2D.add(points2D.get(samplesIndices[2]));
318 subset2D.add(points2D.get(samplesIndices[3]));
319 subset2D.add(points2D.get(samplesIndices[4]));
320 subset2D.add(points2D.get(samplesIndices[5]));
321
322 try {
323 nonRobustEstimator.setLists(subset3D, subset2D);
324
325 final var cam = nonRobustEstimator.estimate();
326 solutions.add(cam);
327 } catch (final Exception e) {
328
329 }
330 }
331
332 @Override
333 public double computeResidual(final PinholeCamera currentEstimation, final int i) {
334
335 final var point3D = points3D.get(i);
336 final var point2D = points2D.get(i);
337
338
339 currentEstimation.project(point3D, testPoint);
340
341
342 return testPoint.distanceTo(point2D);
343 }
344
345 @Override
346 public boolean isReady() {
347 return RANSACDLTPointCorrespondencePinholeCameraRobustEstimator.this.isReady();
348 }
349
350 @Override
351 public void onEstimateStart(final RobustEstimator<PinholeCamera> estimator) {
352 if (listener != null) {
353 listener.onEstimateStart(RANSACDLTPointCorrespondencePinholeCameraRobustEstimator.this);
354 }
355 }
356
357 @Override
358 public void onEstimateEnd(final RobustEstimator<PinholeCamera> estimator) {
359 if (listener != null) {
360 listener.onEstimateEnd(RANSACDLTPointCorrespondencePinholeCameraRobustEstimator.this);
361 }
362 }
363
364 @Override
365 public void onEstimateNextIteration(final RobustEstimator<PinholeCamera> estimator, final int iteration) {
366 if (listener != null) {
367 listener.onEstimateNextIteration(
368 RANSACDLTPointCorrespondencePinholeCameraRobustEstimator.this, iteration);
369 }
370 }
371
372 @Override
373 public void onEstimateProgressChange(final RobustEstimator<PinholeCamera> estimator, final float progress) {
374 if (listener != null) {
375 listener.onEstimateProgressChange(
376 RANSACDLTPointCorrespondencePinholeCameraRobustEstimator.this, progress);
377 }
378 }
379 });
380
381 try {
382 locked = true;
383 inliersData = null;
384 innerEstimator.setComputeAndKeepInliersEnabled(computeAndKeepInliers || refineResult);
385 innerEstimator.setComputeAndKeepResidualsEnabled(computeAndKeepResiduals || refineResult);
386 innerEstimator.setConfidence(confidence);
387 innerEstimator.setMaxIterations(maxIterations);
388 innerEstimator.setProgressDelta(progressDelta);
389 final var result = innerEstimator.estimate();
390 inliersData = innerEstimator.getInliersData();
391 return attemptRefine(result, nonRobustEstimator.getMaxSuggestionWeight());
392 } catch (final com.irurueta.numerical.LockedException e) {
393 throw new LockedException(e);
394 } catch (final com.irurueta.numerical.NotReadyException e) {
395 throw new NotReadyException(e);
396 } finally {
397 locked = false;
398 }
399 }
400
401
402
403
404
405
406 @Override
407 public RobustEstimatorMethod getMethod() {
408 return RobustEstimatorMethod.RANSAC;
409 }
410
411
412
413
414
415
416
417
418
419
420
421
422 @Override
423 protected double getRefinementStandardDeviation() {
424 return threshold;
425 }
426 }