sengerchen's picture
Upload folder using huggingface_hub
1bb1365 verified
# Copyright (C) 2024-present Naver Corporation. All rights reserved.
# Licensed under CC BY-NC-SA 4.0 (non-commercial use only).
#
# --------------------------------------------------------
# main pnp code
# --------------------------------------------------------
import cv2
import numpy as np
import quaternion
from dust3r.utils.geometry import opencv_to_colmap_intrinsics
from packaging import version
try:
import poselib # noqa
HAS_POSELIB = True
except Exception as e:
HAS_POSELIB = False
try:
import pycolmap # noqa
version_number = pycolmap.__version__
if version.parse(version_number) < version.parse("0.5.0"):
HAS_PYCOLMAP = False
else:
HAS_PYCOLMAP = True
except Exception as e:
HAS_PYCOLMAP = False
def run_pnp(
pts2D, pts3D, K, distortion=None, mode="cv2", reprojectionError=5, img_size=None
):
"""
use OPENCV model for distortion (4 values)
"""
assert mode in ["cv2", "poselib", "pycolmap"]
try:
if len(pts2D) > 4 and mode == "cv2":
confidence = 0.9999
iterationsCount = 10_000
if distortion is not None:
cv2_pts2ds = np.copy(pts2D)
cv2_pts2ds = cv2.undistortPoints(
cv2_pts2ds, K, np.array(distortion), R=None, P=K
)
pts2D = cv2_pts2ds.reshape((-1, 2))
success, r_pose, t_pose, _ = cv2.solvePnPRansac(
pts3D,
pts2D,
K,
None,
flags=cv2.SOLVEPNP_SQPNP,
iterationsCount=iterationsCount,
reprojectionError=reprojectionError,
confidence=confidence,
)
if not success:
return False, None
r_pose = cv2.Rodrigues(r_pose)[0] # world2cam == world2cam2
RT = np.r_[np.c_[r_pose, t_pose], [(0, 0, 0, 1)]] # world2cam2
return True, np.linalg.inv(RT) # cam2toworld
elif len(pts2D) > 4 and mode == "poselib":
assert HAS_POSELIB
confidence = 0.9999
iterationsCount = 10_000
# NOTE: `Camera` struct currently contains `width`/`height` fields,
# however these are not used anywhere in the code-base and are provided simply to be consistent with COLMAP.
# so we put garbage in there
colmap_intrinsics = opencv_to_colmap_intrinsics(K)
fx = colmap_intrinsics[0, 0]
fy = colmap_intrinsics[1, 1]
cx = colmap_intrinsics[0, 2]
cy = colmap_intrinsics[1, 2]
width = img_size[0] if img_size is not None else int(cx * 2)
height = img_size[1] if img_size is not None else int(cy * 2)
if distortion is None:
camera = {
"model": "PINHOLE",
"width": width,
"height": height,
"params": [fx, fy, cx, cy],
}
else:
camera = {
"model": "OPENCV",
"width": width,
"height": height,
"params": [fx, fy, cx, cy] + distortion,
}
pts2D = np.copy(pts2D)
pts2D[:, 0] += 0.5
pts2D[:, 1] += 0.5
pose, _ = poselib.estimate_absolute_pose(
pts2D,
pts3D,
camera,
{
"max_reproj_error": reprojectionError,
"max_iterations": iterationsCount,
"success_prob": confidence,
},
{},
)
if pose is None:
return False, None
RT = pose.Rt # (3x4)
RT = np.r_[RT, [(0, 0, 0, 1)]] # world2cam
return True, np.linalg.inv(RT) # cam2toworld
elif len(pts2D) > 4 and mode == "pycolmap":
assert HAS_PYCOLMAP
assert img_size is not None
pts2D = np.copy(pts2D)
pts2D[:, 0] += 0.5
pts2D[:, 1] += 0.5
colmap_intrinsics = opencv_to_colmap_intrinsics(K)
fx = colmap_intrinsics[0, 0]
fy = colmap_intrinsics[1, 1]
cx = colmap_intrinsics[0, 2]
cy = colmap_intrinsics[1, 2]
width = img_size[0]
height = img_size[1]
if distortion is None:
camera_dict = {
"model": "PINHOLE",
"width": width,
"height": height,
"params": [fx, fy, cx, cy],
}
else:
camera_dict = {
"model": "OPENCV",
"width": width,
"height": height,
"params": [fx, fy, cx, cy] + distortion,
}
pycolmap_camera = pycolmap.Camera(
model=camera_dict["model"],
width=camera_dict["width"],
height=camera_dict["height"],
params=camera_dict["params"],
)
pycolmap_estimation_options = dict(
ransac=dict(
max_error=reprojectionError,
min_inlier_ratio=0.01,
min_num_trials=1000,
max_num_trials=100000,
confidence=0.9999,
)
)
pycolmap_refinement_options = dict(
refine_focal_length=False, refine_extra_params=False
)
ret = pycolmap.absolute_pose_estimation(
pts2D,
pts3D,
pycolmap_camera,
estimation_options=pycolmap_estimation_options,
refinement_options=pycolmap_refinement_options,
)
if ret is None:
ret = {"success": False}
else:
ret["success"] = True
if callable(ret["cam_from_world"].matrix):
retmat = ret["cam_from_world"].matrix()
else:
retmat = ret["cam_from_world"].matrix
ret["qvec"] = quaternion.from_rotation_matrix(retmat[:3, :3])
ret["tvec"] = retmat[:3, 3]
if not (ret["success"] and ret["num_inliers"] > 0):
success = False
pose = None
else:
success = True
pr_world_to_querycam = np.r_[
ret["cam_from_world"].matrix(), [(0, 0, 0, 1)]
]
pose = np.linalg.inv(pr_world_to_querycam)
return success, pose
else:
return False, None
except Exception as e:
print(f"error during pnp: {e}")
return False, None