1 /*
2 * Copyright (C) 2015 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.ar.calibration.estimators;
17
18 import com.irurueta.ar.calibration.ImageOfAbsoluteConic;
19 import com.irurueta.geometry.Transformation2D;
20 import com.irurueta.geometry.estimators.LockedException;
21 import com.irurueta.geometry.estimators.NotReadyException;
22
23 import java.util.Arrays;
24 import java.util.List;
25
26 /**
27 * This class defines the interface for an estimator of the Image of Absolute
28 * Conic (IAC). The IAC is directly related to pinhole camera intrinsic
29 * parameters, implementations of this estimator can be used for camera
30 * calibration purposes.
31 * Depending on the constraints imposed on the intrinsic parameters of the
32 * camera, some parameters of the IAC will be known in advance and fewer
33 * equations will be needed.
34 * If no constraints are imposed, then at least 5 equations will be needed to
35 * estimate the DIAC, and hence 3 homographies will be required (2 equations can
36 * be obtained for each homography). 2*n <= 5 ==< n <= 5/2 ==< n <= 2.5 ==<
37 * n <= 3
38 * If skewness is assumed to be known and zero, then one less homography is
39 * required, hence only 2 homographies will be needed.
40 * 2*n + 1 <= 5 ==< n <= 4 / 2 ==< n <= 2
41 * If also principal point is assumed to be known and located at image center
42 * (origin of coordinates), then 2 fewer equations are needed, and hence only
43 * 1 homography is needed:
44 * 2n + 1 + 2 <= 5 ==< n <= 2 / 2 ==< n <= 1
45 * By enabling constraints, results are guaranteed to be more stable (estimation
46 * fails fewer times with an exception) and more accurate, so whenever possible
47 * constraints should be enabled. The principal point at origin introduces more
48 * stability and accuracy than the skewness constraint, but if possible both
49 * should be enabled. By default, both constraints are enable.
50 */
51 public abstract class ImageOfAbsoluteConicEstimator {
52
53 /**
54 * Minimum number of required equations to solve the IAC linear system of
55 * equations.
56 */
57 protected static final int MIN_REQUIRED_EQUATIONS = 5;
58
59 /**
60 * Constant defining whether zero skewness is assumed.
61 */
62 public static final boolean DEFAULT_ZERO_SKEWNESS = true;
63
64 /**
65 * Constant defining whether principal point is assumed to be at origin of
66 * coordinates.
67 */
68 public static final boolean DEFAULT_PRINCIPAL_POINT_AT_ORIGIN = true;
69
70 /**
71 * Constant defining whether aspect ratio of focal distances (i.e. vertical
72 * focal distance divided by horizontal focal distance) is known or not.
73 * Notice that focal distance aspect ratio is not related to image size
74 * aspect ratio. Typically, LCD sensor cells are square and hence aspect
75 * ratio of focal distances is known and equal to 1.
76 */
77 public static final boolean DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO_KNOWN = true;
78
79 /**
80 * Constant defining default aspect ratio of focal distances. This constant
81 * takes into account that typically LCD sensor cells are square and hence
82 * aspect ratio of focal distances is known and equal to 1.
83 */
84 public static final double DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO = 1.0;
85
86 /**
87 * Minimum absolute value allowed for aspect ratio of focal distances.
88 */
89 public static final double MIN_ABS_FOCAL_DISTANCE_ASPECT_RATIO = 1e-6;
90
91 /**
92 * Default estimator type.
93 */
94 public static final ImageOfAbsoluteConicEstimatorType DEFAULT_ESTIMATOR_TYPE =
95 ImageOfAbsoluteConicEstimatorType.LMSE_IAC_ESTIMATOR;
96
97 /**
98 * Indicates whether camera skewness is assumed to be zero or not.
99 */
100 protected boolean zeroSkewness;
101
102 /**
103 * Indicates whether principal point is assumed to be at origin of
104 * coordinates or not.
105 * If false, the principal point will be estimated, otherwise it will be
106 * assumed to be at image center (i.e. origin of coordinates).
107 */
108 protected boolean principalPointAtOrigin;
109
110 /**
111 * Indicates whether aspect ratio of focal distances (i.e. vertical focal
112 * distance divided by horizontal focal distance) is known or not.
113 * Notice that focal distance aspect ratio is not related to image size
114 * aspect ratio. Typically, LCD sensor cells are square and hence aspect
115 * ratio of focal distances is known and equal to 1.
116 * This value is only taken into account if skewness is assumed to be
117 * zero, otherwise it is ignored.
118 */
119 protected boolean focalDistanceAspectRatioKnown;
120
121 /**
122 * Contains aspect ratio of focal distances (i.e. vertical focal distance
123 * divided by horizontal focal distance).
124 * This value is only taken into account if skewness is assumed to be zero
125 * and focal distance aspect ratio is marked as known, otherwise it is
126 * ignored.
127 * By default, this is 1.0, since it is taken into account that typically
128 * LCD sensor cells are square and hence aspect ratio focal distances is
129 * known and equal to 1.
130 * Notice that focal distance aspect ratio is not related to image size
131 * aspect ratio.
132 */
133 protected double focalDistanceAspectRatio;
134
135 /**
136 * True when estimator is estimating IAC.
137 */
138 protected boolean locked;
139
140 /**
141 * Listener to be notified of events such as when estimation starts, ends or
142 * estimation progress changes.
143 */
144 protected ImageOfAbsoluteConicEstimatorListener listener;
145
146 /**
147 * List of homographies (2D transformations) used to estimate the image
148 * of absolute conic (IAC), which can be used to obtain pinhole camera
149 * intrinsic parameters.
150 */
151 protected List<Transformation2D> homographies;
152
153 /**
154 * Constructor.
155 */
156 protected ImageOfAbsoluteConicEstimator() {
157 zeroSkewness = DEFAULT_ZERO_SKEWNESS;
158 principalPointAtOrigin = DEFAULT_PRINCIPAL_POINT_AT_ORIGIN;
159 focalDistanceAspectRatioKnown = DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO_KNOWN;
160 focalDistanceAspectRatio = DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO;
161
162 locked = false;
163 listener = null;
164 homographies = null;
165 }
166
167 /**
168 * Constructor with listener.
169 *
170 * @param listener listener to be notified of events such as when estimation
171 * starts, ends or estimation progress changes.
172 */
173 protected ImageOfAbsoluteConicEstimator(final ImageOfAbsoluteConicEstimatorListener listener) {
174 this();
175 this.listener = listener;
176 }
177
178 /**
179 * Constructor.
180 *
181 * @param homographies list of homographies (2D transformations) used to
182 * estimate the image of absolute conic (IAC), which can be used to obtain
183 * pinhole camera intrinsic parameters.
184 * @throws IllegalArgumentException if not enough homographies are provided
185 * for default settings. Hence, at least 1 homography must be provided.
186 */
187 protected ImageOfAbsoluteConicEstimator(final List<Transformation2D> homographies) {
188 this();
189 internalSetHomographies(homographies);
190 }
191
192 /**
193 * Constructor.
194 *
195 * @param homographies list of homographies (2D transformations) used to
196 * estimate the image of absolute conic (IAC), which can be used to obtain
197 * pinhole camera intrinsic parameters.
198 * @param listener listener to be notified of events such as when estimation
199 * starts, ends or estimation progress changes.
200 * @throws IllegalArgumentException if not enough homographies are provided
201 * for default settings. Hence, at least 1 homography must be provided.
202 */
203 protected ImageOfAbsoluteConicEstimator(
204 final List<Transformation2D> homographies, final ImageOfAbsoluteConicEstimatorListener listener) {
205 this(listener);
206 internalSetHomographies(homographies);
207 }
208
209 /**
210 * Returns boolean indicating whether camera skewness is assumed to be zero
211 * or not.
212 * Skewness determines whether LCD sensor cells are properly aligned or not,
213 * where zero indicates perfect alignment.
214 * Typically, skewness is a value equal or very close to zero.
215 *
216 * @return true if camera skewness is assumed to be zero, otherwise camera
217 * skewness is estimated.
218 */
219 public boolean isZeroSkewness() {
220 return zeroSkewness;
221 }
222
223 /**
224 * Sets boolean indicating whether camera skewness is assumed to be zero or
225 * not.
226 * Skewness determines whether LCD sensor cells are properly aligned or not,
227 * where zero indicates perfect alignment.
228 * Typically, skewness is a value equal or very close to zero.
229 *
230 * @param zeroSkewness true if camera skewness is assumed to be zero,
231 * otherwise camera skewness is estimated.
232 * @throws LockedException if estimator is locked.
233 */
234 public void setZeroSkewness(final boolean zeroSkewness) throws LockedException {
235 if (isLocked()) {
236 throw new LockedException();
237 }
238
239 this.zeroSkewness = zeroSkewness;
240 }
241
242 /**
243 * Returns boolean indicating whether principal point is assumed to be at
244 * origin of coordinates or not.
245 * Typically principal point is located at image center (origin of
246 * coordinates), and usually matches the center of radial distortion if
247 * it is taken into account.
248 *
249 * @return true if principal point is assumed to be at origin of
250 * coordinates, false if principal point must be estimated.
251 */
252 public boolean isPrincipalPointAtOrigin() {
253 return principalPointAtOrigin;
254 }
255
256 /**
257 * Sets boolean indicating whether principal point is assumed to be at
258 * origin of coordinates or not.
259 * Typically principal point is located at image center (origin of
260 * coordinates), and usually matches the center of radial distortion if it
261 * is taken into account.
262 *
263 * @param principalPointAtOrigin true if principal point is assumed to be at
264 * origin of coordinates, false if principal point must be estimated.
265 * @throws LockedException if estimator is locked.
266 */
267 public void setPrincipalPointAtOrigin(final boolean principalPointAtOrigin) throws LockedException {
268 if (isLocked()) {
269 throw new LockedException();
270 }
271
272 this.principalPointAtOrigin = principalPointAtOrigin;
273 }
274
275 /**
276 * Returns boolean indicating whether aspect ratio of focal distances (i.e.
277 * vertical focal distance divided by horizontal focal distance) is known or
278 * not.
279 * Notice that focal distance aspect ratio is not related to image size
280 * aspect ratio. Typically, LCD sensor cells are square and hence aspect
281 * ratio of focal distances is known and equal to 1.
282 * This value is only taken into account if skewness is assumed to be zero,
283 * otherwise it is ignored.
284 *
285 * @return true if focal distance aspect ratio is known, false otherwise.
286 */
287 public boolean isFocalDistanceAspectRatioKnown() {
288 return focalDistanceAspectRatioKnown;
289 }
290
291 /**
292 * Sets value indicating whether aspect ratio of focal distances (i.e.
293 * vertical focal distance divided by horizontal focal distance) is known or
294 * not.
295 * Notice that focal distance aspect ratio is not related to image size
296 * aspect ratio. Typically, LCD sensor cells are square and hence aspect
297 * ratio of focal distances is known and equal to 1.
298 * This value is only taken into account if skewness is assumed to be zero,
299 * otherwise it is ignored.
300 *
301 * @param focalDistanceAspectRatioKnown true if focal distance aspect ratio
302 * is known, false otherwise.
303 * @throws LockedException if estimator is locked.
304 */
305 public void setFocalDistanceAspectRatioKnown(final boolean focalDistanceAspectRatioKnown) throws LockedException {
306 if (isLocked()) {
307 throw new LockedException();
308 }
309
310 this.focalDistanceAspectRatioKnown = focalDistanceAspectRatioKnown;
311 }
312
313 /**
314 * Returns aspect ratio of focal distances (i.e. vertical focal distance
315 * divided by horizontal focal distance).
316 * This value is only taken into account if skewness is assumed to be zero
317 * and focal distance aspect ratio is marked as known, otherwise it is
318 * ignored.
319 * By default, this is 1.0, since it is taken into account that typically
320 * LCD sensor cells are square and hence aspect ratio focal distances is
321 * known and equal to 1.
322 * Notice that focal distance aspect ratio is not related to image size
323 * aspect ratio
324 * Notice that a negative aspect ratio indicates that vertical axis is
325 * reversed. This can be useful in some situations where image vertical
326 * coordinates are reversed respect to the physical world (i.e. in computer
327 * graphics typically image vertical coordinates go downwards, while in
328 * physical world they go upwards).
329 *
330 * @return aspect ratio of focal distances.
331 */
332 public double getFocalDistanceAspectRatio() {
333 return focalDistanceAspectRatio;
334 }
335
336 /**
337 * Sets aspect ratio of focal distances (i.e. vertical focal distance
338 * divided by horizontal focal distance).
339 * This value is only taken into account if skewness is assumed to be zero
340 * and focal distance aspect ratio is marked as known, otherwise it is
341 * ignored.
342 * By default, this is 1.0, since it is taken into account that typically
343 * LCD sensor cells are square and hence aspect ratio focal distances is
344 * known and equal to 1.
345 * Notice that focal distance aspect ratio is not related to image size
346 * aspect ratio.
347 * Notice that a negative aspect ratio indicates that vertical axis is
348 * reversed. This can be useful in some situations where image vertical
349 * coordinates are reversed respect to the physical world (i.e. in computer
350 * graphics typically image vertical coordinates go downwards, while in
351 * physical world they go upwards).
352 *
353 * @param focalDistanceAspectRatio aspect ratio of focal distances to be
354 * set.
355 * @throws LockedException if estimator is locked.
356 * @throws IllegalArgumentException if focal distance aspect ratio is too
357 * close to zero, as it might produce numerical instabilities.
358 */
359 public void setFocalDistanceAspectRatio(final double focalDistanceAspectRatio) throws LockedException {
360 if (isLocked()) {
361 throw new LockedException();
362 }
363 if (Math.abs(focalDistanceAspectRatio) < MIN_ABS_FOCAL_DISTANCE_ASPECT_RATIO) {
364 throw new IllegalArgumentException();
365 }
366
367 this.focalDistanceAspectRatio = focalDistanceAspectRatio;
368 }
369
370 /**
371 * Indicates whether this instance is locked.
372 *
373 * @return true if this estimator is busy estimating an IAC, false
374 * otherwise.
375 */
376 public boolean isLocked() {
377 return locked;
378 }
379
380 /**
381 * Returns listener to be notified of events such as when estimation starts,
382 * ends or estimation progress changes.
383 *
384 * @return listener to be notified of events.
385 */
386 public ImageOfAbsoluteConicEstimatorListener getListener() {
387 return listener;
388 }
389
390 /**
391 * Sets listener to be notified of events such as when estimation starts,
392 * ends or estimation progress changes.
393 *
394 * @param listener listener to be notified of events.
395 * @throws LockedException if estimator is locked.
396 */
397 public void setListener(final ImageOfAbsoluteConicEstimatorListener listener) throws LockedException {
398 if (isLocked()) {
399 throw new LockedException();
400 }
401 this.listener = listener;
402 }
403
404 /**
405 * Gets list of homographies to estimate IAC.
406 *
407 * @return list of homographies to estimate IAC.
408 */
409 public List<Transformation2D> getHomographies() {
410 return homographies;
411 }
412
413 /**
414 * Sets list of homographies to estimate IAC.
415 *
416 * @param homographies list of homographies to estimate IAC.
417 * @throws LockedException if estimator is locked.
418 * @throws IllegalArgumentException if provided list of homographies does not
419 * contain enough elements to estimate the IAC using current settings.
420 */
421 public void setHomographies(final List<Transformation2D> homographies) throws LockedException {
422 if (isLocked()) {
423 throw new LockedException();
424 }
425 internalSetHomographies(homographies);
426 }
427
428 /**
429 * Returns minimum number of required homographies needed to estimate the
430 * Image of Absolute Conic (IAC).
431 * If no constraints are imposed, then at least 3 homographies are required.
432 * For each constraint imposed, one less equation will be required, hence
433 * if skewness is assumed to be known (by using its typical value of zero),
434 * then only 4 equations will be needed (2 homographies).
435 * If also the horizontal and vertical coordinates of the principal point
436 * are assumed to be known (by being placed at the 2D origin of coordinates,
437 * which is a typical value), then only 2 equations will be needed
438 * (1 homography).
439 *
440 * @return minimum number of required homographies required to estimate the
441 * IAC
442 */
443 public int getMinNumberOfRequiredHomographies() {
444 var numEquations = MIN_REQUIRED_EQUATIONS;
445 if (zeroSkewness) {
446 if (focalDistanceAspectRatioKnown) {
447 numEquations--;
448 }
449 numEquations--;
450 }
451 if (principalPointAtOrigin) {
452 numEquations -= 2;
453 }
454
455 return (numEquations / 2) + (numEquations % 2);
456 }
457
458 /**
459 * Returns value indicating whether required data has been provided so that
460 * IAC estimation can start.
461 * If true, estimator is ready to compute the IAC, otherwise more data needs
462 * to be provided.
463 *
464 * @return true if estimator is ready, false otherwise.
465 */
466 public boolean isReady() {
467 return homographies != null && homographies.size() >= getMinNumberOfRequiredHomographies();
468 }
469
470 /**
471 * Estimates Image of Absolute Conic (IAC).
472 *
473 * @return estimated IAC.
474 * @throws LockedException if estimator is locked.
475 * @throws NotReadyException if input has not yet been provided.
476 * @throws ImageOfAbsoluteConicEstimatorException if an error occurs during
477 * estimation, usually because repeated homographies are
478 * provided, or homographies corresponding to degenerate
479 * camera movements such as pure parallel translations
480 * where no additional data is really provided. Indeed,
481 * if provided homographies belong to the group of affine
482 * transformations (or other groups contained within such
483 * as metric or Euclidean ones), this exception will
484 * raise because camera movements will be degenerate. To
485 * avoid this exception, homographies must be purely
486 * projective.
487 */
488 public abstract ImageOfAbsoluteConic estimate() throws LockedException, NotReadyException,
489 ImageOfAbsoluteConicEstimatorException;
490
491 /**
492 * Returns type of IAC estimator.
493 *
494 * @return type of IAC estimator.
495 */
496 public abstract ImageOfAbsoluteConicEstimatorType getType();
497
498 /**
499 * Creates an instance of an IAC estimator using provided default type.
500 *
501 * @return an instance of an IAC estimator.
502 */
503 public static ImageOfAbsoluteConicEstimator create() {
504 return create(DEFAULT_ESTIMATOR_TYPE);
505 }
506
507 /**
508 * Creates an instance of an IAC estimator using provided listener and
509 * default type.
510 *
511 * @param listener listener to be notified of events such as when estimation
512 * starts, ends or estimation progress changes.
513 * @return an instance of an IAC estimator.
514 */
515 public static ImageOfAbsoluteConicEstimator create(final ImageOfAbsoluteConicEstimatorListener listener) {
516 return create(listener, DEFAULT_ESTIMATOR_TYPE);
517 }
518
519 /**
520 * Creates an instance of an IAC estimator using provided homographies
521 *
522 * @param homographies list of homographies (2D transformations) used to
523 * estimate the image of absolute conic (IAC), which can be used to obtain
524 * pinhole camera intrinsic parameters.
525 * @return an instance of an IAC estimator.
526 * @throws IllegalArgumentException if not enough homographies are provided
527 * for default IAC estimation constraints.
528 */
529 public static ImageOfAbsoluteConicEstimator create(final List<Transformation2D> homographies) {
530 return create(homographies, DEFAULT_ESTIMATOR_TYPE);
531 }
532
533 /**
534 * Creates an instance of an IAC estimator using provided homographies and
535 * listener.
536 *
537 * @param homographies list of homographies (2D transformations) used to
538 * estimate the image of absolute conic (IAC), which can be used to obtain
539 * pinhole camera intrinsic parameters.
540 * @param listener listener to be notified of events such as when estimation
541 * starts, ends or estimation progress changes.
542 * @return an instance of an IAC estimator.
543 * @throws IllegalArgumentException if not enough homographies are provided
544 * for default IAC estimation constraints.
545 */
546 public static ImageOfAbsoluteConicEstimator create(
547 final List<Transformation2D> homographies, final ImageOfAbsoluteConicEstimatorListener listener) {
548 return create(homographies, listener, DEFAULT_ESTIMATOR_TYPE);
549 }
550
551
552 /**
553 * Creates an instance of an IAC estimator using provided type.
554 *
555 * @param type type of IAC estimator to create.
556 * @return an instance of an IAC estimator.
557 */
558 public static ImageOfAbsoluteConicEstimator create(final ImageOfAbsoluteConicEstimatorType type) {
559 return type == ImageOfAbsoluteConicEstimatorType.WEIGHTED_IAC_ESTIMATOR
560 ? new WeightedImageOfAbsoluteConicEstimator() : new LMSEImageOfAbsoluteConicEstimator();
561 }
562
563 /**
564 * Creates an instance of an IAC estimator using provided listener and
565 * type.
566 *
567 * @param listener listener to be notified of events such as when estimation
568 * starts, ends or estimation progress changes.
569 * @param type type of IAC estimator to create.
570 * @return an instance of an IAC estimator.
571 */
572 public static ImageOfAbsoluteConicEstimator create(
573 final ImageOfAbsoluteConicEstimatorListener listener, final ImageOfAbsoluteConicEstimatorType type) {
574 return type == ImageOfAbsoluteConicEstimatorType.WEIGHTED_IAC_ESTIMATOR
575 ? new WeightedImageOfAbsoluteConicEstimator(listener)
576 : new LMSEImageOfAbsoluteConicEstimator(listener);
577 }
578
579 /**
580 * Creates an instance of an IAC estimator using provided homographies
581 * and type.
582 *
583 * @param homographies list of homographies (2D transformations) used to
584 * estimate the image of absolute conic (IAC), which can be used to obtain
585 * pinhole camera intrinsic parameters.
586 * @param type type of IAC estimator to create.
587 * @return an instance of an IAC estimator.
588 * @throws IllegalArgumentException if not enough homographies are provided
589 * for default IAC estimation constraints.
590 */
591 public static ImageOfAbsoluteConicEstimator create(
592 final List<Transformation2D> homographies, final ImageOfAbsoluteConicEstimatorType type) {
593 switch (type) {
594 case WEIGHTED_IAC_ESTIMATOR:
595 final var weights = new double[homographies.size()];
596 Arrays.fill(weights, 1.0);
597 return new WeightedImageOfAbsoluteConicEstimator(homographies, weights);
598 case LMSE_IAC_ESTIMATOR:
599 default:
600 return new LMSEImageOfAbsoluteConicEstimator(homographies);
601 }
602 }
603
604 /**
605 * Creates an instance of an IAC estimator using provided homographies,
606 * listener and type.
607 *
608 * @param homographies list of homographies (2D transformations) used to
609 * estimate the image of absolute conic (IAC), which can be used to obtain
610 * pinhole camera intrinsic parameters.
611 * @param listener listener to be notified of events such as when estimation
612 * starts, ends or estimation progress changes.
613 * @param type type of IAC estimator to create.
614 * @return an instance of an IAC estimator.
615 * @throws IllegalArgumentException if not enough homographies are provided
616 * for default IAC estimation constraints.
617 */
618 public static ImageOfAbsoluteConicEstimator create(
619 final List<Transformation2D> homographies, final ImageOfAbsoluteConicEstimatorListener listener,
620 final ImageOfAbsoluteConicEstimatorType type) {
621 switch (type) {
622 case WEIGHTED_IAC_ESTIMATOR:
623 final var weights = new double[homographies.size()];
624 Arrays.fill(weights, 1.0);
625 return new WeightedImageOfAbsoluteConicEstimator(homographies, weights, listener);
626 case LMSE_IAC_ESTIMATOR:
627 default:
628 return new LMSEImageOfAbsoluteConicEstimator(homographies, listener);
629 }
630 }
631
632 /**
633 * Sets list of homographies to estimate IAC.
634 * This method does not check whether estimator is locked.
635 *
636 * @param homographies list of homographies to estimate IAC.
637 * @throws IllegalArgumentException if provided list of homographies does not
638 * contain enough elements to estimate the DIAC using current settings.
639 */
640 protected final void internalSetHomographies(final List<Transformation2D> homographies) {
641 if (homographies == null || homographies.size() < getMinNumberOfRequiredHomographies()) {
642 throw new IllegalArgumentException();
643 }
644 this.homographies = homographies;
645 }
646 }