コード例 #1
0
def generate_poses(n: int, noise_list: list):

    # groud truth hand eye calibration matrix and chessboard pose
    hec = HT.from_matrix(
        np.array([[1, 0, 0, 50], [0, 1, 0, 0], [0, 0, 1, 100], [0, 0, 0, 1]]))
    cb_pose = HT.from_matrix(
        np.array([[0, -1, 0, 200], [1, 0, 0, 70], [0, 0, 1, 0], [0, 0, 0, 1]]))

    Ai = []
    Bi = []

    nx = 20
    ny = 13
    obj_pts = np.zeros((nx * ny, 4))
    obj_pts[:, 3] = 1
    # obj_pts[:, :2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2)*20.0
    obj_pts[:, :2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2) * 20.0
    obj_pts[:, :3] = obj_pts[:, :3] - np.mean(obj_pts[:, :3], axis=0)
    Ry_180 = HT(np.pi, np.array([0, 1, 0]))

    # chessboard_pts = cb_pose @ obj_pts.T

    for i in range(n):
        a_rvec = np.pi * np.random.randn(3)
        a_tvec = 300 * np.sqrt(3) * np.random.randn(3)
        a_tvec[2] = np.abs(a_tvec[2])
        A_i = HT.from_vecs(a_rvec, a_tvec)
        if A_i.matrix[2, 2] > 0:
            A_i = A_i @ Ry_180

        Ai.append(A_i)

        # temp_Bi = (Ai[i] @ hec).inv() @ cb_pose
        # b_rvec = temp_Bi.rvec()
        # b_tvec = temp_Bi.t# + noise * np.random.randn(3)
        # Bi.append(HT.from_vecs(b_rvec, b_tvec))
        Bi.append((Ai[i] @ hec).inv() @ cb_pose)
    bpts = []
    bplanes = []

    for noise in noise_list:

        board_points = []
        board_poses_plane = []
        for i in range(n):
            point_noise = np.zeros((4, nx * ny))
            point_noise[:3, :] = noise * np.random.randn(3, nx * ny)
            chessboard_pts = cb_pose @ (obj_pts + point_noise.T).T

            board_points.append(((
                (Ai[i] @ hec).inv() @ chessboard_pts).T))  # + point_noise).T)

            board_poses_plane.append(plane_fit(board_points[i], nx, ny)[0])

        bpts.append(board_points)
        bplanes.append(board_poses_plane)

    return Ai, Bi, bpts, bplanes
コード例 #2
0
    def calculate_chessboard_poses_2D(self):
        '''
        Calculates the poses of the calibration objects in self.point_clouds using
        opencv camera calibration, and strores them in the list self.chessboard_poses.
        If the intrinsic parameters of the camera are known,
        and set with the method self.setIntrinsics(...) cv2.solvePnP(...) is used, else
        cv2.CalibrateCamera(...) is used to calibrate the intrinsic and extrinsic camera
        parameters.
        '''
        assert (len(self.point_clouds) > 0), 'No calibration images loaded'
        print('Calculating chessboard poses')
        self.method = '2D'
        img_pts, obj_pts, self.XYZs, self.corners, self.rgbs, img_size = calibration_pts(
            self.nx, self.ny, self.square_size, self.point_clouds)

        if self.camera_matrix is not None and self.dist_coeffs is not None:
            print('solvepnp')
            for i in range(len(self.point_clouds)):
                _, rvec, tvec = \
                    cv2.solvePnP(obj_pts[i].astype('float32'), img_pts[i].astype(
                        'float32'), self.camera_matrix, self.dist_coeffs)
                self.rvecs.append(rvec)
                self.tvecs.append(tvec)
        else:
            _, self.camera_matrix, self.dist_coeffs, self.rvecs, self.tvecs = \
                cv2.calibrateCamera(obj_pts.astype(
                    'float32'), img_pts.astype('float32'), img_size, None, None)

        self.chessboard_poses = [
            HT.from_vecs(r, t) for (r, t) in zip(self.rvecs, self.tvecs)
        ]
コード例 #3
0
def load_quat_poses(path: str):
    files = sorted(glob.glob(f'{path}/*.txt'))
    poses = [
        HT.from_quat_pose(
            np.fromfile(pose_file, dtype=float, count=-1, sep=' '))
        for pose_file in files
    ]
    return files, poses
