Esempio n. 1
0
def build_view_mat(
    common_obj: np.ndarray, common_img: np.ndarray, common_ids: np.ndarray,
    intrinsic_mat: np.ndarray
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, float]:
    _, rvec, tvec, inliers = cv2.solvePnPRansac(
        common_obj,
        common_img,
        intrinsic_mat,
        None,
        #flags=cv2.SOLVEPNP_EPNP,
        reprojectionError=RANSAC_REPROJECTION_ERROR,
        iterationsCount=100)
    mat = rodrigues_and_translation_to_view_mat3x4(rvec, tvec)

    inliers = np.array(inliers).reshape(-1)
    inlier_points = common_obj[inliers]
    inlier_img = common_img[inliers]
    inlier_ids = common_ids[inliers]
    reprojection_errors = compute_reprojection_errors(inlier_points,
                                                      inlier_img,
                                                      intrinsic_mat @ mat)
    #to_take = reprojection_errors < RANSAC_REPROJECTION_ERROR
    #reprojection_error = compute_reprojection_errors(inlier_points, inlier_img, intrinsic_mat @ mat).mean()

    #reprojection_error = np.linalg.norm(common_img - projections, axis=-1).mean()

    #return mat, inlier_points[to_take], inlier_ids[to_take], reprojection_errors[to_take].mean()
    return mat, inlier_points, inlier_ids, reprojection_errors.mean()
Esempio n. 2
0
 def pnp(self, cloud: PointCloudBuilder, camera):
     ids1, ids2 = build_index_intersection(cloud.ids, self.corners.ids)
     try:
         ret, rvec, tvec, inliers = cv2.solvePnPRansac(
             cloud.points[ids1],
             self.corners.points[ids2],
             camera,
             None,
             reprojectionError=MAX_REPROJECTION_ERROR)
     except:
         return self.last_inliners
     if not ret or len(inliers) < FrameTrack.MIN_INLIERS or np.linalg.norm(
             tvec) > MAX_TRANSLATION:
         return self.last_inliners
     potential_new_mtx = rodrigues_and_translation_to_view_mat3x4(
         rvec, tvec)
     potential_reprojection_error = compute_reprojection_errors(
         cloud.points[ids1], self.corners.points[ids2],
         camera @ potential_new_mtx)
     if self.current_reproject_error is None or potential_reprojection_error.mean(
     ) < self.current_reproject_error:
         self.mtx = potential_new_mtx
         self.current_reproject_error = potential_reprojection_error.mean()
         self.last_inliners = cloud.ids[ids1][np.array(inliers)]
     return self.last_inliners
Esempio n. 3
0
    def try_solve_pnp(self, points_3d: np.ndarray, points_2d: np.ndarray) -> Optional[Tuple[np.ndarray, np.ndarray]]:
        if len(points_3d) < 6:
            return None
        ok, r_vec, t_vec, inliers = cv2.solvePnPRansac(
            objectPoints=points_3d,
            imagePoints=points_2d,
            cameraMatrix=self.intrinsic_mat,
            distCoeffs=None,
            confidence=PNP_RANSAC_CONFIDENCE,
            reprojectionError=PNP_RANSAC_INLIERS_MAX_REPROJECTION_ERROR,
            flags=cv2.SOLVEPNP_EPNP
        )
        if not ok:
            return None
        inliers = inliers.flatten()

        if len(inliers) < 6:
            return None

        _, r_vec, t_vec = cv2.solvePnP(
            points_3d,
            points_2d,
            self.intrinsic_mat,
            distCoeffs=None,
            rvec=r_vec,
            tvec=t_vec,
            useExtrinsicGuess=True,
            flags=cv2.SOLVEPNP_ITERATIVE
        )

        return rodrigues_and_translation_to_view_mat3x4(r_vec, t_vec), inliers
Esempio n. 4
0
 def calc_vec_errors(vec, point2d):
     r, t = vec[0:3], vec[3:6]
     view_mat, point3d = rodrigues_and_translation_to_view_mat3x4(
         r.reshape(3, 1), t.reshape(3, 1)), vec[6:9]
     return compute_reprojection_errors(point3d.reshape(1, -1),
                                        point2d.reshape(1, -1),
                                        intrinsic_mat @ view_mat)[0]
Esempio n. 5
0
    def solve_pnp_ransac_one(self, frame_id):
        ids_3d = self.point_cloud_builder.ids
        ids_2d = self.corner_storage[frame_id].ids
        ids_intersection, _ = snp.intersect(ids_3d.flatten(), ids_2d.flatten(), indices=True)
        idx3d = [i for i, j in enumerate(ids_3d) if j in ids_intersection]
        idx2d = [i for i, j in enumerate(ids_2d) if j in ids_intersection]
        points3d = self.point_cloud_builder.points[idx3d]
        points2d = self.corner_storage[frame_id].points[idx2d]

        if len(points3d) < 6:
            return None, []

        _, _, _, inliers = cv2.solvePnPRansac(
            objectPoints=points3d,
            imagePoints=points2d,
            cameraMatrix=self.intrinsic_mat,
            distCoeffs=np.array([]),
            iterationsCount=250,
            flags=cv2.SOLVEPNP_EPNP
        )

        if len(points3d[inliers]) < 6:
            return None, []

        _, r_vec, t_vec = cv2.solvePnP(
            objectPoints=points3d[inliers],
            imagePoints=points2d[inliers],
            cameraMatrix=self.intrinsic_mat,
            distCoeffs=np.array([]),
            flags=cv2.SOLVEPNP_ITERATIVE
        )
        view_mat = rodrigues_and_translation_to_view_mat3x4(r_vec, t_vec)
        return view_mat, inliers
Esempio n. 6
0
    def _get_pos(self, frame_number):
        corners = self.corner_storage[frame_number]
        cur_corners, cur_cloud_pts = [], []
        for i, corner in zip(corners.ids.flatten(), corners.points):
            if i in self.point_cloud.keys():
                cur_corners.append(corner)
                cur_cloud_pts.append(self.point_cloud[i].pos)
        cur_corners, cur_cloud_pts = np.array(cur_corners), np.array(
            cur_cloud_pts)
        if len(cur_cloud_pts) < 4:
            return None  # Not enough points for ransac

        is_success, r_vec, t_vec, inliers = cv2.solvePnPRansac(
            cur_cloud_pts,
            cur_corners,
            self.intrinsic_mat,
            None,
            flags=cv2.SOLVEPNP_EPNP)
        if not is_success:
            return None

        _, r_vec, t_vec = cv2.solvePnP(cur_cloud_pts[inliers],
                                       cur_corners[inliers],
                                       self.intrinsic_mat,
                                       distCoeffs=None,
                                       flags=cv2.SOLVEPNP_ITERATIVE,
                                       useExtrinsicGuess=True,
                                       rvec=r_vec,
                                       tvec=t_vec)

        pos = rodrigues_and_translation_to_view_mat3x4(r_vec, t_vec)
        inliers_n = len(np.array(inliers).flatten())
        return CameraInfo(pos, inliers_n)
Esempio n. 7
0
def camera_pose(id,
                corner_storage,
                point_cloud_builder,
                intrinsic_mat,
                dist_coef=None):
    frame_corners = corner_storage[id]
    points = frame_corners.points
    frame_ids = frame_corners.ids
    cloud_ids = point_cloud_builder.ids
    ids, frame_indexes, cloud_indexes = np.intersect1d(frame_ids,
                                                       cloud_ids,
                                                       return_indices=True)
    if ids.shape[0] < 4:
        return None

    cloud_points = point_cloud_builder.points[cloud_indexes]
    frame_points = points[frame_indexes]
    retval, rvec, tvec, inliers = cv2.solvePnPRansac(cloud_points,
                                                     frame_points,
                                                     intrinsic_mat, dist_coef)
    if retval is None:
        return None
    retval, rvec, tvec = cv2.solvePnP(cloud_points[inliers],
                                      frame_points[inliers], intrinsic_mat,
                                      dist_coef)
    if retval is None:
        return None
    return view_mat3x4_to_pose(
        rodrigues_and_translation_to_view_mat3x4(rvec, tvec)), np.setdiff1d(
            ids, inliers)
