v01
This commit is contained in:
237
thirdparty/opengv/python/tests.py
vendored
Normal file
237
thirdparty/opengv/python/tests.py
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
import pyopengv
|
||||
import numpy as np
|
||||
|
||||
|
||||
def normalized(x):
|
||||
return x / np.linalg.norm(x)
|
||||
|
||||
|
||||
def generateRandomPoint(maximumDepth, minimumDepth):
|
||||
cleanPoint = np.random.uniform(-1.0, 1.0, 3)
|
||||
direction = normalized(cleanPoint)
|
||||
return (maximumDepth - minimumDepth) * cleanPoint + minimumDepth * direction
|
||||
|
||||
|
||||
def generateRandomTranslation(maximumParallax):
|
||||
return np.random.uniform(-maximumParallax, maximumParallax, 3)
|
||||
|
||||
|
||||
def generateRandomRotation(maxAngle):
|
||||
rpy = np.random.uniform(-maxAngle, maxAngle, 3)
|
||||
|
||||
R1 = np.array([[1.0, 0.0, 0.0],
|
||||
[0.0, np.cos(rpy[0]), -np.sin(rpy[0])],
|
||||
[0.0, np.sin(rpy[0]), np.cos(rpy[0])]])
|
||||
|
||||
R2 = np.array([[np.cos(rpy[1]), 0.0, np.sin(rpy[1])],
|
||||
[0.0, 1.0, 0.0],
|
||||
[-np.sin(rpy[1]), 0.0, np.cos(rpy[1])]])
|
||||
|
||||
R3 = np.array([[np.cos(rpy[2]), -np.sin(rpy[2]), 0.0],
|
||||
[np.sin(rpy[2]), np.cos(rpy[2]), 0.0],
|
||||
[0.0, 0.0, 1.0]])
|
||||
|
||||
return R3.dot(R2.dot(R1))
|
||||
|
||||
|
||||
def addNoise(noiseLevel, cleanPoint):
|
||||
noisyPoint = cleanPoint + np.random.uniform(-noiseLevel, noiseLevel, 3)
|
||||
return normalized(noisyPoint)
|
||||
|
||||
|
||||
def extractRelativePose(position1, position2, rotation1, rotation2):
|
||||
relativeRotation = rotation1.T.dot(rotation2)
|
||||
relativePosition = rotation1.T.dot(position2 - position1)
|
||||
return relativePosition, relativeRotation
|
||||
|
||||
|
||||
def essentialMatrix(position, rotation):
|
||||
# E transforms vectors from vp 2 to 1: x_1^T * E * x_2 = 0
|
||||
# and E = (t)_skew*R
|
||||
t_skew = np.zeros((3, 3))
|
||||
t_skew[0, 1] = -position[2]
|
||||
t_skew[0, 2] = position[1]
|
||||
t_skew[1, 0] = position[2]
|
||||
t_skew[1, 2] = -position[0]
|
||||
t_skew[2, 0] = -position[1]
|
||||
t_skew[2, 1] = position[0]
|
||||
|
||||
E = t_skew.dot(rotation)
|
||||
return normalized(E)
|
||||
|
||||
|
||||
def getPerturbedPose(position, rotation, amplitude):
|
||||
dp = generateRandomTranslation(amplitude)
|
||||
dR = generateRandomRotation(amplitude)
|
||||
return position + dp, rotation.dot(dR)
|
||||
|
||||
|
||||
def proportional(x, y, tol=1e-2):
|
||||
xn = normalized(x)
|
||||
yn = normalized(y)
|
||||
return (np.allclose(xn, yn, rtol=1e20, atol=tol) or
|
||||
np.allclose(xn, -yn, rtol=1e20, atol=tol))
|
||||
|
||||
|
||||
def matrix_in_list(a, l):
|
||||
for b in l:
|
||||
if proportional(a, b):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def same_transformation(position, rotation, transformation):
|
||||
R = transformation[:, :3]
|
||||
t = transformation[:, 3]
|
||||
return proportional(position, t) and proportional(rotation, R)
|
||||
|
||||
|
||||
class RelativePoseDataset:
|
||||
|
||||
def __init__(self, num_points, noise, outlier_fraction, rotation_only=False):
|
||||
# generate a random pose for viewpoint 1
|
||||
position1 = np.zeros(3)
|
||||
rotation1 = np.eye(3)
|
||||
|
||||
# generate a random pose for viewpoint 2
|
||||
if rotation_only:
|
||||
position2 = np.zeros(3)
|
||||
else:
|
||||
position2 = generateRandomTranslation(2.0)
|
||||
rotation2 = generateRandomRotation(0.5)
|
||||
|
||||
# derive correspondences based on random point-cloud
|
||||
self.generateCorrespondences(
|
||||
position1, rotation1, position2, rotation2,
|
||||
num_points, noise, outlier_fraction)
|
||||
|
||||
# Extract the relative pose
|
||||
self.position, self.rotation = extractRelativePose(
|
||||
position1, position2, rotation1, rotation2)
|
||||
if not rotation_only:
|
||||
self.essential = essentialMatrix(self.position, self.rotation)
|
||||
|
||||
def generateCorrespondences(self,
|
||||
position1, rotation1,
|
||||
position2, rotation2,
|
||||
num_points,
|
||||
noise, outlier_fraction):
|
||||
min_depth = 4
|
||||
max_depth = 8
|
||||
|
||||
# initialize point-cloud
|
||||
self.points = np.empty((num_points, 3))
|
||||
for i in range(num_points):
|
||||
self.points[i] = generateRandomPoint(max_depth, min_depth)
|
||||
|
||||
self.bearing_vectors1 = np.empty((num_points, 3))
|
||||
self.bearing_vectors2 = np.empty((num_points, 3))
|
||||
for i in range(num_points):
|
||||
# get the point in viewpoint 1
|
||||
body_point1 = rotation1.T.dot(self.points[i] - position1)
|
||||
|
||||
# get the point in viewpoint 2
|
||||
body_point2 = rotation2.T.dot(self.points[i] - position2)
|
||||
|
||||
self.bearing_vectors1[i] = normalized(body_point1)
|
||||
self.bearing_vectors2[i] = normalized(body_point2)
|
||||
|
||||
# add noise
|
||||
if noise > 0.0:
|
||||
self.bearing_vectors1[i] = addNoise(noise, self.bearing_vectors1[i])
|
||||
self.bearing_vectors2[i] = addNoise(noise, self.bearing_vectors2[i])
|
||||
|
||||
# add outliers
|
||||
num_outliers = int(outlier_fraction * num_points)
|
||||
for i in range(num_outliers):
|
||||
# create random point
|
||||
p = generateRandomPoint(max_depth, min_depth)
|
||||
|
||||
# project this point into viewpoint 2
|
||||
body_point = rotation2.T.dot(p - position2)
|
||||
|
||||
# normalize the bearing vector
|
||||
self.bearing_vectors2[i] = normalized(body_point)
|
||||
|
||||
|
||||
def test_relative_pose():
|
||||
print("Testing relative pose")
|
||||
|
||||
d = RelativePoseDataset(10, 0.0, 0.0)
|
||||
|
||||
# running experiments
|
||||
twopt_translation = pyopengv.relative_pose_twopt(
|
||||
d.bearing_vectors1, d.bearing_vectors2, d.rotation)
|
||||
fivept_nister_essentials = pyopengv.relative_pose_fivept_nister(
|
||||
d.bearing_vectors1, d.bearing_vectors2)
|
||||
fivept_kneip_rotations = pyopengv.relative_pose_fivept_kneip(
|
||||
d.bearing_vectors1, d.bearing_vectors2)
|
||||
sevenpt_essentials = pyopengv.relative_pose_sevenpt(d.bearing_vectors1, d.bearing_vectors2)
|
||||
eightpt_essential = pyopengv.relative_pose_eightpt(d.bearing_vectors1, d.bearing_vectors2)
|
||||
t_perturbed, R_perturbed = getPerturbedPose(d.position, d.rotation, 0.01)
|
||||
eigensolver_rotation = pyopengv.relative_pose_eigensolver(
|
||||
d.bearing_vectors1, d.bearing_vectors2, R_perturbed)
|
||||
t_perturbed, R_perturbed = getPerturbedPose(d.position, d.rotation, 0.1)
|
||||
nonlinear_transformation = pyopengv.relative_pose_optimize_nonlinear(
|
||||
d.bearing_vectors1, d.bearing_vectors2, t_perturbed, R_perturbed)
|
||||
|
||||
assert proportional(d.position, twopt_translation)
|
||||
assert matrix_in_list(d.essential, fivept_nister_essentials)
|
||||
assert matrix_in_list(d.rotation, fivept_kneip_rotations)
|
||||
assert matrix_in_list(d.essential, sevenpt_essentials)
|
||||
assert proportional(d.essential, eightpt_essential)
|
||||
assert proportional(d.rotation, eigensolver_rotation)
|
||||
assert same_transformation(d.position, d.rotation, nonlinear_transformation)
|
||||
|
||||
print("Done testing relative pose")
|
||||
|
||||
|
||||
def test_relative_pose_ransac():
|
||||
print("Testing relative pose ransac")
|
||||
|
||||
d = RelativePoseDataset(100, 0.0, 0.3)
|
||||
|
||||
ransac_transformation = pyopengv.relative_pose_ransac(
|
||||
d.bearing_vectors1, d.bearing_vectors2, "NISTER", 0.01, 1000)
|
||||
|
||||
assert same_transformation(d.position, d.rotation, ransac_transformation)
|
||||
|
||||
print("Done testing relative pose ransac")
|
||||
|
||||
|
||||
def test_relative_pose_ransac_rotation_only():
|
||||
print("Testing relative pose ransac rotation only")
|
||||
|
||||
d = RelativePoseDataset(100, 0.0, 0.3, rotation_only=True)
|
||||
|
||||
ransac_rotation = pyopengv.relative_pose_ransac_rotation_only(
|
||||
d.bearing_vectors1, d.bearing_vectors2, 0.01, 1000)
|
||||
|
||||
assert proportional(d.rotation, ransac_rotation)
|
||||
|
||||
print("Done testing relative pose ransac rotation only")
|
||||
|
||||
|
||||
def test_triangulation():
|
||||
print("Testing triangulation")
|
||||
|
||||
d = RelativePoseDataset(10, 0.0, 0.0)
|
||||
|
||||
points1 = pyopengv.triangulation_triangulate(
|
||||
d.bearing_vectors1, d.bearing_vectors2, d.position, d.rotation)
|
||||
|
||||
assert np.allclose(d.points, points1)
|
||||
|
||||
points2 = pyopengv.triangulation_triangulate2(
|
||||
d.bearing_vectors1, d.bearing_vectors2, d.position, d.rotation)
|
||||
|
||||
assert np.allclose(d.points, points2)
|
||||
|
||||
print("Done testing triangulation")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_relative_pose()
|
||||
test_relative_pose_ransac()
|
||||
test_relative_pose_ransac_rotation_only()
|
||||
test_triangulation()
|
||||
Reference in New Issue
Block a user