32
32
K = gtsam .symbol_shorthand .K
33
33
34
34
# Methods to compare
35
- methods = ["SimpleF" , "Fundamental" , "Essential+Ks" , "Calibrated" ]
35
+ methods = ["SimpleF" , "Fundamental" , "Essential+Ks" , "Essential+K" , " Calibrated" , "Binary+Ks" , "Binary+K " ]
36
36
37
37
38
38
# Formatter function for printing keys
@@ -76,8 +76,8 @@ def simulate_data(points, poses, cal, rng, noise_std):
76
76
return measurements
77
77
78
78
79
- # Function to compute ground truth matrices
80
79
def compute_ground_truth (method , poses , cal ):
80
+ """Function to compute ground truth edge variables."""
81
81
E1 = EssentialMatrix .FromPose3 (poses [0 ].between (poses [1 ]))
82
82
E2 = EssentialMatrix .FromPose3 (poses [0 ].between (poses [2 ]))
83
83
F1 = FundamentalMatrix (cal .K (), E1 , cal .K ())
@@ -90,58 +90,80 @@ def compute_ground_truth(method, poses, cal):
90
90
SF1 = SimpleFundamentalMatrix (E1 , f , f , c , c )
91
91
SF2 = SimpleFundamentalMatrix (E2 , f , f , c , c )
92
92
return SF1 , SF2
93
- elif method == "Essential+Ks" or method == "Calibrated" :
94
- return E1 , E2
95
93
else :
96
- raise ValueError ( f"Unknown method { method } " )
94
+ return E1 , E2
97
95
98
96
99
97
def build_factor_graph (method , num_cameras , measurements , cal ):
100
98
"""build the factor graph"""
101
99
graph = NonlinearFactorGraph ()
102
100
101
+ # Determine the FactorClass based on the method
103
102
if method == "Fundamental" :
104
103
FactorClass = gtsam .TransferFactorFundamentalMatrix
105
104
elif method == "SimpleF" :
106
105
FactorClass = gtsam .TransferFactorSimpleFundamentalMatrix
107
- elif method == "Essential+Ks" :
106
+ elif method in [ "Essential+Ks" , "Essential+K" ] :
108
107
FactorClass = gtsam .EssentialTransferFactorKCal3f
109
- # add priors on all calibrations :
110
- for i in range ( num_cameras ):
111
- model = gtsam . noiseModel . Isotropic . Sigma ( 1 , 10.0 )
112
- graph . addPriorCal3f ( K ( i ), cal , model )
108
+ elif method == "Binary+K" :
109
+ FactorClass = gtsam . EssentialMatrixFactor4Cal3f
110
+ elif method == "Binary+Ks" :
111
+ FactorClass = gtsam . EssentialMatrixFactor5Cal3f
113
112
elif method == "Calibrated" :
114
113
FactorClass = gtsam .EssentialTransferFactorCal3f
115
- # No priors on calibration needed
116
114
else :
117
115
raise ValueError (f"Unknown method { method } " )
118
116
117
+ # Add priors on calibrations if necessary
118
+ if method in ["Essential+Ks" , "Binary+Ks" ]:
119
+ for i in range (num_cameras ):
120
+ model = gtsam .noiseModel .Isotropic .Sigma (1 , 10.0 )
121
+ graph .addPriorCal3f (K (i ), cal , model )
122
+ elif method in ["Essential+K" , "Binary+K" ]:
123
+ model = gtsam .noiseModel .Isotropic .Sigma (1 , 10.0 )
124
+ graph .addPriorCal3f (K (0 ), cal , model )
125
+
119
126
z = measurements # shorthand
120
127
121
128
for a in range (num_cameras ):
122
129
b = (a + 1 ) % num_cameras # Next camera
123
130
c = (a + 2 ) % num_cameras # Camera after next
124
-
125
- # Vectors to collect tuples for each factor
126
- tuples1 = []
127
- tuples2 = []
128
- tuples3 = []
129
-
130
- # Collect data for the three factors
131
- for j in range (len (measurements [0 ])):
132
- tuples1 .append ((z [a ][j ], z [b ][j ], z [c ][j ]))
133
- tuples2 .append ((z [a ][j ], z [c ][j ], z [b ][j ]))
134
- tuples3 .append ((z [c ][j ], z [b ][j ], z [a ][j ]))
135
-
136
- # Add transfer factors between views a, b, and c.
137
- if method in ["Calibrated" ]:
138
- graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (b , c ), tuples1 , cal ))
139
- graph .add (FactorClass (EdgeKey (a , b ), EdgeKey (b , c ), tuples2 , cal ))
140
- graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (a , b ), tuples3 , cal ))
131
+ if method in ["Binary+Ks" , "Binary+K" ]:
132
+ # Add binary Essential Matrix factors
133
+ ab , ac = EdgeKey (a , b ).key (), EdgeKey (a , c ).key ()
134
+ for j in range (len (measurements [0 ])):
135
+ if method == "Binary+Ks" :
136
+ graph .add (FactorClass (ab , K (a ), K (b ), z [a ][j ], z [b ][j ]))
137
+ graph .add (FactorClass (ac , K (a ), K (c ), z [a ][j ], z [c ][j ]))
138
+ else : # Binary+K
139
+ graph .add (FactorClass (ab , K (0 ), z [a ][j ], z [b ][j ]))
140
+ graph .add (FactorClass (ac , K (0 ), z [a ][j ], z [c ][j ]))
141
141
else :
142
- graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (b , c ), tuples1 ))
143
- graph .add (FactorClass (EdgeKey (a , b ), EdgeKey (b , c ), tuples2 ))
144
- graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (a , b ), tuples3 ))
142
+ # Add transfer factors between views a, b, and c
143
+
144
+ # Vectors to collect tuples for each factor
145
+ tuples1 = []
146
+ tuples2 = []
147
+ tuples3 = []
148
+
149
+ for j in range (len (measurements [0 ])):
150
+ tuples1 .append ((z [a ][j ], z [b ][j ], z [c ][j ]))
151
+ tuples2 .append ((z [a ][j ], z [c ][j ], z [b ][j ]))
152
+ tuples3 .append ((z [c ][j ], z [b ][j ], z [a ][j ]))
153
+
154
+ # Add transfer factors between views a, b, and c.
155
+ if method in ["Calibrated" ]:
156
+ graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (b , c ), tuples1 , cal ))
157
+ graph .add (FactorClass (EdgeKey (a , b ), EdgeKey (b , c ), tuples2 , cal ))
158
+ graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (a , b ), tuples3 , cal ))
159
+ elif method == "Essential+K" :
160
+ graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (b , c ), K (0 ), tuples1 ))
161
+ graph .add (FactorClass (EdgeKey (a , b ), EdgeKey (b , c ), K (0 ), tuples2 ))
162
+ graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (a , b ), K (0 ), tuples3 ))
163
+ else :
164
+ graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (b , c ), tuples1 ))
165
+ graph .add (FactorClass (EdgeKey (a , b ), EdgeKey (b , c ), tuples2 ))
166
+ graph .add (FactorClass (EdgeKey (a , c ), EdgeKey (a , b ), tuples3 ))
145
167
146
168
return graph
147
169
@@ -159,22 +181,23 @@ def get_initial_estimate(method, num_cameras, ground_truth, cal):
159
181
initialEstimate .insert (EdgeKey (a , b ).key (), F1 )
160
182
initialEstimate .insert (EdgeKey (a , c ).key (), F2 )
161
183
total_dimension += F1 .dim () + F2 .dim ()
162
- elif method in ["Essential+Ks" , "Calibrated" ]:
184
+ elif method in ["Essential+Ks" , "Essential+K" , "Binary+Ks" , "Binary+K" , " Calibrated" ]:
163
185
E1 , E2 = ground_truth
164
186
for a in range (num_cameras ):
165
- b = (a + 1 ) % num_cameras # Next camera
166
- c = (a + 2 ) % num_cameras # Camera after next
187
+ b = (a + 1 ) % num_cameras
188
+ c = (a + 2 ) % num_cameras
167
189
initialEstimate .insert (EdgeKey (a , b ).key (), E1 )
168
190
initialEstimate .insert (EdgeKey (a , c ).key (), E2 )
169
191
total_dimension += E1 .dim () + E2 .dim ()
170
- else :
171
- raise ValueError (f"Unknown method { method } " )
172
192
173
- if method == "Essential+Ks" :
174
- # Insert initial calibrations
193
+ # Insert initial calibrations
194
+ if method in [ "Essential+Ks" , "Binary+Ks" ]:
175
195
for i in range (num_cameras ):
176
196
initialEstimate .insert (K (i ), cal )
177
197
total_dimension += cal .dim ()
198
+ elif method in ["Essential+K" , "Binary+K" ]:
199
+ initialEstimate .insert (K (0 ), cal )
200
+ total_dimension += cal .dim ()
178
201
179
202
print (f"Total dimension of the problem: { total_dimension } " )
180
203
return initialEstimate
@@ -205,7 +228,7 @@ def compute_distances(method, result, ground_truth, num_cameras, cal):
205
228
key_ab = EdgeKey (a , b ).key ()
206
229
key_ac = EdgeKey (a , c ).key ()
207
230
208
- if method in ["Essential+Ks" , "Calibrated" ]:
231
+ if method in ["Essential+Ks" , "Essential+K" , "Binary+Ks" , "Binary+K" , " Calibrated" ]:
209
232
E_est_ab = result .atEssentialMatrix (key_ab )
210
233
E_est_ac = result .atEssentialMatrix (key_ac )
211
234
@@ -218,15 +241,18 @@ def compute_distances(method, result, ground_truth, num_cameras, cal):
218
241
SF_est_ac = result .atSimpleFundamentalMatrix (key_ac ).matrix ()
219
242
F_est_ab = FundamentalMatrix (SF_est_ab )
220
243
F_est_ac = FundamentalMatrix (SF_est_ac )
221
- elif method == "Essential+Ks" :
222
- # Retrieve calibrations from result:
244
+ elif method in [ "Essential+Ks" , "Binary+Ks" ] :
245
+ # Retrieve calibrations from result for each camera
223
246
cal_a = result .atCal3f (K (a ))
224
247
cal_b = result .atCal3f (K (b ))
225
248
cal_c = result .atCal3f (K (c ))
226
-
227
- # Convert estimated EssentialMatrices to FundamentalMatrices
228
249
F_est_ab = FundamentalMatrix (cal_a .K (), E_est_ab , cal_b .K ())
229
250
F_est_ac = FundamentalMatrix (cal_a .K (), E_est_ac , cal_c .K ())
251
+ elif method in ["Essential+K" , "Binary+K" ]:
252
+ # Use single shared calibration
253
+ cal_shared = result .atCal3f (K (0 ))
254
+ F_est_ab = FundamentalMatrix (cal_shared .K (), E_est_ab , cal_shared .K ())
255
+ F_est_ac = FundamentalMatrix (cal_shared .K (), E_est_ac , cal_shared .K ())
230
256
elif method == "Calibrated" :
231
257
# Use ground truth calibration
232
258
F_est_ab = FundamentalMatrix (cal .K (), E_est_ab , cal .K ())
0 commit comments