Spaces:
Running on Zero
Running on Zero
| import pickle | |
| from pathlib import Path | |
| import numpy as np | |
| import poselib | |
| import pycolmap | |
| from siclib.models.extractor import VP | |
| from .models.extractor import GeoCalib | |
| from .utils.image import load_image | |
| # flake8: noqa | |
| # mypy: ignore-errors | |
| class AbsolutePoseEstimator: | |
| default_opts = { | |
| "ransac": "poselib_gravity", # pycolmap, poselib, poselib_gravity | |
| "refinement": "pycolmap_gravity", # pycolmap, pycolmap_gravity, none | |
| "gravity_weight": 50000, | |
| "max_reproj_error": 48.0, | |
| "loss_function_scale": 1.0, | |
| "use_vp": False, | |
| "max_uncertainty": 10.0 / 180.0 * 3.1415, # radians | |
| "cache_path": "../../outputs/inloc/calib.pickle", | |
| } | |
| def __init__(self, pose_opts=None): | |
| pose_opts = {} if pose_opts is None else pose_opts | |
| self.opts = {**self.default_opts, **pose_opts} | |
| self.device = "cuda" | |
| if self.opts["use_vp"]: | |
| self.calib = VP().to(self.device) | |
| self.cache_path = str(self.opts["cache_path"]).replace(".pickle", "_vp.pickle") | |
| else: | |
| self.calib = GeoCalib().to(self.device) | |
| self.cache_path = str(self.opts["cache_path"]) | |
| # self.read_cache() | |
| self.cache = {} | |
| def read_cache(self): | |
| print(f"Reading cache from {self.cache_path} ({Path(self.cache_path).exists()})") | |
| if not Path(self.cache_path).exists(): | |
| self.cache = {} | |
| return | |
| with open(self.cache_path, "rb") as handle: | |
| self.cache = pickle.load(handle) | |
| def write_cache(self): | |
| with open(self.cache_path, "wb") as handle: | |
| pickle.dump(self.cache, handle, protocol=pickle.HIGHEST_PROTOCOL) | |
| def __call__(self, query_path, p2d, p3d, camera_dict): | |
| focal_length = pycolmap.Camera(camera_dict).mean_focal_length() | |
| if query_path in self.cache: | |
| calib = self.cache[query_path] | |
| else: | |
| calib = self.calib.calibrate( | |
| load_image(query_path).to(self.device), priors={"f": focal_length} | |
| ) | |
| calib = {k: v[0].detach().cpu().numpy() for k, v in calib.items()} | |
| self.cache[query_path] = calib | |
| # self.write_cache() | |
| if self.opts["ransac"] == "pycolmap": | |
| ret = pycolmap.absolute_pose_estimation( | |
| p2d, p3d, camera_dict, self.opts["max_reproj_error"] # , do_refine=False | |
| ) | |
| elif self.opts["ransac"] == "poselib": | |
| M, ret = poselib.estimate_absolute_pose( | |
| p2d, | |
| p3d, | |
| camera_dict, | |
| ransac_opt={"max_reproj_error": self.opts["max_reproj_error"]}, | |
| ) | |
| ret["success"] = M is not None | |
| ret["qvec"] = M.q | |
| ret["tvec"] = M.t | |
| elif self.opts["ransac"] == "poselib_gravity": | |
| g_q = calib["gravity"].vec3d | |
| g_qu = calib.get("gravity_uncertainty", self.opts["max_uncertainty"]) | |
| M, ret = poselib.estimate_absolute_pose_gravity( | |
| p2d, | |
| p3d, | |
| camera_dict, | |
| g_q, | |
| g_qu * 2 * 180 / 3.1415, # convert to scalar | |
| ransac_opt={"max_reproj_error": self.opts["max_reproj_error"]}, | |
| ) | |
| ret["success"] = M is not None | |
| ret["qvec"] = M.q | |
| ret["tvec"] = M.t | |
| else: | |
| raise NotImplementedError(self.opts["ransac"]) | |
| r_opts = { | |
| "refine_focal_length": False, | |
| "refine_extra_params": False, | |
| "print_summary": False, | |
| "loss_function_scale": self.opts["loss_function_scale"], | |
| } | |
| if self.opts["refinement"] == "pycolmap_gravity": | |
| g_q = calib["gravity"].vec3d | |
| g_qu = calib.get("gravity_uncertainty", self.opts["max_uncertainty"]) | |
| if g_qu <= self.opts["max_uncertainty"]: | |
| g_gt = np.array([0, 0, 1]) # world frame | |
| ret_ref = pycolmap.pose_refinement_gravity( | |
| ret["tvec"], | |
| ret["qvec"], | |
| p2d, | |
| p3d, | |
| ret["inliers"], | |
| camera_dict, | |
| g_q, | |
| g_gt, | |
| self.opts["gravity_weight"], | |
| r_opts, | |
| ) | |
| else: | |
| ret_ref = pycolmap.pose_refinement( | |
| ret["tvec"], | |
| ret["qvec"], | |
| p2d, | |
| p3d, | |
| ret["inliers"], | |
| camera_dict, | |
| r_opts, | |
| ) | |
| elif self.opts["refinement"] == "pycolmap": | |
| ret_ref = pycolmap.pose_refinement( | |
| ret["tvec"], | |
| ret["qvec"], | |
| p2d, | |
| p3d, | |
| ret["inliers"], | |
| camera_dict, | |
| r_opts, | |
| ) | |
| elif self.opts["refinement"] == "none": | |
| ret_ref = {} | |
| else: | |
| raise NotImplementedError(self.opts["refinement"]) | |
| ret = {**ret, **ret_ref} | |
| ret["camera_dict"] = camera_dict | |
| return ret, calib | |