1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.geometry.estimators;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.algebra.SingularValueDecomposer;
20 import com.irurueta.geometry.PinholeCamera;
21 import com.irurueta.geometry.Point2D;
22 import com.irurueta.geometry.Point3D;
23
24 import java.util.List;
25
26
27
28
29
30 @SuppressWarnings("DuplicatedCode")
31 public class DLTPointCorrespondencePinholeCameraEstimator extends PointCorrespondencePinholeCameraEstimator {
32
33
34
35
36 public static final int MIN_NUMBER_OF_EQUATIONS = 11;
37
38
39
40
41
42 public static final boolean DEFAULT_ALLOW_LMSE_SOLUTION = false;
43
44
45
46
47
48
49
50 private boolean allowLMSESolution;
51
52
53
54
55 public DLTPointCorrespondencePinholeCameraEstimator() {
56 super();
57 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
58 }
59
60
61
62
63
64
65
66 public DLTPointCorrespondencePinholeCameraEstimator(final PinholeCameraEstimatorListener listener) {
67 super(listener);
68 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
69 }
70
71
72
73
74
75
76
77
78
79
80 public DLTPointCorrespondencePinholeCameraEstimator(
81 final List<Point3D> points3D, final List<Point2D> points2D) throws WrongListSizesException {
82 super(points3D, points2D);
83 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97 public DLTPointCorrespondencePinholeCameraEstimator(
98 final List<Point3D> points3D, final List<Point2D> points2D, final PinholeCameraEstimatorListener listener)
99 throws WrongListSizesException {
100 super(points3D, points2D, listener);
101 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
102 }
103
104
105
106
107
108
109
110
111
112 public boolean isLMSESolutionAllowed() {
113 return allowLMSESolution;
114 }
115
116
117
118
119
120
121
122
123
124
125 public void setLMSESolutionAllowed(final boolean allowed) throws LockedException {
126 if (isLocked()) {
127 throw new LockedException();
128 }
129 allowLMSESolution = allowed;
130 }
131
132
133
134
135
136
137 @Override
138 public boolean isReady() {
139 return areListsAvailable() && areValidLists(points3D, points2D);
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 @Override
157 protected Matrix internalEstimate(
158 final List<Point3D> points3D, final List<Point2D> points2D) throws PinholeCameraEstimatorException {
159
160 try {
161 final var nPoints = points2D.size();
162
163 final Matrix a;
164 if (isLMSESolutionAllowed()) {
165
166 a = new Matrix(2 * nPoints, 12);
167 } else {
168
169
170 a = new Matrix(MIN_NUMBER_OF_EQUATIONS, 12);
171 }
172
173 final var iterator2D = points2D.iterator();
174 final var iterator3D = points3D.iterator();
175
176 Point2D point2D;
177 Point3D point3D;
178 var counter = 0;
179 double homImageX;
180 double homImageY;
181 double homImageW;
182 double homWorldX;
183 double homWorldY;
184 double homWorldZ;
185 double homWorldW;
186 double rowNorm;
187 while (iterator2D.hasNext() && iterator3D.hasNext()) {
188 point2D = iterator2D.next();
189 point3D = iterator3D.next();
190
191
192 point2D.normalize();
193 point3D.normalize();
194
195 homImageX = point2D.getHomX();
196 homImageY = point2D.getHomY();
197 homImageW = point2D.getHomW();
198
199 homWorldX = point3D.getHomX();
200 homWorldY = point3D.getHomY();
201 homWorldZ = point3D.getHomZ();
202 homWorldW = point3D.getHomW();
203
204
205 a.setElementAt(counter, 0, homImageW * homWorldX);
206 a.setElementAt(counter, 1, homImageW * homWorldY);
207 a.setElementAt(counter, 2, homImageW * homWorldZ);
208 a.setElementAt(counter, 3, homImageW * homWorldW);
209
210
211
212 a.setElementAt(counter, 8, -homImageX * homWorldX);
213 a.setElementAt(counter, 9, -homImageX * homWorldY);
214 a.setElementAt(counter, 10, -homImageX * homWorldZ);
215 a.setElementAt(counter, 11, -homImageX * homWorldW);
216
217
218 rowNorm = Math.sqrt(Math.pow(a.getElementAt(counter, 0), 2.0)
219 + Math.pow(a.getElementAt(counter, 1), 2.0)
220 + Math.pow(a.getElementAt(counter, 2), 2.0)
221 + Math.pow(a.getElementAt(counter, 3), 2.0)
222 + Math.pow(a.getElementAt(counter, 8), 2.0)
223 + Math.pow(a.getElementAt(counter, 9), 2.0)
224 + Math.pow(a.getElementAt(counter, 10), 2.0)
225 + Math.pow(a.getElementAt(counter, 11), 2.0));
226
227 a.setElementAt(counter, 0, a.getElementAt(counter, 0) / rowNorm);
228 a.setElementAt(counter, 1, a.getElementAt(counter, 1) / rowNorm);
229 a.setElementAt(counter, 2, a.getElementAt(counter, 2) / rowNorm);
230 a.setElementAt(counter, 3, a.getElementAt(counter, 3) / rowNorm);
231 a.setElementAt(counter, 8, a.getElementAt(counter, 8) / rowNorm);
232 a.setElementAt(counter, 9, a.getElementAt(counter, 9) / rowNorm);
233 a.setElementAt(counter, 10, a.getElementAt(counter, 10) / rowNorm);
234 a.setElementAt(counter, 11, a.getElementAt(counter, 11) / rowNorm);
235 counter++;
236
237
238
239 if (!isLMSESolutionAllowed() && (counter >= MIN_NUMBER_OF_EQUATIONS)) {
240 break;
241 }
242
243
244
245
246
247 a.setElementAt(counter, 4, homImageW * homWorldX);
248 a.setElementAt(counter, 5, homImageW * homWorldY);
249 a.setElementAt(counter, 6, homImageW * homWorldZ);
250 a.setElementAt(counter, 7, homImageW * homWorldW);
251
252 a.setElementAt(counter, 8, -homImageY * homWorldX);
253 a.setElementAt(counter, 9, -homImageY * homWorldY);
254 a.setElementAt(counter, 10, -homImageY * homWorldZ);
255 a.setElementAt(counter, 11, -homImageY * homWorldW);
256
257
258 rowNorm = Math.sqrt(Math.pow(a.getElementAt(counter, 4), 2.0)
259 + Math.pow(a.getElementAt(counter, 5), 2.0)
260 + Math.pow(a.getElementAt(counter, 6), 2.0)
261 + Math.pow(a.getElementAt(counter, 7), 2.0)
262 + Math.pow(a.getElementAt(counter, 8), 2.0)
263 + Math.pow(a.getElementAt(counter, 9), 2.0)
264 + Math.pow(a.getElementAt(counter, 10), 2.0)
265 + Math.pow(a.getElementAt(counter, 11), 2.0));
266
267 a.setElementAt(counter, 4, a.getElementAt(counter, 4) / rowNorm);
268 a.setElementAt(counter, 5, a.getElementAt(counter, 5) / rowNorm);
269 a.setElementAt(counter, 6, a.getElementAt(counter, 6) / rowNorm);
270 a.setElementAt(counter, 7, a.getElementAt(counter, 7) / rowNorm);
271 a.setElementAt(counter, 8, a.getElementAt(counter, 8) / rowNorm);
272 a.setElementAt(counter, 9, a.getElementAt(counter, 9) / rowNorm);
273 a.setElementAt(counter, 10, a.getElementAt(counter, 10) / rowNorm);
274 a.setElementAt(counter, 11, a.getElementAt(counter, 11) / rowNorm);
275 counter++;
276 }
277
278 final var decomposer = new SingularValueDecomposer(a);
279 decomposer.decompose();
280
281 if (decomposer.getNullity() > 1) {
282
283
284
285 throw new PinholeCameraEstimatorException();
286 }
287
288 final var v = decomposer.getV();
289
290
291
292
293
294
295 final var pinholeCameraMatrix = new Matrix(
296 PinholeCamera.PINHOLE_CAMERA_MATRIX_ROWS, PinholeCamera.PINHOLE_CAMERA_MATRIX_COLS);
297
298 pinholeCameraMatrix.setElementAt(0, 0, v.getElementAt(0, 11));
299 pinholeCameraMatrix.setElementAt(0, 1, v.getElementAt(1, 11));
300 pinholeCameraMatrix.setElementAt(0, 2, v.getElementAt(2, 11));
301 pinholeCameraMatrix.setElementAt(0, 3, v.getElementAt(3, 11));
302
303 pinholeCameraMatrix.setElementAt(1, 0, v.getElementAt(4, 11));
304 pinholeCameraMatrix.setElementAt(1, 1, v.getElementAt(5, 11));
305 pinholeCameraMatrix.setElementAt(1, 2, v.getElementAt(6, 11));
306 pinholeCameraMatrix.setElementAt(1, 3, v.getElementAt(7, 11));
307
308 pinholeCameraMatrix.setElementAt(2, 0, v.getElementAt(8, 11));
309 pinholeCameraMatrix.setElementAt(2, 1, v.getElementAt(9, 11));
310 pinholeCameraMatrix.setElementAt(2, 2, v.getElementAt(10, 11));
311 pinholeCameraMatrix.setElementAt(2, 3, v.getElementAt(11, 11));
312
313
314
315
316
317 return pinholeCameraMatrix;
318
319 } catch (final PinholeCameraEstimatorException e) {
320 throw e;
321 } catch (final Exception e) {
322 throw new PinholeCameraEstimatorException(e);
323 }
324 }
325
326
327
328
329
330
331 @Override
332 public PinholeCameraEstimatorType getType() {
333 return PinholeCameraEstimatorType.DLT_POINT_PINHOLE_CAMERA_ESTIMATOR;
334 }
335 }