Esempio n. 8
0
    def _get_pos(self, frame_number) -> np.ndarray:
        corners = self.corner_storage[frame_number]
        _, pts_ids, corners_ids = np.intersect1d(self.pc_builder.ids, corners.ids, assume_unique=True,
                                                 return_indices=True)

        common_pts_3d = self.pc_builder.points[pts_ids]
        common_ids = self.pc_builder.ids[pts_ids]
        common_corners = corners.points[corners_ids]
        inlier_mask = np.zeros_like(common_pts_3d, dtype=np.bool)
        inlier_counter = 0
        for common_id, mask_elem in zip(common_ids[:, 0], inlier_mask):
            if common_id not in self.outliers:
                mask_elem[:] = True
                inlier_counter += 1
        if inlier_counter > 7:
            common_pts_3d = common_pts_3d[inlier_mask].reshape(-1, 3)
            common_ids = common_ids[inlier_mask[:, :1]].reshape(-1, 1)
            common_corners = common_corners[inlier_mask[:, :2]].reshape(-1, 2)
        max_reproj_error = 3.0
        if len(common_pts_3d) < 4:
            raise TrackingError('Not enough points to solve RANSAC on frame ' + str(frame_number))
        _, rot_vec, tr_vec, inliers = cv2.solvePnPRansac(common_pts_3d,
                                                         common_corners,
                                                         self.intrinsic_mat,
                                                         None,
                                                         reprojectionError=max_reproj_error,
                                                         flags=cv2.SOLVEPNP_EPNP)
        extrinsic_mat = rodrigues_and_translation_to_view_mat3x4(rot_vec, tr_vec)
        proj_matr = self.intrinsic_mat @ extrinsic_mat
        if inliers is None:
            raise TrackingError('Failed to solve PnP on frame' + str(frame_number))

        while len(inliers) < 8 and max_reproj_error < 50:
            max_reproj_error *= 1.2
            inliers = calc_inlier_indices(common_pts_3d, common_corners, proj_matr, max_reproj_error)
        inlier_pts = common_pts_3d[inliers]
        inlier_corners = common_corners[inliers]
        outlier_ids = np.setdiff1d(common_ids, common_ids[inliers], assume_unique=True)
        self.outliers.update(outlier_ids)
        if len(inliers) < 4:
            inlier_pts = common_pts_3d
            inlier_corners = common_corners
        print('Found position on', len(inlier_corners), 'inliers')
        _, rot_vec, tr_vec, inliers = cv2.solvePnPRansac(inlier_pts, inlier_corners, self.intrinsic_mat, None,
                                                         rot_vec, tr_vec, useExtrinsicGuess=True)
        return rodrigues_and_translation_to_view_mat3x4(rot_vec, tr_vec)
Esempio n. 9
0
 def f(rtp):
     r_vec = rtp[:3].reshape(3, 1)
     t_vec = rtp[3:6].reshape(3, 1)
     p = rtp[6:]
     proj = intrinsic_mat @ rodrigues_and_translation_to_view_mat3x4(
         r_vec, t_vec) @ p
     proj /= proj[2]
     return np.square(proj - point2d).sum()
Esempio n. 10
0
 def apply_res(res_):
     for i in range(len(intersected)):
         p_ = res_[6 * len(frames) + i * 3:6 * len(frames) + i * 3 + 3]
         _idx = np.argwhere(self.point_cloud_builder.ids == intersected[i])[0][0]
         _p = self.point_cloud_builder.points[_idx]
         check_point(_p, p_, intersected[i])
     for i in range(len(frames)):
         r_vec_ = np.array([res_[i * 6], res_[i * 6 + 1], res_[i * 6 + 2]])
         t_vec_ = np.array([[res_[i * 6 + 3]], [res_[i * 6 + 4]], [res_[i * 6 + 5]]])
         v_mat = rodrigues_and_translation_to_view_mat3x4(r_vec_, t_vec_)
         self.view_mats[frames[i]] = v_mat
Esempio n. 11
0
def solve_pnp(points2d: np.ndarray,
              points3d: np.ndarray,
              intrinsic_mat: np.ndarray) -> np.ndarray:
    _, rvev, tvec = cv2.solvePnP(
        objectPoints=points3d.astype(np.float64),
        imagePoints=points2d,
        cameraMatrix=intrinsic_mat,
        distCoeffs=None
    )

    return rodrigues_and_translation_to_view_mat3x4(rvev, tvec)
Esempio n. 12
0
def solve_frame(frame_num, corner_storage, point_cloud_builder, view_mat,
                intrinsic_mat, direction):
    print("Frame ", frame_num)
    corners = corner_storage[frame_num]

    _, corner_indexes, points_indexes = np.intersect1d(corners.ids,
                                                       point_cloud_builder.ids,
                                                       assume_unique=True,
                                                       return_indices=True)
    corners = corners.points[corner_indexes]
    points = point_cloud_builder.points[points_indexes]
    x, r, t, inliers = cv2.solvePnPRansac(points,
                                          corners,
                                          intrinsic_mat,
                                          None,
                                          reprojectionError=1.0,
                                          flags=cv2.SOLVEPNP_EPNP)

    good_corners = corners[inliers]
    good_points = points[inliers]
    x, r, t = cv2.solvePnP(good_points,
                           good_corners,
                           intrinsic_mat,
                           None,
                           r,
                           t,
                           useExtrinsicGuess=True,
                           flags=cv2.SOLVEPNP_ITERATIVE)
    print("Points in cloud ", len(point_cloud_builder.ids))

    new_views = rodrigues_and_translation_to_view_mat3x4(r, t)
    if new_views is None:
        view_mat[frame_num] = view_mat[frame_num + direction]
    else:
        view_mat[frame_num] = new_views

    for i in range(40):
        other_frame_num = frame_num + i * direction
        if check_baseline(view_mat[other_frame_num], view_mat[frame_num], 0.1):
            correspondences = build_correspondences(
                corner_storage[other_frame_num],
                corner_storage[frame_num],
                ids_to_remove=point_cloud_builder.ids)
            if len(correspondences) != 0:
                new_points, ids, _ = triangulate_correspondences(
                    correspondences, view_mat[other_frame_num],
                    view_mat[frame_num], intrinsic_mat,
                    TriangulationParameters(1.0, 1.0, 0.1))
                point_cloud_builder.add_points(ids, new_points)
Esempio n. 13
0
def get_ransac(point_cloud_builder, corners_i, intrinsic_mat):
    intersection, (indexes_cloud, indexes_corners) = snp.intersect(
        point_cloud_builder.ids.flatten(),
        corners_i.ids.flatten(),
        indices=True)
    if len(intersection) < 6:
        return False, None, None, None
    try:
        res_code, rvec, tvec, inliers = cv2.solvePnPRansac(
            point_cloud_builder.points[indexes_cloud],
            corners_i.points[indexes_corners],
            intrinsic_mat,
            distCoeffs=None,
            reprojectionError=1.5)
    except Exception:
        print('Exception happened in solving PnP, continuing')
        return False, None, None, None
    rodrig = None
    cloud_points = None
    if res_code:
        rodrig = rodrigues_and_translation_to_view_mat3x4(rvec, tvec)
        cloud_points = point_cloud_builder.points[indexes_cloud][
            inliers.flatten()]
    return res_code, rodrig, inliers, cloud_points
Esempio n. 14
0
 def track(self):
     for cur_index in range(self._length):
         print(f'Processing frame {cur_index}/{self._length}')
         corners = self._corner_storage[cur_index]
         ids = []
         object_points = []
         image_points = []
         for id, point in zip(corners.ids, corners.points):
             indices_x, _ = np.where(self._builder.ids == id)
             if len(indices_x) == 0:
                 continue
             ids.append(id)
             object_points.append(self._builder.points[indices_x[0]])
             image_points.append(point)
         if len(object_points) < 5:
             continue
         retval, rvec, tvec, inliers = cv2.solvePnPRansac(
             np.array(object_points),
             np.array(image_points),
             self._intrinsic_mat,
             None,
             flags=cv2.SOLVEPNP_EPNP)
         if not retval:
             continue
         view_mat = rodrigues_and_translation_to_view_mat3x4(rvec, tvec)
         print(f'Position based on {len(inliers)} inliers')
         self._track[cur_index] = view_mat
         updatesCount = sum([self._update_cloud(cur_index, next_index) for next_index in range(cur_index) \
                             if self._track[next_index] is not None])
         print(
             f'Points updated:{updatesCount} Current cloud size:{len(self._builder.ids)}'
         )
     for i in range(len(self._track)):
         self._track[i] = self._track[i] if self._track[
             i] is not None else self._track[i - 1]
     return np.array(self._track), self._builder