コード例 #4
0
def load_t4s(path: str):
    files = sorted(glob.glob(f'{path}/*.t4'))
    poses = [
        HT.from_matrix(
            np.fromfile(pose_file, dtype=float, count=-1,
                        sep=' ').reshape(4, 4)) for pose_file in files
    ]
    return files, poses
コード例 #5
0
def pnt_cld_transf(pnt_cld1: np.ndarray, pnt_cld2: np.ndarray):
    c1 = np.mean(pnt_cld1, axis=0)
    c2 = np.mean(pnt_cld2, axis=0)

    U, Z, V = np.linalg.svd((pnt_cld2 - c2).T @ (pnt_cld1 - c1))

    S = np.diag([1, 1, np.linalg.det(V.T @ U.T)])
    R = V.T @ S @ U.T
    t = c1.T - R @ c2.T

    T = np.zeros((4, 4))
    T[:3, :3] = R
    T[:3, 3] = t
    return HT.from_matrix(T)
コード例 #6
0
def calib_err_2D(hec, rob_poses: list, board_poses: list, eye_in_hand=True):
    '''Uses the variation in the constant transformation between
        - robot base frame and object points for eye-in-hand calibration
        - end-effector frame and object points for eye-in-base calibration
        to calculate an estimate for the accuracy of the calibration.
    '''
    if eye_in_hand:
        T_bo = np.array([
            (rob_pose @ hec @ board_pose).matrix
            for rob_pose, board_pose in zip(rob_poses, board_poses)
        ])
    else:
        T_bo = np.array([
            (rob_pose.inv() @ hec @ board_pose).matrix
            for rob_pose, board_pose in zip(rob_poses, board_poses)
        ])

    mean_r = np.mean(np.array([HT.from_matrix(T).rvec() for T in T_bo]),
                     axis=0)
    mean_theta = np.mean(
        np.array([HT.from_matrix(T).angle_axis()[0] for T in T_bo]))
    mean_t = np.mean(T_bo[:, :3, 3], axis=0)
    mean_board_pose = HT.from_vecs(mean_r, mean_t)

    trans_err = np.zeros((len(rob_poses), 3))
    rot_err = np.zeros((len(rob_poses)))
    theta_err = np.zeros((len(rob_poses)))
    for i in range(len(rob_poses)):
        Terr = HT.from_matrix(mean_board_pose.inv() @ T_bo[i])
        trans_err[i, :3] = Terr.t
        rot_err[i] = np.rad2deg(Terr.angle_axis()[0])
        theta_err[i] = np.rad2deg(
            np.abs(HT.from_matrix(T_bo[i]).angle_axis()[0] - mean_theta))

    return (np.mean(np.linalg.norm(trans_err,
                                   axis=1)), np.mean(np.abs(theta_err)))
コード例 #7
0
def plane_fit(pnt_cld: np.ndarray, nx: int, ny: int):
    U, Z, V = np.linalg.svd(pnt_cld)
    P = V.T[:, 3]
    if P[3] < 0:
        P = -P

    x_ctrl = (pnt_cld[nx-2]-pnt_cld[0]) / \
        np.linalg.norm(pnt_cld[nx-2]-pnt_cld[0])

    # best fit x:
    X = pnt_cld  # np.array(pnt_cld[:nx-1])
    _, _, v = np.linalg.svd(X[:, :3] - np.mean(X[:, :3], axis=0))
    x = v[0] / np.linalg.norm(v[0])
    # ensure x is pointing in the correct direction
    if (np.isclose(x, -x_ctrl[0:3], rtol=0.1).any()):
        x = -x

    # z-axis normal to chessboard plane, and unit vector
    z = P[0:3] / np.linalg.norm(P[0:3])
    # z = -v[2]/np.linalg.norm(v[2])
    # if z[2] > 0:
    #     z = -z
    # ensure x is orthogonal to z

    x = x - ((x @ z) / np.linalg.norm(z)**2) * z
    x = x / np.linalg.norm(x)
    # y is orthogonal to x and z, xyz is now an orthogonal basis in R3
    y = np.cross(z, x)
    # centroid selected as origin
    t = np.mean(pnt_cld, axis=0)
    # if(t[2]<0):
    #     x=-x
    #     z=-z

    T = np.zeros((4, 4))
    T[:3, 0] = x[0:3]
    T[:3, 1] = y[0:3]
    T[:3, 2] = z[0:3]
    T[:, 3] = t
    T = HT.from_matrix(T)
    return T, P
