Triangulator¶
Prepare camera parameters
Build a triangulator
Triangulate points from 2D to 3D
Get reprojection error
Camera selection
Prepare camera parameters¶
A triangulator requires a list of camera parameters to triangulate points. Each camera parameter should be an instance of PinholeCameraParameter
or it’s sub-class. There are several ways to create the camera parameter list.
a. Assign camera parameters manually.
from xrprimer.data_structure.camera import PinholeCameraParameter
cam_param_list = []
for kinect_index in range(n_view):
cam_param = PinholeCameraParameter(
name=f'cam_{kinect_index:02d}',
world2cam=True)
cam_param.set_KRT(
K=intrinsics[kinect_index],
R=rotations[kinect_index],
T=translations[kinect_index])
cam_param_list.append(cam_param)
b. Load dumped camera parameter files.
from xrprimer.data_structure.camera import PinholeCameraParameter
cam_param_list = []
for kinect_index in range(n_view):
cam_param_path = os.path.join(input_dir,
f'cam_{kinect_index:02d}.json')
cam_param = PinholeCameraParameter()
cam_param.load(cam_param_path)
cam_param_list.append(cam_param)
Note that convention
and world2cam
shall be set correctly. It is essential for the triangulator to know how to deal with input parameters.
Build a triangulator¶
In XRprimer, we use registry and builder to build a certain triangulator among multiple alternative classes.
import mmcv
from xrprimer.ops.triangulation.builder import build_triangulator
triangulator_config = dict(
mmcv.Config.fromfile(
'config/ops/triangulation/opencv_triangulator.py'))
triangulator_config['camera_parameters'] = cam_param_list
triangulator = build_triangulator(triangulator_config)
Set cameras of a triangulator¶
Camera parameters can also be set after building.
triangulator.set_cameras(cam_param_list)
Triangulate points from 2D to 3D¶
If there’s only one point in 3D space, we could use triangulate_single_point()
.
# points2d in shape [n_view, 2], in type numpy.ndarray, or nested list/tuple
point3d = triangulator.triangulate_single_point(points2d)
# points3d in shape [3, ], in type numpy.ndarray
For more than one point, triangulate()
is recommended.
# points2d in shape [n_view, n_point, 2], in type numpy.ndarray, or nested list/tuple
point3d = triangulator.triangulate(points2d)
# points3d in shape [n_point, 3], in type numpy.ndarray
In multi-view scenario, not every view is helpful. To filter the good sources in 2D space, points_mask
is introduced.
# points_mask in shape [n_view, n_point 1]
# point0 point1 point2
# view0 0 nan 1
# view1 1 nan 1
# view2 1 nan 1
# result combine 1,2 nan combine 0,1,2
point3d = triangulator.triangulate_single_point(points2d, points_mask)
Get reprojection error¶
To evaluate the triangulation quality, we also provide a point-wise reprojection error, between input points2d and reprojected points2d. points_mask
is also functional here.
point3d = triangulator.triangulate(points2d, points_mask)
error2d = triangulator.get_reprojection_error(points2d, points3d, points_mask)
# error2d has the same shape as points2d
Camera selection¶
To select a sub-set of all the cameras, we provide a selection method.
# select two cameras by index list
sub_triangulator = triangulator[[0, 1]]
# a tuple argument is same as list
sub_triangulator = triangulator[(0, 1)]
# select the first 3 cameras by slice
sub_triangulator = triangulator[:3]
# select cameras whose index is divisible by 2
sub_triangulator = triangulator[::2]
Get a conjugated projector¶
The returned multi-view projector will have the same cameras as triangulator.
projector = triangulator.get_projector()