Esempio n. 15
0
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                          frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:
    if known_view_1 is None or known_view_2 is None:
        raise NotImplementedError()

    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])

    view_mats_tmp = [None for _ in range(len(corner_storage))]
    all_points = {}
    not_none_mats = [known_view_1[0], known_view_2[0]]
    none_mats = set(
        [ind for ind in range(len(view_mats_tmp)) if ind not in not_none_mats])

    view_mats_tmp[known_view_1[0]] = pose_to_view_mat3x4(known_view_1[1])
    view_mats_tmp[known_view_2[0]] = pose_to_view_mat3x4(known_view_2[1])
    add_new_points(corner_storage, view_mats_tmp, known_view_1[0],
                   known_view_2[0], all_points, intrinsic_mat)

    old_len = 2
    for _ in range(len(view_mats_tmp)):
        for ind in none_mats:
            corner_ids = list(corner_storage[ind].ids.reshape(-1))
            intersection_inds = [
                point_ind for point_ind in corner_ids if
                point_ind in all_points and all_points[point_ind] is not None
            ]
            # There is an assert, so points number has to be at least 5
            if len(intersection_inds) < 5:
                continue
            # print(ind, len(corner_storage), len(corner_storage[ind].points), np.max(intersection_inds))
            corner_points = {
                i: p
                for i, p in zip(corner_ids, corner_storage[ind].points)
            }
            intersection_points_c = np.array(
                [corner_points[i] for i in intersection_inds])
            intersection_points_f = np.array(
                [all_points[i] for i in intersection_inds])
            # print(intersection_points_f)
            # print(intersection_points_f.shape, intersection_points_c.shape, intrinsic_mat)
            retval, rvec, tvec, inliers = cv2.solvePnPRansac(
                intersection_points_f, intersection_points_c, intrinsic_mat,
                None)

            if not retval:
                continue

            print(f'Processing frame: {ind}')

            newly_none_number = 0
            for i in intersection_inds:
                if i not in inliers:
                    newly_none_number += 1
                    all_points[i] = None

            print(
                f'{newly_none_number} points filled as None, len of inliers: {inliers.shape[0]}'
            )
            print(
                f'Number of not points: {len([p for p in all_points.keys() if all_points[p] is not None])}'
            )

            view_mats_tmp[ind] = rodrigues_and_translation_to_view_mat3x4(
                rvec, tvec)

            for not_none_ind in not_none_mats:
                add_new_points(corner_storage, view_mats_tmp, ind,
                               not_none_ind, all_points, intrinsic_mat)

            not_none_mats.append(ind)
            none_mats.remove(ind)
            break

        if len(not_none_mats) == old_len:
            break
        old_len = len(not_none_mats)

    view_mats = [None for _ in range(len(corner_storage))]
    for view_mat_ind in not_none_mats:
        view_mats[view_mat_ind] = view_mats_tmp[view_mat_ind]
    last_ind = 0
    for i in range(len(view_mats)):
        if view_mats[i] is None:
            view_mats[i] = view_mats[last_ind]
        else:
            last_ind = i
    all_points = {k: v for k, v in all_points.items() if v is not None}
    point_cloud_builder = PointCloudBuilder(
        np.array(list(all_points.keys()), dtype=np.int),
        np.array(list(all_points.values())))

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
Esempio n. 16
0
def track_and_find_point_cloud(intrinsic_mat, corner_storage, known_view_1, known_view_2):
    num_frames = len(corner_storage)

    view_mats = [None] * num_frames
    point_cloud_builder = PointCloudBuilder()

    print(f'Frames with known views: {known_view_1[0]} and {known_view_2[0]}')
    view_mats[known_view_1[0]] = pose_to_view_mat3x4(known_view_1[1])
    view_mats[known_view_2[0]] = pose_to_view_mat3x4(known_view_2[1])

    triang_params = TriangulationParameters(max_reprojection_error=MAX_REPR_ERR,
                                            min_triangulation_angle_deg=MIN_TRIANG_ANGLE_DEG,
                                            min_depth=MIN_DEPTH)

    add_points_to_cloud(point_cloud_builder,
                        corner_storage[known_view_1[0]],
                        corner_storage[known_view_2[0]],
                        view_mats[known_view_1[0]],
                        view_mats[known_view_2[0]],
                        intrinsic_mat,
                        triang_params)

    while True:
        was_updated = False

        for i in range(num_frames):
            if view_mats[i] is not None:
                continue

            print(f"\nCurrent frame: {i}")

            # find intersection of current point cloud and current frame
            corners = corner_storage[i]
            corner_ids = []
            points_3d = []
            points_2d = []

            for id, corner in zip(corners.ids, corners.points):
                if id not in point_cloud_builder.ids:
                    continue
                ind_in_builder, _ = np.nonzero(point_cloud_builder.ids == id)
                corner_ids.append(id)
                points_3d.append(point_cloud_builder.points[ind_in_builder[0]])
                points_2d.append(corner)

            print(f"Size of intersection of current point cloud and current frame: {len(corner_ids)}")

            if len(corner_ids) < 5:
                continue

            points_3d = np.array(points_3d)
            points_2d = np.array(points_2d)

            retval, rvec, tvec, inliers = cv2.solvePnPRansac(points_3d.reshape((-1, 1, 3)),
                                                             points_2d.reshape((-1, 1, 2)),
                                                             cameraMatrix=intrinsic_mat,
                                                             distCoeffs=None,
                                                             reprojectionError=PNP_REPROJ_ERROR)

            if not retval:
                print("Unsuccessful solution of PnP")
                continue

            print(f"Position found by {len(inliers)} inliers")

            view_mat = rodrigues_and_translation_to_view_mat3x4(rvec, tvec)
            view_mats[i] = view_mat

            for j in range(num_frames):
                if i != j and view_mats[j] is not None:
                    points_added = add_points_to_cloud(point_cloud_builder,
                                        corner_storage[i],
                                        corner_storage[j],
                                        view_mats[i],
                                        view_mats[j],
                                        intrinsic_mat,
                                        triang_params)
                    if points_added > 0:
                        was_updated = True

            print(f"Current size of point cloud: {point_cloud_builder.points.size}")

        if was_updated is False:
            break

    for i in range(num_frames):
        if view_mats[i] is None:
            view_mats[i] = view_mats[i - 1]

    return view_mats, point_cloud_builder
Esempio n. 17
0
def bundle_adjustment(view_mats, point_cloud_builder, intrinsic_mat,
                      corner_storage):
    ids2d, ids3d, frameids = [], [], []
    for frame in range(len(view_mats)):
        _, (id1, id2) = snp.intersect(point_cloud_builder.ids.flatten(),
                                      corner_storage[frame].ids.flatten(),
                                      indices=True)
        inliers = calc_inlier_indices(point_cloud_builder.points[id1],
                                      corner_storage[frame].points[id2],
                                      intrinsic_mat @ view_mats[frame], 1.0)
        for i in inliers:
            ids2d.append(id2[i])
            ids3d.append(id1[i])
            frameids.append(frame)

    view_mats_vec = []
    for view_mat in view_mats:
        tvec = view_mat[:, 3]
        rvec, _ = cv2.Rodrigues(view_mat[:, :3])
        view_mats_vec.append(np.concatenate([rvec.squeeze(), tvec]))
    view_mats_vec = np.array(view_mats_vec)

    used_3ds = list(set(ids3d))
    points3d_vec = np.array(point_cloud_builder.points[used_3ds])
    for i in range(len(ids3d)):
        ids3d[i] = used_3ds.index(ids3d[i])

    n, m = len(view_mats_vec.reshape(-1)), len(points3d_vec.reshape(-1))

    def calc_vec_errors(vec, point2d):
        r, t = vec[0:3], vec[3:6]
        view_mat, point3d = rodrigues_and_translation_to_view_mat3x4(
            r.reshape(3, 1), t.reshape(3, 1)), vec[6:9]
        return compute_reprojection_errors(point3d.reshape(1, -1),
                                           point2d.reshape(1, -1),
                                           intrinsic_mat @ view_mat)[0]

    def calc_jacobian():
        J = np.zeros((len(frameids), n + m))
        for i in range(len(frameids)):
            frameid, id3d, id2d = frameids[i], ids3d[i], ids2d[i]
            point3d = points3d_vec[id3d]
            point2d = corner_storage[frameid].points[id2d]
            vec = np.concatenate([view_mats_vec[frameid], point3d])
            der = scipy.optimize.approx_fprime(
                vec, lambda vec: calc_vec_errors(vec, point2d),
                np.full(vec.shape, 1e-7))
            J[i, n + 3 * id3d:n + 3 * id3d + 3] = der[6:]
            J[i, 6 * frameid:6 * frameid + 6] = der[:6]
        return J

    def calc_errors():
        errors = []
        for i in range(len(frameids)):
            frameid, id3d, id2d = frameids[i], ids3d[i], ids2d[i]
            errors.append(
                calc_vec_errors(
                    np.concatenate(
                        [view_mats_vec[frameid], points3d_vec[id3d]]),
                    corner_storage[frameid].points[id2d]))
        return errors

    error_before_bundle_adjustment = np.mean(calc_errors())

    for iter in range(5):
        J = calc_jacobian()
        u = np.array(calc_errors())
        g = J.T @ u
        gx, gc = g[n:], g[:n]
        Q = J.T @ J + 10 * np.diag(np.diag(J.T @ J))
        U, W, V = Q[:n, :n], Q[:n, n:], Q[n:, n:]
        try:
            V_inv = np.linalg.inv(V)
            deltac = np.linalg.solve(U - W @ V_inv @ W.T, W @ V_inv @ gx - gc)
            deltax = -V_inv @ (gx + W.T @ deltac)
            view_mats_vec = (view_mats_vec.reshape(-1) + deltac).reshape(
                (-1, 6))
            points3d_vec = (points3d_vec.reshape(-1) + deltax).reshape((-1, 3))
        except:
            pass
        print('Bundle-adjustment: iteration {}, error {}'.format(
            iter, np.mean(calc_errors())))
        sys.stdout.flush()

    error_after_bundle_adjustment = np.mean(calc_errors())

    if error_after_bundle_adjustment > error_before_bundle_adjustment:
        print('Better without bundle adjustment')
        return view_mats

    point_cloud_builder.update_points(point_cloud_builder.ids[used_3ds],
                                      points3d_vec)
    new_view_mats = []
    for vec in view_mats_vec:
        rvec, tvec = vec[0:3], vec[3:6]
        view_mat = rodrigues_and_translation_to_view_mat3x4(
            rvec.reshape(3, 1), tvec.reshape(3, 1))
        new_view_mats.append(view_mat)
    return np.array(new_view_mats)