コード例 #8
0
def park_martin(A: list, B: list):
    '''Calculates the transformation between the robot end-effector frame and the camera frame.
        Using lists containing pairs of relative motions of camera and robot.
        Method: AX = XB in the style of Park and Martin.

        Parameters: A, B lists of HTransf objects.
        Returns: HTransf object representing the transformation
        between robot end-effector frame and the camera frame
        '''
    K_a = np.zeros((3, len(A)))
    K_b = np.zeros((3, len(B)))

    for i in range(len(A)):
        angle_a, axis_a = A[i].angle_axis()
        angle_b, axis_b = B[i].angle_axis()
        K_a[:, i] = (angle_a * axis_a).flatten()
        K_b[:, i] = (angle_b * axis_b).flatten()
    # calcualte the optimal least squares solution for the
    # rotation matrix between camrea frame and end-effector frame
    H = K_b @ K_a.T
    U, Z, V = np.linalg.svd(H)

    # umeyama correction, to correct for reflection matrices
    S = np.diag([1, 1, np.linalg.det(V.T @ U.T)])
    R_optimal = HT.from_matrix(V.T @ S @ U.T)

    # calculate the best fit translation (dependent on the rotation)
    C = np.zeros((3 * len(A), 3))
    d = np.zeros((3 * len(B), 1))
    for i in range(0, len(A) * 3, 3):
        C[i:i + 3, :] = A[int(i / 3)].rot_matrix - np.identity(3)
        d[i:i+3, 0] = R_optimal @ B[int(i/3)].get_translation() - \
            A[int(i/3)].get_translation()
        C[i:i + 3, :] = np.identity(3) - A[int(i / 3)].rot_matrix
        d[i:i+3, 0] = A[int(i/3)].get_translation() - \
            R_optimal @ B[int(i/3)].get_translation()

    t_optimal = np.linalg.lstsq(C, d, rcond=None)[0]

    a, k = R_optimal.angle_axis()
    return HT(a, k, t_optimal)
コード例 #9
0
            f1 = plt.figure('Translation')
            plt.plot(range(3, self.num_imgs + 1), trans_errs)
            f2 = plt.figure('Rotation')
            plt.plot(range(3, self.num_imgs + 1), rot_errs)
            plt.show(block=False)
        print(hec)
        print(trans_err, rot_err)
        return trans_errs, rot_errs


if __name__ == '__main__':
    '''example taken from You Cheung Shiu et al.
       "calibration of wrist-mounted robotic sensors by solving 
       homogeneous transformation equations of the form AX=XB"
    '''
    X_act = HT(a=0.2, k=np.array([1, 0, 0]), t=np.array([10, 50, 100]))
    A1 = HT(a=3.0, k=np.array([0, 0, 1]), t=np.array([0, 0, 0]))
    A2 = HT(a=1.5, k=np.array([0, 1, 0]), t=np.array([-400, 0, 400]))
    B1 = X_act.inv() @ A1 @ X_act
    B2 = X_act.inv() @ A2 @ X_act
    # print(A1, A2, B1, B2)
    A11 = np.array([[-0.989992, -0.141120, 0.0, 0.0],
                    [0.141120, -0.989992, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1]])
    B11 = np.array([[-0.989992, -0.138307, 0.028036, -26.9559],
                    [0.138307, -0.911449, 0.387470, -96.1332],
                    [-0.028036, 0.387470, 0.921456, 19.4872],
                    [0.0, 0.0, 0.0, 1]])
    A22 = np.array([[0.070737, 0.0, 0.997495, -400.0], [0.0, 1.0, 0.0, 0.0],
                    [-0.997495, 0.0, 0.070737, 400.0], [0.0, 0.0, 0.0, 1]])
    B22 = np.array([[0.070737, 0.198172, 0.997612, -309.543],