def test_project_points_invalid_as_input_null(): with pytest.raises(ValueError): pu.project_points(None, None, None, None) with pytest.raises(ValueError): pu.project_points(np.zeros([4, 3]), None, None, None) with pytest.raises(ValueError): pu.project_points(np.zeros([4, 3]), np.zeros([4, 4]), None, None)
def test_camera_projection(setup_vtk_overlay_window): vtk_overlay, factory, vtk_std_err, app = setup_vtk_overlay_window # See data: # chessboard_14_10_3_no_ID.txt - 3D chessboard coordinates # left-1095.png - image taken of chessboard # left-1095.png.points.txt - detected 2D image points # calib.intrinsic.txt - top 3x3 matrix are intrinsic parameters # left-1095.extrinsic.txt - model to camera matrix, a.k.a camera extrinsics, a.k.a pose # Load 3D points model_points_file = 'tests/data/calibration/chessboard_14_10_3_no_ID.txt' model_points = np.loadtxt(model_points_file) number_model_points = model_points.shape[0] model_polydata = [sm.VTKSurfaceModel('tests/data/calibration/chessboard_14_10_3.vtk', (1.0, 1.0, 0.0))] # Load images left_image = cv2.imread('tests/data/calibration/left-1095-undistorted.png') left_mask = cv2.imread('tests/data/calibration/left-1095-undistorted-mask.png') left_mask = cv2.cvtColor(left_mask, cv2.COLOR_RGB2GRAY) # Load 2D points image_points_file ='tests/data/calibration/left-1095-undistorted.png.points.txt' image_points = np.loadtxt(image_points_file) number_image_points = image_points.shape[0] # Load intrinsics for projection matrix. intrinsics_file = 'tests/data/calibration/calib.left.intrinsic.txt' intrinsics = np.loadtxt(intrinsics_file) # Load extrinsics for camera pose (position, orientation). extrinsics_file = 'tests/data/calibration/left-1095.extrinsic.txt' extrinsics = np.loadtxt(extrinsics_file) # OpenCV maps from chessboard to camera. # Assume chessboard == world, so the input matrix is world_to_camera. # We need camera_to_world to position the camera in world coordinates. # So, invert it. camera_to_world = np.linalg.inv(extrinsics) assert number_model_points == 140 assert number_image_points == 140 assert len(image_points) == 140 assert len(model_points) == 140 screen = app.primaryScreen() width = left_image.shape[1] height = left_image.shape[0] while width >= screen.geometry().width() or height >= screen.geometry().height(): width //= 2 height //= 2 vtk_overlay.add_vtk_models(model_polydata) vtk_overlay.set_video_image(left_image) vtk_overlay.set_camera_pose(camera_to_world) vtk_overlay.resize(width, height) vtk_overlay.show() vtk_renderer = vtk_overlay.get_foreground_renderer() vtk_camera = vtk_overlay.get_foreground_camera() vtk_renderwindow_size = vtk_overlay.GetRenderWindow().GetSize() # Wierdly, vtkRenderWindow, sometimes seems to use the wrong resolution, # like its trying to render at high resolution, maybe for anti-aliasing or averaging? scale_x = left_image.shape[1] / vtk_renderwindow_size[0] scale_y = left_image.shape[0] / vtk_renderwindow_size[1] # Print out some debug. On some displays, the widget size and the size of the vtkRenderWindow don't match. six.print_('Left image = (' + str(left_image.shape[1]) + ', ' + str(left_image.shape[0]) + ')') six.print_('Chosen size = (' + str(width) + ', ' + str(height) + ')') six.print_('Render window = ' + str(vtk_overlay.GetRenderWindow().GetSize())) six.print_('Widget = (' + str(vtk_overlay.width()) + ', ' + str(vtk_overlay.height()) + ')') six.print_('Viewport = ' + str(vtk_renderer.GetViewport())) six.print_('Scale = ' + str(scale_x) + ', ' + str(scale_y)) # Set intrisic parameters, which internally sets vtkCamera vars. vtk_overlay.set_camera_matrix(intrinsics) # Compute the rms error, using a vtkCoordinate loop, which is slow. rms = pu.compute_rms_error(model_points, image_points, vtk_renderer, scale_x, scale_y, left_image.shape[0] ) six.print_('rms using VTK =' + str(rms)) # Now check the rms error, using an OpenCV projection, which should be faster. projected_points = pu.project_points(model_points, camera_to_world, intrinsics ) counter = 0 rms_opencv = 0 for counter in range(0, number_model_points): i_c = image_points[counter] dx = projected_points[counter][0][0] - float(i_c[0]) dy = projected_points[counter][0][1] - float(i_c[1]) rms_opencv += (dx * dx + dy * dy) counter += 1 rms_opencv /= float(counter) rms_opencv = np.sqrt(rms_opencv) six.print_('rms using OpenCV =' + str(rms_opencv)) assert rms < 1.2 assert rms_opencv < 0.7 model_polydata_points = model_polydata[0].get_points_as_numpy() model_polydata_normals = model_polydata[0].get_normals_as_numpy() six.print_('model_points=' + str(model_polydata_points)) projected_facing_points = pu.project_facing_points(model_polydata_points, model_polydata_normals, camera_to_world, intrinsics ) assert projected_facing_points.shape[0] == 4 assert projected_facing_points.shape[2] == 2 # Can't think how to do this more efficiently yet. masked = [] for point_index in range(projected_facing_points.shape[0]): x = projected_facing_points[point_index][0][0] y = projected_facing_points[point_index][0][1] val = left_mask[int(y), int(x)] six.print_('p=' + str(x) + ', ' + str(y)) if int(x) >= 0 \ and int(x) < left_mask.shape[1] \ and int(y) >= 0 \ and int(y) < left_mask.shape[0] \ and val > 0: masked.append((x, y)) assert len(masked) == 2
def test_stereo_overlay_window(vtk_interlaced_stereo_window): widget, _, app = vtk_interlaced_stereo_window model_points_file = 'tests/data/calibration/chessboard_14_10_3_no_ID.txt' model_points = np.loadtxt(model_points_file) number_model_points = model_points.shape[0] assert number_model_points == 140 # Load images left_image = cv2.imread('tests/data/calibration/left-1095-undistorted.png') right_image = cv2.imread('tests/data/calibration/right-1095-undistorted.png') # Load left intrinsics for projection matrix. left_intrinsics_file = 'tests/data/calibration/calib.left.intrinsic.txt' left_intrinsics = np.loadtxt(left_intrinsics_file) # Load right intrinsics for projection matrix. right_intrinsics_file = 'tests/data/calibration/calib.right.intrinsic.txt' right_intrinsics = np.loadtxt(right_intrinsics_file) # Load 2D points image_points_file ='tests/data/calibration/right-1095-undistorted.png.points.txt' image_points = np.loadtxt(image_points_file) number_image_points = image_points.shape[0] assert number_model_points == number_image_points # Load extrinsics for camera pose (position, orientation). extrinsics_file = 'tests/data/calibration/left-1095.extrinsic.txt' extrinsics = np.loadtxt(extrinsics_file) left_camera_to_world = np.linalg.inv(extrinsics) # Load extrinsics for stereo. stereo_extrinsics_file = 'tests/data/calibration/calib.l2r.4x4' stereo_extrinsics = np.loadtxt(stereo_extrinsics_file) screen = app.primaryScreen() width = left_image.shape[1] height = left_image.shape[0] while width >= screen.geometry().width() or height >= screen.geometry().height(): width /= 2 height /= 2 # Create a vtk point model. vtk_points = vtk_point_model.VTKPointModel(model_points.astype(np.float), model_points.astype(np.byte)) widget.add_vtk_actor(vtk_points.actor) widget.set_video_images(left_image, right_image) widget.set_camera_matrices(left_intrinsics, right_intrinsics) widget.set_left_to_right(stereo_extrinsics) widget.set_camera_poses(left_camera_to_world) widget.resize(width, height) widget.show() widget.set_current_viewer_index(0) widget.set_current_viewer_index(1) widget.set_current_viewer_index(2) widget.render() six.print_('Chosen size = (' + str(width) + 'x' + str(height) + ')') six.print_('Left image = :' + str(left_image.shape)) six.print_('Right image = :' + str(right_image.shape)) six.print_('Widget = (' + str(widget.width()) + ', ' + str(widget.height()) + ')') # Project points using OpenCV. right_camera_to_world = cam.compute_right_camera_pose(left_camera_to_world, stereo_extrinsics) right_points = pu.project_points(model_points, right_camera_to_world, right_intrinsics ) rms_opencv = 0 for counter in range(0, number_model_points): i_c = image_points[counter] dx = right_points[counter][0][0] - i_c[0] dy = right_points[counter][0][1] - i_c[1] rms_opencv += (dx * dx + dy * dy) rms_opencv /= number_model_points rms_opencv = np.sqrt(rms_opencv) assert rms_opencv < 1 widget.save_scene_to_file('tests/output/test_interlaced_stereo_window.png') #app.exec_()
def test_project_points_invalid_as_distortion_wrong_number_rows(): with pytest.raises(ValueError): pu.project_points(np.zeros([4, 3]), np.eye(4), np.eye(3), np.zeros([2, 4]))
def test_project_points_invalid_as_intrinsics_wrong_size(): with pytest.raises(ValueError): pu.project_points(np.zeros([4, 3]), np.zeros([4, 4]), np.eye(2), np.zeros([1, 4]))
def test_project_points_invalid_as_extrinsics_wrong_number_columns(): with pytest.raises(ValueError): pu.project_points(np.zeros([4, 3]), np.zeros([4, 5]), np.eye(3), None)
def test_project_points_invalid_as_extrinsics_not_2d(): with pytest.raises(ValueError): pu.project_points(np.zeros([4, 3]), np.zeros([4, 4, 4]), np.eye(3), None)
def test_project_points_invalid_as_extrinsics_not_numpy_array(): with pytest.raises(TypeError): pu.project_points(np.zeros([4, 3]), "invalid", np.eye(3), None)
def test_project_points_invalid_as_points_not_3_columns(): with pytest.raises(ValueError): pu.project_points(np.zeros([4, 4]), np.zeros([4, 4]), np.eye(3), None)