Esempio n. 18
0
def track_and_calc_colors(
    camera_parameters: CameraParameters,
    corner_storage: CornerStorage,
    frame_sequence_path: str,
    known_view_1: Optional[Tuple[int, Pose]] = None,
    known_view_2: Optional[Tuple[int, Pose]] = None
) -> Tuple[List[Pose], PointCloud]:
    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])

    if known_view_1 is None or known_view_2 is None:
        known_view_1, known_view_2 = calculate_known_views(
            intrinsic_mat, corner_storage)
        print('Calculated known views: {} and {}'.format(
            known_view_1[0], known_view_2[0]))

    random.seed(239)

    view_mats = np.full((len(rgb_sequence), ), None)
    view_mats[known_view_1[0]] = pose_to_view_mat3x4(known_view_1[1])
    view_mats[known_view_2[0]] = pose_to_view_mat3x4(known_view_2[1])

    point_cloud_builder = PointCloudBuilder()

    def triangulate_and_add_points(corners1, corners2, view_mat1, view_mat2):
        points3d, ids, median_cos = triangulate_correspondences(
            build_correspondences(corners1, corners2), view_mat1, view_mat2,
            intrinsic_mat, triang_params)
        point_cloud_builder.add_points(ids, points3d)

    triangulate_and_add_points(corner_storage[known_view_1[0]],
                               corner_storage[known_view_2[0]],
                               view_mats[known_view_1[0]],
                               view_mats[known_view_2[0]])

    inliers_points3d, inliers_points2d = None, None

    def find_errs(rtvecs):
        rvecs, tvecs = rtvecs[:3], rtvecs[3:]
        rmat, _ = cv2.Rodrigues(np.expand_dims(rvecs, axis=1))
        rmat = np.concatenate((rmat, np.expand_dims(tvecs, axis=1)), axis=1)
        return (project_points(inliers_points3d, intrinsic_mat @ rmat) -
                inliers_points2d).flatten()

    while True:
        random_ids = list(range(len(view_mats)))
        random.shuffle(random_ids)
        found_new_view_mat = False
        for i in random_ids:
            if view_mats[i] is not None:
                continue
            common, (ids1,
                     ids2) = snp.intersect(point_cloud_builder.ids.flatten(),
                                           corner_storage[i].ids.flatten(),
                                           indices=True)
            if len(common) <= 10:
                continue

            points3d = point_cloud_builder.points[ids1]
            points2d = corner_storage[i].points[ids2]
            retval, rvecs, tvecs, inliers = cv2.solvePnPRansac(
                points3d,
                points2d,
                intrinsic_mat,
                iterationsCount=108,
                reprojectionError=triang_params.max_reprojection_error,
                distCoeffs=None,
                confidence=0.999,
                flags=cv2.SOLVEPNP_EPNP)
            if retval:
                # M-оценки
                inliers_points3d = points3d[inliers.flatten()]
                inliers_points2d = points2d[inliers.flatten()]
                rtvecs = least_squares(find_errs,
                                       x0=np.concatenate(
                                           (rvecs, tvecs)).flatten(),
                                       loss='huber',
                                       method='trf').x
                rvecs = rtvecs[:3].reshape((-1, 1))
                tvecs = rtvecs[3:].reshape((-1, 1))
            if not retval:
                continue

            print(
                'Iteration {}/{}, processing {}th frame: {} inliers, {} points in point cloud'
                .format(
                    len([v for v in view_mats if v is not None]) - 1,
                    len(rgb_sequence) - 2, i, len(inliers),
                    len(point_cloud_builder.points)))

            view_mats[i] = rodrigues_and_translation_to_view_mat3x4(
                rvecs, tvecs)
            found_new_view_mat = True

            # Add new points
            inliers = np.array(inliers).astype(int).flatten()
            inlier_corners = FrameCorners(
                *[c[inliers] for c in corner_storage[i]])
            for j in range(len(view_mats)):
                if view_mats[j] is not None:
                    triangulate_and_add_points(corner_storage[j],
                                               inlier_corners, view_mats[j],
                                               view_mats[i])

            sys.stdout.flush()

        if not found_new_view_mat:
            break

    for i in range(0, len(view_mats)):
        if view_mats[i] is None:
            print('Я сдох: не все кадры обработаны :(')
            exit(1)

    if len(view_mats) < 100:  # Иначе долго работает
        view_mats = bundle_adjustment(view_mats, point_cloud_builder,
                                      intrinsic_mat, corner_storage)

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                          frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:

    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    frames_num = len(rgb_sequence)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])

    if known_view_1 is None or known_view_2 is None:
        known_view_1, known_view_2 = select_frames(rgb_sequence,
                                                   corner_storage,
                                                   intrinsic_mat)
        if known_view_2[0] == -1:
            print("Failed to find good starting frames")
            exit(0)

    correspondences = build_correspondences(corner_storage[known_view_1[0]],
                                            corner_storage[known_view_2[0]])
    view_mat1 = pose_to_view_mat3x4(known_view_1[1])
    view_mat2 = pose_to_view_mat3x4(known_view_2[1])

    points, ids, _ = triangulate_correspondences(correspondences, view_mat1,
                                                 view_mat2, intrinsic_mat,
                                                 TRIANG_PARAMS)

    if len(ids) < 8:
        print("Bad frames: too few correspondences!")
        exit(0)

    view_mats, point_cloud_builder = [None] * frames_num, PointCloudBuilder(
        ids, points)
    view_mats[known_view_1[0]] = view_mat1
    view_mats[known_view_2[0]] = view_mat2

    updated = True
    pass_num = 0
    while updated:
        updated = False
        pass_num += 1

        for i in range(frames_num):
            if view_mats[i] is not None:
                continue

            corners = corner_storage[i]

            _, ind1, ind2 = np.intersect1d(point_cloud_builder.ids,
                                           corners.ids.flatten(),
                                           return_indices=True)
            try:
                _, rvec, tvec, inliers = cv2.solvePnPRansac(
                    point_cloud_builder.points[ind1],
                    corners.points[ind2],
                    intrinsic_mat,
                    distCoeffs=None)

                if inliers is None:
                    print(f"Pass {pass_num}, frame {i}. No inliers!")
                    continue

                print(
                    f"Pass {pass_num}, frame {i}. Number of inliers == {len(inliers)}"
                )

                view_mats[i] = rodrigues_and_translation_to_view_mat3x4(
                    rvec, tvec)
            except Exception:
                continue

            updated = True

            cloud_changed = add_points(point_cloud_builder, corner_storage, i,
                                       view_mats, intrinsic_mat)
            if cloud_changed:
                print(f"Size of point cloud == {len(point_cloud_builder.ids)}")

    first_not_none = next(item for item in view_mats if item is not None)
    if view_mats[0] is None:
        view_mats[0] = first_not_none

    for i in range(frames_num):
        if view_mats[i] is None:
            view_mats[i] = view_mats[i - 1]

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)

    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
