def report(self, stage=""): overall = error_stats(self.reprojection_error) inliers = error_stats(self.reprojection_inliers) if self.inlier_mask is not None: info(f"{stage} reprojection RMS={inliers.rms:.3f} ({overall.rms:.3f}), " f"n={inliers.n} ({overall.n}), quantiles={overall.quantiles}") else: info(f"{stage} reprojection RMS={overall.rms:.3f}, n={overall.n}, " f"quantiles={overall.quantiles}")
def reject_outliers(self, threshold): """ Set outlier threshold """ errors, valid = tables.reprojection_error(self.reprojected, self.point_table) inliers = (errors < threshold) & valid num_outliers = valid.sum() - inliers.sum() inlier_percent = 100.0 * inliers.sum() / valid.sum() info(f"Rejecting {num_outliers} outliers with error > {threshold:.2f} pixels, " f"keeping {inliers.sum()} / {valid.sum()} inliers, ({inlier_percent:.2f}%)") return self.copy(inlier_mask = inliers)
def try_load_detections(filename, cache_key={}): try: with open(filename, "rb") as file: loaded = pickle.load(file) # Check that the detections match the metadata if (loaded.get('cache_key', {}) == cache_key): info(f"Loaded detections from {filename}") return loaded.detected_points else: info( f"Config changed, not using loaded detections in {filename}" ) except (OSError, IOError, EOFError, AttributeError) as e: return None
def adjust_outliers(self, num_adjustments=3, select_scale=None, select_outliers=None, **kwargs): info(f"Beginning adjustments ({num_adjustments}) enabled: {self.optimize}, options: {kwargs}") for i in range(num_adjustments): self.report(f"Adjust_outliers {i}:") f_scale = apply_none(select_scale, self.reprojection_error) or 1.0 if select_scale is not None: info(f"Auto scaling for outliers influence at {f_scale:.2f} pixels") if select_outliers is not None: self = self.reject_outliers(select_outliers(self.reprojection_error)) self = self.bundle_adjust(f_scale=f_scale, **kwargs) self.report(f"Adjust_outliers end:") return self
def find_board_config(image_path, board_file=None): assert board_file is None or path.isfile( board_file), f"board file {board_file} not found" board_file = board_file or path.join(image_path, "boards.yaml") calico_file = path.join(image_path, "../network_specification_file.txt") boards = {} if path.isfile(board_file): boards = load_config(board_file) elif path.isfile(calico_file): boards = load_calico(calico_file) # CALICO board specification file else: assert False, f"no boards found, use --boards or add boards.yaml to image path" info("Using boards:") for name, b in boards.items(): info(f"{name} {b}") return boards
def find_camera_images(image_path, cameras=None, camera_pattern=None, matching=True, extensions=image.find.image_extensions): camera_paths = image.find.find_cameras(image_path, cameras, camera_pattern, extensions=extensions) camera_names = list(camera_paths.keys()) find_images = image.find.find_images_matching if matching else image.find.find_images_unmatched image_names, filenames = find_images(camera_paths, extensions=extensions) info("Found camera directories {} with {} matching images".format( camera_names, len(image_names))) return struct(image_path=image_path, cameras=camera_names, image_names=image_names, filenames=filenames)
def initialise(args, paths): ws = workspace.Workspace() setup_logging(args.log_level, [ws.log_handler], log_file=paths.log_file) info(args) board_file = args.boards or path.join(args.image_path, "boards.yaml") if args.boards is None: assert path.isfile(board_file),\ f"either specify boards description file with --boards or add boards.yaml to image path" else: assert path.isfile(args.boards), f"board file {args.boards} not found" boards = board.load_config(board_file) info("Using boards:") for name, b in boards.items(): info(f"{name} {b}") cameras = map_none(str.split, args.cameras, ",") ws.find_images_matching(args.image_path, cameras, args.camera_pattern, master = args.master) ws.load_images(j=args.j) ws.detect_boards(boards, cache_file=paths.detection_cache, load_cache=not args.no_cache, j=args.j) ws.calibrate_single(args.distortion_model, fix_aspect=args.fix_aspect, has_skew=args.allow_skew, max_images=args.intrinsic_images) motion_model = None if args.motion_model == "rolling": motion_model = RollingFrames elif args.motion_model == "static": motion_model = StaticFrames else: assert False, f"unknown motion model {args.motion_model}, (static|rolling)" ws.initialise_poses(motion_model=motion_model) return ws
def calibrate_intrinsic(args): paths = setup_paths(args.paths) setup_logging(args.runtime.log_level, [], log_file=paths.log_file) info(pformat_struct(args)) image_path = os.path.expanduser(args.paths.image_path) info(f"Finding images in {image_path}") camera_images = find_camera_images(image_path, args.paths.cameras, args.paths.camera_pattern, matching=False) image_counts = { k: len(files) for k, files in zip(camera_images.cameras, camera_images.filenames) } info("Found camera directories with images {}".format(image_counts)) board_names, boards = split_dict( find_board_config(image_path, args.paths.boards)) info("Loading images..") images = image.detect.load_images(camera_images.filenames, prefix=camera_images.image_path, j=args.runtime.num_threads) image_sizes = map_list(common_image_size, images) info({ k: image_size for k, image_size in zip(camera_images.cameras, image_sizes) }) cache_key = struct(boards=boards, image_sizes=image_sizes, filenames=camera_images.filenames) detected_points = detect_boards_cached(boards, images, paths.detections, cache_key, j=args.runtime.num_threads) cameras, errs = calibrate_cameras(boards, detected_points, image_sizes, model=args.camera.distortion_model, fix_aspect=args.camera.fix_aspect, has_skew=args.camera.allow_skew, max_images=args.camera.limit_intrinsic) for name, camera, err in zip(camera_images.cameras, cameras, errs): info(f"Calibrated {name}, with RMS={err:.2f}") info(camera) info("") info(f"Writing single calibrations to {paths.calibration_file}") export_single(paths.calibration_file, cameras, camera_images.cameras, camera_images.filenames)