opensfm/src/map/python/pybind.cc (622 lines of code) (raw):

#include <foundation/optional.h> #include <foundation/types.h> #include <geometry/camera.h> #include <geometry/pose.h> #include <map/dataviews.h> #include <map/defines.h> #include <map/ground_control_points.h> #include <map/landmark.h> #include <map/map.h> #include <map/pybind_utils.h> #include <map/rig.h> #include <map/shot.h> #include <pybind11/eigen.h> #include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <iostream> #include <typeinfo> namespace py = pybind11; template <typename T> void DeclareShotMeasurement(py::module &m, const std::string &type_name) { using SM = foundation::OptionalValue<T>; std::string class_name = std::string("ShotMeasurement") + type_name; py::class_<SM>(m, class_name.c_str()) .def(py::init<>()) .def_property_readonly("has_value", &SM::HasValue) .def_property("value", py::overload_cast<>(&SM::Value, py::const_), &SM::SetValue) .def("reset", &SM::Reset) .def(py::pickle( [](const SM &sm) { return py::make_tuple(sm.HasValue(), sm.Value()); }, [](py::tuple p) { SM sm; const auto has_value = p[0].cast<bool>(); if (has_value) { sm.SetValue(p[1].cast<T>()); } return sm; })); } PYBIND11_MODULE(pymap, m) { py::module::import("opensfm.pygeometry"); py::module::import("opensfm.pygeo"); // Some initial defintions to resolve cyclic dependencies // Landmark <> Shot py::class_<map::Shot> shotCls(m, "Shot"); // Landmark/Shot/...View <> Map py::class_<map::Map> mapCls(m, "Map"); DeclareShotMeasurement<int>(m, "Int"); DeclareShotMeasurement<double>(m, "Double"); DeclareShotMeasurement<Vec3d>(m, "Vec3d"); DeclareShotMeasurement<std::string>(m, "String"); py::enum_<map::Map::ErrorType>(m, "ErrorType") .value("Pixel", map::Map::Pixel) .value("Normalized", map::Map::Normalized) .value("Angular", map::Map::Angular) .export_values(); py::class_<map::Observation>(m, "Observation") .def(py::init<double, double, double, int, int, int, int, int, int>(), py::arg("x"), py::arg("y"), py::arg("s"), py::arg("r"), py::arg("g"), py::arg("b"), py::arg("feature"), py::arg("segmentation") = map::Observation::NO_SEMANTIC_VALUE, py::arg("instance") = map::Observation::NO_SEMANTIC_VALUE) .def_readwrite("point", &map::Observation::point) .def_readwrite("scale", &map::Observation::scale) .def_readwrite("id", &map::Observation::feature_id) .def_readwrite("color", &map::Observation::color) .def_readwrite("segmentation", &map::Observation::segmentation_id) .def_readwrite("instance", &map::Observation::instance_id) .def_readonly_static("NO_SEMANTIC_VALUE", &map::Observation::NO_SEMANTIC_VALUE) .def( "copy", [](const map::Observation &to_copy) { map::Observation copy = to_copy; return copy; }, py::return_value_policy::copy); py::class_<map::Landmark>(m, "Landmark") .def(py::init<const map::LandmarkId &, const Vec3d &>()) .def_readonly("id", &map::Landmark::id_) .def_property("coordinates", &map::Landmark::GetGlobalPos, &map::Landmark::SetGlobalPos) .def("get_observations", &map::Landmark::GetObservations, py::return_value_policy::reference_internal) .def("number_of_observations", &map::Landmark::NumberOfObservations) .def_property("reprojection_errors", &map::Landmark::GetReprojectionErrors, &map::Landmark::SetReprojectionErrors) .def_property("color", &map::Landmark::GetColor, &map::Landmark::SetColor); py::class_<map::ShotMeasurements>(m, "ShotMeasurements") .def(py::init<>()) .def_readwrite("gps_accuracy", &map::ShotMeasurements::gps_accuracy_) .def_readwrite("gps_position", &map::ShotMeasurements::gps_position_) .def_readwrite("orientation", &map::ShotMeasurements::orientation_) .def_readwrite("capture_time", &map::ShotMeasurements::capture_time_) .def_readwrite("accelerometer", &map::ShotMeasurements::accelerometer_) .def_readwrite("compass_angle", &map::ShotMeasurements::compass_angle_) .def_readwrite("compass_accuracy", &map::ShotMeasurements::compass_accuracy_) .def_readwrite("opk_angles", &map::ShotMeasurements::opk_angles_) .def_readwrite("opk_accuracy", &map::ShotMeasurements::opk_accuracy_) .def_readwrite("sequence_key", &map::ShotMeasurements::sequence_key_) .def_property("attributes", &map::ShotMeasurements::GetAttributes, &map::ShotMeasurements::SetAttributes) .def(py::pickle( [](const map::ShotMeasurements &s) { return py::make_tuple( s.gps_accuracy_, s.gps_position_, s.orientation_, s.capture_time_, s.accelerometer_, s.compass_angle_, s.compass_accuracy_, s.opk_angles_, s.opk_accuracy_, s.sequence_key_, s.GetAttributes()); }, [](py::tuple s) { map::ShotMeasurements sm; sm.gps_accuracy_ = s[0].cast<decltype(sm.gps_accuracy_)>(); sm.gps_position_ = s[1].cast<decltype(sm.gps_position_)>(); sm.orientation_ = s[2].cast<decltype(sm.orientation_)>(); sm.capture_time_ = s[3].cast<decltype(sm.capture_time_)>(); sm.accelerometer_ = s[4].cast<decltype(sm.accelerometer_)>(); sm.compass_angle_ = s[5].cast<decltype(sm.compass_angle_)>(); sm.compass_accuracy_ = s[6].cast<decltype(sm.compass_accuracy_)>(); sm.opk_angles_ = s[7].cast<decltype(sm.opk_angles_)>(); sm.opk_accuracy_ = s[8].cast<decltype(sm.opk_accuracy_)>(); sm.sequence_key_ = s[9].cast<decltype(sm.sequence_key_)>(); sm.GetMutableAttributes() = s[10].cast<decltype(sm.attributes_)>(); return sm; })) .def( "__copy__", [](const map::ShotMeasurements &to_copy) { map::ShotMeasurements copy; copy.Set(to_copy); return copy; }, py::return_value_policy::copy) .def("set", &map::ShotMeasurements::Set); py::class_<map::ShotMesh>(m, "ShotMesh") .def_property("faces", &map::ShotMesh::GetFaces, &map::ShotMesh::SetFaces) .def_property("vertices", &map::ShotMesh::GetVertices, &map::ShotMesh::SetVertices); py::class_<map::RigCamera>(m, "RigCamera") .def(py::init<>()) .def(py::init<const geometry::Pose &, const map::RigCameraId &>()) .def_readwrite("id", &map::RigCamera::id) .def_readwrite("pose", &map::RigCamera::pose) // pickle support .def(py::pickle( [](const map::RigCamera &rc) { return py::make_tuple(rc.pose, rc.id); }, [](py::tuple s) { return map::RigCamera(s[0].cast<geometry::Pose>(), s[1].cast<map::RigCameraId>()); })); py::class_<map::RigInstance>(m, "RigInstance") .def(py::init<map::RigInstanceId>()) .def_readwrite("id", &map::RigInstance::id) .def_property_readonly("shots", py::overload_cast<>(&map::RigInstance::GetShots), py::return_value_policy::reference_internal) .def_property_readonly( "rig_cameras", py::overload_cast<>(&map::RigInstance::GetRigCameras), py::return_value_policy::reference_internal) .def_property_readonly( "rig_camera_ids", [](const map::RigInstance &ri) { std::map<map::ShotId, map::RigCameraId> rig_camera_ids; for (const auto &rig_camera : ri.GetRigCameras()) { rig_camera_ids[rig_camera.first] = rig_camera.second->id; } return rig_camera_ids; }) .def_property_readonly("camera_ids", [](const map::RigInstance &ri) { std::map<map::ShotId, map::CameraId> camera_ids; for (const auto &shot : ri.GetShots()) { camera_ids[shot.first] = shot.second->GetCamera()->id; } return camera_ids; }) .def("keys", &map::RigInstance::GetShotIDs) .def_property("pose", py::overload_cast<>(&map::RigInstance::GetPose), &map::RigInstance::SetPose, py::return_value_policy::reference_internal) .def("add_shot", &map::RigInstance::AddShot) .def("remove_shot", &map::RigInstance::RemoveShot) .def("update_instance_pose_with_shot", &map::RigInstance::UpdateInstancePoseWithShot) .def("update_rig_camera_pose", &map::RigInstance::UpdateRigCameraPose); shotCls .def(py::init<const map::ShotId &, const geometry::Camera &, const geometry::Pose &>()) .def_readonly("id", &map::Shot::id_) .def_readwrite("mesh", &map::Shot::mesh) .def_property("covariance", &map::Shot::GetCovariance, &map::Shot::SetCovariance) .def_readwrite("merge_cc", &map::Shot::merge_cc) .def_readwrite("scale", &map::Shot::scale) .def_property_readonly("rig_instance", &map::Shot::GetRigInstance) .def_property_readonly("rig_camera", &map::Shot::GetRigCamera) .def_property_readonly("rig_instance_id", &map::Shot::GetRigInstanceId) .def_property_readonly("rig_camera_id", &map::Shot::GetRigCameraId) .def("set_rig", &map::Shot::SetRig) .def("get_observation", &map::Shot::GetObservation, py::return_value_policy::reference_internal) .def("get_valid_landmarks", &map::Shot::ComputeValidLandmarks) .def("remove_observation", &map::Shot::RemoveLandmarkObservation) .def_property("metadata", py::overload_cast<>(&map::Shot::GetShotMeasurements), &map::Shot::SetShotMeasurements, py::return_value_policy::reference_internal) .def_property("pose", py::overload_cast<>(&map::Shot::GetPose), &map::Shot::SetPose, py::return_value_policy::reference_internal) .def_property_readonly("camera", &map::Shot::GetCamera, py::return_value_policy::reference_internal) .def("get_landmark_observation", &map::Shot::GetLandmarkObservation, py::return_value_policy::reference_internal) .def("get_observation_landmark", &map::Shot::GetObservationLandmark, py::return_value_policy::reference_internal) .def("project", &map::Shot::Project) .def("project_many", &map::Shot::ProjectMany) .def("bearing", &map::Shot::Bearing) .def("bearing_many", &map::Shot::BearingMany); py::class_<map::GroundControlPointObservation>( m, "GroundControlPointObservation") .def(py::init()) .def(py::init<const map::ShotId &, const Vec2d &>()) .def_readwrite("shot_id", &map::GroundControlPointObservation::shot_id_) .def_readwrite("projection", &map::GroundControlPointObservation::projection_); py::class_<map::GroundControlPoint>(m, "GroundControlPoint") .def(py::init()) .def_readwrite("id", &map::GroundControlPoint::id_) .def_readwrite("has_altitude", &map::GroundControlPoint::has_altitude_) .def_readwrite("lla", &map::GroundControlPoint::lla_) .def_property("lla_vec", &map::GroundControlPoint::GetLlaVec3d, &map::GroundControlPoint::SetLla) .def_property("observations", &map::GroundControlPoint::GetObservations, &map::GroundControlPoint::SetObservations) .def("add_observation", &map::GroundControlPoint::AddObservation); py::class_<map::TracksManager>(m, "TracksManager") .def(py::init()) .def_static("instanciate_from_file", &map::TracksManager::InstanciateFromFile, py::call_guard<py::gil_scoped_release>()) .def_static("instanciate_from_string", &map::TracksManager::InstanciateFromString, py::call_guard<py::gil_scoped_release>()) .def_static("merge_tracks_manager", &map::TracksManager::MergeTracksManager) .def("add_observation", &map::TracksManager::AddObservation) .def("remove_observation", &map::TracksManager::RemoveObservation) .def("num_shots", &map::TracksManager::NumShots) .def("num_tracks", &map::TracksManager::NumTracks) .def("get_shot_ids", &map::TracksManager::GetShotIds) .def("get_track_ids", &map::TracksManager::GetTrackIds) .def("get_observation", &map::TracksManager::GetObservation) .def("get_shot_observations", &map::TracksManager::GetShotObservations) .def("get_track_observations", &map::TracksManager::GetTrackObservations) .def("construct_sub_tracks_manager", &map::TracksManager::ConstructSubTracksManager) .def("write_to_file", &map::TracksManager::WriteToFile) .def("as_string", &map::TracksManager::AsString) .def("get_all_common_observations", &map::TracksManager::GetAllCommonObservations, py::call_guard<py::gil_scoped_release>()) .def("get_all_pairs_connectivity", &map::TracksManager::GetAllPairsConnectivity, py::arg("shots") = std::vector<map::ShotId>(), py::arg("tracks") = std::vector<map::TrackId>(), py::call_guard<py::gil_scoped_release>()); py::class_<map::PanoShotView>(m, "PanoShotView") .def(py::init<map::Map &>(), py::keep_alive<1, 2>()) // Keep map alive while view is used .def("__len__", &map::PanoShotView::NumberOfShots) .def( "items", [](const map::PanoShotView &sv) { auto &shots = sv.GetShots(); return py::make_ref_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "values", [](const map::PanoShotView &sv) { auto &shots = sv.GetShots(); return py::make_ref_value_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "__iter__", [](const map::PanoShotView &sv) { const auto &shots = sv.GetShots(); return py::make_key_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "keys", [](const map::PanoShotView &sv) { const auto &shots = sv.GetShots(); return py::make_key_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def("get", &map::PanoShotView::GetShot, py::return_value_policy::reference_internal) .def("__getitem__", &map::PanoShotView::GetShot, py::return_value_policy::reference_internal) .def("__contains__", &map::PanoShotView::HasShot); py::class_<map::ShotView>(m, "ShotView") .def(py::init<map::Map &>(), py::keep_alive<1, 2>()) // Keep map alive while view is used .def("__len__", &map::ShotView::NumberOfShots) .def( "items", [](const map::ShotView &sv) { const auto &shots = sv.GetShots(); return py::make_ref_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "values", [](const map::ShotView &sv) { const auto &shots = sv.GetShots(); return py::make_ref_value_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "__iter__", [](const map::ShotView &sv) { const auto &shots = sv.GetShots(); return py::make_key_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "keys", [](const map::ShotView &sv) { const auto &shots = sv.GetShots(); return py::make_key_iterator(shots.begin(), shots.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def("get", &map::ShotView::GetShot, py::return_value_policy::reference_internal) .def("__getitem__", &map::ShotView::GetShot, py::return_value_policy::reference_internal) .def("__contains__", &map::ShotView::HasShot); py::class_<map::LandmarkView>(m, "LandmarkView") .def(py::init<map::Map &>(), py::keep_alive<1, 2>()) // Keep map alive while view is used .def("__len__", &map::LandmarkView::NumberOfLandmarks) .def( "items", [](const map::LandmarkView &sv) { auto &lms = sv.GetLandmarks(); return py::make_ref_iterator(lms.begin(), lms.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "values", [](const map::LandmarkView &sv) { auto &lms = sv.GetLandmarks(); return py::make_ref_value_iterator(lms.begin(), lms.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "__iter__", [](const map::LandmarkView &sv) { const auto &lms = sv.GetLandmarks(); return py::make_key_iterator(lms.begin(), lms.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "keys", [](const map::LandmarkView &sv) { const auto &lms = sv.GetLandmarks(); return py::make_key_iterator(lms.begin(), lms.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def("get", &map::LandmarkView::GetLandmark, py::return_value_policy::reference_internal) .def("__getitem__", &map::LandmarkView::GetLandmark, py::return_value_policy::reference_internal) .def("__contains__", &map::LandmarkView::HasLandmark); py::class_<map::CameraView>(m, "CameraView") .def(py::init<map::Map &>(), py::keep_alive<1, 2>()) // Keep map alive while view is used .def("__len__", &map::CameraView::NumberOfCameras) .def( "items", [](const map::CameraView &sv) { const auto &cams = sv.GetCameras(); return py::make_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "values", [](map::CameraView &sv) { auto &cams = sv.GetCameras(); return py::make_ref_value_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "__iter__", [](const map::CameraView &sv) { const auto &cams = sv.GetCameras(); return py::make_key_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "keys", [](const map::CameraView &sv) { const auto &cams = sv.GetCameras(); return py::make_key_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def("get", &map::CameraView::GetCamera, py::return_value_policy::reference_internal) .def("__getitem__", &map::CameraView::GetCamera, py::return_value_policy::reference_internal) .def("__contains__", &map::CameraView::HasCamera); py::class_<map::BiasView>(m, "BiasView") .def(py::init<map::Map &>(), py::keep_alive<1, 2>()) // Keep map alive while view is used .def("__len__", &map::BiasView::NumberOfBiases) .def( "items", [](const map::BiasView &sv) { const auto &biases = sv.GetBiases(); return py::make_iterator(biases.begin(), biases.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "values", [](map::BiasView &sv) { auto &biases = sv.GetBiases(); return py::make_ref_value_iterator(biases.begin(), biases.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "__iter__", [](const map::BiasView &sv) { const auto &biases = sv.GetBiases(); return py::make_key_iterator(biases.begin(), biases.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "keys", [](const map::BiasView &sv) { const auto &biases = sv.GetBiases(); return py::make_key_iterator(biases.begin(), biases.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def("get", &map::BiasView::GetBias, py::return_value_policy::reference_internal) .def("__getitem__", &map::BiasView::GetBias, py::return_value_policy::reference_internal) .def("__contains__", &map::BiasView::HasBias); py::class_<map::RigCameraView>(m, "RigCameraView") .def(py::init<map::Map &>(), py::keep_alive<1, 2>()) // Keep map alive while view is used .def("__len__", &map::RigCameraView::NumberOfRigCameras) .def( "items", [](const map::RigCameraView &sv) { const auto &cams = sv.GetRigCameras(); return py::make_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "values", [](map::RigCameraView &sv) { auto &cams = sv.GetRigCameras(); return py::make_ref_value_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "__iter__", [](const map::RigCameraView &sv) { const auto &cams = sv.GetRigCameras(); return py::make_key_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "keys", [](const map::RigCameraView &sv) { const auto &cams = sv.GetRigCameras(); return py::make_key_iterator(cams.begin(), cams.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def("get", &map::RigCameraView::GetRigCamera, py::return_value_policy::reference_internal) .def("__getitem__", &map::RigCameraView::GetRigCamera, py::return_value_policy::reference_internal) .def("__contains__", &map::RigCameraView::HasRigCamera); py::class_<map::RigInstanceView>(m, "RigInstanceView") .def(py::init<map::Map &>(), py::keep_alive<1, 2>()) // Keep map alive while view is used .def("__len__", &map::RigInstanceView::NumberOfRigInstances) .def( "items", [](const map::RigInstanceView &sv) { const auto &instances = sv.GetRigInstances(); return py::make_iterator(instances.begin(), instances.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "values", [](map::RigInstanceView &sv) { auto &instances = sv.GetRigInstances(); return py::make_ref_value_iterator(instances.begin(), instances.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "__iter__", [](const map::RigInstanceView &sv) { const auto &instances = sv.GetRigInstances(); return py::make_iterator(instances.begin(), instances.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def( "keys", [](const map::RigInstanceView &sv) { const auto &instances = sv.GetRigInstances(); return py::make_key_iterator(instances.begin(), instances.end()); }, py::keep_alive<0, 1>()) // Keep view alive while iterator is used .def("get", &map::RigInstanceView::GetRigInstance, py::return_value_policy::reference_internal) .def("__getitem__", &map::RigInstanceView::GetRigInstance, py::return_value_policy::reference_internal) .def("__contains__", &map::RigInstanceView::HasRigInstance); mapCls .def(py::init()) // Camera .def("create_camera", &map::Map::CreateCamera, py::arg("camera"), py::return_value_policy::reference_internal) .def("get_camera", py::overload_cast<const map::CameraId &>(&map::Map::GetCamera), py::return_value_policy::reference_internal) // Bias .def("set_bias", &map::Map::SetBias, py::return_value_policy::reference_internal) .def("get_bias", &map::Map::GetBias, py::return_value_policy::reference_internal) // Rigs .def("create_rig_camera", &map::Map::CreateRigCamera, py::return_value_policy::reference_internal) .def("create_rig_instance", &map::Map::CreateRigInstance, py::return_value_policy::reference_internal) .def("update_rig_instance", &map::Map::UpdateRigInstance, py::return_value_policy::reference_internal) .def("remove_rig_instance", &map::Map::RemoveRigInstance) // Landmark .def("create_landmark", &map::Map::CreateLandmark, py::arg("lm_id"), py::arg("global_position"), py::return_value_policy::reference_internal) .def("remove_landmark", (void (map::Map::*)(const map::Landmark *const)) & map::Map::RemoveLandmark) .def("remove_landmark", (void (map::Map::*)(const map::LandmarkId &)) & map::Map::RemoveLandmark) .def("has_landmark", &map::Map::HasLandmark) .def("get_landmark", py::overload_cast<const map::LandmarkId &>(&map::Map::GetLandmark), py::return_value_policy::reference_internal) .def("clear_observations_and_landmarks", &map::Map::ClearObservationsAndLandmarks) .def("clean_landmarks_below_min_observations", &map::Map::CleanLandmarksBelowMinObservations) // Shot .def( "create_shot", py::overload_cast<const map::ShotId &, const map::CameraId &, const map::RigCameraId &, const map::RigInstanceId &, const geometry::Pose &>( &map::Map::CreateShot), py::return_value_policy::reference_internal) .def("create_shot", py::overload_cast<const map::ShotId &, const map::CameraId &, const map::RigCameraId &, const map::RigInstanceId &>(&map::Map::CreateShot), py::return_value_policy::reference_internal) .def("remove_shot", &map::Map::RemoveShot) .def("get_shot", py::overload_cast<const map::ShotId &>(&map::Map::GetShot), py::return_value_policy::reference_internal) .def("update_shot", &map::Map::UpdateShot, py::return_value_policy::reference_internal) // Pano Shot .def("create_pano_shot", &map::Map::CreatePanoShot, py::return_value_policy::reference_internal) .def("remove_pano_shot", &map::Map::RemovePanoShot) .def("get_pano_shot", py::overload_cast<const map::ShotId &>(&map::Map::GetPanoShot), py::return_value_policy::reference_internal) .def("update_pano_shot", &map::Map::UpdatePanoShot, py::return_value_policy::reference_internal) // Observation .def("add_observation", (void (map::Map::*)(map::Shot *const, map::Landmark *const, const map::Observation &)) & map::Map::AddObservation, py::arg("shot"), py::arg("landmark"), py::arg("observation")) .def("add_observation", (void (map::Map::*)(const map::ShotId &, const map::LandmarkId &, const map::Observation &)) & map::Map::AddObservation, py::arg("shot_Id"), py::arg("landmark_id"), py::arg("observation")) .def("remove_observation", (void (map::Map::*)(const map::ShotId &, const map::LandmarkId &)) & map::Map::RemoveObservation, py::arg("shot"), py::arg("landmark")) // Getters .def("get_shots", &map::Map::GetShotView) .def("get_pano_shots", &map::Map::GetPanoShotView) .def("get_cameras", &map::Map::GetCameraView) .def("get_biases", &map::Map::GetBiasView) .def("get_camera_view", &map::Map::GetCameraView) .def("get_landmarks", &map::Map::GetLandmarkView) .def("get_landmark_view", &map::Map::GetLandmarkView) .def("set_reference", &map::Map::SetTopocentricConverter) // Reference .def("get_reference", [](const map::Map &map) { py::module::import("opensfm.pygeo"); return map.GetTopocentricConverter(); }) // Tracks manager x Reconstruction intersection .def("compute_reprojection_errors", &map::Map::ComputeReprojectionErrors) .def("get_valid_observations", &map::Map::GetValidObservations) .def("to_tracks_manager", &map::Map::ToTracksManager); }