Compare in F-manifold
parent
fcf51faf0c
commit
5ce728ab46
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Compare the Fundamental Matrix and Essential Matrix methods for optimizing the view-graph.
|
||||
It measures the distance from the ground truth matrices in terms of the norm of local coordinates (geodesic distance)
|
||||
on the respective manifolds. It also plots the final error of the optimization.
|
||||
on the F-manifold. It also plots the final error of the optimization.
|
||||
Author: Frank Dellaert (with heavy assist from ChatGPT)
|
||||
Date: October 2024
|
||||
"""
|
||||
|
@ -113,18 +113,18 @@ def build_factor_graph(method, num_cameras, measurements):
|
|||
|
||||
|
||||
# Function to get initial estimates
|
||||
def get_initial_estimate(method, num_cameras, ground_truth_matrices, K_initial):
|
||||
def get_initial_estimate(method, num_cameras, ground_truth, K):
|
||||
initialEstimate = Values()
|
||||
|
||||
if method == "FundamentalMatrix":
|
||||
F1, F2 = ground_truth_matrices
|
||||
F1, F2 = ground_truth
|
||||
for a in range(num_cameras):
|
||||
b = (a + 1) % num_cameras # Next camera
|
||||
c = (a + 2) % num_cameras # Camera after next
|
||||
initialEstimate.insert(EdgeKey(a, b).key(), F1)
|
||||
initialEstimate.insert(EdgeKey(a, c).key(), F2)
|
||||
elif method == "EssentialMatrix":
|
||||
E1, E2 = ground_truth_matrices
|
||||
E1, E2 = ground_truth
|
||||
for a in range(num_cameras):
|
||||
b = (a + 1) % num_cameras # Next camera
|
||||
c = (a + 2) % num_cameras # Camera after next
|
||||
|
@ -132,7 +132,7 @@ def get_initial_estimate(method, num_cameras, ground_truth_matrices, K_initial):
|
|||
initialEstimate.insert(EdgeKey(a, c).key(), E2)
|
||||
# Insert initial calibrations
|
||||
for i in range(num_cameras):
|
||||
initialEstimate.insert(K_sym(i), K_initial)
|
||||
initialEstimate.insert(K_sym(i), K)
|
||||
else:
|
||||
raise ValueError(f"Unknown method {method}")
|
||||
|
||||
|
@ -150,38 +150,43 @@ def optimize(graph, initialEstimate):
|
|||
|
||||
|
||||
# Function to compute distances from ground truth
|
||||
def compute_distances(method, result, ground_truth_matrices, num_cameras):
|
||||
def compute_distances(method, result, ground_truth, num_cameras, K):
|
||||
distances = []
|
||||
|
||||
if method == "FundamentalMatrix":
|
||||
F1, F2 = ground_truth_matrices
|
||||
F1, F2 = ground_truth
|
||||
elif method == "EssentialMatrix":
|
||||
E1, E2 = ground_truth
|
||||
# Convert ground truth EssentialMatrices to FundamentalMatrices using GTSAM method
|
||||
F1 = gtsam.FundamentalMatrix(K, E1, K)
|
||||
F2 = gtsam.FundamentalMatrix(K, E2, K)
|
||||
else:
|
||||
raise ValueError(f"Unknown method {method}")
|
||||
|
||||
for a in range(num_cameras):
|
||||
b = (a + 1) % num_cameras
|
||||
c = (a + 2) % num_cameras
|
||||
key_ab = EdgeKey(a, b).key()
|
||||
key_ac = EdgeKey(a, c).key()
|
||||
|
||||
if method == "FundamentalMatrix":
|
||||
F_est_ab = result.atFundamentalMatrix(key_ab)
|
||||
F_est_ac = result.atFundamentalMatrix(key_ac)
|
||||
# Compute local coordinates
|
||||
elif method == "EssentialMatrix":
|
||||
E_est_ab = result.atEssentialMatrix(key_ab)
|
||||
E_est_ac = result.atEssentialMatrix(key_ac)
|
||||
# Convert estimated EssentialMatrices to FundamentalMatrices using GTSAM method
|
||||
F_est_ab = gtsam.FundamentalMatrix(K, E_est_ab, K)
|
||||
F_est_ac = gtsam.FundamentalMatrix(K, E_est_ac, K)
|
||||
else:
|
||||
raise ValueError(f"Unknown method {method}")
|
||||
|
||||
# Compute local coordinates (geodesic distance on the F-manifold)
|
||||
dist_ab = np.linalg.norm(F1.localCoordinates(F_est_ab))
|
||||
dist_ac = np.linalg.norm(F2.localCoordinates(F_est_ac))
|
||||
distances.append(dist_ab)
|
||||
distances.append(dist_ac)
|
||||
elif method == "EssentialMatrix":
|
||||
E1, E2 = ground_truth_matrices
|
||||
for a in range(num_cameras):
|
||||
b = (a + 1) % num_cameras
|
||||
c = (a + 2) % num_cameras
|
||||
key_ab = EdgeKey(a, b).key()
|
||||
key_ac = EdgeKey(a, c).key()
|
||||
E_est_ab = result.atEssentialMatrix(key_ab)
|
||||
E_est_ac = result.atEssentialMatrix(key_ac)
|
||||
# Compute local coordinates
|
||||
dist_ab = np.linalg.norm(E1.localCoordinates(E_est_ab))
|
||||
dist_ac = np.linalg.norm(E2.localCoordinates(E_est_ac))
|
||||
distances.append(dist_ab)
|
||||
distances.append(dist_ac)
|
||||
else:
|
||||
raise ValueError(f"Unknown method {method}")
|
||||
|
||||
return distances
|
||||
|
||||
|
||||
|
@ -224,22 +229,22 @@ def main():
|
|||
print(f"Running method: {method}")
|
||||
|
||||
# Simulate data
|
||||
points, poses, measurements, K_initial = simulate_data(args.num_cameras)
|
||||
points, poses, measurements, K = simulate_data(args.num_cameras)
|
||||
|
||||
# Compute ground truth matrices
|
||||
ground_truth_matrices = compute_ground_truth_matrices(method, poses, K_initial)
|
||||
ground_truth = compute_ground_truth_matrices(method, poses, K)
|
||||
|
||||
# Build the factor graph
|
||||
graph = build_factor_graph(method, args.num_cameras, measurements)
|
||||
|
||||
# Get initial estimates
|
||||
initialEstimate = get_initial_estimate(method, args.num_cameras, ground_truth_matrices, K_initial)
|
||||
initialEstimate = get_initial_estimate(method, args.num_cameras, ground_truth, K)
|
||||
|
||||
# Optimize the graph
|
||||
result = optimize(graph, initialEstimate)
|
||||
|
||||
# Compute distances from ground truth
|
||||
distances = compute_distances(method, result, ground_truth_matrices, args.num_cameras)
|
||||
distances = compute_distances(method, result, ground_truth, args.num_cameras, K)
|
||||
|
||||
# Compute final error
|
||||
final_error = graph.error(result)
|
||||
|
|
Loading…
Reference in New Issue