1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.ar.calibration.estimators;
17
18 import com.irurueta.ar.calibration.RadialDistortion;
19 import com.irurueta.geometry.CoordinatesType;
20 import com.irurueta.geometry.Point2D;
21 import com.irurueta.geometry.estimators.LockedException;
22 import com.irurueta.geometry.estimators.NotReadyException;
23 import com.irurueta.numerical.robust.PROSACRobustEstimator;
24 import com.irurueta.numerical.robust.PROSACRobustEstimatorListener;
25 import com.irurueta.numerical.robust.RobustEstimator;
26 import com.irurueta.numerical.robust.RobustEstimatorException;
27 import com.irurueta.numerical.robust.RobustEstimatorMethod;
28
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33
34
35
36
37
38 public class PROSACRadialDistortionRobustEstimator extends RadialDistortionRobustEstimator {
39
40
41
42
43
44
45
46 public static final double DEFAULT_THRESHOLD = 1.0;
47
48
49
50
51
52 public static final double MIN_THRESHOLD = 0.0;
53
54
55
56
57
58
59
60 private double threshold;
61
62
63
64
65
66 private double[] qualityScores;
67
68
69
70
71 public PROSACRadialDistortionRobustEstimator() {
72 super();
73 threshold = DEFAULT_THRESHOLD;
74 }
75
76
77
78
79
80
81
82 public PROSACRadialDistortionRobustEstimator(final RadialDistortionRobustEstimatorListener listener) {
83 super(listener);
84 threshold = DEFAULT_THRESHOLD;
85 }
86
87
88
89
90
91
92
93
94
95
96 public PROSACRadialDistortionRobustEstimator(
97 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints) {
98 super(distortedPoints, undistortedPoints);
99 threshold = DEFAULT_THRESHOLD;
100 }
101
102
103
104
105
106
107
108
109
110
111
112
113 public PROSACRadialDistortionRobustEstimator(final List<Point2D> distortedPoints,
114 final List<Point2D> undistortedPoints,
115 final RadialDistortionRobustEstimatorListener listener) {
116 super(distortedPoints, undistortedPoints, listener);
117 threshold = DEFAULT_THRESHOLD;
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132 public PROSACRadialDistortionRobustEstimator(final List<Point2D> distortedPoints,
133 final List<Point2D> undistortedPoints,
134 final Point2D distortionCenter) {
135 super(distortedPoints, undistortedPoints, distortionCenter);
136 threshold = DEFAULT_THRESHOLD;
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 public PROSACRadialDistortionRobustEstimator(final List<Point2D> distortedPoints,
154 final List<Point2D> undistortedPoints,
155 final Point2D distortionCenter,
156 final RadialDistortionRobustEstimatorListener listener) {
157 super(distortedPoints, undistortedPoints, distortionCenter, listener);
158 threshold = DEFAULT_THRESHOLD;
159 }
160
161
162
163
164
165
166
167
168 public PROSACRadialDistortionRobustEstimator(final double[] qualityScores) {
169 this();
170 internalSetQualityScores(qualityScores);
171 }
172
173
174
175
176
177
178
179
180
181
182 public PROSACRadialDistortionRobustEstimator(
183 final double[] qualityScores, final RadialDistortionRobustEstimatorListener listener) {
184 this(listener);
185 internalSetQualityScores(qualityScores);
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199 public PROSACRadialDistortionRobustEstimator(final List<Point2D> distortedPoints,
200 final List<Point2D> undistortedPoints,
201 final double[] qualityScores) {
202 this(distortedPoints, undistortedPoints);
203 internalSetQualityScores(qualityScores);
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 public PROSACRadialDistortionRobustEstimator(final List<Point2D> distortedPoints,
220 final List<Point2D> undistortedPoints,
221 final double[] qualityScores,
222 final RadialDistortionRobustEstimatorListener listener) {
223 this(distortedPoints, undistortedPoints, listener);
224 internalSetQualityScores(qualityScores);
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241 public PROSACRadialDistortionRobustEstimator(final List<Point2D> distortedPoints,
242 final List<Point2D> undistortedPoints,
243 final double[] qualityScores,
244 final Point2D distortionCenter) {
245 this(distortedPoints, undistortedPoints, distortionCenter);
246 internalSetQualityScores(qualityScores);
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 public PROSACRadialDistortionRobustEstimator(final List<Point2D> distortedPoints,
266 final List<Point2D> undistortedPoints,
267 final double[] qualityScores,
268 final Point2D distortionCenter,
269 final RadialDistortionRobustEstimatorListener listener) {
270 this(distortedPoints, undistortedPoints, distortionCenter, listener);
271 internalSetQualityScores(qualityScores);
272 }
273
274
275
276
277
278
279
280
281
282
283 public double getThreshold() {
284 return threshold;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299 public void setThreshold(final double threshold) throws LockedException {
300 if (isLocked()) {
301 throw new LockedException();
302 }
303 if (threshold <= MIN_THRESHOLD) {
304 throw new IllegalArgumentException();
305 }
306 this.threshold = threshold;
307 }
308
309
310
311
312
313
314
315 @Override
316 public double[] getQualityScores() {
317 return qualityScores;
318 }
319
320
321
322
323
324
325
326
327
328
329
330 @Override
331 public void setQualityScores(final double[] qualityScores) throws LockedException {
332 if (isLocked()) {
333 throw new LockedException();
334 }
335 internalSetQualityScores(qualityScores);
336 }
337
338
339
340
341
342
343
344
345
346 @Override
347 public boolean isReady() {
348 return super.isReady() && qualityScores != null && qualityScores.length == distortedPoints.size();
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363 @SuppressWarnings("DuplicatedCode")
364 @Override
365 public RadialDistortion estimate() throws LockedException, NotReadyException, RobustEstimatorException {
366 if (isLocked()) {
367 throw new LockedException();
368 }
369 if (!isReady()) {
370 throw new NotReadyException();
371 }
372
373 final var innerEstimator = new PROSACRobustEstimator<RadialDistortion>(new PROSACRobustEstimatorListener<>() {
374
375
376 private final Point2D testPoint = Point2D.create(CoordinatesType.INHOMOGENEOUS_COORDINATES);
377
378
379 private final LMSERadialDistortionEstimator radialDistortionEstimator = new LMSERadialDistortionEstimator();
380
381
382 private final List<Point2D> subsetDistorted = new ArrayList<>();
383
384
385 private final List<Point2D> subsetUndistorted = new ArrayList<>();
386
387 @Override
388 public double getThreshold() {
389 return threshold;
390 }
391
392 @Override
393 public int getTotalSamples() {
394 return distortedPoints.size();
395 }
396
397 @Override
398 public int getSubsetSize() {
399 return RadialDistortionRobustEstimator.MIN_NUMBER_OF_POINTS;
400 }
401
402 @Override
403 public void estimatePreliminarSolutions(
404 final int[] samplesIndices, final List<RadialDistortion> solutions) {
405 subsetDistorted.clear();
406 subsetDistorted.add(distortedPoints.get(samplesIndices[0]));
407 subsetDistorted.add(distortedPoints.get(samplesIndices[1]));
408
409 subsetUndistorted.clear();
410 subsetUndistorted.add(undistortedPoints.get(samplesIndices[0]));
411 subsetUndistorted.add(undistortedPoints.get(samplesIndices[1]));
412
413 try {
414 radialDistortionEstimator.setPoints(distortedPoints, undistortedPoints);
415 radialDistortionEstimator.setPoints(subsetDistorted, subsetUndistorted);
416
417 final var distortion = radialDistortionEstimator.estimate();
418 solutions.add(distortion);
419 } catch (final Exception e) {
420
421 }
422 }
423
424 @Override
425 public double computeResidual(final RadialDistortion currentEstimation, final int i) {
426 final var distortedPoint = distortedPoints.get(i);
427 final var undistortedPoint = undistortedPoints.get(i);
428
429 currentEstimation.distort(undistortedPoint, testPoint);
430
431 return testPoint.distanceTo(distortedPoint);
432 }
433
434 @Override
435 public boolean isReady() {
436 return PROSACRadialDistortionRobustEstimator.this.isReady();
437 }
438
439 @Override
440 public void onEstimateStart(final RobustEstimator<RadialDistortion> estimator) {
441 try {
442 radialDistortionEstimator.setLMSESolutionAllowed(false);
443 radialDistortionEstimator.setIntrinsic(getIntrinsic());
444 } catch (final Exception e) {
445 Logger.getLogger(PROSACRadialDistortionRobustEstimator.class.getName()).log(Level.WARNING,
446 "Could not set intrinsic parameters on radial distortion estimator", e);
447 }
448
449 if (listener != null) {
450 listener.onEstimateStart(PROSACRadialDistortionRobustEstimator.this);
451 }
452 }
453
454 @Override
455 public void onEstimateEnd(final RobustEstimator<RadialDistortion> estimator) {
456 if (listener != null) {
457 listener.onEstimateEnd(PROSACRadialDistortionRobustEstimator.this);
458 }
459 }
460
461 @Override
462 public void onEstimateNextIteration(
463 final RobustEstimator<RadialDistortion> estimator, final int iteration) {
464 if (listener != null) {
465 listener.onEstimateNextIteration(PROSACRadialDistortionRobustEstimator.this, iteration);
466 }
467 }
468
469 @Override
470 public void onEstimateProgressChange(
471 final RobustEstimator<RadialDistortion> estimator, final float progress) {
472 if (listener != null) {
473 listener.onEstimateProgressChange(PROSACRadialDistortionRobustEstimator.this, progress);
474 }
475 }
476
477 @Override
478 public double[] getQualityScores() {
479 return qualityScores;
480 }
481 });
482
483 try {
484 locked = true;
485 innerEstimator.setConfidence(confidence);
486 innerEstimator.setMaxIterations(maxIterations);
487 innerEstimator.setProgressDelta(progressDelta);
488 return innerEstimator.estimate();
489 } catch (final com.irurueta.numerical.LockedException e) {
490 throw new LockedException(e);
491 } catch (final com.irurueta.numerical.NotReadyException e) {
492 throw new NotReadyException(e);
493 } finally {
494 locked = false;
495 }
496 }
497
498
499
500
501
502
503 @Override
504 public RobustEstimatorMethod getMethod() {
505 return RobustEstimatorMethod.PROSAC;
506 }
507
508
509
510
511
512
513
514
515
516
517 private void internalSetQualityScores(final double[] qualityScores) {
518 if (qualityScores.length < MIN_NUMBER_OF_POINTS) {
519 throw new IllegalArgumentException();
520 }
521
522 this.qualityScores = qualityScores;
523 }
524 }