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.
|
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)
|
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)
|
Author: Frank Dellaert (with heavy assist from ChatGPT)
|
||||||
Date: October 2024
|
Date: October 2024
|
||||||
"""
|
"""
|
||||||
|
@ -113,18 +113,18 @@ def build_factor_graph(method, num_cameras, measurements):
|
||||||
|
|
||||||
|
|
||||||
# Function to get initial estimates
|
# 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()
|
initialEstimate = Values()
|
||||||
|
|
||||||
if method == "FundamentalMatrix":
|
if method == "FundamentalMatrix":
|
||||||
F1, F2 = ground_truth_matrices
|
F1, F2 = ground_truth
|
||||||
for a in range(num_cameras):
|
for a in range(num_cameras):
|
||||||
b = (a + 1) % num_cameras # Next camera
|
b = (a + 1) % num_cameras # Next camera
|
||||||
c = (a + 2) % num_cameras # Camera after next
|
c = (a + 2) % num_cameras # Camera after next
|
||||||
initialEstimate.insert(EdgeKey(a, b).key(), F1)
|
initialEstimate.insert(EdgeKey(a, b).key(), F1)
|
||||||
initialEstimate.insert(EdgeKey(a, c).key(), F2)
|
initialEstimate.insert(EdgeKey(a, c).key(), F2)
|
||||||
elif method == "EssentialMatrix":
|
elif method == "EssentialMatrix":
|
||||||
E1, E2 = ground_truth_matrices
|
E1, E2 = ground_truth
|
||||||
for a in range(num_cameras):
|
for a in range(num_cameras):
|
||||||
b = (a + 1) % num_cameras # Next camera
|
b = (a + 1) % num_cameras # Next camera
|
||||||
c = (a + 2) % num_cameras # Camera after next
|
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)
|
initialEstimate.insert(EdgeKey(a, c).key(), E2)
|
||||||
# Insert initial calibrations
|
# Insert initial calibrations
|
||||||
for i in range(num_cameras):
|
for i in range(num_cameras):
|
||||||
initialEstimate.insert(K_sym(i), K_initial)
|
initialEstimate.insert(K_sym(i), K)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unknown method {method}")
|
raise ValueError(f"Unknown method {method}")
|
||||||
|
|
||||||
|
@ -150,38 +150,43 @@ def optimize(graph, initialEstimate):
|
||||||
|
|
||||||
|
|
||||||
# Function to compute distances from ground truth
|
# 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 = []
|
distances = []
|
||||||
|
|
||||||
if method == "FundamentalMatrix":
|
if method == "FundamentalMatrix":
|
||||||
F1, F2 = ground_truth_matrices
|
F1, F2 = ground_truth
|
||||||
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()
|
|
||||||
F_est_ab = result.atFundamentalMatrix(key_ab)
|
|
||||||
F_est_ac = result.atFundamentalMatrix(key_ac)
|
|
||||||
# Compute local coordinates
|
|
||||||
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":
|
elif method == "EssentialMatrix":
|
||||||
E1, E2 = ground_truth_matrices
|
E1, E2 = ground_truth
|
||||||
for a in range(num_cameras):
|
# Convert ground truth EssentialMatrices to FundamentalMatrices using GTSAM method
|
||||||
b = (a + 1) % num_cameras
|
F1 = gtsam.FundamentalMatrix(K, E1, K)
|
||||||
c = (a + 2) % num_cameras
|
F2 = gtsam.FundamentalMatrix(K, E2, K)
|
||||||
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:
|
else:
|
||||||
raise ValueError(f"Unknown method {method}")
|
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)
|
||||||
|
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)
|
||||||
|
|
||||||
return distances
|
return distances
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,22 +229,22 @@ def main():
|
||||||
print(f"Running method: {method}")
|
print(f"Running method: {method}")
|
||||||
|
|
||||||
# Simulate data
|
# 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
|
# 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
|
# Build the factor graph
|
||||||
graph = build_factor_graph(method, args.num_cameras, measurements)
|
graph = build_factor_graph(method, args.num_cameras, measurements)
|
||||||
|
|
||||||
# Get initial estimates
|
# 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
|
# Optimize the graph
|
||||||
result = optimize(graph, initialEstimate)
|
result = optimize(graph, initialEstimate)
|
||||||
|
|
||||||
# Compute distances from ground truth
|
# 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
|
# Compute final error
|
||||||
final_error = graph.error(result)
|
final_error = graph.error(result)
|
||||||
|
|
Loading…
Reference in New Issue