Esempio n. 20
0
def run_bundle_adjustment(intrinsic_mat: np.ndarray,
                          list_of_corners: List[FrameCorners],
                          max_inlier_reprojection_error: float,
                          view_mats: List[np.ndarray],
                          pc_builder: PointCloudBuilder) -> List[np.ndarray]:
    n_frames = len(view_mats)
    inliers = get_inliers(intrinsic_mat, list_of_corners,
                          max_inlier_reprojection_error, view_mats, pc_builder)
    rs = [cv2.Rodrigues(i[:, :3])[0].flatten() for i in view_mats]
    ts = [i[:, 3] for i in view_mats]
    point_id_to_cloud = -np.ones(pc_builder.ids.max() + 1, dtype=np.int32)
    point_id_to_cloud[pc_builder.ids.flatten()] = np.arange(len(
        pc_builder.ids))

    re = calc_reprojection_error(inliers, pc_builder, point_id_to_cloud,
                                 list_of_corners, intrinsic_mat, view_mats)
    print('Reprojection error before bundle adjustment:', re)
    for start in range(0, n_frames, FRAMES_STEP):
        end = min(start + FRAMES_STEP, n_frames)
        cameras_params_dim = (end - start) * 6

        matches = get_matches(inliers[start:end], len(list_of_corners), start)
        relevant_point_ids = np.array(
            list(
                sorted(
                    {point_id
                     for point_id, frame_id, point_index in matches})))
        point_id_to_cur = {p: i for i, p in enumerate(relevant_point_ids)}
        _, (_, cloud_indices) = snp.intersect(relevant_point_ids,
                                              pc_builder.ids.flatten(),
                                              indices=True)
        relevant_points = pc_builder.points[cloud_indices]

        alpha = ALPHA_INITIAL
        us_mean_prev = -float('inf')

        for i in range(ITERATIONS):
            us = get_residuals(pc_builder, point_id_to_cloud, list_of_corners,
                               intrinsic_mat, matches, view_mats)
            jacobian = calc_jacobian(matches, cameras_params_dim, rs, ts,
                                     pc_builder, list_of_corners,
                                     point_id_to_cur, point_id_to_cloud,
                                     intrinsic_mat, start)
            jtj = jacobian.T @ jacobian

            us_mean = us.mean()
            alpha = alpha / ALPHA_DEC_STEP if us_mean < us_mean_prev else alpha * ALPHA_INC_STEP
            us_mean_prev = us_mean
            alpha_multiplier = 1 + alpha
            jtj[np.arange(jtj.shape[0]),
                np.arange(jtj.shape[0])] *= alpha_multiplier

            u = jtj[:cameras_params_dim, :cameras_params_dim]
            v = jtj[cameras_params_dim:, cameras_params_dim:]
            w = jtj[:cameras_params_dim, cameras_params_dim:]
            wt = jtj[cameras_params_dim:, :cameras_params_dim]
            v_inv = block_inv(v)
            g = jacobian.T @ us
            b = w @ v_inv @ g[cameras_params_dim:] - g[:cameras_params_dim]
            a = (u - w @ v_inv @ wt).toarray()
            delta_c = np.linalg.solve(a, b)
            delta_x = v_inv @ (-g[cameras_params_dim:] - wt @ delta_c)
            for k, j in enumerate(range(start, end)):
                rs[j] += delta_c[k * 6:k * 6 + 3]
                ts[j] += delta_c[k * 6 + 3:k * 6 + 6]
                view_mats[j] = rodrigues_and_translation_to_view_mat3x4(
                    rs[j], ts[j].reshape(3, 1))
            relevant_points += delta_x.reshape((-1, 3))
            pc_builder.update_points(relevant_point_ids, relevant_points)
    re = calc_reprojection_error(inliers, pc_builder, point_id_to_cloud,
                                 list_of_corners, intrinsic_mat, view_mats)
    print('Reprojection error after bundle adjustment:', re)
    return view_mats
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                          frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:

    # функция для проверки что матрица поворота дейтсвительно матрица поворота
    def check_if_mat_is_rot_mat(mat):
        mat = mat[:, :3]
        det = np.linalg.det(mat)
        # определитель должен быть = 1
        diff1 = abs(1 - det)
        x = mat @ mat.T
        # обратная матрица должна получаться транспонированием
        diff2 = abs(np.sum(np.eye(3) - x))
        eps = 0.001
        return diff1 < eps and diff2 < eps

    MAX_REPROJECTION_ERROR = 1.6
    MIN_DIST_TRIANGULATE = 0.01

    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])

    frame_count = len(corner_storage)
    t_vecs = [None] * frame_count
    view_mats = [None] * frame_count  # позиции камеры на всех кадрах

    # для каждого уголка находим все кадры на котором он есть и его порядковый номер в каждом из них
    cur_corners_occurencies = {}
    frames_of_corner = {}
    for i, corners in enumerate(corner_storage):
        for id_in_list, j in enumerate(corners.ids.flatten()):
            cur_corners_occurencies[j] = 0
            if j not in frames_of_corner.keys():
                frames_of_corner[j] = [[i, id_in_list]]
            else:
                frames_of_corner[j].append([i, id_in_list])

    #по двум кадрам находим общие точки и восстанавливаем их позиции в 3D
    def triangulate(frame_0, frame_1, params=TriangulationParameters(2, 1e-3, 1e-4), ids_to_remove=None) \
            -> Tuple[np.ndarray, np.ndarray, float]:
        corrs = build_correspondences(corner_storage[frame_0],
                                      corner_storage[frame_1])
        return triangulate_correspondences(corrs, view_mats[frame_0],
                                           view_mats[frame_1], intrinsic_mat,
                                           params)

    #константы для инициализации
    BASELINE_THRESHOLD = 0.9
    REPROJECTION_ERROR_THRESHOLD = 1.4
    MIN_3D_POINTS = 10
    frame_steps = [9, 30, 40]

    #нахождение относительного движения между двумя данными кадрами
    def get_first_cam_pose(frame_0, frame_1):
        corrs = build_correspondences(corner_storage[frame_0],
                                      corner_storage[frame_1])
        e_mat, _ = cv2.findEssentialMat(corrs.points_1, corrs.points_2,
                                        intrinsic_mat, cv2.RANSAC, 0.999, 2.0)

        def essential_mat_to_camera_view_matrix(e_mat):
            U, S, VH = np.linalg.svd(e_mat, full_matrices=True)
            W = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]], dtype=np.float)
            u3 = U[:, 2]
            possible_R = [U @ W @ VH, U @ W.T @ VH]
            possible_t = [u3, -u3]
            best_R = None
            best_t = None
            max_positive_z = 0
            for R in possible_R:
                for t in possible_t:
                    view_mat0 = np.hstack((np.eye(3), np.zeros((3, 1))))
                    view_mat1 = np.hstack((R, t.reshape((3, 1))))
                    view_mats[frame_0] = view_mat0
                    view_mats[frame_1] = view_mat1
                    points3d, ids, median_cos = triangulate(frame_0, frame_1)
                    cur_positive_z = 0
                    for pt in points3d:
                        pt = np.append(pt, np.zeros((1))).reshape((4, 1))
                        pt_transformed0 = (view_mat0 @ pt).flatten()
                        z0 = pt_transformed0[2]
                        pt_transformed1 = (view_mat1 @ pt).flatten()
                        z1 = pt_transformed1[2]
                        cur_positive_z += (z0 > 0.1) + (z1 > 0.1)
                    if cur_positive_z > max_positive_z:
                        max_positive_z = cur_positive_z
                        best_R = R
                        best_t = t
            return best_R, best_t

        R, t = essential_mat_to_camera_view_matrix(e_mat)
        baseline = np.linalg.norm(t)

        view_mat0 = np.hstack((np.eye(3), np.zeros((3, 1))))
        view_mat1 = np.hstack((R, t.reshape((3, 1))))
        view_mats[frame_0] = view_mat0
        view_mats[frame_1] = view_mat1
        points3d, ids, median_cos = triangulate(frame_0, frame_1)
        points0 = []
        points1 = []
        for i in ids:
            for j in frames_of_corner[i]:
                if j[0] == frame_0:
                    points0.append(j[1])
                if j[0] == frame_1:
                    points1.append(j[1])
        points0 = np.array(points0)
        points1 = np.array(points1)
        sum_error = compute_reprojection_errors(
            points3d, corner_storage[frame_0].points[points0],
            intrinsic_mat @ view_mat0) + compute_reprojection_errors(
                points3d, corner_storage[frame_1].points[points1],
                intrinsic_mat @ view_mat1)
        reprojection_error = np.mean(sum_error)
        points3d_count = len(points3d)

        view_mats[frame_0] = None
        view_mats[frame_1] = None

        #проверяем насколько хороша данная пара кадров, и заодно проверяем что матрица R - реально поворот
        if baseline < BASELINE_THRESHOLD or reprojection_error > REPROJECTION_ERROR_THRESHOLD or points3d_count < MIN_3D_POINTS or not check_if_mat_is_rot_mat(
                np.hstack((R, t.reshape((3, 1))))):
            return False, baseline, reprojection_error, points3d_count, None, None
        else:
            return True, baseline, reprojection_error, points3d_count, R, t

    #делаем перебор пар кадров для инициализации
    INF = 1e9
    best_frame_step = 5
    best = [-INF, INF, -INF]
    ind = None
    for frame_step in frame_steps:
        for i in range(frame_count // 2):
            if i + frame_step < frame_count * 0.85:
                ok, baseline, reproection_error, points3d_count, Rx, tx = get_first_cam_pose(
                    i, i + frame_step)
                if ok:
                    best = [baseline, reproection_error, points3d_count]
                    ind = i
                    best_frame_step = frame_step
                    if frame_count > 100:
                        break

    # крашаемся, если не удалось инициализироваться ни по какой паре кадров
    if ind is None:
        raise NotImplementedError()

    #инициализируемся по лучшей найденной паре
    frame_0 = ind
    frame_1 = ind + best_frame_step
    ok, baseline, reproection_error, points3d_count, R, t = get_first_cam_pose(
        frame_0, frame_1)
    print('INITIALIZATION RESULTS:')
    print('FRAMES: frame_0={}, frame_1={}, total_frames={}'.format(
        frame_0, frame_1, frame_count))
    print(baseline, reproection_error, points3d_count, R, t)
    view_mat0 = np.hstack((np.eye(3), np.zeros((3, 1))))
    view_mat1 = np.hstack((R, t.reshape((3, 1))))
    view_mats[frame_0] = view_mat0
    view_mats[frame_1] = view_mat1
    t_vecs[frame_0] = np.zeros((3), dtype=np.float64)
    t_vecs[frame_1] = t

    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    # зачем хранить инфу о пендинг точках вперемешку с остальными точками облака???
    # 'id': coords [., ., .] 3d coordinates, rays [(frame, coords)] - for new points addition
    points_cloud = {}

    # инициализируем облако точек по 2 положениям
    points3d, ids, median_cos = triangulate(frame_0, frame_1)
    for id, point3d in zip(ids, points3d):
        points_cloud[id] = point3d

    def find_camera_pose(frame_id):
        # сначала находим инлаеры ранзаком
        # потом на инлаерах делаем пнп с итеративной мин кв
        corners = corner_storage[frame_id]
        points3d = []
        points2d = []
        for id, point2d in zip(corners.ids.flatten(), corners.points):
            if id in points_cloud.keys():
                points3d.append(points_cloud[id])
                points2d.append(point2d)
        # чтобы епнп работал
        points3d = np.array(points3d, dtype=np.float64)
        points2d = np.array(points2d, dtype=np.float64)
        if len(points3d) < 4:
            return None

        # выбираем эталонную 4 точек, строим по ней R и t
        # затем смотрим, на какой выборке эталонных точек больше всего других точек
        # спроецируются корректно
        success, R, t, inliers = cv2.solvePnPRansac(
            objectPoints=points3d,
            imagePoints=points2d,
            cameraMatrix=intrinsic_mat,
            distCoeffs=None,
            flags=cv2.SOLVEPNP_EPNP,
            confidence=0.9995,
            reprojectionError=MAX_REPROJECTION_ERROR)

        if not success:
            return None

        inliers = np.asarray(inliers, dtype=np.int32).flatten()
        points3d = np.array(points3d)
        points2d = np.array(points2d)
        points3d = points3d[inliers]
        points2d = points2d[inliers]
        retval, R, t = cv2.solvePnP(objectPoints=points3d,
                                    imagePoints=points2d,
                                    cameraMatrix=intrinsic_mat,
                                    distCoeffs=None,
                                    flags=cv2.SOLVEPNP_ITERATIVE,
                                    useExtrinsicGuess=True,
                                    rvec=R,
                                    tvec=t)
        return R, t, len(inliers)

    # можно ускорить
    def frames_without_pose():
        frames = []
        for ind, mat in enumerate(view_mats):
            if mat is None:
                frames.append(ind)
        return frames

    def try_add_new_point_to_cloud(corner_id):
        # все фреймы на которых есть данный уголок, и у которых уже найдена view_mat
        # а можно для уголка хранить не все фреймы где он есть, а только те, где он инлаер!
        frames = []
        for frame in frames_of_corner[corner_id]:
            if view_mats[frame[0]] is not None:
                frames.append(frame)
        if len(frames) < 2:
            return

        max_dist = 0
        best_frames = [None, None]
        best_ids = [None, None]

        # можно ускорить хотя бы вдвое
        for frame_1 in frames:
            for frame_2 in frames:
                if frame_1 == frame_2:
                    continue
                # эм, по идее это не возможно, когда есть view_mat есть и t_vec
                if t_vecs[frame_1[0]] is None or t_vecs[frame_2[0]] is None:
                    continue
                t_vec_1 = t_vecs[frame_1[0]]
                t_vec_2 = t_vecs[frame_2[0]]
                dist = np.linalg.norm(t_vec_1 - t_vec_2)
                if max_dist < dist:
                    max_dist = dist
                    best_frames = [frame_1[0], frame_2[0]]
                    best_ids = [frame_1[1], frame_2[1]]

        if max_dist > MIN_DIST_TRIANGULATE:
            ids = np.array([corner_id])
            points1 = corner_storage[best_frames[0]].points[np.array(
                [best_ids[0]])]
            points2 = corner_storage[best_frames[1]].points[np.array(
                [best_ids[1]])]
            # что за ужасный синтаксис??????
            corrs = corrs = Correspondences(ids, points1, points2)
            points3d, ids, med_cos = triangulate_correspondences(
                corrs,
                view_mats[best_frames[0]],
                view_mats[best_frames[1]],
                intrinsic_mat,
                parameters=TriangulationParameters(2, 1e-3, 1e-4))
            # зачем проверка??? зачем делаем поп?????
            if len(points3d) > 0:
                points_cloud[ids[0]] = points3d[0]
                cur_corners_occurencies.pop(ids[0], None)

    # в этой функции мы еще бонусом возвращаем те точки, которые встречаются хотя бы 2 раза
    # а также мы добавляем оккуранси тем точкам которые уже в облаке))))))))))))))))))))))))))))
    def add_corners_occurencies(frame_id):
        two_and_greater = []
        for id in corner_storage[frame_id].ids.flatten():
            if id in cur_corners_occurencies.keys():
                cur_corners_occurencies[id] += 1
                if cur_corners_occurencies[id] >= 2:
                    two_and_greater.append(id)
        return two_and_greater

    # очень эффективно))))))))))
    while len(frames_without_pose()) > 0:
        # пока есть не найденные положения камеры будем искать лучшее для восстановления
        # т.е. такое, где больше всего инлаеров после применения пнп ранзака
        wanted_frames = frames_without_pose()
        # inliers_amount = [] не понял зачем этот лист
        max_col = -1
        best_frame_id = -1
        best_R = None
        best_t = None
        for frame_id in wanted_frames:
            result = find_camera_pose(frame_id)
            if result is not None:
                R, t, col = result
                if col > max_col:
                    max_col = col
                    best_frame_id = frame_id
                    best_R = R
                    best_t = t
        if max_col == -1:
            # больше позиции камер не находятся
            break

        view_mats[best_frame_id] = rodrigues_and_translation_to_view_mat3x4(
            best_R, best_t)
        t_vecs[best_frame_id] = best_t

        try_add = add_corners_occurencies(best_frame_id)
        for corner in try_add:
            try_add_new_point_to_cloud(corner)
        print(
            'Now we add camera pose on {}-th frame, camera pose was calculated by {} inliers'
            .format(best_frame_id, max_col))
        ttl_poses_calculated = np.sum([mat is not None for mat in view_mats])
        percent = "{:.0f}".format(ttl_poses_calculated / frame_count * 100.0)
        print('{}% poses calculated'.format(percent))

        print('{} points in 3D points cloud'.format(len(points_cloud)))

    last_view_mat = None
    for i in range(frame_count):
        if view_mats[i] is None:
            view_mats[i] = last_view_mat
        else:
            last_view_mat = view_mats[i]

    #check that all matrices are rotation matrices
    for ind, i in enumerate(view_mats):
        if not check_if_mat_is_rot_mat(i):
            print(
                'In frame {}/{} we have matrix wich is not rotation matrix:('.
                format(ind + 1, frame_count))
            raise NotImplementedError()

    ids = []
    points = []
    for id in points_cloud.keys():
        ids.append(id)
        points.append(points_cloud[id])

    point_cloud_builder = PointCloudBuilder(np.array(ids, dtype=np.int32),
                                            np.array(points))

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
Esempio n. 22
0
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                          frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:
    if known_view_1 is None or known_view_2 is None:
        raise NotImplementedError()

    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])

    triang_params = TriangulationParameters(
        max_reprojection_error=MAX_PROJ_ERROR,
        min_triangulation_angle_deg=MIN_TRIANG_ANG,
        min_depth=MIN_DEPTH)

    correspondences = build_correspondences(corner_storage[known_view_1[0]],
                                            corner_storage[known_view_2[0]])
    view_mat_1 = pose_to_view_mat3x4(known_view_1[1])
    view_mat_2 = pose_to_view_mat3x4(known_view_2[1])
    points, ids, median_cos = triangulate_correspondences(
        correspondences, view_mat_1, view_mat_2, intrinsic_mat, triang_params)
    if len(points) < 10:
        print("\rPlease, try other frames")
        exit(0)

    view_mats = [None] * len(rgb_sequence)
    view_mats[known_view_1[0]] = view_mat_1
    view_mats[known_view_2[0]] = view_mat_2

    point_cloud_builder = PointCloudBuilder(ids, points)
    was_update = True
    while was_update:
        was_update = False
        for i, (frame, corners) in enumerate(zip(rgb_sequence,
                                                 corner_storage)):
            if view_mats[i] is not None:
                continue
            _, (idx_1,
                idx_2) = snp.intersect(point_cloud_builder.ids.flatten(),
                                       corners.ids.flatten(),
                                       indices=True)
            try:
                retval, rvec, tvec, inliers = cv2.solvePnPRansac(
                    point_cloud_builder.points[idx_1],
                    corners.points[idx_2],
                    intrinsic_mat,
                    distCoeffs=None)
                inliers = np.array(inliers, dtype=int)
                if len(inliers) > 0:
                    view_mats[i] = rodrigues_and_translation_to_view_mat3x4(
                        rvec, tvec)
                    was_update = True
                print(
                    f"\rFrame {i} out of {len(rgb_sequence)}, inliners: {len(inliers)}",
                    end="")
            except Exception:
                print(f"\rFrame {i} out of {len(rgb_sequence)}, inliners: {0}",
                      end="")
            if view_mats[i] is None:
                continue
            cur_corner = filter_frame_corners(corner_storage[i],
                                              inliers.flatten())

            for j in range(len(rgb_sequence)):
                if view_mats[j] is None:
                    continue
                correspondences = build_correspondences(
                    corner_storage[j], cur_corner)
                if len(correspondences.ids) == 0:
                    continue
                points, ids, median_cos = triangulate_correspondences(
                    correspondences, view_mats[j], view_mats[i], intrinsic_mat,
                    triang_params)
                point_cloud_builder.add_points(ids, points)

        print()

    first_mat = next((mat for mat in view_mats if mat is not None), None)
    if first_mat is None:
        print("\rFail")
        exit(0)

    view_mats[0] = first_mat
    for i in range(1, len(view_mats)):
        if view_mats[i] is None:
            view_mats[i] = view_mats[i - 1]
    view_mats = np.array(view_mats)

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
Esempio n. 23
0
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                          frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:
    if known_view_1 is None or known_view_2 is None:
        raise NotImplementedError()

    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])

    view_mats = np.zeros((len(corner_storage), 3, 4), dtype=np.float64)
    processed_frames = np.zeros(len(corner_storage), dtype=np.bool)
    points3d = np.zeros((corner_storage.max_corner_id() + 1, 3),
                        dtype=np.float64)
    added_points = np.zeros(corner_storage.max_corner_id() + 1, dtype=np.bool)

    print('Trying to extract 3d points from known frames...')

    view_mats[known_view_1[0]] = pose_to_view_mat3x4(known_view_1[1])
    view_mats[known_view_2[0]] = pose_to_view_mat3x4(known_view_2[1])
    processed_frames[known_view_1[0]] = processed_frames[
        known_view_2[0]] = True
    extracted_points = extract_points(corner_storage[known_view_1[0]],
                                      corner_storage[known_view_2[0]],
                                      view_mats[known_view_1[0]],
                                      view_mats[known_view_2[0]],
                                      intrinsic_mat)
    if not extracted_points:
        print(
            'Extracting 3d points from known frames failed: '
            'either there are no common points, or triangulation angle between frames is too small.\n'
            'Try to choose another initial frames.',
            file=sys.stderr)
        exit(0)
    print('Succeeded! Trying to build point cloud...')

    added_points[extracted_points[0]] = True
    points3d[extracted_points[0]] = extracted_points[1]

    was_updated = True
    while was_updated:
        was_updated = False
        unprocessed_frames = np.arange(len(corner_storage),
                                       dtype=np.int32)[~processed_frames]
        for frame in unprocessed_frames:
            points3d_ids = np.arange(corner_storage.max_corner_id() + 1,
                                     dtype=np.int32)[added_points]
            common, (indices1, indices2) = snp.intersect(
                points3d_ids,
                corner_storage[frame].ids.flatten(),
                indices=True)
            if len(common) <= 5:
                continue

            try:
                print(f'Processing frame {frame}: ', end='')
                retval, rvec, tvec, inliers = cv2.solvePnPRansac(
                    objectPoints=points3d[common],
                    imagePoints=corner_storage[frame].points[indices2],
                    cameraMatrix=intrinsic_mat,
                    distCoeffs=None)
            except:
                retval = False

            if not retval:
                print(f'failed to solve PnP RANSAC, trying another frame')
                continue

            print(f'succeeded, found {len(inliers)} inliers')
            was_updated = True
            view_mats[frame] = rodrigues_and_translation_to_view_mat3x4(
                rvec, tvec)
            for processed_frame in np.arange(len(corner_storage),
                                             dtype=np.int32)[processed_frames]:
                extracted_points = extract_points(
                    corner_storage[frame], corner_storage[processed_frame],
                    view_mats[frame], view_mats[processed_frame],
                    intrinsic_mat, points3d_ids)

                if extracted_points:
                    added_points[extracted_points[0]] = True
                    points3d[extracted_points[0]] = extracted_points[1]
            processed_frames[frame] = True
            print(f'Current point cloud contains {sum(added_points)} points')

    for _ in range(2):
        for i in range(1, len(corner_storage)):
            if not processed_frames[i]:
                processed_frames[i] = True
                view_mats[i] = view_mats[i - 1]
        processed_frames = processed_frames[::-1]
        view_mats = view_mats[::-1]

    print(
        f'Finished building point cloud, now it contains {sum(added_points)} points'
    )

    point_cloud_builder = PointCloudBuilder(ids=np.arange(
        corner_storage.max_corner_id() + 1, dtype=np.int32)[added_points],
                                            points=points3d[added_points])

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
Esempio n. 24
0
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                          frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:
    if known_view_1 is None or known_view_2 is None:
        raise NotImplementedError()

    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(
        camera_parameters,
        rgb_sequence[0].shape[0]
    )

    # TODO: implement
    frame_count = len(corner_storage)
    view_mats = [None] * frame_count
    view_1_id, view_1 = known_view_1[0], pose_to_view_mat3x4(known_view_1[1])
    view_2_id, view_2 = known_view_2[0], pose_to_view_mat3x4(known_view_2[1])

    view_mats[view_1_id] = view_1
    view_mats[view_2_id] = view_2

    correspondences = build_correspondences(corner_storage[view_1_id], corner_storage[view_2_id], None)
    triangulation_parameters = TriangulationParameters(1, 5, 0)
    points, ids, _ = triangulate_correspondences(correspondences, view_1, view_2,
                                                 intrinsic_mat, TriangulationParameters(0.1, 0.1, 0))

    #corners_0 = corner_storage[0]
    point_cloud_builder = PointCloudBuilder(ids, points)

    unknown_frames = frame_count - 2
    known_frames = {view_1_id, view_2_id}

    while unknown_frames > 0:
        for i in range(frame_count):
            if view_mats[i] is None:
                corners = corner_storage[i]
                interesting_ids, in_corners, in_cloud = np.intersect1d(corners.ids.flatten(), point_cloud_builder.ids.flatten(), return_indices=True)
                points_2d = corners.points[in_corners]
                points_3d = point_cloud_builder.points[in_cloud]

                if len(ids) < 3:
                    continue

                method = cv2.SOLVEPNP_EPNP
                if len(ids) == 3:
                    method = cv2.SOLVEPNP_P3P
                retval, rvec, tvec, inliers = cv2.solvePnPRansac(points_3d, points_2d, intrinsic_mat, None,
                                                                 flags=method)
                if not retval:
                    continue
                retval, rvec, tvec = cv2.solvePnP(points_3d[inliers], points_2d[inliers], intrinsic_mat, None,
                                                  rvec=rvec, tvec=tvec, useExtrinsicGuess=True)
                if not retval:
                    continue

                view_mats[i] = rodrigues_and_translation_to_view_mat3x4(rvec, tvec)
                unknown_frames -= 1
                known_frames.add(i)

                outliers = np.delete(interesting_ids, inliers)
                for frame in known_frames:
                    correspondences = build_correspondences(corners, corner_storage[frame], outliers)
                    points_3d, corner_ids, _ = triangulate_correspondences(
                        correspondences, view_mats[i], view_mats[frame], intrinsic_mat, triangulation_parameters)
                    point_cloud_builder.add_points(corner_ids, points_3d)




    calc_point_cloud_colors(
        point_cloud_builder,
        rgb_sequence,
        view_mats,
        intrinsic_mat,
        corner_storage,
        5.0
    )
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
Esempio n. 25
0
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                          frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:
    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])
    frame_count = len(corner_storage)
    view_mats = [None] * frame_count

    if known_view_1 is None or known_view_2 is None:
        known_view_1, known_view_2 = init_first_camera_positions(
            intrinsic_mat, corner_storage)
        id_1, view_mat_1 = known_view_1
        id_2, view_mat_2 = known_view_2
        view_mats[id_1], view_mats[id_2] = view_mat_1, view_mat_2
    else:
        id_1, pose_1 = known_view_1
        id_2, pose_2 = known_view_2
        view_mats[id_1] = pose_to_view_mat3x4(pose_1)
        view_mats[id_2] = pose_to_view_mat3x4(pose_2)
    params = TriangulationParameters(max_reprojection_error=2,
                                     min_triangulation_angle_deg=1,
                                     min_depth=0.5)
    correspondences = build_correspondences(corner_storage[id_1],
                                            corner_storage[id_2])
    points, ids, _ = triangulate_correspondences(correspondences,
                                                 view_mats[id_1],
                                                 view_mats[id_2],
                                                 intrinsic_mat, params)

    point_cloud_builder = PointCloudBuilder(ids.reshape(-1), points)

    while True:
        update = False
        for i in range(frame_count):
            if view_mats[i] is not None:
                continue
            corners = corner_storage[i]
            ids, ids1, ids2 = np.intersect1d(corners.ids,
                                             point_cloud_builder.ids,
                                             return_indices=True)
            points_2d, points_3d = corners.points[
                ids1], point_cloud_builder.points[ids2]
            if len(ids) < 6:
                continue
            retval, rvec, tvec, inliers = solvePnPRansac(points_3d,
                                                         points_2d,
                                                         intrinsic_mat,
                                                         distCoeffs=None)
            if not retval:
                continue
            retval, rvec, tvec = solvePnP(points_3d[inliers],
                                          points_2d[inliers],
                                          intrinsic_mat,
                                          distCoeffs=None,
                                          rvec=rvec,
                                          tvec=tvec,
                                          useExtrinsicGuess=True)
            if not retval:
                continue
            view_mats[i] = rodrigues_and_translation_to_view_mat3x4(rvec, tvec)
            update = True
            outliers = np.delete(ids, inliers)
            for j in range(i):
                if view_mats[j] is None:
                    continue
                correspondences = build_correspondences(corners,
                                                        corner_storage[j],
                                                        ids_to_remove=outliers)
                points, ids, _ = triangulate_correspondences(
                    correspondences, view_mats[i], view_mats[j], intrinsic_mat,
                    params)
                point_cloud_builder.add_points(ids.reshape(-1), points)
            click.echo("Process frame %d/%d. %d 3D points found. inliners=%d" %
                       (i + 1, frame_count, len(
                           point_cloud_builder.points), len(inliers)))
        if not update:
            break

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud
Esempio n. 26
0
def track_and_calc_colors(camera_parameters: CameraParameters,
                          corner_storage: CornerStorage,
                            frame_sequence_path: str,
                          known_view_1: Optional[Tuple[int, Pose]] = None,
                          known_view_2: Optional[Tuple[int, Pose]] = None) \
        -> Tuple[List[Pose], PointCloud]:

    rgb_sequence = frameseq.read_rgb_f32(frame_sequence_path)
    intrinsic_mat = to_opencv_camera_mat3x3(camera_parameters,
                                            rgb_sequence[0].shape[0])

    if known_view_1 is None or known_view_2 is None:
        known_view_1, known_view_2 = calc_known_views(corner_storage,
                                                      intrinsic_mat)

    # TODO: implement
    num_frames_retr = 10
    triang_params = TriangulationParameters(8.0, 1.0, .1)

    num_frames = len(corner_storage)

    frame_1 = known_view_1[0]
    frame_2 = known_view_2[0]

    print(f'{frame_1}, {frame_2}')

    tvecs = [None] * num_frames
    tvecs[frame_1] = known_view_1[1].t_vec
    tvecs[frame_2] = known_view_2[1].t_vec

    view_mat_1 = pose_to_view_mat3x4(known_view_1[1])
    view_mat_2 = pose_to_view_mat3x4(known_view_2[1])

    view_mats = [None] * num_frames
    view_mats[frame_1] = view_mat_1
    view_mats[frame_2] = view_mat_2

    cloud = {}

    corrs = build_correspondences(corner_storage[frame_1],
                                  corner_storage[frame_2])
    points3d, ids, _ = triangulate_correspondences(corrs, view_mat_1,
                                                   view_mat_2, intrinsic_mat,
                                                   triang_params)
    for point3d, id in zip(points3d, ids):
        cloud[id] = point3d

    current_corners_occurences = {}
    corner_to_frames = {}

    for i, corners in enumerate(corner_storage):
        for j, id in enumerate(corners.ids.flatten()):
            current_corners_occurences[id] = 0
            if id not in corner_to_frames.keys():
                corner_to_frames[id] = [[i, j]]
            else:
                corner_to_frames[id].append([i, j])

    while len(untracked_frames(view_mats)) > 0:
        untr_frames = untracked_frames(view_mats)

        max_num_inl = -1
        best_frame = -1
        best_rvec = None
        best_tvec = None

        for frame in untr_frames:
            rvec, tvec, num_inl = calc_camera_pose(frame, corner_storage,
                                                   cloud, intrinsic_mat)
            if rvec is not None:
                if num_inl > max_num_inl:
                    best_frame = frame
                    max_num_inl = num_inl
                    best_rvec = rvec
                    best_tvec = tvec

        if max_num_inl == -1:
            break

        corners_to_add = []
        for id in corner_storage[best_frame].ids.flatten():
            if id in current_corners_occurences.keys():
                current_corners_occurences[id] += 1
                if current_corners_occurences[id] >= 2:
                    corners_to_add.append(id)

        for corner in corners_to_add:
            add_new_point(corner, corner_to_frames, view_mats, tvecs,
                          corner_storage, cloud, current_corners_occurences,
                          intrinsic_mat)

        print(f"Frame: {best_frame}, Inliers: {max_num_inl}")
        print(f"Cloud size: {len(cloud)}")
        view_mats[best_frame] = rodrigues_and_translation_to_view_mat3x4(
            best_rvec, best_tvec)
        tvecs[best_frame] = best_tvec

    last_mat = None
    for frame in range(num_frames):
        if view_mats[frame] is None:
            view_mats[frame] = last_mat
        else:
            last_mat = view_mats[frame]

    ids = []
    points = []

    for id in cloud.keys():
        ids.append(id)
        points.append(cloud[id])

    point_cloud_builder = PointCloudBuilder(np.array(ids, dtype=np.int),
                                            np.array(points))

    calc_point_cloud_colors(point_cloud_builder, rgb_sequence, view_mats,
                            intrinsic_mat, corner_storage, 5.0)
    point_cloud = point_cloud_builder.build_point_cloud()
    poses = list(map(view_mat3x4_to_pose, view_mats))
    return poses, point_cloud