1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.ar.epipolar;
17
18 import com.irurueta.algebra.AlgebraException;
19 import com.irurueta.algebra.Complex;
20 import com.irurueta.algebra.Matrix;
21 import com.irurueta.geometry.CoordinatesType;
22 import com.irurueta.geometry.GeometryException;
23 import com.irurueta.geometry.HomogeneousPoint2D;
24 import com.irurueta.geometry.Point2D;
25 import com.irurueta.geometry.ProjectiveTransformation2D;
26 import com.irurueta.geometry.estimators.NotReadyException;
27 import com.irurueta.numerical.NumericalException;
28 import com.irurueta.numerical.roots.LaguerrePolynomialRootsEstimator;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class GoldStandardSingleCorrector extends SingleCorrector {
49
50
51
52
53 private static final double EPS = 1e-6;
54
55
56
57
58 public GoldStandardSingleCorrector() {
59 super();
60 }
61
62
63
64
65
66
67
68 public GoldStandardSingleCorrector(final FundamentalMatrix fundamentalMatrix) {
69 super(fundamentalMatrix);
70 }
71
72
73
74
75
76
77
78 public GoldStandardSingleCorrector(final Point2D leftPoint, final Point2D rightPoint) {
79 super(leftPoint, rightPoint);
80 }
81
82
83
84
85
86
87
88
89 public GoldStandardSingleCorrector(final Point2D leftPoint, final Point2D rightPoint,
90 final FundamentalMatrix fundamentalMatrix) {
91 super(leftPoint, rightPoint, fundamentalMatrix);
92 }
93
94
95
96
97
98
99
100
101 @Override
102 public void correct() throws NotReadyException, CorrectionException {
103 if (!isReady()) {
104 throw new NotReadyException();
105 }
106
107 leftCorrectedPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
108 rightCorrectedPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
109 correct(leftPoint, rightPoint, fundamentalMatrix, leftCorrectedPoint, rightCorrectedPoint);
110 }
111
112
113
114
115
116
117 @Override
118 public CorrectorType getType() {
119 return CorrectorType.GOLD_STANDARD;
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 @SuppressWarnings("DuplicatedCode")
137 public static void correct(
138 final Point2D leftPoint, final Point2D rightPoint, final FundamentalMatrix fundamentalMatrix,
139 final Point2D correctedLeftPoint, final Point2D correctedRightPoint) throws NotReadyException,
140 CorrectionException {
141
142
143 leftPoint.normalize();
144 rightPoint.normalize();
145 fundamentalMatrix.normalize();
146
147 try {
148
149
150 final var leftTranslationMatrix = Matrix.identity(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
151 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
152
153 leftTranslationMatrix.setElementAt(0, 2, -leftPoint.getInhomX());
154 leftTranslationMatrix.setElementAt(1, 2, -leftPoint.getInhomY());
155
156
157 var invLeftTranslationMatrix = Matrix.identity(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
158 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
159
160 invLeftTranslationMatrix.setElementAt(0, 2, leftPoint.getInhomX());
161 invLeftTranslationMatrix.setElementAt(1, 2, leftPoint.getInhomY());
162
163 final var rightTranslationMatrix = Matrix.identity(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
164 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
165
166 rightTranslationMatrix.setElementAt(0, 2, -rightPoint.getInhomX());
167 rightTranslationMatrix.setElementAt(1, 2, -rightPoint.getInhomY());
168
169
170 var invTransRightTranslationMatrix = Matrix.identity(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
171 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
172
173 invTransRightTranslationMatrix.setElementAt(2, 0, rightPoint.getInhomX());
174 invTransRightTranslationMatrix.setElementAt(2, 1, rightPoint.getInhomY());
175
176
177
178
179 var fundInternalMatrix = fundamentalMatrix.getInternalMatrix();
180 fundInternalMatrix.multiply(invLeftTranslationMatrix);
181 invTransRightTranslationMatrix.multiply(fundInternalMatrix);
182
183
184
185
186 final var transformedFundamentalMatrix = new FundamentalMatrix(invTransRightTranslationMatrix);
187 transformedFundamentalMatrix.computeEpipoles();
188 final var leftEpipole = transformedFundamentalMatrix.getLeftEpipole();
189 final var rightEpipole = transformedFundamentalMatrix.getRightEpipole();
190
191
192
193
194 final var normLeftEpipole = Math.pow(leftEpipole.getHomX(), 2.0) + Math.pow(leftEpipole.getHomY(), 2.0);
195 final var normRightEpipole = Math.pow(rightEpipole.getHomX(), 2.0) + Math.pow(rightEpipole.getHomY(), 2.0);
196
197 leftEpipole.setHomogeneousCoordinates(
198 leftEpipole.getHomX() / normLeftEpipole,
199 leftEpipole.getHomY() / normLeftEpipole,
200 leftEpipole.getHomW() / normLeftEpipole);
201 rightEpipole.setHomogeneousCoordinates(
202 rightEpipole.getHomX() / normRightEpipole,
203 rightEpipole.getHomY() / normRightEpipole,
204 rightEpipole.getHomW() / normRightEpipole);
205
206 final var leftRotationMatrix = new Matrix(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
207 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
208 leftRotationMatrix.setElementAt(0, 0, leftEpipole.getHomX());
209 leftRotationMatrix.setElementAt(1, 0, -leftEpipole.getHomY());
210 leftRotationMatrix.setElementAt(0, 1, leftEpipole.getHomY());
211 leftRotationMatrix.setElementAt(1, 1, leftEpipole.getHomX());
212 leftRotationMatrix.setElementAt(2, 2, 1.0);
213
214
215 final var invLeftRotationMatrix = leftRotationMatrix.transposeAndReturnNew();
216
217 final var rightRotationMatrix = new Matrix(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
218 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
219 rightRotationMatrix.setElementAt(0, 0, rightEpipole.getHomX());
220 rightRotationMatrix.setElementAt(1, 0, -rightEpipole.getHomY());
221 rightRotationMatrix.setElementAt(0, 1, rightEpipole.getHomY());
222 rightRotationMatrix.setElementAt(1, 1, rightEpipole.getHomX());
223 rightRotationMatrix.setElementAt(2, 2, 1.0);
224
225
226 final var invRightRotationMatrix = rightRotationMatrix.transposeAndReturnNew();
227
228
229
230 fundInternalMatrix = invTransRightTranslationMatrix;
231 fundInternalMatrix.multiply(invLeftRotationMatrix);
232 rightRotationMatrix.multiply(fundInternalMatrix);
233 invTransRightTranslationMatrix = rightRotationMatrix;
234
235
236
237
238
239
240
241
242 final var a = invTransRightTranslationMatrix.getElementAt(1, 1);
243 final var b = invTransRightTranslationMatrix.getElementAt(1, 2);
244 final var c = invTransRightTranslationMatrix.getElementAt(2, 1);
245 final var d = invTransRightTranslationMatrix.getElementAt(2, 2);
246 final double f1;
247 final double f2;
248 if (Math.abs(b) > Math.abs(d)) {
249 f1 = -invTransRightTranslationMatrix.getElementAt(1, 0) / b;
250 } else {
251 f1 = -invTransRightTranslationMatrix.getElementAt(2, 0) / d;
252 }
253 if (Math.abs(c) > Math.abs(d)) {
254 f2 = -invTransRightTranslationMatrix.getElementAt(0, 1) / c;
255 } else {
256 f2 = -invTransRightTranslationMatrix.getElementAt(0, 2) / d;
257 }
258
259
260
261
262 final var tmp1 = Math.pow(a, 2.0) * d - a * b * c;
263 final var tmp2 = Math.pow(a, 2.0) + Math.pow(c, 2.0) * Math.pow(f2, 2.0);
264 final var tmp3 = a * b * d - Math.pow(b, 2.0) * c;
265 final var tmp4 = tmp3 * c;
266 final var tmp5 = a * b + c * d * Math.pow(f2, 2.0);
267 final var tmp6 = Math.pow(b, 2.0) + Math.pow(d, 2.0) * Math.pow(f2, 2.0);
268
269 final var realA = -tmp1 * c * Math.pow(f1, 4.0);
270 final var realB = Math.pow(tmp2, 2.0) - ((Math.pow(a, 2) * d - a * b * c) * d + tmp4) * Math.pow(f1, 4.0);
271 final var realC = (4.0 * tmp2 * tmp5 - (2.0 * tmp1 * c * Math.pow(f1, 2.0) + tmp3 * d * Math.pow(f1, 4.0)));
272 final var realD = 2.0 * (tmp2 * tmp6 + 2.0 * Math.pow(tmp5, 2.0) - (tmp1 * d + tmp4) * Math.pow(f1, 2.0));
273 final var realE = (4.0 * tmp5 * tmp6 - (tmp1 * c + 2.0 * tmp3 * d * Math.pow(f1, 2.0)));
274 final var realF = (Math.pow(tmp6, 2.0) - (tmp1 * d + tmp4));
275 final var realG = -tmp3 * d;
276
277 final var complexA = new Complex(realA);
278 final var complexB = new Complex(realB);
279 final var complexC = new Complex(realC);
280 final var complexD = new Complex(realD);
281 final var complexE = new Complex(realE);
282 final var complexF = new Complex(realF);
283 final var complexG = new Complex(realG);
284 final var polyParams = new Complex[]{complexG, complexF, complexE, complexD, complexC, complexB, complexA};
285 final var rootEstimator = new LaguerrePolynomialRootsEstimator(polyParams);
286 rootEstimator.estimate();
287 final var roots = rootEstimator.getRoots();
288
289
290
291 var minimum = Double.MAX_VALUE;
292 Complex bestRoot = null;
293 for (final var root : roots) {
294
295 if (Math.abs(root.getImaginary()) > EPS) {
296 continue;
297 }
298
299 final var value = s(root.getReal(), a, b, c, d, f1, f2);
300 if (value < minimum) {
301 minimum = value;
302 bestRoot = root;
303 }
304 }
305
306 if (bestRoot == null) {
307 throw new CorrectionException();
308 }
309
310 final var tmin = bestRoot.getReal();
311
312
313 final var transformedLeftPoint = new HomogeneousPoint2D(
314 -Math.pow(tmin, 2.0) * f1, tmin, 1.0 + Math.pow(tmin * f1, 2.0));
315
316 final var tmp7 = Math.pow(c * tmin + d, 2.0);
317 final var transformedRightPoint = new HomogeneousPoint2D(
318 f2 * tmp7,
319 -(a * tmin + b) * (c * tmin + d),
320 Math.pow(a * tmin + b, 2.0) + Math.pow(f2, 2.0) * tmp7);
321
322
323
324
325
326
327 invLeftTranslationMatrix = Matrix.identity(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
328 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
329
330 invLeftTranslationMatrix.setElementAt(0, 2, leftPoint.getInhomX());
331 invLeftTranslationMatrix.setElementAt(1, 2, leftPoint.getInhomY());
332
333
334 final var invRightTranslationMatrix = Matrix.identity(Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH,
335 Point2D.POINT2D_HOMOGENEOUS_COORDINATES_LENGTH);
336
337 invRightTranslationMatrix.setElementAt(0, 2, rightPoint.getInhomX());
338 invRightTranslationMatrix.setElementAt(1, 2, rightPoint.getInhomY());
339
340 invLeftTranslationMatrix.multiply(invLeftRotationMatrix);
341 final var invLeftTransformationMatrix = invLeftTranslationMatrix;
342 invRightTranslationMatrix.multiply(invRightRotationMatrix);
343
344 final var invLeftTransformation = new ProjectiveTransformation2D(invLeftTransformationMatrix);
345 final var invRightTransformation = new ProjectiveTransformation2D(invRightTranslationMatrix);
346
347 invLeftTransformation.transform(transformedLeftPoint, correctedLeftPoint);
348 invRightTransformation.transform(transformedRightPoint, correctedRightPoint);
349
350 } catch (final AlgebraException | GeometryException | NumericalException e) {
351 throw new CorrectionException(e);
352 }
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 private static double s(final double t, final double a, final double b, final double c,
369 final double d, final double f1, final double f2) {
370 final var tmp = Math.pow(c * t + d, 2.0);
371 return Math.pow(t, 2.0) / (1 + Math.pow(t * f1, 2.0)) + tmp / (Math.pow(a * t + b, 2.0)
372 + Math.pow(f2, 2.0) * tmp);
373 }
374 }