Switch to using Cal3f

release/4.3a0
Frank Dellaert 2024-10-26 23:53:20 -07:00
parent 0477d20695
commit b9dc9ae459
5 changed files with 41 additions and 48 deletions

View File

@ -16,7 +16,7 @@
* @date October 2024 * @date October 2024
*/ */
#include <gtsam/geometry/Cal3_S2.h> #include <gtsam/geometry/Cal3f.h>
#include <gtsam/geometry/EssentialMatrix.h> #include <gtsam/geometry/EssentialMatrix.h>
#include <gtsam/geometry/PinholeCamera.h> #include <gtsam/geometry/PinholeCamera.h>
#include <gtsam/geometry/Point2.h> #include <gtsam/geometry/Point2.h>
@ -40,7 +40,7 @@ using namespace symbol_shorthand; // For K(symbol)
// Main function // Main function
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Define the camera calibration parameters // Define the camera calibration parameters
Cal3_S2 K_initial(50.0, 50.0, 0.0, 50.0, 50.0); Cal3f cal(50.0, 50.0, 50.0);
// Create the set of 8 ground-truth landmarks // Create the set of 8 ground-truth landmarks
vector<Point3> points = createPoints(); vector<Point3> points = createPoints();
@ -55,7 +55,7 @@ int main(int argc, char* argv[]) {
// Simulate measurements from each camera pose // Simulate measurements from each camera pose
std::array<std::array<Point2, 8>, 4> p; std::array<std::array<Point2, 8>, 4> p;
for (size_t i = 0; i < 4; ++i) { for (size_t i = 0; i < 4; ++i) {
PinholeCamera<Cal3_S2> camera(poses[i], K_initial); PinholeCamera<Cal3f> camera(poses[i], cal);
for (size_t j = 0; j < 8; ++j) { for (size_t j = 0; j < 8; ++j) {
p[i][j] = camera.project(points[j]); p[i][j] = camera.project(points[j]);
} }
@ -63,7 +63,7 @@ int main(int argc, char* argv[]) {
// Create the factor graph // Create the factor graph
NonlinearFactorGraph graph; NonlinearFactorGraph graph;
using Factor = EssentialTransferFactor<Cal3_S2>; using Factor = EssentialTransferFactor<Cal3f>;
for (size_t a = 0; a < 4; ++a) { for (size_t a = 0; a < 4; ++a) {
size_t b = (a + 1) % 4; // Next camera size_t b = (a + 1) % 4; // Next camera
@ -113,7 +113,7 @@ int main(int argc, char* argv[]) {
// Insert initial calibrations (using K symbol) // Insert initial calibrations (using K symbol)
for (size_t i = 0; i < 4; ++i) { for (size_t i = 0; i < 4; ++i) {
initialEstimate.insert(K(i), K_initial); initialEstimate.insert(K(i), cal);
} }
initialEstimate.print("Initial Estimates:\n", formatter); initialEstimate.print("Initial Estimates:\n", formatter);

View File

@ -114,7 +114,7 @@ int main(int argc, char* argv[]) {
initialEstimate.insert(EdgeKey(a, c), F2.retract(delta)); initialEstimate.insert(EdgeKey(a, c), F2.retract(delta));
} }
initialEstimate.print("Initial Estimates:\n", formatter); initialEstimate.print("Initial Estimates:\n", formatter);
graph.printErrors(initialEstimate, "errors: ", formatter); graph.printErrors(initialEstimate, "errors: ", formatter);
/* Optimize the graph and print results */ /* Optimize the graph and print results */
LevenbergMarquardtParams params; LevenbergMarquardtParams params;

View File

@ -18,10 +18,10 @@ import numpy as np
from gtsam.examples import SFMdata from gtsam.examples import SFMdata
import gtsam import gtsam
from gtsam import Cal3_S2, EdgeKey, EssentialMatrix from gtsam import Cal3f, EdgeKey, EssentialMatrix
from gtsam import EssentialTransferFactorCal3_S2 as Factor from gtsam import EssentialTransferFactorCal3f as Factor
from gtsam import (LevenbergMarquardtOptimizer, LevenbergMarquardtParams, from gtsam import (LevenbergMarquardtOptimizer, LevenbergMarquardtParams,
NonlinearFactorGraph, PinholeCameraCal3_S2, Values) NonlinearFactorGraph, PinholeCameraCal3f, Values)
# For symbol shorthand (e.g., X(0), L(1)) # For symbol shorthand (e.g., X(0), L(1))
K = gtsam.symbol_shorthand.K K = gtsam.symbol_shorthand.K
@ -39,7 +39,7 @@ def formatter(key):
def main(): def main():
# Define the camera calibration parameters # Define the camera calibration parameters
K_initial = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0) cal = Cal3f(50.0, 50.0, 50.0)
# Create the set of 8 ground-truth landmarks # Create the set of 8 ground-truth landmarks
points = SFMdata.createPoints() points = SFMdata.createPoints()
@ -54,7 +54,7 @@ def main():
# Simulate measurements from each camera pose # Simulate measurements from each camera pose
p = [[None for _ in range(8)] for _ in range(4)] p = [[None for _ in range(8)] for _ in range(4)]
for i in range(4): for i in range(4):
camera = PinholeCameraCal3_S2(poses[i], K_initial) camera = PinholeCameraCal3f(poses[i], cal)
for j in range(8): for j in range(8):
p[i][j] = camera.project(points[j]) p[i][j] = camera.project(points[j])
@ -95,7 +95,7 @@ def main():
# Insert initial calibrations # Insert initial calibrations
for i in range(4): for i in range(4):
initialEstimate.insert(K(i), K_initial) initialEstimate.insert(K(i), cal)
# Optimize the graph and print results # Optimize the graph and print results
params = LevenbergMarquardtParams() params = LevenbergMarquardtParams()

View File

@ -6,26 +6,19 @@
Date: October 2024 Date: October 2024
""" """
import argparse
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
from gtsam.examples import SFMdata from gtsam.examples import SFMdata
import gtsam import gtsam
import argparse from gtsam import (Cal3f, EdgeKey, EssentialMatrix, FundamentalMatrix,
from gtsam import ( LevenbergMarquardtOptimizer, LevenbergMarquardtParams,
Cal3_S2, NonlinearFactorGraph, PinholeCameraCal3f, Values)
EdgeKey,
EssentialMatrix,
FundamentalMatrix,
LevenbergMarquardtOptimizer,
LevenbergMarquardtParams,
NonlinearFactorGraph,
PinholeCameraCal3_S2,
Values,
)
# For symbol shorthand (e.g., K(0), K(1)) # For symbol shorthand (e.g., K(0), K(1))
K_sym = gtsam.symbol_shorthand.K K = gtsam.symbol_shorthand.K
# Methods to compare # Methods to compare
methods = ["FundamentalMatrix", "EssentialMatrix"] methods = ["FundamentalMatrix", "EssentialMatrix"]
@ -44,7 +37,7 @@ def formatter(key):
# Function to simulate data # Function to simulate data
def simulate_data(num_cameras): def simulate_data(num_cameras):
# Define the camera calibration parameters # Define the camera calibration parameters
K = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0) cal = Cal3f(50.0, 50.0, 50.0)
# Create the set of 8 ground-truth landmarks # Create the set of 8 ground-truth landmarks
points = SFMdata.createPoints() points = SFMdata.createPoints()
@ -55,18 +48,18 @@ def simulate_data(num_cameras):
# Simulate measurements from each camera pose # Simulate measurements from each camera pose
measurements = [[None for _ in range(len(points))] for _ in range(num_cameras)] measurements = [[None for _ in range(len(points))] for _ in range(num_cameras)]
for i in range(num_cameras): for i in range(num_cameras):
camera = PinholeCameraCal3_S2(poses[i], K) camera = PinholeCameraCal3f(poses[i], cal)
for j in range(len(points)): for j in range(len(points)):
measurements[i][j] = camera.project(points[j]) measurements[i][j] = camera.project(points[j])
return points, poses, measurements, K return points, poses, measurements, cal
# Function to compute ground truth matrices # Function to compute ground truth matrices
def compute_ground_truth_matrices(method, poses, K): def compute_ground_truth(method, poses, cal):
if method == "FundamentalMatrix": if method == "FundamentalMatrix":
F1 = FundamentalMatrix(K, poses[0].between(poses[1]), K) F1 = FundamentalMatrix(cal.K(), poses[0].between(poses[1]), cal.K())
F2 = FundamentalMatrix(K, poses[0].between(poses[2]), K) F2 = FundamentalMatrix(cal.K(), poses[0].between(poses[2]), cal.K())
return F1, F2 return F1, F2
elif method == "EssentialMatrix": elif method == "EssentialMatrix":
E1 = EssentialMatrix.FromPose3(poses[0].between(poses[1])) E1 = EssentialMatrix.FromPose3(poses[0].between(poses[1]))
@ -84,8 +77,8 @@ def build_factor_graph(method, num_cameras, measurements):
# Use TransferFactorFundamentalMatrix # Use TransferFactorFundamentalMatrix
FactorClass = gtsam.TransferFactorFundamentalMatrix FactorClass = gtsam.TransferFactorFundamentalMatrix
elif method == "EssentialMatrix": elif method == "EssentialMatrix":
# Use EssentialTransferFactorCal3_S2 # Use EssentialTransferFactorCal3f
FactorClass = gtsam.EssentialTransferFactorCal3_S2 FactorClass = gtsam.EssentialTransferFactorCal3f
else: else:
raise ValueError(f"Unknown method {method}") raise ValueError(f"Unknown method {method}")
@ -113,7 +106,7 @@ 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, K): def get_initial_estimate(method, num_cameras, ground_truth, cal):
initialEstimate = Values() initialEstimate = Values()
if method == "FundamentalMatrix": if method == "FundamentalMatrix":
@ -132,7 +125,7 @@ def get_initial_estimate(method, num_cameras, ground_truth, K):
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) initialEstimate.insert(K(i), cal)
else: else:
raise ValueError(f"Unknown method {method}") raise ValueError(f"Unknown method {method}")
@ -150,7 +143,7 @@ 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, num_cameras, K): def compute_distances(method, result, ground_truth, num_cameras, cal):
distances = [] distances = []
if method == "FundamentalMatrix": if method == "FundamentalMatrix":
@ -158,8 +151,8 @@ def compute_distances(method, result, ground_truth, num_cameras, K):
elif method == "EssentialMatrix": elif method == "EssentialMatrix":
E1, E2 = ground_truth E1, E2 = ground_truth
# Convert ground truth EssentialMatrices to FundamentalMatrices using GTSAM method # Convert ground truth EssentialMatrices to FundamentalMatrices using GTSAM method
F1 = gtsam.FundamentalMatrix(K, E1, K) F1 = gtsam.FundamentalMatrix(cal.K(), E1, cal.K())
F2 = gtsam.FundamentalMatrix(K, E2, K) F2 = gtsam.FundamentalMatrix(cal.K(), E2, cal.K())
else: else:
raise ValueError(f"Unknown method {method}") raise ValueError(f"Unknown method {method}")
@ -176,8 +169,8 @@ def compute_distances(method, result, ground_truth, num_cameras, K):
E_est_ab = result.atEssentialMatrix(key_ab) E_est_ab = result.atEssentialMatrix(key_ab)
E_est_ac = result.atEssentialMatrix(key_ac) E_est_ac = result.atEssentialMatrix(key_ac)
# Convert estimated EssentialMatrices to FundamentalMatrices using GTSAM method # Convert estimated EssentialMatrices to FundamentalMatrices using GTSAM method
F_est_ab = gtsam.FundamentalMatrix(K, E_est_ab, K) F_est_ab = gtsam.FundamentalMatrix(cal.K(), E_est_ab, cal.K())
F_est_ac = gtsam.FundamentalMatrix(K, E_est_ac, K) F_est_ac = gtsam.FundamentalMatrix(cal.K(), E_est_ac, cal.K())
else: else:
raise ValueError(f"Unknown method {method}") raise ValueError(f"Unknown method {method}")
@ -229,22 +222,22 @@ def main():
print(f"Running method: {method}") print(f"Running method: {method}")
# Simulate data # Simulate data
points, poses, measurements, K = simulate_data(args.num_cameras) points, poses, measurements, cal = simulate_data(args.num_cameras)
# Compute ground truth matrices # Compute ground truth matrices
ground_truth = compute_ground_truth_matrices(method, poses, K) ground_truth = compute_ground_truth(method, poses, cal)
# 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, K) initialEstimate = get_initial_estimate(method, args.num_cameras, ground_truth, cal)
# 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, args.num_cameras, K) distances = compute_distances(method, result, ground_truth, args.num_cameras, cal)
# Compute final error # Compute final error
final_error = graph.error(result) final_error = graph.error(result)

View File

@ -32,7 +32,7 @@ def formatter(key):
def main(): def main():
# Define the camera calibration parameters # Define the camera calibration parameters
K = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0) cal = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)
# Create the set of 8 ground-truth landmarks # Create the set of 8 ground-truth landmarks
points = SFMdata.createPoints() points = SFMdata.createPoints()
@ -41,13 +41,13 @@ def main():
poses = SFMdata.posesOnCircle(4, 30) poses = SFMdata.posesOnCircle(4, 30)
# Calculate ground truth fundamental matrices, 1 and 2 poses apart # Calculate ground truth fundamental matrices, 1 and 2 poses apart
F1 = FundamentalMatrix(K, poses[0].between(poses[1]), K) F1 = FundamentalMatrix(cal.K(), poses[0].between(poses[1]), cal.K())
F2 = FundamentalMatrix(K, poses[0].between(poses[2]), K) F2 = FundamentalMatrix(cal.K(), poses[0].between(poses[2]), cal.K())
# Simulate measurements from each camera pose # Simulate measurements from each camera pose
p = [[None for _ in range(8)] for _ in range(4)] p = [[None for _ in range(8)] for _ in range(4)]
for i in range(4): for i in range(4):
camera = PinholeCameraCal3_S2(poses[i], K) camera = PinholeCameraCal3_S2(poses[i], cal)
for j in range(8): for j in range(8):
p[i][j] = camera.project(points[j]) p[i][j] = camera.project(points[j])