Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
gtsam / tests / ViewGraphExample.py
Size: Mime:
"""
  GTSAM Copyright 2010, Georgia Tech Research Corporation,
  Atlanta, Georgia 30332-0415
  All Rights Reserved
  Authors: Frank Dellaert, et al. (see THANKS for the full author list)

  See LICENSE for the license information
"""

"""
Python version of ViewGraphExample.cpp
View-graph calibration on a simulated dataset, a la Sweeney 2015
Author: Frank Dellaert
Date: October 2024
"""

import numpy as np
from gtsam.examples import SFMdata

from gtsam import (Cal3_S2, EdgeKey, FundamentalMatrix,
                   LevenbergMarquardtOptimizer, LevenbergMarquardtParams,
                   NonlinearFactorGraph, PinholeCameraCal3_S2)
from gtsam import TransferFactorFundamentalMatrix as Factor
from gtsam import Values


# Formatter function for printing keys
def formatter(key):
    edge = EdgeKey(key)
    return f"({edge.i()},{edge.j()})"


def main():
    # Define the camera calibration parameters
    cal = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)

    # Create the set of 8 ground-truth landmarks
    points = SFMdata.createPoints()

    # Create the set of 4 ground-truth poses
    poses = SFMdata.posesOnCircle(4, 30)

    # Calculate ground truth fundamental matrices, 1 and 2 poses apart
    F1 = FundamentalMatrix(cal.K(), poses[0].between(poses[1]), cal.K())
    F2 = FundamentalMatrix(cal.K(), poses[0].between(poses[2]), cal.K())

    # Simulate measurements from each camera pose
    p = [[None for _ in range(8)] for _ in range(4)]
    for i in range(4):
        camera = PinholeCameraCal3_S2(poses[i], cal)
        for j in range(8):
            p[i][j] = camera.project(points[j])

    # Create the factor graph
    graph = NonlinearFactorGraph()

    for a in range(4):
        b = (a + 1) % 4  # Next camera
        c = (a + 2) % 4  # Camera after next

        # Vectors to collect tuples for each factor
        tuples1 = []
        tuples2 = []
        tuples3 = []

        # Collect data for the three factors
        for j in range(8):
            tuples1.append((p[a][j], p[b][j], p[c][j]))
            tuples2.append((p[a][j], p[c][j], p[b][j]))
            tuples3.append((p[c][j], p[b][j], p[a][j]))

        # Add transfer factors between views a, b, and c.
        graph.add(Factor(EdgeKey(a, c), EdgeKey(b, c), tuples1))
        graph.add(Factor(EdgeKey(a, b), EdgeKey(b, c), tuples2))
        graph.add(Factor(EdgeKey(a, c), EdgeKey(a, b), tuples3))

    # Print the factor graph
    graph.print("Factor Graph:\n", formatter)

    # Create a delta vector to perturb the ground truth
    delta = np.array([1, 2, 3, 4, 5, 6, 7]) * 1e-5

    # Create the data structure to hold the initial estimate to the solution
    initialEstimate = Values()
    for a in range(4):
        b = (a + 1) % 4  # Next camera
        c = (a + 2) % 4  # Camera after next
        initialEstimate.insert(EdgeKey(a, b).key(), F1.retract(delta))
        initialEstimate.insert(EdgeKey(a, c).key(), F2.retract(delta))

    initialEstimate.print("Initial Estimates:\n", formatter)
    graph.printErrors(initialEstimate, "Initial Errors:\n", formatter)

    # Optimize the graph and print results
    params = LevenbergMarquardtParams()
    params.setlambdaInitial(1000.0)  # Initialize lambda to a high value
    params.setVerbosityLM("SUMMARY")
    optimizer = LevenbergMarquardtOptimizer(graph, initialEstimate, params)
    result = optimizer.optimize()

    print(f"Initial error = {graph.error(initialEstimate)}")
    print(f"Final error = {graph.error(result)}")

    result.print("Final Results:\n", formatter)

    print("Ground Truth F1:\n", F1.matrix())
    print("Ground Truth F2:\n", F2.matrix())


if __name__ == "__main__":
    main()