1 /*
2 * Copyright (C) 2013 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.geometry.estimators;
17
18 import com.irurueta.geometry.InhomogeneousPoint2D;
19 import com.irurueta.geometry.InhomogeneousPoint3D;
20 import com.irurueta.geometry.PinholeCamera;
21 import com.irurueta.geometry.Quaternion;
22
23 /**
24 * This class defines the interface for an estimator for pinhole cameras.
25 */
26 public abstract class PinholeCameraEstimator {
27
28 /**
29 * Default estimator type.
30 */
31 public static final PinholeCameraEstimatorType DEFAULT_ESTIMATOR_TYPE =
32 PinholeCameraEstimatorType.DLT_POINT_PINHOLE_CAMERA_ESTIMATOR;
33
34 /**
35 * Default value indicating whether skewness value is suggested or not.
36 * By default, this is disabled.
37 */
38 public static final boolean DEFAULT_SUGGEST_SKEWNESS_VALUE_ENABLED = false;
39
40 /**
41 * Default value of skewness to be suggested when suggestion is enabled.
42 * By default suggested skewness is zero.
43 */
44 public static final double DEFAULT_SUGGESTED_SKEWNESS_VALUE = 0.0;
45
46 /**
47 * Default value indicating whether horizontal focal length value is
48 * suggested or not. By default, this is disabled.
49 */
50 public static final boolean DEFAULT_SUGGEST_HORIZONTAL_FOCAL_LENGTH_ENABLED = false;
51
52 /**
53 * Default value indicating whether vertical focal length value is suggested
54 * or not. By default, this is disabled.
55 */
56 public static final boolean DEFAULT_SUGGEST_VERTICAL_FOCAL_LENGTH_ENABLED = false;
57
58 /**
59 * Default value indicating whether aspect ratio is suggested or not. By
60 * default, this is disabled.
61 */
62 public static final boolean DEFAULT_SUGGEST_ASPECT_RATIO_ENABLED = false;
63
64 /**
65 * Default value of aspect ratio to be suggested when suggestion is enabled.
66 * By default, suggested aspect ratio is 1.0, although also -1.0 is a typical
67 * value when vertical coordinates increase downwards.
68 */
69 public static final double DEFAULT_SUGGESTED_ASPECT_RATIO_VALUE = 1.0;
70
71 /**
72 * Default value indicating whether principal point is suggested or not. By
73 * default, this is disabled.
74 */
75 public static final boolean DEFAULT_SUGGEST_PRINCIPAL_POINT_ENABLED = false;
76
77 /**
78 * Default value indicating whether rotation is suggested or not. By default,
79 * this is disabled.
80 */
81 public static final boolean DEFAULT_SUGGEST_ROTATION_ENABLED = false;
82
83 /**
84 * Default value indicating whether center is suggested or not. By default,
85 * this is disabled.
86 */
87 public static final boolean DEFAULT_SUGGEST_CENTER_ENABLED = false;
88
89 /**
90 * Default value for minimum suggestion weight. This weight is used to
91 * slowly draw original camera parameters into desired suggested values.
92 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
93 * to find a solution so that the algorithm can converge into desired value.
94 * The faster the weights are increased the less likely that suggested
95 * values can be converged if they differ too much from the original ones.
96 */
97 public static final double DEFAULT_MIN_SUGGESTION_WEIGHT = 0.1;
98
99 /**
100 * Default value for maximum suggestion weight. This weight is used to
101 * slowly draw original camera parameters into desired suggested values.
102 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
103 * to find a solution so that the algorithm can converge into desired value.
104 * The faster the weights are increased the less likely that suggested
105 * values can be converged if they differ too much from the original ones.
106 */
107 public static final double DEFAULT_MAX_SUGGESTION_WEIGHT = 2.0;
108
109 /**
110 * Default value for the step to increase suggestion weight. This weight is
111 * used to slowly draw original camera parameters into desired suggested
112 * values. Suggestion weight slowly increases each time Levenberg-Marquardt
113 * is used to find a solution so that the algorithm can converge into
114 * desired value. The faster the weights are increased the less likely that
115 * suggested values can be converged if they differ too much from the
116 * original ones.
117 */
118 public static final double DEFAULT_SUGGESTION_WEIGHT_STEP = 0.475;
119
120 /**
121 * True when an estimator is estimating a camera.
122 */
123 protected boolean locked;
124
125 /**
126 * Listener to be notified of events such as when estimation starts, ends
127 * or estimation progress changes.
128 */
129 protected PinholeCameraEstimatorListener listener;
130
131 /**
132 * Indicates whether skewness value is suggested or not. When enabled, the
133 * estimator will attempt to enforce suggested value in an iterative manner
134 * starting from an initially estimated camera.
135 * Even when suggestion is enabled, the iterative algorithm might not reach
136 * suggested value if the initial value largely differs from the suggested
137 * value.
138 */
139 protected boolean suggestSkewnessValueEnabled = DEFAULT_SUGGEST_SKEWNESS_VALUE_ENABLED;
140
141 /**
142 * Suggested skewness value to be reached when suggestion is enabled.
143 * Suggested value should be close to the initially estimated value
144 * otherwise the iterative refinement might not converge to provided
145 * value.
146 */
147 protected double suggestedSkewnessValue = DEFAULT_SUGGESTED_SKEWNESS_VALUE;
148
149 /**
150 * Indicates whether horizontal focal length is suggested or not. When
151 * enabled, the estimator will attempt to enforce suggested value in an
152 * iterative manner starting from an initially estimated camera.
153 * Even when suggestion is enabled, the iterative algorithm might not reach
154 * suggested value if the initial value largely differs from the suggested
155 * value.
156 */
157 protected boolean suggestHorizontalFocalLengthEnabled = DEFAULT_SUGGEST_HORIZONTAL_FOCAL_LENGTH_ENABLED;
158
159 /**
160 * Suggested horizontal focal length value to be reached when suggestion is
161 * enabled.
162 * Suggested value should be close to the initially estimated value
163 * otherwise the iterative refinement might not converge to provided value.
164 */
165 protected double suggestedHorizontalFocalLengthValue;
166
167 /**
168 * Indicates whether vertical focal length is suggested or not. When
169 * enabled, the estimator will attempt to enforce suggested value in an
170 * iterative manner starting from an initially estimated camera.
171 * Even when suggestion is enabled, the iterative algorithm might not reach
172 * suggested value if the initial value largely differs from the suggested
173 * value.
174 */
175 protected boolean suggestVerticalFocalLengthEnabled = DEFAULT_SUGGEST_VERTICAL_FOCAL_LENGTH_ENABLED;
176
177 /**
178 * Suggested vertical focal length value to be reached when suggestion is
179 * enabled.
180 * Suggested value should be close to the initially estimated value
181 * otherwise the iterative refinement might not converge to provided value.
182 */
183 protected double suggestedVerticalFocalLengthValue;
184
185 /**
186 * Indicates whether aspect ratio is suggested or not. When enabled, the
187 * estimator will attempt to enforce suggested value in an iterative manner
188 * starting from an initially estimated camera.
189 * Even when suggestion is enabled, the iterative algorithm might not reach
190 * suggested value if the initial value largely differs from the suggested
191 * value.
192 */
193 protected boolean suggestAspectRatioEnabled = DEFAULT_SUGGEST_ASPECT_RATIO_ENABLED;
194
195 /**
196 * Suggested aspect ratio value to be reached when suggestion is enabled.
197 * Suggested value should be close to the initially estimated value
198 * otherwise the iterative refinement might not converge to provided value.
199 */
200 protected double suggestedAspectRatioValue = DEFAULT_SUGGESTED_ASPECT_RATIO_VALUE;
201
202 /**
203 * Indicates whether principal point is suggested or not. When enabled, the
204 * estimator will attempt to enforce suggested value in an iterative manner
205 * starting from an initially estimated camera.
206 * Even when suggestion is enabled, the iterative algorithm might not reach
207 * suggested value if the initial value largely differs from the suggested
208 * value.
209 */
210 protected boolean suggestPrincipalPointEnabled = DEFAULT_SUGGEST_PRINCIPAL_POINT_ENABLED;
211
212 /**
213 * Suggested principal point value to be reached when suggestion is enabled.
214 * Suggested value should be close to the initially estimated value
215 * otherwise the iterative refinement might not converge to provided value.
216 */
217 protected InhomogeneousPoint2D suggestedPrincipalPointValue;
218
219 /**
220 * Indicates whether camera rotation is suggested or not. When enabled, the
221 * estimator will attempt to enforce suggested value in an iterative manner
222 * starting from an initially estimated camera.
223 * Even when suggestion is enabled, the iterative algorithm might not reach
224 * suggested value if the initial value largely differs from the suggested
225 * value.
226 */
227 protected boolean suggestRotationEnabled = DEFAULT_SUGGEST_ROTATION_ENABLED;
228
229 /**
230 * Suggested rotation to be reached when suggestion is enabled.
231 * Suggested value should be close to the initially estimated value
232 * otherwise the iterative refinement might not converge to provided value.
233 */
234 protected Quaternion suggestedRotationValue;
235
236 /**
237 * Indicates whether camera center is suggested or not. When enabled, the
238 * estimator will attempt to enforce suggested value in an iterative manner
239 * starting from an initially estimated camera.
240 * Even when suggestion is enabled, the iterative algorithm might not reach
241 * suggested value if the initial value largely differs from the suggested
242 * value.
243 */
244 protected boolean suggestCenterEnabled;
245
246 /**
247 * Suggested center to be reached when suggestion is enabled.
248 * Suggested value should be close to the initially estimated value
249 * otherwise the iterative refinement might not converge to provided value.
250 */
251 protected InhomogeneousPoint3D suggestedCenterValue;
252
253 /**
254 * Minimum suggestion weight. This weight is used to slowly draw original
255 * camera parameters into desired suggested values.
256 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
257 * to find a solution so that the algorithm can converge into desired value.
258 * The faster the weights are increased the less likely that suggested
259 * values can be converged if they differ too much from the original ones.
260 */
261 protected double minSuggestionWeight = DEFAULT_MIN_SUGGESTION_WEIGHT;
262
263 /**
264 * Maximum suggestion weight. This weight is used to slowly draw original
265 * camera parameters into desired suggested values.
266 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
267 * to find a solution so that the algorithm can converge into desired value.
268 * The faster the weights are increased the less likely that suggested
269 * values can be converged if they differ too much from the original ones.
270 */
271 protected double maxSuggestionWeight = DEFAULT_MAX_SUGGESTION_WEIGHT;
272
273 /**
274 * Step to increase suggestion weight. This weight is used to slowly draw
275 * original camera parameters into desired suggested values. Suggestion
276 * weight slowly increases each time Levenberg-Marquardt is used to find a
277 * solution so that the algorithm can converge into desired value. The
278 * faster the weights are increased the less likely that suggested values
279 * can be converged if they differ too much from the original ones.
280 */
281 protected double suggestionWeightStep = DEFAULT_SUGGESTION_WEIGHT_STEP;
282
283 /**
284 * Constructor.
285 */
286 protected PinholeCameraEstimator() {
287 locked = false;
288 listener = null;
289 }
290
291 /**
292 * Constructor with listener.
293 *
294 * @param listener listener to be notified of events such as when estimation
295 * starts, ends or estimation progress changes.
296 */
297 protected PinholeCameraEstimator(final PinholeCameraEstimatorListener listener) {
298 locked = false;
299 this.listener = listener;
300 }
301
302 /**
303 * Returns listener to be notified of events such as when estimation starts,
304 * ends or estimation progress changes.
305 *
306 * @return listener to be notified of events.
307 */
308 public PinholeCameraEstimatorListener getListener() {
309 return listener;
310 }
311
312 /**
313 * Sets listener to be notified of events such as when estimation starts,
314 * ends or estimation progress changes.
315 *
316 * @param listener listener to be notified of events.
317 * @throws LockedException if estimator is locked.
318 */
319 public void setListener(final PinholeCameraEstimatorListener listener) throws LockedException {
320 if (isLocked()) {
321 throw new LockedException();
322 }
323 this.listener = listener;
324 }
325
326 /**
327 * Indicates whether skewness value is suggested or not. When enabled, the
328 * estimator will attempt to enforce suggested value in an iterative manner
329 * starting from an initially estimated camera.
330 * Even when suggestion is enabled, the iterative algorithm might not reach
331 * suggested value if the initial value largely differs from the suggested
332 * value.
333 *
334 * @return true if skewness value is suggested, false otherwise.
335 */
336 public boolean isSuggestSkewnessValueEnabled() {
337 return suggestSkewnessValueEnabled;
338 }
339
340 /**
341 * Specifies whether skewness value is suggested or not. When enabled, the
342 * estimator will attempt to enforce suggested value in an iterative manner
343 * starting from an initially estimated camera.
344 * Even when suggestion is enabled, the iterative algorithm might not reach
345 * suggested value if the initial value largely differs from the suggested
346 * value.
347 *
348 * @param suggestSkewnessValueEnabled true if skewness value is suggested,
349 * false otherwise.
350 * @throws LockedException if estimator is locked.
351 */
352 public void setSuggestSkewnessValueEnabled(final boolean suggestSkewnessValueEnabled) throws LockedException {
353 if (isLocked()) {
354 throw new LockedException();
355 }
356 this.suggestSkewnessValueEnabled = suggestSkewnessValueEnabled;
357 }
358
359 /**
360 * Gets suggested skewness value to be reached when suggestion is enabled.
361 * Suggested value should be close to the initially estimated value
362 * otherwise the iterative refinement might not converge to provided value.
363 *
364 * @return suggested skewness value.
365 */
366 public double getSuggestedSkewnessValue() {
367 return suggestedSkewnessValue;
368 }
369
370 /**
371 * Sets suggested skewness value to be reached when suggestion is enabled.
372 * Suggested value should be close to the initially estimated value
373 * otherwise the iterative refinement might not converge to provided value.
374 *
375 * @param suggestedSkewnessValue suggested skewness value.
376 * @throws LockedException if estimator is locked.
377 */
378 public void setSuggestedSkewnessValue(final double suggestedSkewnessValue) throws LockedException {
379 if (isLocked()) {
380 throw new LockedException();
381 }
382 this.suggestedSkewnessValue = suggestedSkewnessValue;
383 }
384
385 /**
386 * Indicates whether horizontal focal length is suggested or not. When
387 * enabled, the estimator will attempt to enforce suggested value in an
388 * iterative manner starting from an initially estimated camera.
389 * Even when suggestion is enabled, the iterative algorithm might not reach
390 * suggested value if the initial value largely differs from the suggested
391 * value.
392 *
393 * @return true if horizontal focal length is suggested, false otherwise.
394 */
395 public boolean isSuggestHorizontalFocalLengthEnabled() {
396 return suggestHorizontalFocalLengthEnabled;
397 }
398
399 /**
400 * Specifies whether horizontal focal length is suggested or not. When
401 * enabled, the estimator will attempt to enforce suggested value in an
402 * iterative manner starting from an initially estimated camera.
403 * Even when suggestion is enabled, the iterative algorithm might not reach
404 * suggested value if the initial value largely differs from the suggested
405 * value.
406 *
407 * @param suggestHorizontalFocalLengthEnabled true if horizontal focal
408 * length is suggested, false otherwise.
409 * @throws LockedException if estimator is locked.
410 */
411 public void setSuggestHorizontalFocalLengthEnabled(final boolean suggestHorizontalFocalLengthEnabled)
412 throws LockedException {
413 if (isLocked()) {
414 throw new LockedException();
415 }
416 this.suggestHorizontalFocalLengthEnabled =
417 suggestHorizontalFocalLengthEnabled;
418 }
419
420 /**
421 * Gets suggested horizontal focal length value to be reached when
422 * suggestion is enabled.
423 * Suggested value should be close to the initially estimated value
424 * otherwise the iterative refinement might not converge to provided value.
425 *
426 * @return suggested horizontal focal length value.
427 */
428 public double getSuggestedHorizontalFocalLengthValue() {
429 return suggestedHorizontalFocalLengthValue;
430 }
431
432 /**
433 * Sets suggested horizontal focal length value to be reached when
434 * suggestion is enabled.
435 * Suggested value should be close to the initially estimated value
436 * otherwise the iterative refinement might not converge to provided value.
437 *
438 * @param suggestedHorizontalFocalLengthValue suggested horizontal focal
439 * length value.
440 * @throws LockedException if estimator is locked.
441 */
442 public void setSuggestedHorizontalFocalLengthValue(final double suggestedHorizontalFocalLengthValue)
443 throws LockedException {
444 if (isLocked()) {
445 throw new LockedException();
446 }
447 this.suggestedHorizontalFocalLengthValue = suggestedHorizontalFocalLengthValue;
448 }
449
450 /**
451 * Indicates whether vertical focal length is suggested or not. When
452 * enabled, the estimator will attempt to enforce suggested value in an
453 * iterative manner starting from an initially estimated camera.
454 * Even when suggestion is enabled, the iterative algorithm might not reach
455 * suggested value if the initial value largely differs from the suggested
456 * value.
457 *
458 * @return true if vertical focal length is suggested, false otherwise.
459 */
460 public boolean isSuggestVerticalFocalLengthEnabled() {
461 return suggestVerticalFocalLengthEnabled;
462 }
463
464 /**
465 * Specifies whether vertical focal length is suggested or not. When
466 * enabled, the estimator will attempt to enforce suggested value in an
467 * iterative manner starting from an initially estimated camera.
468 * Even when suggestion is enabled, the iterative algorithm might not reach
469 * suggested value if the initial value largely differs from the suggested
470 * value.
471 *
472 * @param suggestVerticalFocalLengthEnabled true if vertical focal length is
473 * suggested, false otherwise.
474 * @throws LockedException if estimator is locked.
475 */
476 public void setSuggestVerticalFocalLengthEnabled(final boolean suggestVerticalFocalLengthEnabled)
477 throws LockedException {
478 if (isLocked()) {
479 throw new LockedException();
480 }
481 this.suggestVerticalFocalLengthEnabled = suggestVerticalFocalLengthEnabled;
482 }
483
484 /**
485 * Gets suggested vertical focal length value to be reached when suggestion
486 * is enabled.
487 * Suggested value should be close to the initially estimated value
488 * otherwise the iterative refinement might not converge to provided value.
489 *
490 * @return suggested vertical focal length.
491 */
492 public double getSuggestedVerticalFocalLengthValue() {
493 return suggestedVerticalFocalLengthValue;
494 }
495
496 /**
497 * Sets suggested vertical focal length value to be reached when suggestion
498 * is enabled.
499 * Suggested value should be close to the initially estimated value
500 * otherwise the iterative refinement might not converge to provided value.
501 *
502 * @param suggestedVerticalFocalLengthValue suggested vertical focal length.
503 * @throws LockedException if estimator is locked.
504 */
505 public void setSuggestedVerticalFocalLengthValue(final double suggestedVerticalFocalLengthValue)
506 throws LockedException {
507 if (isLocked()) {
508 throw new LockedException();
509 }
510 this.suggestedVerticalFocalLengthValue = suggestedVerticalFocalLengthValue;
511 }
512
513 /**
514 * Indicates whether aspect ratio is suggested or not. When enabled, the
515 * estimator will attempt to enforce suggested value in an iterative manner
516 * starting from an initially estimated camera.
517 * Even when suggestion is enabled, the iterative algorithm might not reach
518 * suggested value if the initial value largely differs from the suggested
519 * value.
520 *
521 * @return true if aspect ratio is suggested, false otherwise.
522 */
523 public boolean isSuggestAspectRatioEnabled() {
524 return suggestAspectRatioEnabled;
525 }
526
527 /**
528 * Specifies whether aspect ratio is suggested or not. When enabled, the
529 * estimator will attempt to enforce suggested value in an iterative manner
530 * starting from an initially estimated camera.
531 * Even when suggestion is enabled, the iterative algorithm might not reach
532 * suggested value if the initial value largely differs from the suggested
533 * value.
534 *
535 * @param suggestAspectRatioEnabled true if aspect ratio is suggested, false
536 * otherwise.
537 * @throws LockedException if estimator is locked.
538 */
539 public void setSuggestAspectRatioEnabled(final boolean suggestAspectRatioEnabled) throws LockedException {
540 if (isLocked()) {
541 throw new LockedException();
542 }
543 this.suggestAspectRatioEnabled = suggestAspectRatioEnabled;
544 }
545
546 /**
547 * Gets suggested aspect ratio value to be reached when suggestion is
548 * enabled. Suggested value should be close to the initially estimated value
549 * otherwise the iterative refinement might not converge to provided value.
550 *
551 * @return suggested aspect ratio value.
552 */
553 public double getSuggestedAspectRatioValue() {
554 return suggestedAspectRatioValue;
555 }
556
557 /**
558 * Sets suggested aspect ratio value to be reached when suggestion is
559 * enabled. Suggested value should be close to the initially estimated value
560 * otherwise the iterative refinement might not converge to provided value.
561 *
562 * @param suggestedAspectRatioValue suggested aspect ratio value.
563 * @throws LockedException if estimator is locked.
564 */
565 public void setSuggestedAspectRatioValue(final double suggestedAspectRatioValue) throws LockedException {
566 if (isLocked()) {
567 throw new LockedException();
568 }
569 this.suggestedAspectRatioValue = suggestedAspectRatioValue;
570 }
571
572 /**
573 * Indicates whether principal point is suggested or not. When enabled, the
574 * estimator will attempt to enforce suggested value in an iterative manner
575 * starting from an initially estimated camera.
576 * Even when suggestion is enabled, the iterative algorithm might not reach
577 * suggested value if the initial value largely differs from the suggested
578 * value.
579 *
580 * @return true if principal point is suggested, false otherwise.
581 */
582 public boolean isSuggestPrincipalPointEnabled() {
583 return suggestPrincipalPointEnabled;
584 }
585
586 /**
587 * Specifies whether principal point is suggested or not. When enabled, the
588 * estimator will attempt to enforce suggested value in an iterative manner
589 * starting from an initially estimated camera.
590 * Even when suggestion is enabled, the iterative algorithm might not reach
591 * suggested value if the initial value largely differs from the suggested
592 * value.
593 *
594 * @param suggestPrincipalPointEnabled true if principal point is suggested,
595 * false otherwise.
596 * @throws LockedException if estimator is locked.
597 */
598 public void setSuggestPrincipalPointEnabled(final boolean suggestPrincipalPointEnabled) throws LockedException {
599 if (isLocked()) {
600 throw new LockedException();
601 }
602 this.suggestPrincipalPointEnabled = suggestPrincipalPointEnabled;
603 if (suggestPrincipalPointEnabled && suggestedPrincipalPointValue == null) {
604 suggestedPrincipalPointValue = new InhomogeneousPoint2D();
605 }
606 }
607
608 /**
609 * Gets suggested principal point value to be reached when suggestion is
610 * enabled. Suggested value should be close to the initially estimated value
611 * otherwise the iterative refinement might not converge to provided value.
612 *
613 * @return suggested principal point value to be reached when suggestion is
614 * enabled.
615 */
616 public InhomogeneousPoint2D getSuggestedPrincipalPointValue() {
617 return suggestedPrincipalPointValue;
618 }
619
620 /**
621 * Sets suggested principal point value to be reached when suggestion is
622 * enabled. Suggested value should be close to the initially estimated value
623 * otherwise the iterative refinement might not converge to provided value.
624 *
625 * @param suggestedPrincipalPointValue suggested principal point value to be
626 * reached when suggestion is enabled.
627 * @throws LockedException if estimator is locked.
628 */
629 public void setSuggestedPrincipalPointValue(final InhomogeneousPoint2D suggestedPrincipalPointValue)
630 throws LockedException {
631 if (isLocked()) {
632 throw new LockedException();
633 }
634 this.suggestedPrincipalPointValue = suggestedPrincipalPointValue;
635 }
636
637 /**
638 * Indicates whether camera rotation is suggested or not. When enabled, the
639 * estimator will attempt to enforce suggested value in an iterative manner
640 * starting from an initially estimated camera.
641 * Even when suggestion is enabled, the iterative algorithm might not reach
642 * suggested value if the initial value largely differs from the suggested
643 * value.
644 *
645 * @return true if camera rotation is suggested, false otherwise.
646 */
647 public boolean isSuggestRotationEnabled() {
648 return suggestRotationEnabled;
649 }
650
651 /**
652 * Specifies whether camera rotation is suggested or not. When enabled, the
653 * estimator will attempt to enforce suggested value in an iterative manner
654 * starting from an initially estimated camera.
655 * Even when suggestion is enabled, the iterative algorithm might not reach
656 * suggested value if the initial value largely differs from the suggested
657 * value.
658 *
659 * @param suggestRotationEnabled true if camera rotation is suggested, false
660 * otherwise.
661 * @throws LockedException if estimator is locked.
662 */
663 public void setSuggestRotationEnabled(final boolean suggestRotationEnabled) throws LockedException {
664 if (isLocked()) {
665 throw new LockedException();
666 }
667 this.suggestRotationEnabled = suggestRotationEnabled;
668 if (suggestRotationEnabled && suggestedRotationValue == null) {
669 suggestedRotationValue = new Quaternion();
670 }
671 }
672
673 /**
674 * Gets suggested rotation to be reached when suggestion is enabled.
675 * Suggested value should be close to the initially estimated value
676 * otherwise the iterative refinement might not converge to provided value.
677 *
678 * @return suggested rotation to be reached when suggestion is enabled.
679 */
680 public Quaternion getSuggestedRotationValue() {
681 return suggestedRotationValue;
682 }
683
684 /**
685 * Sets suggested rotation to be reached when suggestion is enabled.
686 * Suggested value should be close to the initially estimated value
687 * otherwise the iterative refinement might not converge to provided value.
688 *
689 * @param suggestedRotationValue suggested rotation to be reached when
690 * suggestion is enabled.
691 * @throws LockedException if estimator is locked.
692 */
693 public void setSuggestedRotationValue(final Quaternion suggestedRotationValue) throws LockedException {
694 if (isLocked()) {
695 throw new LockedException();
696 }
697 this.suggestedRotationValue = suggestedRotationValue;
698 }
699
700 /**
701 * Indicates whether camera center is suggested or not. When enabled, the
702 * estimator will attempt to enforce suggested value in an iterative manner
703 * starting from an initially estimated camera.
704 * Even when suggestion is enabled, the iterative algorithm might not reach
705 * suggested value if the initial value largely differs from the suggested
706 * value.
707 *
708 * @return true if camera center is suggested, false otherwise.
709 */
710 public boolean isSuggestCenterEnabled() {
711 return suggestCenterEnabled;
712 }
713
714 /**
715 * Specifies whether camera center is suggested or not. When enabled, the
716 * estimator will attempt to enforce suggested value in an iterative manner
717 * starting from an initially estimated camera.
718 * Even when suggestion is enabled, the iterative algorithm might not reach
719 * suggested value if the initial value largely differs from the suggested
720 * value.
721 *
722 * @param suggestCenterEnabled true if camera is suggested, false otherwise.
723 * @throws LockedException if estimator is locked.
724 */
725 public void setSuggestCenterEnabled(final boolean suggestCenterEnabled) throws LockedException {
726 if (isLocked()) {
727 throw new LockedException();
728 }
729 this.suggestCenterEnabled = suggestCenterEnabled;
730 if (suggestCenterEnabled && suggestedCenterValue == null) {
731 suggestedCenterValue = new InhomogeneousPoint3D();
732 }
733 }
734
735 /**
736 * Gets suggested center to be reached when suggestion is enabled.
737 * Suggested value should be close to the initially estimated value
738 * otherwise the iterative refinement might not converge to provided value.
739 *
740 * @return suggested center to be reached when suggestion is enabled.
741 */
742 public InhomogeneousPoint3D getSuggestedCenterValue() {
743 return suggestedCenterValue;
744 }
745
746 /**
747 * Sets suggested center to be reached when suggestion is enabled.
748 * Suggested value should be close to the initially estimated value
749 * otherwise the iterative refinement might not converge to provided value.
750 *
751 * @param suggestedCenterValue suggested center to be reached when
752 * suggestion is enabled.
753 * @throws LockedException if estimator is locked.
754 */
755 public void setSuggestedCenterValue(final InhomogeneousPoint3D suggestedCenterValue) throws LockedException {
756 if (isLocked()) {
757 throw new LockedException();
758 }
759 this.suggestedCenterValue = suggestedCenterValue;
760 }
761
762 /**
763 * Gets minimum suggestion weight. This weight is used to slowly draw
764 * original camera parameters into desired suggested values.
765 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
766 * to find a solution so that the algorithm can converge into desired value.
767 * The faster the weights are increased the less likely that suggested
768 * values can be converged if they differ too much from the original ones.
769 *
770 * @return minimum suggestion weight.
771 */
772 public double getMinSuggestionWeight() {
773 return minSuggestionWeight;
774 }
775
776 /**
777 * Sets minimum suggestion weight. This weight is used to slowly draw
778 * original camera parameters into desired suggested values.
779 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
780 * to find a solution so that the algorithm can converge into desired value.
781 * The faster the weights are increased the less likely that suggested
782 * values can be converged if they differ too much from the original ones.
783 *
784 * @param minSuggestionWeight minimum suggestion weight.
785 * @throws LockedException if estimator is locked.
786 */
787 public void setMinSuggestionWeight(final double minSuggestionWeight) throws LockedException {
788 if (isLocked()) {
789 throw new LockedException();
790 }
791 this.minSuggestionWeight = minSuggestionWeight;
792 }
793
794 /**
795 * Gets maximum suggestion weight. This weight is used to slowly draw
796 * original camera parameters into desired suggested values.
797 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
798 * to find a solution so that the algorithm can converge into desired value.
799 * The faster the weights are increased the less likely that suggested
800 * values can be converged if they differ too much from the original ones.
801 *
802 * @return maximum suggestion weight.
803 */
804 public double getMaxSuggestionWeight() {
805 return maxSuggestionWeight;
806 }
807
808 /**
809 * Sets maximum suggestion weight. This weight is used to slowly draw
810 * original camera parameters into desired suggested values.
811 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
812 * to find a solution so that the algorithm can converge into desired value.
813 * The faster the weights are increased the less likely that suggested
814 * values can be converged if they differ too much from the original ones.
815 *
816 * @param maxSuggestionWeight maximum suggestion weight.
817 * @throws LockedException if estimator is locked.
818 */
819 public void setMaxSuggestionWeight(final double maxSuggestionWeight) throws LockedException {
820 if (isLocked()) {
821 throw new LockedException();
822 }
823 this.maxSuggestionWeight = maxSuggestionWeight;
824 }
825
826 /**
827 * Sets minimum and maximum suggestion weights. Suggestion weight is used to
828 * slowly draw original camera parameters into desired suggested values.
829 * Suggestion weight slowly increases each time Levenberg-Marquardt is used
830 * to find a solution so that the algorithm can converge into desired value.
831 * The faster the weights are increased the less likely that suggested
832 * values can be converged if they differ too much from the original ones.
833 *
834 * @param minSuggestionWeight minimum suggestion weight.
835 * @param maxSuggestionWeight maximum suggestion weight.
836 * @throws LockedException if estimator is locked.
837 * @throws IllegalArgumentException if minimum suggestion weight is greater
838 * or equal than maximum value.
839 */
840 public void setMinMaxSuggestionWeight(final double minSuggestionWeight, final double maxSuggestionWeight)
841 throws LockedException {
842 if (isLocked()) {
843 throw new LockedException();
844 }
845 if (minSuggestionWeight >= maxSuggestionWeight) {
846 throw new IllegalArgumentException();
847 }
848
849 this.minSuggestionWeight = minSuggestionWeight;
850 this.maxSuggestionWeight = maxSuggestionWeight;
851 }
852
853 /**
854 * Gets step to increase suggestion weight. This weight is used to slowly
855 * draw original camera parameters into desired suggested values. Suggestion
856 * weight slowly increases each time Levenberg-Marquardt is used to find a
857 * solution so that the algorithm can converge into desired value. The
858 * faster the weights are increased the less likely that suggested values
859 * can be converged if they differ too much from the original ones.
860 *
861 * @return step to increase suggestion weight.
862 */
863 public double getSuggestionWeightStep() {
864 return suggestionWeightStep;
865 }
866
867 /**
868 * Sets step to increase suggestion weight. This weight is used to slowly
869 * draw original camera parameters into desired suggested values. Suggestion
870 * weight slowly increases each time Levenberg-Marquardt is used to find a
871 * solution so that the algorithm can converge into desired value. The
872 * faster the weights are increased the less likely that suggested values
873 * can be converged if they differ too much from the original ones.
874 *
875 * @param suggestionWeightStep step to increase suggestion weight.
876 * @throws LockedException if estimator is locked.
877 * @throws IllegalArgumentException if provided step is negative or zero.
878 */
879 public void setSuggestionWeightStep(final double suggestionWeightStep) throws LockedException {
880 if (isLocked()) {
881 throw new LockedException();
882 }
883 if (suggestionWeightStep <= 0.0) {
884 throw new IllegalArgumentException();
885 }
886
887 this.suggestionWeightStep = suggestionWeightStep;
888 }
889
890 /**
891 * Indicates whether this instance is locked.
892 *
893 * @return true if this estimator is busy estimating a camera, false
894 * otherwise.
895 */
896 public boolean isLocked() {
897 return locked;
898 }
899
900 /**
901 * Indicates if this estimator is ready to start the estimation.
902 *
903 * @return true if estimator is ready, false otherwise.
904 */
905 public abstract boolean isReady();
906
907 /**
908 * Estimates a pinhole camera.
909 *
910 * @return estimated pinhole camera.
911 * @throws LockedException if estimator is locked.
912 * @throws NotReadyException if input has not yet been provided.
913 * @throws PinholeCameraEstimatorException if an error occurs during
914 * estimation, usually because input data is not valid.
915 */
916 public abstract PinholeCamera estimate() throws LockedException, NotReadyException, PinholeCameraEstimatorException;
917
918 /**
919 * Returns type of pinhole camera estimator.
920 *
921 * @return type of pinhole camera estimator.
922 */
923 public abstract PinholeCameraEstimatorType getType();
924
925 /**
926 * Creates an instance of a pinhole camera estimator using default type.
927 *
928 * @return an instance of a pinhole camera estimator.
929 */
930 public static PinholeCameraEstimator create() {
931 return create(DEFAULT_ESTIMATOR_TYPE);
932 }
933
934 /**
935 * Creates an instance of a pinhole camera estimator using provided type.
936 *
937 * @param type type of pinhole camera estimator.
938 * @return an instance of a pinhole camera estimator.
939 */
940 public static PinholeCameraEstimator create(final PinholeCameraEstimatorType type) {
941 return switch (type) {
942 case DLT_LINE_PLANE_PINHOLE_CAMERA_ESTIMATOR -> new DLTLinePlaneCorrespondencePinholeCameraEstimator();
943 case WEIGHTED_LINE_PLANE_PINHOLE_CAMERA_ESTIMATOR ->
944 new WeightedLinePlaneCorrespondencePinholeCameraEstimator();
945 case WEIGHTED_POINT_PINHOLE_CAMERA_ESTIMATOR -> new WeightedPointCorrespondencePinholeCameraEstimator();
946 default -> new DLTPointCorrespondencePinholeCameraEstimator();
947 };
948 }
949
950 /**
951 * Attempts to refine provided camera using requested suggestions.
952 * If no suggestions are requested or if refinement fails, provided
953 * camera is returned instead.
954 *
955 * @param pinholeCamera camera to be refined.
956 * @return refined camera.
957 */
958 protected abstract PinholeCamera attemptRefine(final PinholeCamera pinholeCamera);
959
960 /**
961 * Indicates whether obtained solution requires refinement to apply provided
962 * suggestions.
963 *
964 * @return true if solution requires refinement to apply provided
965 * suggestions, false otherwise.
966 */
967 protected boolean hasSuggestions() {
968 return hasIntrinsicSuggestions() || hasExtrinsicSuggestions();
969 }
970
971 /**
972 * Indicates whether suggestions for any intrinsic parameter are required
973 * or not.
974 *
975 * @return true if suggestions for any intrinsic parameters are required,
976 * false otherwise.
977 */
978 private boolean hasIntrinsicSuggestions() {
979 return suggestSkewnessValueEnabled || suggestHorizontalFocalLengthEnabled || suggestVerticalFocalLengthEnabled
980 || suggestAspectRatioEnabled;
981 }
982
983 /**
984 * Indicates whether suggestions for any extrinsic parameter are required
985 * or not.
986 *
987 * @return true if suggestions for any extrinsic parameter are required,
988 * false otherwise.
989 */
990 private boolean hasExtrinsicSuggestions() {
991 return suggestPrincipalPointEnabled || suggestRotationEnabled || suggestCenterEnabled;
992 }
993 }