View Javadoc
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.epipolar;
17  
18  import com.irurueta.geometry.CoordinatesType;
19  import com.irurueta.geometry.Line2D;
20  import com.irurueta.geometry.Point2D;
21  import com.irurueta.geometry.estimators.LockedException;
22  import com.irurueta.geometry.estimators.NotReadyException;
23  
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  /**
28   * Fixes matched pairs of points so that they perfectly follow a given epipolar
29   * geometry.
30   * When matching points typically the matching precision is about 1 pixel,
31   * however this makes that matched points under a given epipolar geometry (i.e.
32   * fundamental or essential matrix), do not lie perfectly on the corresponding
33   * epipolar plane or epipolar lines.
34   * The consequence is that triangularization of these matches will fail or
35   * produce inaccurate results.
36   * By fixing matched points using a corrector following a given epipolar
37   * geometry, this effect is alleviated.
38   * This corrector uses the Sampson approximation which is capable to remove
39   * small errors when matches are close to their real epipolar lines. This method
40   * is faster than the Gold Standard method, but can only correct small errors
41   * (1 or 2 pixels).
42   */
43  public class SampsonCorrector extends Corrector {
44  
45      /**
46       * Constructor.
47       */
48      public SampsonCorrector() {
49          super();
50      }
51  
52      /**
53       * Constructor.
54       *
55       * @param fundamentalMatrix fundamental matrix to be set.
56       */
57      public SampsonCorrector(final FundamentalMatrix fundamentalMatrix) {
58          super(fundamentalMatrix);
59      }
60  
61      /**
62       * Constructor.
63       *
64       * @param leftPoints  points to be corrected on left view.
65       * @param rightPoints points to be corrected on right view.
66       * @throws IllegalArgumentException if provided lists of points don't have
67       *                                  the same size.
68       */
69      public SampsonCorrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
70          super(leftPoints, rightPoints);
71      }
72  
73      /**
74       * Constructor.
75       *
76       * @param leftPoints        points to be corrected on left view.
77       * @param rightPoints       points to be corrected on right view.
78       * @param fundamentalMatrix fundamental matrix to be set.
79       * @throws IllegalArgumentException if provided lists of points don't have
80       *                                  the same size.
81       */
82      public SampsonCorrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints,
83                              final FundamentalMatrix fundamentalMatrix) {
84          super(leftPoints, rightPoints, fundamentalMatrix);
85      }
86  
87      /**
88       * Constructor.
89       *
90       * @param listener listener to handle events generated by this class.
91       */
92      public SampsonCorrector(final CorrectorListener listener) {
93          super(listener);
94      }
95  
96      /**
97       * Constructor.
98       *
99       * @param fundamentalMatrix fundamental matrix to be set.
100      * @param listener          listener to handle events generated by this class.
101      */
102     public SampsonCorrector(final FundamentalMatrix fundamentalMatrix, final CorrectorListener listener) {
103         super(fundamentalMatrix, listener);
104     }
105 
106     /**
107      * Constructor.
108      *
109      * @param leftPoints  points to be corrected on left view.
110      * @param rightPoints points to be corrected on right view.
111      * @param listener    listener to handle events generated by this class.
112      * @throws IllegalArgumentException if provided lists of points don't have
113      *                                  the same size.
114      */
115     public SampsonCorrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints,
116                             final CorrectorListener listener) {
117         super(leftPoints, rightPoints, listener);
118     }
119 
120     /**
121      * Constructor.
122      *
123      * @param leftPoints        points to be corrected on left view.
124      * @param rightPoints       points to be corrected on right view.
125      * @param fundamentalMatrix fundamental matrix to be set.
126      * @param listener          listener to handle events generated by this class.
127      * @throws IllegalArgumentException if provided lists of points don't have
128      *                                  the same size.
129      */
130     public SampsonCorrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints,
131                             final FundamentalMatrix fundamentalMatrix, final CorrectorListener listener) {
132         super(leftPoints, rightPoints, fundamentalMatrix, listener);
133     }
134 
135     /**
136      * Corrects the lists of provided matched points to be corrected.
137      *
138      * @throws NotReadyException if this instance is not ready (either points or
139      *                           fundamental matrix has not been provided yet).
140      * @throws LockedException   if this instance is locked doing computations.
141      */
142     @SuppressWarnings("DuplicatedCode")
143     @Override
144     public void correct() throws NotReadyException, LockedException {
145         if (isLocked()) {
146             throw new LockedException();
147         }
148         if (!isReady()) {
149             throw new NotReadyException();
150         }
151 
152         locked = true;
153 
154         if (listener != null) {
155             listener.onCorrectStart(this);
156         }
157 
158         // epipolar lines to be reused for memory efficiency
159         final var leftEpipolarLine = new Line2D();
160         final var rightEpipolarLine = new Line2D();
161 
162         leftCorrectedPoints = new ArrayList<>();
163         rightCorrectedPoints = new ArrayList<>();
164 
165         final var size = leftPoints.size();
166         float progress;
167         var previousProgress = 0.0f;
168         for (var i = 0; i < size; i++) {
169             final var leftPoint = leftPoints.get(i);
170             final var rightPoint = rightPoints.get(i);
171 
172             final var leftCorrectedPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
173             final var rightCorrectedPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
174 
175             // correct single pair
176             SampsonSingleCorrector.correct(leftPoint, rightPoint, fundamentalMatrix, leftCorrectedPoint,
177                     rightCorrectedPoint, leftEpipolarLine, rightEpipolarLine);
178 
179             leftCorrectedPoints.add(leftCorrectedPoint);
180             rightCorrectedPoints.add(rightCorrectedPoint);
181 
182             if (listener != null) {
183                 progress = i / (float) size;
184                 if (progress - previousProgress > progressDelta) {
185                     // progress has changed significantly
186                     previousProgress = progress;
187                     listener.onCorrectProgressChange(this, progress);
188                 }
189             }
190         }
191 
192         if (listener != null) {
193             listener.onCorrectEnd(this);
194         }
195 
196         locked = false;
197     }
198 
199     /**
200      * Gets type of correction being used.
201      *
202      * @return type of correction.
203      */
204     @Override
205     public CorrectorType getType() {
206         return CorrectorType.SAMPSON_CORRECTOR;
207     }
208 }