def init_first_camera_positions(intrinsic_mat, corner_storage): frame_count = len(corner_storage) best_pair = (-1, -1) zero_view_mat = eye3x4() best_view_mat = None best_triangulated_points = -1 confidence = 0.9 params = TriangulationParameters(max_reprojection_error=2, min_triangulation_angle_deg=1, min_depth=0.5) for i in range(0, frame_count, 10): print("Init first camera. Frame %d/%d" % (i + 1, frame_count)) for j in range(i + 3, min(i + 30, frame_count), 3): correspondences = build_correspondences(corner_storage[i], corner_storage[j]) if len(correspondences.ids) < 5: continue points_1, points_2 = correspondences.points_1, correspondences.points_2 e_matrix, e_mask = findEssentialMat(points_1, points_2, intrinsic_mat, method=RANSAC, threshold=2, prob=confidence) h_matrix, h_mask = findHomography(points_1, points_2, method=RANSAC, ransacReprojThreshold=2, confidence=confidence) e_inliers, h_inliers = sum(e_mask.reshape(-1)), sum( h_mask.reshape(-1)) if e_inliers / h_inliers < 0.1: continue outliers = np.delete(correspondences.ids, correspondences.ids[e_mask]) correspondences = build_correspondences(corner_storage[i], corner_storage[j], outliers) R1, R2, t = decomposeEssentialMat(e_matrix) for rv in [R1, R2]: for tv in [-t, t]: candidate_veiw_mat = np.hstack((rv, tv)) points, ids, _ = triangulate_correspondences( correspondences, zero_view_mat, candidate_veiw_mat, intrinsic_mat, params) if len(points) > best_triangulated_points: best_triangulated_points = len(points) best_pair = (i, j) best_view_mat = candidate_veiw_mat return (best_pair[0], zero_view_mat), (best_pair[1], best_view_mat)
def track_camera(corner_storage, intrinsic_mat, known_view1, known_view2): n = len(corner_storage) point_cloud_builder = PointCloudBuilder() view_mat = [eye3x4()] * n view_mat[known_view1[0]] = pose_to_view_mat3x4(known_view1[1]) view_mat[known_view2[0]] = pose_to_view_mat3x4(known_view2[1]) min_angle = 1.0 max_error = 1.0 new_points = [] ids = [] correspondences = build_correspondences(corner_storage[known_view1[0]], corner_storage[known_view2[0]]) while len(new_points) < 10: new_points, ids, _ = triangulate_correspondences( correspondences, pose_to_view_mat3x4(known_view1[1]), pose_to_view_mat3x4(known_view2[1]), intrinsic_mat, TriangulationParameters(max_error, min_angle, 0)) min_angle -= 0.2 max_error += 0.4 point_cloud_builder.add_points(ids, new_points) for i in range(known_view1[0] - 1, -1, -1): solve_frame(i, corner_storage, point_cloud_builder, view_mat, intrinsic_mat, 1) for i in range(known_view1[0] + 1, n): solve_frame(i, corner_storage, point_cloud_builder, view_mat, intrinsic_mat, -1) return view_mat, point_cloud_builder
def pose_by_frames(frame1: FrameCorners, frame2: FrameCorners, intrinsic_mat: np.ndarray) -> Tuple[Pose, int]: correspondences = build_correspondences(frame1, frame2) mat, mask = cv2.findEssentialMat(correspondences.points_1, correspondences.points_2, intrinsic_mat, cv2.RANSAC, 0.99, 1) if mat is None or mat.shape != (3, 3): return None, 0 if mask is not None: correspondences = _remove_correspondences_with_ids( correspondences, np.argwhere(mask.flatten() == 0)) R1, R2, t = cv2.decomposeEssentialMat(mat) max_pose = None max_npoints = 0 for mat in [R1.T, R2.T]: for vec in [t, -t]: pose = Pose(mat, mat @ vec) points, _, _ = triangulate_correspondences( correspondences, eye3x4(), pose_to_view_mat3x4(pose), intrinsic_mat, INITIAL_TRIANGULATION_PARAMETERS) if len(points) > max_npoints: max_pose = pose max_npoints = len(points) return max_pose, max_npoints
def _test_frame_pair(intrinsic_mat: np.ndarray, corners_1: FrameCorners, corners_2: FrameCorners, param_koeff: float = 1) -> Tuple[int, Optional[Pose]]: correspondences = build_correspondences(corners_1, corners_2) if len(correspondences.ids) < 6: return 0, None points2d_1 = correspondences.points_1 points2d_2 = correspondences.points_2 essential, essential_inliers = cv2.findEssentialMat(points2d_1, points2d_2, intrinsic_mat, threshold=param_koeff) homography, homography_inliers = cv2.findHomography(points2d_1, points2d_2, method=cv2.RANSAC) if len(np.where(homography_inliers > 0)[0]) > len(np.where(essential_inliers > 0)[0]): return 0, None if essential.shape != (3, 3): return 0, None num_passed, rot, t, mask = cv2.recoverPose(essential, points2d_1, points2d_2, intrinsic_mat, mask=essential_inliers) outlier_ids = np.array( [pt_id for pt_id, mask_elem in zip(correspondences.ids, mask) if mask_elem[0] == 0], dtype=correspondences.ids.dtype) inlier_correspondences = _remove_correspondences_with_ids(correspondences, outlier_ids) if len(inlier_correspondences.ids) < 4: return 0, None view_matr_1 = eye3x4() view_matr_2 = np.hstack((rot, t)) triangulation_params = TriangulationParameters(param_koeff, 1.0 / param_koeff, 0.0) pts_3d, trianulated_ids, med_cos = triangulate_correspondences(inlier_correspondences, view_matr_1, view_matr_2, intrinsic_mat, triangulation_params) if len(pts_3d) < 4: return 0, None print(len(inlier_correspondences.ids), len(pts_3d)) return len(pts_3d), view_mat3x4_to_pose(view_matr_2)
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)
def calc_known_views(corner_storage, intrinsic_mat, indent=5): num_frames = len(corner_storage) known_view_1 = (None, None) known_view_2 = (None, None) num_points = -1 for frame_1 in range(num_frames): for frame_2 in range(frame_1 + indent, num_frames): corrs = build_correspondences(corner_storage[frame_1], corner_storage[frame_2]) if len(corrs.ids) < 6: continue points_1 = corrs.points_1 points_2 = corrs.points_2 H, mask_h = cv2.findHomography(points_1, points_2, method=cv2.RANSAC) if mask_h is None: continue mask_h = mask_h.reshape(-1) E, mask_e = cv2.findEssentialMat(points_1, points_2, method=cv2.RANSAC, cameraMatrix=intrinsic_mat) if mask_e is None: continue mask_e = mask_e.reshape(-1) if mask_h.sum() / mask_e.sum() > 0.5: continue corrs = Correspondences(corrs.ids[(mask_e == 1)], points_1[(mask_e == 1)], points_2[(mask_e == 1)]) R1, R2, t = cv2.decomposeEssentialMat(E) for poss_pose in [ Pose(R1.T, R1.T @ t), Pose(R1.T, R1.T @ (-t)), Pose(R2.T, R2.T @ t), Pose(R2.T, R2.T @ (-t)) ]: points3d, _, _ = triangulate_correspondences( corrs, eye3x4(), pose_to_view_mat3x4(poss_pose), intrinsic_mat, TriangulationParameters(1, 2, .1)) if len(points3d) > num_points: num_points = len(points3d) known_view_1 = (frame_1, view_mat3x4_to_pose(eye3x4())) known_view_2 = (frame_2, poss_pose) return known_view_1, known_view_2
def add_points_to_cloud(point_cloud_builder, corners1, corners2, view1, view2, intrinsic_mat, triang_params): correspondences = build_correspondences(corners1, corners2, ids_to_remove=point_cloud_builder.ids) points, ids, median_cos = triangulate_correspondences(correspondences, view1, view2, intrinsic_mat, triang_params) point_cloud_builder.add_points(ids, points) return len(points)
def track(iters, trackers, cloud, camera): start_ids, start_points = cloud.ids, cloud.points for iter in range(iters): for frame_num, t1 in enumerate(trackers): print("\rIteration {}/{}, triangulate for frame {}/{}".format( iter + 1, iters, t1.id, len(trackers)), end=' ' * 20) if t1.mtx is None: continue for j in range(frame_num - FRAMES_MAX_WINDOW, frame_num + FRAMES_MAX_WINDOW + 1, FRAMES_STEP): if j < 0 or j >= len(trackers): continue t2 = trackers[j] if abs(t1.id - t2.id) <= FRAMES_MIN_WINDOW or t2.mtx is None: continue corrs = build_correspondences(t1.corners, t2.corners) if not len(corrs.ids): continue points, ids, _ = triangulate_correspondences( corrs, t1.mtx, t2.mtx, camera, triang_params) if len(points): cloud.add_points(ids, points) fc = FrequencyCounter() for t in trackers: inliers = t.pnp(cloud, camera) inliers = np.array(inliers).flatten().astype(int) print("\rIteration {}/{}, PnP for frame {}/{}, {} inliners".format( iter + 1, iters, t.id, len(trackers), len(inliers)), end=' ' * 20) if len(inliers): ids1, ids2 = build_index_intersection(cloud.ids, inliers) fc.add(inliers[ids2], cloud.points[ids1], t.corners.ids) good_points_ids, good_points = fc.get_freqs_above( INLINER_FREQUENCY_TRASHHOLD, MIN_INLINER_FRAMES) cloud = PointCloudBuilder(good_points_ids, good_points) for t in trackers: t.pnp(cloud, camera) print("\rIteration {}/{}, {} points in the cloud".format( iter + 1, iters, len(cloud.ids)), end=' ' * 20 + "\n") fc = FrequencyCounter() for t in trackers: inliers = t.pnp(cloud, camera) inliers = np.array(inliers).flatten().astype(int) if len(inliers): ids1, ids2 = build_index_intersection(cloud.ids, inliers) fc.add(inliers[ids2], cloud.points[ids1], t.corners.ids) good_points_ids, good_points = fc.get_freqs_above( INLINER_FREQUENCY_TRASHHOLD, MIN_INLINER_FRAMES) cloud = PointCloudBuilder(good_points_ids, good_points) return cloud
def get_matrix_poses(corner_storage, intrisinc_mat): pairs = get_best_intersected(corner_storage) best_pair = -1, -1 best_pair_result = -1 for i, j, _ in pairs[:100]: ids1, ids2 = build_index_intersection(corner_storage[i].ids, corner_storage[j].ids) points1 = corner_storage[i].points[ids1] points2 = corner_storage[j].points[ids2] E, mask = cv2.findEssentialMat(points1, points2, focal=intrisinc_mat[0][0]) if mask.sum() < 10: continue F, mask = cv2.findFundamentalMat(points1, points2) if mask.sum() < 10: continue _, R, t, mask = cv2.recoverPose(E, points1, points1, focal=intrisinc_mat[0][0]) if mask.sum() < 10: continue corrs = build_correspondences(corner_storage[i], corner_storage[j]) points, ids, _ = triangulate_correspondences( corrs, eye3x4(), np.hstack((R, t)), intrisinc_mat, TriangulationParameters(max_reprojection_error=5, min_triangulation_angle_deg=5., min_depth=0.001)) current_result = len(ids) // 20 if current_result > best_pair_result: best_pair = i, j best_pair_result = current_result i, j = best_pair ids1, ids2 = build_index_intersection(corner_storage[i].ids, corner_storage[j].ids) points1 = corner_storage[i].points[ids1] points2 = corner_storage[j].points[ids2] E, mask = cv2.findEssentialMat(points1, points2, focal=intrisinc_mat[0][0]) F, mask = cv2.findFundamentalMat(points1, points2) _, R, t, mask = cv2.recoverPose(E, points1, points1, focal=intrisinc_mat[0][0]) print(f"Chosen frames {i} and {j}") return (i, view_mat3x4_to_pose(eye3x4())),\ (j, view_mat3x4_to_pose(np.hstack((R, t))))
def _update_cloud(self, ind1, ind2): frame1, frame2 = self._corner_storage[ind1], self._corner_storage[ind2] mat1, mat2 = self._track[ind1], self._track[ind2] correspondences = build_correspondences(frame1, frame2) if len(correspondences.ids) == 0: return 0 points, ids, _ = triangulate_correspondences( correspondences, mat1, mat2, self._intrinsic_mat, self._triangulation_parameters) self._builder.add_points(ids, points) return len(ids)
def enrich_point_cloud(self, view_1: np.ndarray, view_2: np.ndarray, corners_1: FrameCorners, corners_2: FrameCorners, triangulation_parameters: TriangulationParameters) -> None: correspondences = build_correspondences(corners_1, corners_2) points, ids, median_cos = triangulate_correspondences( correspondences, view_1, view_2, self.intrinsic_mat, triangulation_parameters) self.point_cloud_builder.add_points(ids, points)
def update_cloud(j): if i != j and j not in err_indexes: correspondences_i = build_correspondences(corner_storage[i], corner_storage[j]) points3d_j, corr_ids_j, median_cos = triangulate_correspondences( correspondences_i, view_mats[i], view_mats[j], intrinsic_mat, TRIANG_PARAMS) if len(points3d_j) > MIN_SIZE: point_cloud_builder.add_points(corr_ids_j.astype(np.int64), points3d_j) tqdm_iter.set_description( template.format(len(inliers), len(points3d_j), len(point_cloud_builder._points)))
def initial_views_generator(self, leniency: np.float64): for frame_1 in range(self.frame_count): print('Trying to match frame {} with a subsequent frame...'.format(frame_1)) for frame_2 in range(frame_1 + INIT_MIN_FRAME_DISTANCE, min(frame_1 + 1 + INIT_MAX_FRAME_DISTANCE, self.frame_count)): correspondences = build_correspondences(self.corner_storage[frame_1], self.corner_storage[frame_2]) result = self.try_restore_relative_pose( correspondences, INIT_MAX_LINE_DISTANCE * leniency, INIT_HOMOGRAPHY_MAX_REPROJECTION_ERROR / leniency, INIT_MAX_HOMOGRAPHY_INLIER_RATIO ) if result is not None: yield frame_1, frame_2, *result
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)
def get_pose_with_score(frame_1, frame_2, corner_storage, intrinsic_mat): corners1, corners2 = corner_storage[frame_1], corner_storage[frame_2] correspondences = build_correspondences(corners1, corners2) essential_mat, mask_essential = cv2.findEssentialMat(correspondences[1], correspondences[2], intrinsic_mat, method=cv2.RANSAC, threshold=1.0) if essential_mat is None or mask_essential is None: return None, 0 _, mask_homography = cv2.findHomography(correspondences[1], correspondences[2], method=cv2.RANSAC) essential_inliers, homography_inliers = mask_essential.flatten().sum( ), mask_homography.flatten().sum() if homography_inliers > essential_inliers * 0.5: return None, 0 correspondences = _remove_correspondences_with_ids( correspondences, np.argwhere(mask_essential == 0)) R1, R2, t = cv2.decomposeEssentialMat(essential_mat) candidates = [ Pose(R1.T, R1.T @ t), Pose(R1.T, R1.T @ (-t)), Pose(R2.T, R2.T @ t), Pose(R2.T, R2.T @ (-t)) ] best_pose_score, best_pose = 0, None triangulation_parameters = TriangulationParameters(1, 2, .1) for pose in candidates: points, _, _ = triangulate_correspondences(correspondences, eye3x4(), pose_to_view_mat3x4(pose), intrinsic_mat, triangulation_parameters) if len(points) > best_pose_score: best_pose_score = len(points) best_pose = pose return best_pose, best_pose_score
def triangulate(ind_1, ind_2, pose_1, pose_2, corner_storage, intrinsic_mat, ids_to_remove, parameters=TriangulationParameters(8.0, 0, 2)): frame_corners_1, frame_corners_2 = corner_storage[ind_1], corner_storage[ ind_2] correspondences = build_correspondences(frame_corners_1, frame_corners_2, ids_to_remove) view_1, view_2 = pose_to_view_mat3x4(pose_1), pose_to_view_mat3x4(pose_2) return triangulate_correspondences(correspondences, view_1, view_2, intrinsic_mat, parameters)
def __init__(self, corner_storage, intrinsic_mat, view_1, view_2): self.corner_storage = corner_storage self.frame_count = len(corner_storage) self.intrinsic_mat = intrinsic_mat self.triangulation_parameters = TriangulationParameters(1, 3, .1) self.view_mats = {} if view_1 is None or view_2 is None: print('Finding initial poses') pose1_idx, pose1, pose2_idx, pose2 = self.find_best_start_poses() print('Initial poses found in frames {0} and {1}'.format(pose1_idx, pose2_idx)) else: pose1 = pose_to_view_mat3x4(view_1[1]) pose2 = pose_to_view_mat3x4(view_2[1]) pose1_idx = view_1[0] pose2_idx = view_2[0] corners_1 = self.corner_storage[pose1_idx] corners_2 = self.corner_storage[pose2_idx] corrs = build_correspondences(corners_1, corners_2) p, ids, med = triangulate_correspondences(corrs, pose1, pose2, self.intrinsic_mat, self.triangulation_parameters) self.ids = ids self.point_cloud_builder = PointCloudBuilder(ids, p) self.point_frames = {} self.last_retriangulated = {} for i in ids: self.point_frames[i] = [pose1_idx, pose2_idx] self.last_retriangulated[i] = 2 self.used_inliers = {} self.view_nones = {i for i in range(self.frame_count)} self.view_mats[pose1_idx] = pose1 self.used_inliers[pose1_idx] = 0 self.view_nones.remove(pose1_idx) self.view_mats[pose2_idx] = pose2 self.used_inliers[pose2_idx] = 0 self.view_nones.remove(pose2_idx) self.last_added_idx = pose2_idx self.last_inliers = [] self.retriangulate_frames = 3 self.max_repr_error = 1.5 self.used_inliers_point = {} self.step = 0
def calculate_known_views( intrinsic_mat, corner_storage: CornerStorage, min_correspondencies_count=100, max_homography=0.7, ) -> Tuple[Tuple[int, Pose], Tuple[int, Pose]]: best_points_num, best_known_views = -1, ((None, None), (None, None)) for i in range(len(corner_storage)): for j in range(i + 1, min(i + 40, len(corner_storage))): corresp = build_correspondences(corner_storage[i], corner_storage[j]) if len(corresp[0]) < min_correspondencies_count: break E, mask = cv2.findEssentialMat(corresp.points_1, corresp.points_2, cameraMatrix=intrinsic_mat, method=cv2.RANSAC) mask = (mask.squeeze() == 1) corresp = Correspondences(corresp.ids[mask], corresp.points_1[mask], corresp.points_2[mask]) if E is None: continue # Validate E using homography H, mask = cv2.findHomography(corresp.points_1, corresp.points_2, method=cv2.RANSAC) if np.count_nonzero(mask) / len(corresp.ids) > max_homography: continue R1, R2, T = cv2.decomposeEssentialMat(E) for view_mat2 in [ np.hstack((R, t)) for R in [R1, R2] for t in [T, -T] ]: view_mat1 = np.eye(3, 4) points, _, _ = triangulate_correspondences( corresp, view_mat1, view_mat2, intrinsic_mat, triang_params) print('Try frames {}, {}: {} correspondent points'.format( i, j, len(points))) if len(points) > best_points_num: best_known_views = ((i, view_mat3x4_to_pose(view_mat1)), (j, view_mat3x4_to_pose(view_mat2))) best_points_num = len(points) if best_points_num > 1500: return best_known_views return best_known_views
def _triangulate(self, frame_num_1, frame_num_2): corners_1 = self.corner_storage[frame_num_1] corners_2 = self.corner_storage[frame_num_2] corresps = build_correspondences(corners_1, corners_2, ids_to_remove=np.array(list( map(int, self.point_cloud.keys())), dtype=int)) view_1 = self.tracked_poses[frame_num_1].pos view_2 = self.tracked_poses[frame_num_2].pos triangulation_params = TriangulationParameters(1, 1, 0) pts_3d, triangulated_ids, med_cos = triangulate_correspondences( corresps, view_1, view_2, self.intrinsic_mat, triangulation_params) return pts_3d, triangulated_ids
def select_frames(frames, corner_storage, camera_matrix): frame1 = (0, view_mat3x4_to_pose(eye3x4())) frame2 = (-1, view_mat3x4_to_pose(eye3x4())) mx = 0 for i in range(1, len(frames)): correspondences = build_correspondences(corner_storage[frame1[0]], corner_storage[i]) if len(correspondences.ids) < 8: continue E, mask = cv2.findEssentialMat(correspondences.points_1, correspondences.points_2, camera_matrix, method=cv2.RANSAC) if mask is None: continue correspondences = _remove_correspondences_with_ids( correspondences, np.argwhere(mask.flatten() == 0)) if len(correspondences.ids) < 8 or not validate(correspondences, mask): continue R1, R2, t = cv2.decomposeEssentialMat(E) ps = [ Pose(R1.T, R1.T @ t), Pose(R2.T, R2.T @ t), Pose(R1.T, R1.T @ (-t)), Pose(R2.T, R2.T @ (-t)) ] for pose in ps: points, _, _ = triangulate_correspondences( correspondences, pose_to_view_mat3x4(frame1[1]), pose_to_view_mat3x4(pose), camera_matrix, TRIANG_PARAMS) if len(points) > mx: frame2 = (i, pose) mx = len(points) print(frame1[0], frame2[0]) return frame1, frame2
def calc_starting_points( intrinsic_mat: np.ndarray, corner_storage: CornerStorage, known_view_1: Tuple[int, Pose], known_view_2: Tuple[int, Pose]) -> Tuple[np.ndarray, np.ndarray]: id1, pose1 = known_view_1 id2, pose2 = known_view_2 corners1 = corner_storage[id1] corners2 = corner_storage[id2] mat1 = pose_to_view_mat3x4(pose1) mat2 = pose_to_view_mat3x4(pose2) correspondences = build_correspondences(corners1, corners2) points_3d, points_ids, _ = triangulate_correspondences( correspondences, mat1, mat2, intrinsic_mat, INITIAL_TRIANGULATION_PARAMETERS) return points_3d, points_ids
def add_points(point_cloud_builder, corner_storage, i, view_mats, intrinsic_mat): cloud_changed = False for d in range(-HALF_FRAME_DIST, HALF_FRAME_DIST): if d == 0 or i + d < 0 or i + d >= len(view_mats) or view_mats[ i + d] is None: continue correspondences = build_correspondences(corner_storage[i + d], corner_storage[i], point_cloud_builder.ids) if len(correspondences.ids) > 0: points, ids, _ = triangulate_correspondences( correspondences, view_mats[i + d], view_mats[i], intrinsic_mat, TRIANG_PARAMS) if len(ids) > 0: cloud_changed = True point_cloud_builder.add_points(ids, points) return cloud_changed
def extract_points(corners1, corners2, view_mat1, view_mat2, intrinsic_mat, ids_to_remove=None): corr = build_correspondences(corners1, corners2, ids_to_remove) if not len(corr.ids): return None points3d, corr_ids, median_cos = triangulate_correspondences( corr, view_mat1, view_mat2, intrinsic_mat, TriangulationParameters(max_reprojection_error=1, min_triangulation_angle_deg=1, min_depth=0.1)) if not len(corr_ids): return None return corr_ids, points3d
def add_new_points(frames, view_mats, frame_ind_1, frame_ind_2, all_points, intrinsic_mat): correspondences = build_correspondences(frames[frame_ind_1], frames[frame_ind_2]) points, ids, _ = triangulate_correspondences(correspondences, view_mats[frame_ind_1], view_mats[frame_ind_2], intrinsic_mat, TRIANGULATION_PARAMS) new_points_number = 0 for point, point_id in zip(points, ids): if point_id not in all_points or all_points[point_id] is None: all_points[point_id] = point new_points_number += 1 print( f'Frames: {frame_ind_1} and {frame_ind_2}, found {new_points_number} new points' )
def track(self): while len(self.view_mats) < self.frame_count: print('Processing {0}/{1} frame'.format(len(self.view_mats) + 1, self.frame_count)) for i, v_mat in self.view_mats.items(): corners_1 = self.corner_storage[i] corners_2 = self.corner_storage[self.last_added_idx] corrs = build_correspondences(corners_1, corners_2) try: p, ids, _ = triangulate_correspondences(corrs, v_mat, self.view_mats[self.last_added_idx], self.intrinsic_mat, self.triangulation_parameters) new_corners = [] new_ids = [] for j, pt in zip(ids, p): if j in self.last_inliers or j not in self.point_frames: new_ids += [j] new_corners += [pt] for i_ in ids: if i_ not in self.point_frames: self.point_frames[i_] = [i] if self.last_added_idx not in self.point_frames[i_]: self.point_frames[i_] += [self.last_added_idx] if len(new_ids) > 0: self.point_cloud_builder.add_points(np.array(new_ids), np.array(new_corners)) except: continue print('Points cloud size: {0}'.format(len(self.point_cloud_builder.points))) view_mat, best_idx, inliers = self.solve_pnp_ransac() self.view_mats[best_idx] = view_mat[:3] self.used_inliers[best_idx] = inliers self.view_nones.remove(best_idx) self.last_added_idx = best_idx if self.step % (self.frame_count // 20) == 0 and self.step > 0: self.retriangulate_points() if self.step % (self.frame_count // 10) == 0 and self.step > 0: self.update_tracks() # k = list(self.view_mats.keys()) # k = k[self.step - 10:self.step] # self.bundle_adjustment(k) self.step += 1
def get_pose(self, frame_1, frame_2): p1 = self.corner_storage[frame_1] p2 = self.corner_storage[frame_2] corresp = build_correspondences(p1, p2) if len(corresp.ids) < 6: return None, 0 E, mask_essential = cv2.findEssentialMat(corresp[1], corresp[2], self.intrinsic_mat, method=cv2.RANSAC, threshold=1.0) _, mask_homography = cv2.findHomography(corresp[1], corresp[2], method=cv2.RANSAC) if mask_essential is None or mask_homography is None: return None, 0 essential_inliers = mask_essential.flatten().sum() homography_inliers = mask_homography.flatten().sum() if homography_inliers / essential_inliers > 0.5: return None, 0 corresp = _remove_correspondences_with_ids(corresp, np.argwhere(mask_essential == 0)) R1, R2, t = cv2.decomposeEssentialMat(E) possible_poses = [Pose(R1.T, R1.T @ t), Pose(R1.T, R1.T @ (-t)), Pose(R2.T, R2.T @ t), Pose(R2.T, R2.T @ (-t))] best_pose_points = 0 best_pose = None for pose in possible_poses: p, ids, med = triangulate_correspondences(corresp, eye3x4(), pose_to_view_mat3x4(pose), self.intrinsic_mat, self.triangulation_parameters) if len(p) > best_pose_points: best_pose_points = len(p) best_pose = pose return best_pose, best_pose_points
def calc_new_points(cur_id: int, intrinsic_mat: np.ndarray, corner_storage: CornerStorage, view_mats: List[np.ndarray], points_3d: np.ndarray, points_ids: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: for d in [-32, 32, -16, 16, -8, 8, -4, 4, -2, 2 - 1, 1]: i = cur_id + d if i < 0 or i >= len(corner_storage) or view_mats[i][0, 0] is None: continue mat1 = view_mats[i] mat2 = view_mats[cur_id] corners1 = corner_storage[i] corners2 = corner_storage[cur_id] correspondences = build_correspondences(corners1, corners2) new_points_3d, new_points_ids, _ = triangulate_correspondences( correspondences, mat1, mat2, intrinsic_mat, NEW_TRIANGULATION_PARAMETERS[abs(d)]) points_3d, points_ids = merge_sets(points_3d, points_ids, new_points_3d, new_points_ids) return points_3d, points_ids
def _add_points_from_frame(self, frame_num_1: int, frame_num_2: int, initial_triangulation: bool = False) -> int: corners_1 = self.corner_storage[frame_num_1] corners_2 = self.corner_storage[frame_num_2] correspondences = build_correspondences(corners_1, corners_2, ids_to_remove=self.pc_builder.ids) if len(correspondences.ids) > 0: max_reproj_error = 1.0 min_angle = 1.0 view_1 = self.tracked_views[frame_num_1] view_2 = self.tracked_views[frame_num_2] triangulation_params = TriangulationParameters(max_reproj_error, min_angle, 0) pts_3d, triangulated_ids, med_cos = triangulate_correspondences(correspondences, view_1, view_2, self.intrinsic_mat, triangulation_params) if initial_triangulation: num_iter = 0 while len(pts_3d) < 8 and len(correspondences.ids) > 7 and num_iter < 100: max_reproj_error *= 1.2 min_angle *= 0.8 triangulation_params = TriangulationParameters(max_reproj_error, min_angle, 0) pts_3d, triangulated_ids, med_cos = triangulate_correspondences(correspondences, view_1, view_2, self.intrinsic_mat, triangulation_params) num_iter += 1 if num_iter >= 100 and len(pts_3d) < 4: raise TrackingError('Failed to triangulate enough points') self.pc_builder.add_points(triangulated_ids, pts_3d) return len(pts_3d) elif initial_triangulation: raise TrackingError('Not found correspondences on image pair') else: return 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
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)