def run_kitti_native_script_with_05_iou(checkpoint_name, score_threshold, global_step, output_dir=None): """Runs the kitti native code script.""" if output_dir is None: output_dir = avod.root_dir() + '/data/outputs/' eval_script_dir = os.path.join(output_dir,checkpoint_name) + \ '/predictions' make_script = eval_script_dir + \ '/kitti_native_eval/run_eval_05_iou.sh' script_folder = eval_script_dir + \ '/kitti_native_eval/' if output_dir is None: results_dir = avod.top_dir() + '/scripts/offline_eval/results_05_iou/' else: results_dir = os.path.join( output_dir, checkpoint_name) + '/offline_eval/results_05_iou/' # Round this because protobuf encodes default values as full decimal score_threshold = round(score_threshold, 3) subprocess.call([ make_script, script_folder, str(score_threshold), str(global_step), str(checkpoint_name), str(results_dir) ])
def copy_kitti_native_code(checkpoint_name): """Copies and compiles kitti native code. It also creates neccessary directories for storing the results of the kitti native evaluation code. """ avod_root_dir = avod.root_dir() kitti_native_code_copy = avod_root_dir + '/data/outputs/' + \ checkpoint_name + '/predictions/kitti_native_eval/' # Only copy if the code has not been already copied over if not os.path.exists(kitti_native_code_copy): os.makedirs(kitti_native_code_copy) original_kitti_native_code = avod.top_dir() + \ '/scripts/offline_eval/kitti_native_eval/' predictions_dir = avod_root_dir + '/data/outputs/' + \ checkpoint_name + '/predictions/' # create dir for it first dir_util.copy_tree(original_kitti_native_code, kitti_native_code_copy) # run the script to compile the c++ code script_folder = predictions_dir + \ '/kitti_native_eval/' make_script = script_folder + 'run_make.sh' subprocess.call([make_script, script_folder]) # Set up the results folders if they don't exist results_dir = avod.top_dir() + '/scripts/offline_eval/results' results_05_dir = avod.top_dir() + '/scripts/offline_eval/results_05_iou' if not os.path.exists(results_dir): os.makedirs(results_dir) if not os.path.exists(results_05_dir): os.makedirs(results_05_dir)
def get_configs_from_pipeline_file(pipeline_config_path, is_training): """Reads model configuration from a pipeline_pb2.NetworkPipelineConfig. Args: pipeline_config_path: A path directory to the network pipeline config is_training: A boolean flag to indicate training stage, used for creating the checkpoint directory which must be created at the first training iteration. Returns: model_config: A model_pb2.ModelConfig train_config: A train_pb2.TrainConfig eval_config: A eval_pb2.EvalConfig dataset_config: A kitti_dataset_pb2.KittiDatasetConfig """ pipeline_config = pipeline_pb2.NetworkPipelineConfig() with open(pipeline_config_path, 'r') as f: text_format.Merge(f.read(), pipeline_config) #解析config文件 model_config = pipeline_config.model_config # Make sure the checkpoint name matches the config filename config_file_name = \ os.path.split(pipeline_config_path)[1].split('.')[0] checkpoint_name = model_config.checkpoint_name if config_file_name != checkpoint_name: raise ValueError('Config and checkpoint names must match.') output_root_dir = avod.root_dir() + '/data/outputs/' + checkpoint_name # Construct paths paths_config = model_config.paths_config if not paths_config.checkpoint_dir: checkpoint_dir = output_root_dir + '/checkpoints' if is_training: if not os.path.exists(checkpoint_dir): os.makedirs(checkpoint_dir) paths_config.checkpoint_dir = checkpoint_dir if not paths_config.logdir: paths_config.logdir = output_root_dir + '/logs/' if not paths_config.pred_dir: paths_config.pred_dir = output_root_dir + '/predictions' train_config = pipeline_config.train_config eval_config = pipeline_config.eval_config dataset_config = pipeline_config.dataset_config if is_training: # Copy the config to the experiments folder experiment_config_path = output_root_dir + '/' +\ model_config.checkpoint_name experiment_config_path += '.config' # Copy this even if the config exists, in case some parameters # were modified shutil.copy(pipeline_config_path, experiment_config_path) return model_config, train_config, eval_config, dataset_config
def test_get_clusters(self): # classes = ['Car', 'Pedestrian', 'Cyclist'] num_clusters = [2, 1, 1] label_cluster_utils = LabelClusterUtils(self.dataset) clusters, std_devs = label_cluster_utils.get_clusters() # Check that correct number of clusters are returned clusters_per_class = [len(cls_clusters) for cls_clusters in clusters] std_devs_per_class = [len(cls_std_devs) for cls_std_devs in std_devs] self.assertEqual(clusters_per_class, num_clusters) self.assertEqual(std_devs_per_class, num_clusters) # Check that text files were saved txt_folder_exists = os.path.isdir( avod.root_dir() + "/data/label_clusters/unittest-kitti") self.assertTrue(txt_folder_exists) # Calling get_clusters again should read from files read_clusters, read_std_devs = label_cluster_utils.get_clusters() # Check that read values are the same as generated ones np.testing.assert_allclose(np.vstack(clusters), np.vstack(read_clusters)) np.testing.assert_allclose(np.vstack(std_devs), np.vstack(read_std_devs))
def main(_): parser = argparse.ArgumentParser() # Example usage # --checkpoint_name='avod_cars_example' # --data_split='test' # --ckpt_indices=50 100 112 # Optional arg: # --device=0 parser.add_argument('--checkpoint_name', type=str, dest='checkpoint_name', required=True, help='Checkpoint name must be specified as a str\ and must match the experiment config file name.') parser.add_argument('--data_split', type=str, dest='data_split', required=True, help='Data split must be specified e.g. val or test') parser.add_argument('--ckpt_indices', type=int, nargs='+', dest='ckpt_indices', required=True, help='Checkpoint indices must be a set of \ integers with space in between -> 0 10 20 etc') parser.add_argument('--device', type=str, dest='device', default='0', help='CUDA device id') args = parser.parse_args() if len(sys.argv) == 1: parser.print_help() sys.exit(1) experiment_config = args.checkpoint_name + '.config' # Read the config from the experiment folder experiment_config_path = avod.root_dir() + '/data/outputs/' +\ args.checkpoint_name + '/' + experiment_config model_config, _, eval_config, dataset_config = \ config_builder.get_configs_from_pipeline_file( experiment_config_path, is_training=False) os.environ['CUDA_VISIBLE_DEVICES'] = args.device inference(model_config, eval_config, dataset_config, args.data_split, args.ckpt_indices) # Visualize show_predictions_2d_jhuang.main(args.checkpoint_name)
def setUpClass(cls): pipeline_config = pipeline_pb2.NetworkPipelineConfig() dataset_config = pipeline_config.dataset_config config_path = avod.root_dir() + '/configs/unittest_model.config' cls.model_config = config_build.get_model_config_from_file(config_path) dataset_config.MergeFrom(DatasetBuilder.KITTI_UNITTEST) cls.dataset = DatasetBuilder.build_kitti_dataset(dataset_config)
def __init__(self, dataset): self._dataset = dataset self.cluster_split = dataset.cluster_split self.data_dir = avod.root_dir() + "/data/label_clusters" self.clusters = [] self.std_devs = []
def main(_): experiment_config = 'avod_cars_example.config' # Read the config from the experiment folder experiment_config_path = avod.root_dir() + '/data/outputs/' +\ 'avod_cars_example' + '/' + experiment_config model_config, _, eval_config, dataset_config = \ config_builder.get_configs_from_pipeline_file( experiment_config_path, is_training=False) os.environ['CUDA_VISIBLE_DEVICES'] = '0' test(model_config, eval_config, dataset_config, 'val', -1)
def setUp(self): tf.test.TestCase.setUp(self) test_pipeline_config_path = avod.root_dir() + \ '/configs/unittest_pipeline.config' self.model_config, self.train_config, _, dataset_config = \ config_builder.get_configs_from_pipeline_file( test_pipeline_config_path, is_training=True) # Generate dataset self.dataset = DatasetBuilder.build_kitti_dataset( DatasetBuilder.KITTI_UNITTEST, use_defaults=False, new_cfg=dataset_config)
def main(_): parser = argparse.ArgumentParser() default_pipeline_config_path = avod.root_dir() + \ '/configs/avod_cars_example.config' default_output_dir = '/data/kitti_avod/object/outputs' parser.add_argument('--pipeline_config', type=str, dest='pipeline_config_path', default=default_pipeline_config_path, help='Path to the pipeline config') parser.add_argument('--data_split', type=str, dest='data_split', default='val', help='Data split for evaluation') parser.add_argument('--device', type=str, dest='device', default=None, help='CUDA device id') parser.add_argument('--output_dir', type=str, dest='output_dir', default=default_output_dir, help='output dir to save checkpoints') args = parser.parse_args() # Parse pipeline config model_config, _, eval_config, dataset_config = \ config_builder.get_configs_from_pipeline_file( args.pipeline_config_path, is_training=False, output_dir=args.output_dir) # Overwrite data split dataset_config.data_split = args.data_split # Set CUDA device id if args.device: os.environ['CUDA_VISIBLE_DEVICES'] = args.device evaluate(model_config, eval_config, dataset_config, output_dir=args.output_dir)
def main(_): parser = argparse.ArgumentParser() # Defaults default_pipeline_config_path = avod.root_dir() + \ '/configs/avod_cars_example.config' default_data_split = 'train' default_device = '1' parser.add_argument('--pipeline_config', type=str, dest='pipeline_config_path', default=default_pipeline_config_path, help='Path to the pipeline config') parser.add_argument('--data_split', type=str, dest='data_split', default=default_data_split, help='Data split for training') parser.add_argument('--device', type=str, dest='device', default=default_device, help='CUDA device id') parser.add_argument('--output_dir', type=str, help='out dir') args = parser.parse_args() # Parse pipeline config output = args.output_dir is_training=True model_config, train_config, _, dataset_config = \ config_builder.get_configs_from_pipeline_file( args.pipeline_config_path, is_training, output) # Overwrite data split dataset_config.data_split = args.data_split # Set CUDA device id os.environ['CUDA_VISIBLE_DEVICES'] = args.device train(model_config, train_config, dataset_config)
def run_kitti_native_script(checkpoint_name, score_threshold, global_step): """Runs the kitti native code script.""" eval_script_dir = avod.root_dir() + '/data/outputs/' + \ checkpoint_name + '/predictions' make_script = eval_script_dir + \ '/kitti_native_eval/run_eval.sh' script_folder = eval_script_dir + \ '/kitti_native_eval/' results_dir = avod.top_dir() + '/scripts/offline_eval/results/' # Round this because protobuf encodes default values as full decimal score_threshold = round(score_threshold, 3) subprocess.call([make_script, script_folder, str(score_threshold), str(global_step), str(checkpoint_name), str(results_dir)])
def main(_): parser = argparse.ArgumentParser() default_pipeline_config_path = avod.root_dir() + \ '/configs/avod_cars_example.config' parser.add_argument('--pipeline_config', type=str, dest='pipeline_config_path', default=default_pipeline_config_path, help='Path to the pipeline config') parser.add_argument('--data_split', type=str, dest='data_split', default='val', help='Data split for evaluation') parser.add_argument('--device', type=str, dest='device', default='0', help='CUDA device id') args = parser.parse_args() # Parse pipeline config model_config, _, eval_config, dataset_config = \ config_builder.get_configs_from_pipeline_file( args.pipeline_config_path, is_training=False) # Overwrite data split dataset_config.data_split = args.data_split # Set CUDA device id os.environ['CUDA_VISIBLE_DEVICES'] = args.device evaluate(model_config, eval_config, dataset_config)
def infer_main(checkpoint_name, ckpt_indices, additional_cls, start_perspective=0): experiment_config = checkpoint_name + '.config' # Read the config from the experiment folder experiment_config_path = avod.root_dir() + '/data/outputs/' +\ checkpoint_name + '/' + experiment_config model_config, _, eval_config, dataset_config = \ config_builder.get_configs_from_pipeline_file( experiment_config_path, is_training=False) base_dir = os.path.split(cfg.DATASET_DIR)[0] + '/' os.environ['CUDA_VISIBLE_DEVICES'] = cfg.CUDA_DEVICE inference(model_config, eval_config, dataset_config, base_dir, ckpt_indices, additional_cls, start_perspective=start_perspective)
def main(): parser = argparse.ArgumentParser() # Example usage # --checkpoint_name='avod_exp_example' # --base_dir='/home/<username>/GTAData/' parser.add_argument('--checkpoint_name', type=str, dest='checkpoint_name', required=True, help='Checkpoint name must be specified as a str\ and must match the experiment config file name.') parser.add_argument('--base_dir', type=str, dest='base_dir', required=True, help='Base data directory must be specified') args = parser.parse_args() if len(sys.argv) == 1: parser.print_help() sys.exit(1) experiment_config = args.checkpoint_name + '.config' # Read the config from the experiment folder experiment_config_path = avod.root_dir() + '/data/outputs/' +\ args.checkpoint_name + '/' + experiment_config model_config, _, eval_config, dataset_config = \ config_builder.get_configs_from_pipeline_file( experiment_config_path, is_training=False) filter_gt_labels(dataset_config, args.base_dir)
def main(): """ Converts a set of network predictions into text files required for KITTI evaluation. """ ############################## # Options ############################## checkpoint_name = 'fpn_people_dual_NHSP_train'#'fpn_people_dual_SHPL_train'#'pyramid_people_with_NHSP_example_train'#'pyramid_people_with_NHSP_example' data_split = 'val'#'test'#'val' global_steps = None # global_steps = [28000, 19000, 33000, 34000] score_threshold = 0.1 save_2d = False # Save 2D predictions save_3d = True # Save 2D and 3D predictions together save_alphas = True # Save alphas (observation angles) # Checkpoints below this are skipped min_step = 20000 ############################## # End of Options ############################## # Parse experiment config pipeline_config_file = \ avod.root_dir() + '/data/outputs/' + checkpoint_name + \ '/' + checkpoint_name + '.config' _, _, _, dataset_config = \ config_builder_util.get_configs_from_pipeline_file( pipeline_config_file, is_training=False) # Overwrite defaults dataset_config = config_builder_util.proto_to_obj(dataset_config) dataset_config.data_split = data_split dataset_config.aug_list = [] if data_split == 'test': dataset_config.data_split_dir = 'testing' dataset = DatasetBuilder.build_kitti_dataset(dataset_config, use_defaults=False) # Get available prediction folders predictions_root_dir = avod.root_dir() + '/data/outputs/' + \ checkpoint_name + '/predictions' final_predictions_root_dir = predictions_root_dir + \ '/final_predictions_and_scores/' + dataset.data_split print('Converting detections from', final_predictions_root_dir) if not global_steps: global_steps = os.listdir(final_predictions_root_dir) global_steps.sort(key=int) print('Checkpoints found ', global_steps) for step_idx in range(len(global_steps)): global_step = global_steps[step_idx] # Skip first checkpoint if int(global_step) < min_step: continue final_predictions_dir = final_predictions_root_dir + \ '/' + str(global_step) # 2D and 3D prediction directories kitti_predictions_2d_dir = predictions_root_dir + \ '/kitti_predictions_2d/' + \ dataset.data_split + '/' + \ str(score_threshold) + '/' + \ str(global_step) + '/data' kitti_predictions_3d_dir = predictions_root_dir + \ '/kitti_predictions_3d/' + \ dataset.data_split + '/' + \ str(score_threshold) + '/' + \ str(global_step) + '/data' if save_2d and not os.path.exists(kitti_predictions_2d_dir): os.makedirs(kitti_predictions_2d_dir) if save_3d and not os.path.exists(kitti_predictions_3d_dir): os.makedirs(kitti_predictions_3d_dir) # Do conversion num_samples = dataset.num_samples num_valid_samples = 0 print('\nGlobal step:', global_step) print('Converting detections from:', final_predictions_dir) if save_2d: print('2D Detections saved to:', kitti_predictions_2d_dir) if save_3d: print('3D Detections saved to:', kitti_predictions_3d_dir) for sample_idx in range(num_samples): # Print progress sys.stdout.write('\rConverting {} / {}'.format( sample_idx + 1, num_samples)) sys.stdout.flush() sample_name = dataset.sample_names[sample_idx] prediction_file = sample_name + '.txt' kitti_predictions_2d_file_path = kitti_predictions_2d_dir + \ '/' + prediction_file kitti_predictions_3d_file_path = kitti_predictions_3d_dir + \ '/' + prediction_file predictions_file_path = final_predictions_dir + \ '/' + prediction_file # If no predictions, skip to next file if not os.path.exists(predictions_file_path): if save_2d: np.savetxt(kitti_predictions_2d_file_path, []) if save_3d: np.savetxt(kitti_predictions_3d_file_path, []) continue all_predictions = np.loadtxt(predictions_file_path) # # Swap l, w for predictions where w > l # swapped_indices = all_predictions[:, 4] > all_predictions[:, 3] # fixed_predictions = np.copy(all_predictions) # fixed_predictions[swapped_indices, 3] = all_predictions[ # swapped_indices, 4] # fixed_predictions[swapped_indices, 4] = all_predictions[ # swapped_indices, 3] score_filter = all_predictions[:, 7] >= score_threshold all_predictions = all_predictions[score_filter] # If no predictions, skip to next file if len(all_predictions) == 0: if save_2d: np.savetxt(kitti_predictions_2d_file_path, []) if save_3d: np.savetxt(kitti_predictions_3d_file_path, []) continue # Project to image space sample_name = prediction_file.split('.')[0] img_idx = int(sample_name) # Load image for truncation image = Image.open(dataset.get_rgb_image_path(sample_name)) stereo_calib_p2 = calib_utils.read_calibration(dataset.calib_dir, img_idx).p2 boxes = [] image_filter = [] for i in range(len(all_predictions)): box_3d = all_predictions[i, 0:7] img_box = box_3d_projector.project_to_image_space( box_3d, stereo_calib_p2, truncate=True, image_size=image.size) # Skip invalid boxes (outside image space) if img_box is None: image_filter.append(False) else: image_filter.append(True) boxes.append(img_box) boxes = np.asarray(boxes) all_predictions = all_predictions[image_filter] # If no predictions, skip to next file if len(boxes) == 0: if save_2d: np.savetxt(kitti_predictions_2d_file_path, []) if save_3d: np.savetxt(kitti_predictions_3d_file_path, []) continue num_valid_samples += 1 # To keep each value in its appropriate position, an array of zeros # (N, 16) is allocated but only values [4:16] are used kitti_predictions = np.zeros([len(boxes), 16]) # Get object types all_pred_classes = all_predictions[:, 8].astype(np.int32) obj_types = [dataset.classes[class_idx] for class_idx in all_pred_classes] # Truncation and Occlusion are always empty (see below) # Alpha if not save_alphas: kitti_predictions[:, 3] = -10 * \ np.ones((len(kitti_predictions)), dtype=np.int32) else: alphas = all_predictions[:, 6] - \ np.arctan2(all_predictions[:, 0], all_predictions[:, 2]) kitti_predictions[:, 3] = alphas # 2D predictions kitti_predictions[:, 4:8] = boxes[:, 0:4] # 3D predictions # (l, w, h) kitti_predictions[:, 8] = all_predictions[:, 5] kitti_predictions[:, 9] = all_predictions[:, 4] kitti_predictions[:, 10] = all_predictions[:, 3] # (x, y, z) kitti_predictions[:, 11:14] = all_predictions[:, 0:3] # (ry, score) kitti_predictions[:, 14:16] = all_predictions[:, 6:8] # Round detections to 3 decimal places kitti_predictions = np.round(kitti_predictions, 3) # Empty Truncation, Occlusion kitti_empty_1 = -1 * np.ones((len(kitti_predictions), 2), dtype=np.int32) # Empty 3D (x, y, z) kitti_empty_2 = -1 * np.ones((len(kitti_predictions), 3), dtype=np.int32) # Empty 3D (h, w, l) kitti_empty_3 = -1000 * np.ones((len(kitti_predictions), 3), dtype=np.int32) # Empty 3D (ry) kitti_empty_4 = -10 * np.ones((len(kitti_predictions), 1), dtype=np.int32) # Stack 2D predictions text kitti_text_2d = np.column_stack([obj_types, kitti_empty_1, kitti_predictions[:, 3:8], kitti_empty_2, kitti_empty_3, kitti_empty_4, kitti_predictions[:, 15]]) # Stack 3D predictions text kitti_text_3d = np.column_stack([obj_types, kitti_empty_1, kitti_predictions[:, 3:16]]) # Save to text files if save_2d: np.savetxt(kitti_predictions_2d_file_path, kitti_text_2d, newline='\r\n', fmt='%s') if save_3d: np.savetxt(kitti_predictions_3d_file_path, kitti_text_3d, newline='\r\n', fmt='%s') print('\nNum valid:', num_valid_samples) print('Num samples:', num_samples)
def save_predictions_in_kitti_format(model, checkpoint_name, data_split, score_threshold, global_step, output_dir=None, do_eval_sin=False, do_eval_ain=False, sin_type='rand', sin_level=5, sin_repeat=10, sin_input_name=None, idx_repeat=None): """ Converts a set of network predictions into text files required for KITTI evaluation. """ if output_dir is None: output_dir = avod.root_dir() + '/data/outputs/' dataset = model.dataset # Round this because protobuf encodes default values as full decimal score_threshold = round(score_threshold, 3) # Get available prediction folders predictions_root_dir = os.path.join(output_dir,checkpoint_name) + \ '/predictions' if do_eval_sin: predictions_root_dir += '_sin_{}_{}_{}/{}'.format( sin_type, sin_level, sin_repeat, sin_input_name) elif do_eval_ain: predictions_root_dir += '_ain_{}_{}_{}'.format(sin_type, sin_level, sin_repeat) final_predictions_root_dir = predictions_root_dir + \ '/final_predictions_and_scores/' + dataset.data_split final_predictions_dir = final_predictions_root_dir + \ '/' + str(global_step) # 3D prediction directories if idx_repeat is None: kitti_predictions_3d_dir = predictions_root_dir + \ '/kitti_native_eval/' + \ str(score_threshold) + '_' + data_split + '/' + \ str(global_step) + '/data' else: kitti_predictions_3d_dir = predictions_root_dir + \ '/kitti_native_eval/' + \ str(score_threshold) + '_' + data_split + '_{}_rep/'.format(idx_repeat) + \ str(global_step) + '/data' if not os.path.exists(kitti_predictions_3d_dir): os.makedirs(kitti_predictions_3d_dir) # Do conversion num_samples = dataset.num_samples num_valid_samples = 0 print('\nGlobal step:', global_step) print('Converting detections from:', final_predictions_dir) print('3D Detections being saved to:', kitti_predictions_3d_dir) for sample_idx in range(num_samples): # Print progress sys.stdout.write('\rConverting {} / {}'.format(sample_idx + 1, num_samples)) sys.stdout.flush() sample_name = dataset.sample_names[sample_idx] prediction_file = sample_name + '.txt' kitti_predictions_3d_file_path = kitti_predictions_3d_dir + \ '/' + prediction_file predictions_file_path = final_predictions_dir + \ '/' + prediction_file # If no predictions, skip to next file if not os.path.exists(predictions_file_path): np.savetxt(kitti_predictions_3d_file_path, []) continue all_predictions = np.loadtxt(predictions_file_path) # # Swap l, w for predictions where w > l # swapped_indices = all_predictions[:, 4] > all_predictions[:, 3] # fixed_predictions = np.copy(all_predictions) # fixed_predictions[swapped_indices, 3] = all_predictions[ # swapped_indices, 4] # fixed_predictions[swapped_indices, 4] = all_predictions[ # swapped_indices, 3] score_filter = all_predictions[:, 7] >= score_threshold all_predictions = all_predictions[score_filter] # If no predictions, skip to next file if len(all_predictions) == 0: np.savetxt(kitti_predictions_3d_file_path, []) continue # Project to image space sample_name = prediction_file.split('.')[0] img_idx = int(sample_name) # Load image for truncation image = Image.open(dataset.get_rgb_image_path(sample_name)) stereo_calib_p2 = calib_utils.read_calibration(dataset.calib_dir, img_idx).p2 boxes = [] image_filter = [] for i in range(len(all_predictions)): box_3d = all_predictions[i, 0:7] img_box = box_3d_projector.project_to_image_space( box_3d, stereo_calib_p2, truncate=True, image_size=image.size) # Skip invalid boxes (outside image space) if img_box is None: image_filter.append(False) continue image_filter.append(True) boxes.append(img_box) boxes = np.asarray(boxes) all_predictions = all_predictions[image_filter] # If no predictions, skip to next file if len(boxes) == 0: np.savetxt(kitti_predictions_3d_file_path, []) continue num_valid_samples += 1 # To keep each value in its appropriate position, an array of zeros # (N, 16) is allocated but only values [4:16] are used kitti_predictions = np.zeros([len(boxes), 16]) # Get object types all_pred_classes = all_predictions[:, 8].astype(np.int32) obj_types = [ dataset.classes[class_idx] for class_idx in all_pred_classes ] # Truncation and Occlusion are always empty (see below) # Alpha (Not computed) kitti_predictions[:, 3] = -10 * np.ones( (len(kitti_predictions)), dtype=np.int32) # 2D predictions kitti_predictions[:, 4:8] = boxes[:, 0:4] # 3D predictions # (l, w, h) kitti_predictions[:, 8] = all_predictions[:, 5] kitti_predictions[:, 9] = all_predictions[:, 4] kitti_predictions[:, 10] = all_predictions[:, 3] # (x, y, z) kitti_predictions[:, 11:14] = all_predictions[:, 0:3] # (ry, score) kitti_predictions[:, 14:16] = all_predictions[:, 6:8] # Round detections to 3 decimal places kitti_predictions = np.round(kitti_predictions, 3) # Empty Truncation, Occlusion kitti_empty_1 = -1 * np.ones( (len(kitti_predictions), 2), dtype=np.int32) # Stack 3D predictions text kitti_text_3d = np.column_stack( [obj_types, kitti_empty_1, kitti_predictions[:, 3:16]]) # Save to text files np.savetxt(kitti_predictions_3d_file_path, kitti_text_3d, newline='\r\n', fmt='%s') print('\nNum valid:', num_valid_samples) print('Num samples:', num_samples)
def save_predictions_in_kitti_format(model, checkpoint_name, data_split, score_threshold, global_step): """ Converts a set of network predictions into text files required for KITTI evaluation. """ dataset = model.dataset # Round this because protobuf encodes default values as full decimal score_threshold = round(score_threshold, 3) # Get available prediction folders predictions_root_dir = avod.root_dir() + '/data/outputs/' + \ checkpoint_name + '/predictions' final_predictions_root_dir = predictions_root_dir + \ '/final_predictions_and_scores/' + dataset.data_split final_predictions_dir = final_predictions_root_dir + \ '/' + str(global_step) # 3D prediction directories kitti_predictions_3d_dir = predictions_root_dir + \ '/kitti_native_eval/' + \ str(score_threshold) + '/' + \ str(global_step) + '/data' if not os.path.exists(kitti_predictions_3d_dir): os.makedirs(kitti_predictions_3d_dir) # Do conversion num_samples = dataset.num_samples num_valid_samples = 0 print('\nGlobal step:', global_step) print('Converting detections from:', final_predictions_dir) print('3D Detections being saved to:', kitti_predictions_3d_dir) for sample_idx in range(num_samples): # Print progress sys.stdout.write('\rConverting {} / {}'.format( sample_idx + 1, num_samples)) sys.stdout.flush() sample_name = dataset.sample_names[sample_idx] prediction_file = sample_name + '.txt' kitti_predictions_3d_file_path = kitti_predictions_3d_dir + \ '/' + prediction_file predictions_file_path = final_predictions_dir + \ '/' + prediction_file # If no predictions, skip to next file if not os.path.exists(predictions_file_path): np.savetxt(kitti_predictions_3d_file_path, []) continue all_predictions = np.loadtxt(predictions_file_path) # # Swap l, w for predictions where w > l # swapped_indices = all_predictions[:, 4] > all_predictions[:, 3] # fixed_predictions = np.copy(all_predictions) # fixed_predictions[swapped_indices, 3] = all_predictions[ # swapped_indices, 4] # fixed_predictions[swapped_indices, 4] = all_predictions[ # swapped_indices, 3] score_filter = all_predictions[:, 7] >= score_threshold all_predictions = all_predictions[score_filter] # If no predictions, skip to next file if len(all_predictions) == 0: np.savetxt(kitti_predictions_3d_file_path, []) continue # Project to image space sample_name = prediction_file.split('.')[0] img_idx = int(sample_name) # Load image for truncation image = Image.open(dataset.get_rgb_image_path(sample_name)) #stereo_calib_p2 = calib_utils.read_calibration(dataset.calib_dir, #img_idx).p2 # Get calibration calib = moose_load_calibration.load_calibration(dataset.calib_dir) if img_idx < 100: T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM00']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM elif (img_idx >= 100 and img_idx < 200): T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM01']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM elif (img_idx >= 200 and img_idx < 300): T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM02']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM elif (img_idx >= 300 and img_idx < 400): T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM03']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM elif (img_idx >= 400 and img_idx < 500): T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM04']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM elif (img_idx >= 500 and img_idx < 600): T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM05']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM elif (img_idx >= 600 and img_idx < 700): T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM06']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM elif (img_idx >= 700 and img_idx < 800): T_IMG_CAM = np.eye(4); # identity matrix T_IMG_CAM[0:3, 0:3] = np.array(calib['CAM07']['camera_matrix']['data']).reshape(-1, 3) # camera to image #intrinsic matrix # T_IMG_CAM : 4 x 4 matrix T_IMG_CAM = T_IMG_CAM[0:3, 0:4]; # remove last row, #choose the first 3 rows and get rid of the last column stereo_calib_p2 = T_IMG_CAM else: print("YOLO") boxes = [] image_filter = [] for i in range(len(all_predictions)): box_3d = all_predictions[i, 0:7] img_box = box_3d_projector.project_to_image_space( box_3d, stereo_calib_p2, truncate=True, image_size=image.size) # Skip invalid boxes (outside image space) if img_box is None: image_filter.append(False) continue image_filter.append(True) boxes.append(img_box) boxes = np.asarray(boxes) all_predictions = all_predictions[image_filter] # If no predictions, skip to next file if len(boxes) == 0: np.savetxt(kitti_predictions_3d_file_path, []) continue num_valid_samples += 1 # To keep each value in its appropriate position, an array of zeros # (N, 16) is allocated but only values [4:16] are used kitti_predictions = np.zeros([len(boxes), 16]) # Get object types all_pred_classes = all_predictions[:, 8].astype(np.int32) obj_types = [dataset.classes[class_idx] for class_idx in all_pred_classes] # Truncation and Occlusion are always empty (see below) # Alpha (Not computed) kitti_predictions[:, 3] = -10 * np.ones((len(kitti_predictions)), dtype=np.int32) # 2D predictions kitti_predictions[:, 4:8] = boxes[:, 0:4] # 3D predictions # (l, w, h) kitti_predictions[:, 8] = all_predictions[:, 5] kitti_predictions[:, 9] = all_predictions[:, 4] kitti_predictions[:, 10] = all_predictions[:, 3] # (x, y, z) kitti_predictions[:, 11:14] = all_predictions[:, 0:3] # (ry, score) kitti_predictions[:, 14:16] = all_predictions[:, 6:8] # Round detections to 3 decimal places kitti_predictions = np.round(kitti_predictions, 3) # Empty Truncation, Occlusion kitti_empty_1 = -1 * np.ones((len(kitti_predictions), 2), dtype=np.int32) # Stack 3D predictions text kitti_text_3d = np.column_stack([obj_types, kitti_empty_1, kitti_predictions[:, 3:16]]) # Save to text files np.savetxt(kitti_predictions_3d_file_path, kitti_text_3d, newline='\r\n', fmt='%s') print('\nNum valid:', num_valid_samples) print('Num samples:', num_samples)
def copy_kitti_native_code(checkpoint_name, output_dir=None, do_eval_sin=False, do_eval_ain=False, sin_type='rand', sin_level=5, sin_repeat=10, sin_input_names=None): """Copies and compiles kitti native code. It also creates neccessary directories for storing the results of the kitti native evaluation code. """ if output_dir is None: output_dir = avod.root_dir() + '/data/outputs/' if do_eval_sin: if sin_input_names is None: raise ValueError('{} must have list of sin input names.'.format( sin_input_names)) kitti_native_code_copies = [os.path.join(output_dir,checkpoint_name) + \ '/predictions_sin_{}_{}_{}/{}/kitti_native_eval/'.format( sin_type, sin_level, sin_repeat,sin_input_name) \ for sin_input_name in sin_input_names] elif do_eval_ain: kitti_native_code_copies = [os.path.join(output_dir,checkpoint_name) + \ '/predictions_ain_{}_{}_{}/kitti_native_eval/'.format( sin_type, sin_level, sin_repeat)] else: kitti_native_code_copies = [os.path.join(output_dir,checkpoint_name) + \ '/predictions/kitti_native_eval/'] # Only copy if the code has not been already copied over for (idx, kitti_native_code_copy) in enumerate(kitti_native_code_copies): if not os.path.exists(kitti_native_code_copy): os.makedirs(kitti_native_code_copy) original_kitti_native_code = avod.top_dir() + \ '/scripts/offline_eval/kitti_native_eval/' if do_eval_sin: predictions_dir = os.path.join(output_dir,checkpoint_name) + \ '/predictions_sin_{}_{}_{}/{}/'.format( sin_type, sin_level, sin_repeat,sin_input_names[idx]) elif do_eval_ain: predictions_dir = os.path.join(output_dir,checkpoint_name) + \ '/predictions_ain_{}_{}_{}/'.format( sin_type, sin_level, sin_repeat) else: predictions_dir = os.path.join(output_dir,checkpoint_name) + \ '/predictions/' # create dir for it first dir_util.copy_tree(original_kitti_native_code, kitti_native_code_copy) # run the script to compile the c++ code script_folder = predictions_dir + \ 'kitti_native_eval/' make_script = script_folder + 'run_make.sh' subprocess.call([make_script, script_folder]) # Set up the results folders if they don't exist if output_dir is None: results_dir = avod.top_dir() + '/scripts/offline_eval/results' results_05_dir = avod.top_dir( ) + '/scripts/offline_eval/results_05_iou' else: results_dir = os.path.join( output_dir, checkpoint_name) + '/offline_eval/results' results_05_dir = os.path.join( output_dir, checkpoint_name) + '/offline_eval/results_05_iou' if do_eval_sin: results_dir += '_sin_{}_{}_{}/{}'.format(sin_type, sin_level, sin_repeat, sin_input_names[idx]) results_05_dir += '_sin_{}_{}_{}/{}'.format( sin_type, sin_level, sin_repeat, sin_input_names[idx]) elif do_eval_ain: results_dir += '_ain_{}_{}_{}'.format(sin_type, sin_level, sin_repeat) results_05_dir += '_ain_{}_{}_{}'.format(sin_type, sin_level, sin_repeat) if not os.path.exists(results_dir): os.makedirs(results_dir) if not os.path.exists(results_05_dir): os.makedirs(results_05_dir)
def run_kitti_native_script_with_05_iou(checkpoint_name, score_threshold, global_step, output_dir=None, do_eval_sin=False, do_eval_ain=False, sin_type='rand', sin_level=5, sin_repeat=10, sin_input_name=None, idx_repeat=None, data_split=None): """Runs the kitti native code script.""" if output_dir is None: output_dir = avod.root_dir() + '/data/outputs/' eval_script_dir = os.path.join(output_dir,checkpoint_name) + \ '/predictions' if do_eval_sin: eval_script_dir += '_sin_{}_{}_{}/{}'.format(sin_type, sin_level, sin_repeat, sin_input_name) elif do_eval_ain: eval_script_dir += '_ain_{}_{}_{}'.format(sin_type, sin_level, sin_repeat) make_script = eval_script_dir + \ '/kitti_native_eval/run_eval_05_iou.sh' script_folder = eval_script_dir + \ '/kitti_native_eval/' if output_dir is None: if do_eval_sin: results_dir = avod.top_dir() + \ '/scripts/offline_eval/results_05_iou_sin_{}_{}_{}/{}/'.format( sin_type, sin_level, sin_repeat, sin_input_name) elif do_eval_ain: results_dir = avod.top_dir() + \ '/scripts/offline_eval/results_05_iou_ain_{}_{}_{}/'.format( sin_type, sin_level, sin_repeat) else: results_dir = avod.top_dir() + \ '/scripts/offline_eval/results_05_iou/' else: if do_eval_sin: results_dir = os.path.join(output_dir,checkpoint_name) + \ '/offline_eval/results_05_iou_sin_{}_{}_{}/{}/'.format( sin_type, sin_level, sin_repeat, sin_input_name) elif do_eval_ain: results_dir = os.path.join(output_dir,checkpoint_name) + \ '/offline_eval/results_05_iou_ain_{}_{}_{}/'.format( sin_type, sin_level, sin_repeat) else: results_dir = os.path.join(output_dir,checkpoint_name) + \ '/offline_eval/results_05_iou/' # Round this because protobuf encodes default values as full decimal score_threshold = round(score_threshold, 3) if idx_repeat is None: offline_res_name = str(score_threshold) + '_' + data_split else: # result dir is different offline_res_name = str(score_threshold)+ '_' + data_split + \ '_{}_rep'.format(idx_repeat) subprocess.call([ make_script, script_folder, offline_res_name, str(global_step), str(checkpoint_name), str(results_dir) ])
def main(): parser = argparse.ArgumentParser() default_pipeline_config_path = avod.root_dir() + \ '/configs/avod_ssd_cars_example.config' parser.add_argument('--pipeline_config', type=str, dest='pipeline_config_path', default=default_pipeline_config_path, help='Path to the pipeline config') parser.add_argument('--data_split', type=str, dest='data_split', default='test', help='Data split for evaluation') parser.add_argument('--device', type=str, dest='device', default='0', help='CUDA device id') parser.add_argument('--output', type=str, dest='output', default='model_timeline.json', help='CUDA device id') args = parser.parse_args() model = set_up_model(args.pipeline_config_path, args.data_split) prediction_dict = model.build() # Set CUDA device id os.environ['CUDA_VISIBLE_DEVICES'] = args.device # Set session config config = tf.ConfigProto() config.gpu_options.allow_growth = True # Set run options run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE) run_metadata = tf.RunMetadata() # Create session sess = tf.Session(config=config) init_op = tf.global_variables_initializer() sess.run(init_op) all_feed_dict_times = [] all_inference_times = [] # Run sess a few times since it is usually slow at the start for i in range(5): sys.stdout.write('\r{}'.format(i)) feed_dict = model.create_feed_dict() sess.run(prediction_dict, feed_dict) for i in range(95): sys.stdout.write('\r{}'.format(i + 5)) feed_dict_start_time = time.time() feed_dict = model.create_feed_dict() all_feed_dict_times.append(time.time() - feed_dict_start_time) inference_start_time = time.time() sess.run(prediction_dict, feed_dict) all_inference_times.append(time.time() - inference_start_time) print('\n') print('feed_dict mean', np.mean(all_feed_dict_times)) print('feed_dict median', np.median(all_feed_dict_times)) print('feed_dict min', np.min(all_feed_dict_times)) print('feed_dict max', np.max(all_feed_dict_times)) print('inference mean', np.mean(all_inference_times)) print('inference median', np.median(all_inference_times)) print('inference min', np.min(all_inference_times)) print('inference max', np.max(all_inference_times)) # Run once with full timing sess.run(prediction_dict, feed_dict, options=run_options, run_metadata=run_metadata) inference_start_time = time.time() sess.run(prediction_dict, feed_dict) print('Time:', time.time() - inference_start_time) tf_timeline = timeline.Timeline(run_metadata.step_stats) chrome_trace_fmt = tf_timeline.generate_chrome_trace_format() outputfile = args.output with open(outputfile, 'w') as f: f.write(chrome_trace_fmt) print('Done')
def main(): """This demo shows RPN proposals and AVOD predictions in the 3D point cloud. Keys: F1: Toggle proposals F2: Toggle predictions F3: Toggle 3D voxel grid F4: Toggle point cloud F5: Toggle easy ground truth objects (Green) F6: Toggle medium ground truth objects (Orange) F7: Toggle hard ground truth objects (Red) F8: Toggle all ground truth objects (default off) F9: Toggle ground slice filter (default off) F10: Toggle offset slice filter (default off) """ ############################## # Options ############################## rpn_score_threshold = 0.1 avod_score_threshold = 0.1 proposals_line_width = 1.0 predictions_line_width = 3.0 show_orientations = True point_cloud_source = 'depth' # Config file folder, default (<avod_root>/data/outputs/<checkpoint_name>) config_dir = None checkpoint_name = 'pyramid_cars_with_aug_example' global_step = None # Latest checkpoint global_step = 83000 #data_split = 'val_half' data_split = 'val' # data_split = 'test' # Show 3D iou text draw_ious_3d = True name_list =[] #name_file = '/media/wavelab/d3cd89ab-7705-4996-94f3-01da25ba8f50/moosey/val.txt' #with open(name_file) as f: #for line in f: #newline = line.replace("\n","") #name_list.append(newline) #name_list =['0000000003','0000000009','0000000016','0000000233','0000000234','0000000236','0000000422','0000000473','0000000490','0000000494','0000000547','0000000655',\ #'0000000679','0000000690','0000000692','0000000781'] name_list =['0000000004'] for names in name_list: sample_name = names #sample_name = None # # # Cars # # # # sample_name = '000050' # sample_name = '000104' # sample_name = '000169' # sample_name = '000191' # sample_name = '000360' # sample_name = '001783' # sample_name = '001820' # val split # sample_name = '000181' # sample_name = '000751' # sample_name = '000843' # sample_name = '000944' # sample_name = '006338' # # # People # # # # val_half split # sample_name = '000001' # Hard, 1 far cyc # sample_name = '000005' # Easy, 1 ped # sample_name = '000122' # Easy, 1 cyc # sample_name = '000134' # Hard, lots of people # sample_name = '000167' # Medium, 1 ped, 2 cycs # sample_name = '000187' # Medium, 1 ped on left # sample_name = '000381' # Easy, 1 ped # sample_name = '000398' # Easy, 1 ped # sample_name = '000401' # Hard, obscured peds # sample_name = '000407' # Easy, 1 ped # sample_name = '000448' # Hard, several far people # sample_name = '000486' # Hard 2 obscured peds # sample_name = '000509' # Easy, 1 ped # sample_name = '000718' # Hard, lots of people # sample_name = '002216' # Easy, 1 cyc # val split # sample_name = '000015' # sample_name = '000048' # sample_name = '000058' # sample_name = '000076' # Medium, few ped, 1 cyc # sample_name = '000108' # sample_name = '000118' # sample_name = '000145' # sample_name = '000153' # sample_name = '000186' # sample_name = '000195' # sample_name = '000199' # sample_name = '000397' # sample_name = '004425' # sample_name = '004474' # Hard, many ped, 1 cyc # sample_name = '004657' # Hard, Few cycl, few ped # sample_name = '006071' # sample_name = '006828' # Hard, Few cycl, few ped # sample_name = '006908' # Hard, Few cycl, few ped # sample_name = '007412' # sample_name = '007318' # Hard, Few cycl, few ped ############################## # End of Options ############################## if data_split == 'test': draw_ious_3d = False if config_dir is None: config_dir = avod.root_dir() + '/data/outputs/' + checkpoint_name # Parse experiment config pipeline_config_file = \ config_dir + '/' + checkpoint_name + '.config' _, _, _, dataset_config = \ config_builder_util.get_configs_from_pipeline_file( pipeline_config_file, is_training=False) dataset_config.data_split = data_split if data_split == 'test': dataset_config.data_split_dir = 'testing' dataset_config.has_labels = False dataset = DatasetBuilder.build_kitti_dataset(dataset_config, use_defaults=False) # Random sample if sample_name is None: sample_idx = np.random.randint(0, dataset.num_samples) sample_name = dataset.sample_names[sample_idx] ############################## # Setup Paths ############################## img_idx = int(sample_name) # Text files directory proposals_and_scores_dir = avod.root_dir() + \ '/data/outputs/' + checkpoint_name + '/predictions' + \ '/proposals_and_scores/' + dataset.data_split predictions_and_scores_dir = avod.root_dir() + \ '/data/outputs/' + checkpoint_name + '/predictions' + \ '/final_predictions_and_scores/' + dataset.data_split # Get checkpoint step steps = os.listdir(proposals_and_scores_dir) steps.sort(key=int) print('Available steps: {}'.format(steps)) # Use latest checkpoint if no index provided if global_step is None: global_step = steps[-1] # Output images directory img_out_dir = avod.root_dir() + '/data/outputs/' + checkpoint_name + \ '/predictions/images_3d/{}/{}/{}'.format(dataset.data_split, global_step, rpn_score_threshold) if not os.path.exists(img_out_dir): os.makedirs(img_out_dir) ############################## # Proposals ############################## # Load proposals from files proposals_and_scores = np.loadtxt(proposals_and_scores_dir + "/{}/{}.txt".format(global_step, sample_name)) proposals = proposals_and_scores[:, 0:7] proposal_scores = proposals_and_scores[:, 7] rpn_score_mask = proposal_scores > rpn_score_threshold proposals = proposals[rpn_score_mask] proposal_scores = proposal_scores[rpn_score_mask] print('Proposals:', len(proposal_scores), proposal_scores) proposal_objs = \ [box_3d_encoder.box_3d_to_object_label(proposal, obj_type='Proposal') for proposal in proposals] ############################## # Predictions ############################## # Load proposals from files predictions_and_scores = np.loadtxt(predictions_and_scores_dir + "/{}/{}.txt".format( global_step, sample_name)).reshape(-1, 9) prediction_boxes_3d = predictions_and_scores[:, 0:7] prediction_scores = predictions_and_scores[:, 7] prediction_types = np.asarray(predictions_and_scores[:, 8], dtype=np.int32) avod_score_mask = prediction_scores >= avod_score_threshold prediction_boxes_3d = prediction_boxes_3d[avod_score_mask] prediction_scores = prediction_scores[avod_score_mask] print('Predictions: ', len(prediction_scores), prediction_scores) final_predictions = np.copy(prediction_boxes_3d) # # Swap l, w for predictions where w > l # swapped_indices = predictions[:, 4] > predictions[:, 3] # final_predictions[swapped_indices, 3] = predictions[swapped_indices, 4] # final_predictions[swapped_indices, 4] = predictions[swapped_indices, 3] prediction_objs = [] for pred_idx in range(len(final_predictions)): prediction_box_3d = final_predictions[pred_idx] prediction_type = dataset.classes[prediction_types[pred_idx]] prediction_obj = box_3d_encoder.box_3d_to_object_label( prediction_box_3d, obj_type=prediction_type) prediction_objs.append(prediction_obj) ############################## # Ground Truth ############################## if dataset.has_labels: # Get ground truth labels easy_gt_objs, medium_gt_objs, \ hard_gt_objs, all_gt_objs = \ demo_utils.get_gts_based_on_difficulty(dataset, img_idx) else: easy_gt_objs = medium_gt_objs = hard_gt_objs = all_gt_objs = [] ############################## # 3D IoU ############################## if draw_ious_3d: # Convert to box_3d all_gt_boxes_3d = [box_3d_encoder.object_label_to_box_3d(gt_obj) for gt_obj in all_gt_objs] pred_boxes_3d = [box_3d_encoder.object_label_to_box_3d(pred_obj) for pred_obj in prediction_objs] max_ious_3d = demo_utils.get_max_ious_3d(all_gt_boxes_3d, pred_boxes_3d) ############################## # Point Cloud ############################## image_path = dataset.get_rgb_image_path(sample_name) image = cv2.imread(image_path) print("***************") print(point_cloud_source) print(img_idx) print(image.shape) point_cloud = dataset.kitti_utils.get_point_cloud(point_cloud_source, img_idx, image_shape=image.shape) print("This is the shape of the point_cloud") print(point_cloud.shape) point_cloud = np.asarray(point_cloud) # Filter point cloud to extents area_extents = np.asarray([[-40, 40], [-5, 3], [0, 70]]) bev_extents = area_extents[[0, 2]] points = point_cloud.T point_filter = obj_utils.get_point_filter(point_cloud, area_extents) points = points[point_filter] point_colours = vis_utils.project_img_to_point_cloud(points, image, dataset.calib_dir, img_idx) # Voxelize the point cloud for visualization voxel_grid = VoxelGrid() voxel_grid.voxelize(points, voxel_size=0.1, create_leaf_layout=False) # Ground plane ground_plane = obj_utils.get_road_plane(img_idx, dataset.planes_dir) ############################## # Visualization ############################## # Create VtkVoxelGrid vtk_voxel_grid = VtkVoxelGrid() vtk_voxel_grid.set_voxels(voxel_grid) vtk_point_cloud = VtkPointCloud() vtk_point_cloud.set_points(points, point_colours) # Create VtkAxes vtk_axes = vtk.vtkAxesActor() vtk_axes.SetTotalLength(5, 5, 5) # Create VtkBoxes for proposal boxes vtk_proposal_boxes = VtkBoxes() vtk_proposal_boxes.set_line_width(proposals_line_width) vtk_proposal_boxes.set_objects(proposal_objs, COLOUR_SCHEME_PREDICTIONS) # Create VtkBoxes for prediction boxes vtk_prediction_boxes = VtkPyramidBoxes() vtk_prediction_boxes.set_line_width(predictions_line_width) vtk_prediction_boxes.set_objects(prediction_objs, COLOUR_SCHEME_PREDICTIONS, show_orientations) # Create VtkBoxes for ground truth vtk_hard_gt_boxes = VtkBoxes() vtk_medium_gt_boxes = VtkBoxes() vtk_easy_gt_boxes = VtkBoxes() vtk_all_gt_boxes = VtkBoxes() vtk_hard_gt_boxes.set_objects(hard_gt_objs, COLOUR_SCHEME_PREDICTIONS, show_orientations) vtk_medium_gt_boxes.set_objects(medium_gt_objs, COLOUR_SCHEME_PREDICTIONS, show_orientations) vtk_easy_gt_boxes.set_objects(easy_gt_objs, COLOUR_SCHEME_PREDICTIONS, show_orientations) vtk_all_gt_boxes.set_objects(all_gt_objs, VtkBoxes.COLOUR_SCHEME_KITTI, show_orientations) # Create VtkTextLabels for 3D ious vtk_text_labels = VtkTextLabels() if draw_ious_3d and len(all_gt_boxes_3d) > 0: gt_positions_3d = np.asarray(all_gt_boxes_3d)[:, 0:3] vtk_text_labels.set_text_labels( gt_positions_3d, ['{:0.3f}'.format(iou_3d) for iou_3d in max_ious_3d]) # Create VtkGroundPlane vtk_ground_plane = VtkGroundPlane() vtk_slice_bot_plane = VtkGroundPlane() vtk_slice_top_plane = VtkGroundPlane() vtk_ground_plane.set_plane(ground_plane, bev_extents) vtk_slice_bot_plane.set_plane(ground_plane + [0, 0, 0, -0.2], bev_extents) vtk_slice_top_plane.set_plane(ground_plane + [0, 0, 0, -2.0], bev_extents) # Create Voxel Grid Renderer in bottom half vtk_renderer = vtk.vtkRenderer() vtk_renderer.AddActor(vtk_voxel_grid.vtk_actor) vtk_renderer.AddActor(vtk_point_cloud.vtk_actor) vtk_renderer.AddActor(vtk_proposal_boxes.vtk_actor) vtk_renderer.AddActor(vtk_prediction_boxes.vtk_actor) vtk_renderer.AddActor(vtk_hard_gt_boxes.vtk_actor) vtk_renderer.AddActor(vtk_medium_gt_boxes.vtk_actor) vtk_renderer.AddActor(vtk_easy_gt_boxes.vtk_actor) vtk_renderer.AddActor(vtk_all_gt_boxes.vtk_actor) vtk_renderer.AddActor(vtk_text_labels.vtk_actor) # Add ground plane and slice planes vtk_renderer.AddActor(vtk_ground_plane.vtk_actor) vtk_renderer.AddActor(vtk_slice_bot_plane.vtk_actor) vtk_renderer.AddActor(vtk_slice_top_plane.vtk_actor) vtk_renderer.AddActor(vtk_axes) vtk_renderer.SetBackground(0.2, 0.3, 0.4) # Set initial properties for some actors vtk_point_cloud.vtk_actor.GetProperty().SetPointSize(3) vtk_proposal_boxes.vtk_actor.SetVisibility(0) vtk_voxel_grid.vtk_actor.SetVisibility(0) vtk_all_gt_boxes.vtk_actor.SetVisibility(0) vtk_ground_plane.vtk_actor.SetVisibility(0) vtk_slice_bot_plane.vtk_actor.SetVisibility(0) vtk_slice_top_plane.vtk_actor.SetVisibility(0) vtk_ground_plane.vtk_actor.GetProperty().SetOpacity(0.9) vtk_slice_bot_plane.vtk_actor.GetProperty().SetOpacity(0.9) vtk_slice_top_plane.vtk_actor.GetProperty().SetOpacity(0.9) # Setup Camera current_cam = vtk_renderer.GetActiveCamera() current_cam.Pitch(140.0) current_cam.Roll(180.0) # Zooms out to fit all points on screen vtk_renderer.ResetCamera() # Zoom in slightly current_cam.Zoom(2) # Reset the clipping range to show all points vtk_renderer.ResetCameraClippingRange() # Setup Render Window vtk_render_window = vtk.vtkRenderWindow() vtk_render_window.SetWindowName( "Predictions: Step {}, Sample {}, Min Score {}".format( global_step, sample_name, avod_score_threshold, )) vtk_render_window.SetSize(900, 600) vtk_render_window.AddRenderer(vtk_renderer) # Setup custom interactor style, which handles mouse and key events vtk_render_window_interactor = vtk.vtkRenderWindowInteractor() vtk_render_window_interactor.SetRenderWindow(vtk_render_window) # Add custom interactor to toggle actor visibilities custom_interactor = vis_utils.CameraInfoInteractorStyle([ vtk_proposal_boxes.vtk_actor, vtk_prediction_boxes.vtk_actor, vtk_voxel_grid.vtk_actor, vtk_point_cloud.vtk_actor, vtk_easy_gt_boxes.vtk_actor, vtk_medium_gt_boxes.vtk_actor, vtk_hard_gt_boxes.vtk_actor, vtk_all_gt_boxes.vtk_actor, vtk_ground_plane.vtk_actor, vtk_slice_bot_plane.vtk_actor, vtk_slice_top_plane.vtk_actor, vtk_text_labels.vtk_actor, ]) vtk_render_window_interactor.SetInteractorStyle(custom_interactor) # Render in VTK vtk_render_window.Render() # Take a screenshot window_to_image_filter = vtk.vtkWindowToImageFilter() window_to_image_filter.SetInput(vtk_render_window) window_to_image_filter.Update() png_writer = vtk.vtkPNGWriter() file_name = img_out_dir + "/{}.png".format(sample_name) png_writer.SetFileName(file_name) png_writer.SetInputData(window_to_image_filter.GetOutput()) png_writer.Write() print('Screenshot saved to ', file_name) #vtk_render_window_interactor.Start() # Blocking vtk_render_window_interactor.Initialize() # Non-Blocking
class DatasetBuilder(object): """ Static class to return preconfigured dataset objects """ KITTI_UNITTEST = KittiDatasetConfig( name="unittest-kitti", dataset_dir=avod.root_dir() + "/tests/datasets/Kitti/object", data_split="train", data_split_dir="training", has_labels=True, cluster_split="train", classes=["Car", "Pedestrian", "Cyclist"], num_clusters=[2, 1, 1], ) KITTI_TRAIN = KittiDatasetConfig(name="kitti", data_split="train", data_split_dir="training", has_labels=True, cluster_split="train", classes=["Car"], num_clusters=[2]) KITTI_VAL = KittiDatasetConfig( name="kitti", data_split="val", data_split_dir="training", has_labels=True, cluster_split="train", classes=["Car"], num_clusters=[2], ) KITTI_TEST = KittiDatasetConfig( name="kitti", data_split="test", data_split_dir="testing", has_labels=False, cluster_split="train", classes=["Car"], num_clusters=[2], ) KITTI_TRAINVAL = KittiDatasetConfig( name="kitti", data_split="trainval", data_split_dir="training", has_labels=True, cluster_split="trainval", classes=["Car"], num_clusters=[2], ) KITTI_TRAIN_MINI = KittiDatasetConfig( name="kitti", data_split="train_mini", data_split_dir="training", has_labels=True, cluster_split="train", classes=["Car"], num_clusters=[2], ) KITTI_VAL_MINI = KittiDatasetConfig( name="kitti", data_split="val_mini", data_split_dir="training", has_labels=True, cluster_split="train", classes=["Car"], num_clusters=[2], ) KITTI_TEST_MINI = KittiDatasetConfig( name="kitti", data_split="test_mini", data_split_dir="testing", has_labels=False, cluster_split="train", classes=["Car"], num_clusters=[2], ) CONFIG_DEFAULTS_PROTO = \ """ bev_source: 'lidar' kitti_utils_config { area_extents: [-40, 40, -5, 3, 0, 70] voxel_size: 0.1 anchor_strides: [0.5, 0.5, 0.5, 0.5, 0.5, 0.5] bev_generator { slices { height_lo: -0.2 height_hi: 2.3 num_slices: 5 } } mini_batch_config { density_threshold: 1 rpn_config { iou_2d_thresholds { neg_iou_lo: 0.0 neg_iou_hi: 0.3 pos_iou_lo: 0.5 pos_iou_hi: 1.0 } # iou_3d_thresholds { # neg_iou_lo: 0.0 # neg_iou_hi: 0.005 # pos_iou_lo: 0.1 # pos_iou_hi: 1.0 # } mini_batch_size: 512 } avod_config { iou_2d_thresholds { neg_iou_lo: 0.0 neg_iou_hi: 0.55 pos_iou_lo: 0.65 pos_iou_hi: 1.0 } mini_batch_size: 1024 } } } """ @staticmethod def load_dataset_from_config(dataset_config_path): dataset_config = kitti_dataset_pb2.KittiDatasetConfig() with open(dataset_config_path, 'r') as f: text_format.Merge(f.read(), dataset_config) return DatasetBuilder.build_kitti_dataset(dataset_config, use_defaults=False) @staticmethod def copy_config(cfg): return deepcopy(cfg) @staticmethod def merge_defaults(cfg): cfg_copy = DatasetBuilder.copy_config(cfg) text_format.Merge(DatasetBuilder.CONFIG_DEFAULTS_PROTO, cfg_copy) return cfg_copy @staticmethod def build_kitti_dataset(base_cfg, use_defaults=True, new_cfg=None, use_custom_input=False) -> KittiDataset: """Builds a KittiDataset object using the provided configurations Args: base_cfg: a base dataset configuration use_defaults: whether to use the default config values new_cfg: (optional) a custom dataset configuration, no default values will be used, all config values must be provided Returns: KittiDataset object """ cfg_copy = DatasetBuilder.copy_config(base_cfg) if use_defaults: # Use default values text_format.Merge(DatasetBuilder.CONFIG_DEFAULTS_PROTO, cfg_copy) if new_cfg: # Use new config values if provided cfg_copy.MergeFrom(new_cfg) return KittiDataset(cfg_copy, use_custom_input)
def main(): """This demo shows RPN proposals and AVOD predictions in 3D and 2D in image space. Given certain thresholds for proposals and predictions, it selects and draws the bounding boxes on the image sample. It goes through the entire proposal and prediction samples for the given dataset split. The proposals, overlaid, and prediction images can be toggled on or off separately in the options section. The prediction score and IoU with ground truth can be toggled on or off as well, shown as (score, IoU) above the detection. """ dataset_config = DatasetBuilder.copy_config(DatasetBuilder.KITTI_VAL) ############################## # Options ############################## dataset_config.data_split = 'val' fig_size = (10, 6.1) rpn_score_threshold = 0.1 avod_score_threshold = 0.1 # gt_classes = ['Car'] gt_classes = ['Pedestrian', 'Cyclist'] # gt_classes = ['Car', 'Pedestrian', 'Cyclist'] # Overwrite this to select a specific checkpoint global_step = None checkpoint_name = sys.argv[1] #'pyramid_cars_with_aug_example' # Drawing Toggles draw_proposals_separate = False draw_overlaid = False draw_predictions_separate = True # Show orientation for both GT and proposals/predictions draw_orientations_on_prop = False draw_orientations_on_pred = False # Draw 2D bounding boxes draw_projected_2d_boxes = True # Save images for samples with no detections save_empty_images = True draw_score = True draw_iou = True ############################## # End of Options ############################## # Get the dataset dataset = DatasetBuilder.build_kitti_dataset(dataset_config) # Setup Paths predictions_dir = avod.root_dir() + \ '/data/outputs/' + checkpoint_name + '/predictions' proposals_and_scores_dir = predictions_dir + \ '/proposals_and_scores/' + dataset.data_split predictions_and_scores_dir = predictions_dir + \ '/final_predictions_and_scores/' + dataset.data_split # Output images directories output_dir_base = predictions_dir + '/images_2d' # Get checkpoint step steps = os.listdir(proposals_and_scores_dir) steps.sort(key=int) print('Available steps: {}'.format(steps)) # Use latest checkpoint if no index provided if global_step is None: global_step = steps[-1] if draw_proposals_separate: prop_out_dir = output_dir_base + '/proposals/{}/{}/{}'.format( dataset.data_split, global_step, rpn_score_threshold) if not os.path.exists(prop_out_dir): os.makedirs(prop_out_dir) print('Proposal images saved to:', prop_out_dir) if draw_overlaid: overlaid_out_dir = output_dir_base + '/overlaid/{}/{}/{}'.format( dataset.data_split, global_step, avod_score_threshold) if not os.path.exists(overlaid_out_dir): os.makedirs(overlaid_out_dir) print('Overlaid images saved to:', overlaid_out_dir) if draw_predictions_separate: pred_out_dir = output_dir_base + '/predictions/{}/{}/{}'.format( dataset.data_split, global_step, avod_score_threshold) if not os.path.exists(pred_out_dir): os.makedirs(pred_out_dir) print('Prediction images saved to:', pred_out_dir) # Rolling average array of times for time estimation avg_time_arr_length = 10 last_times = np.repeat(time.time(), avg_time_arr_length) + \ np.arange(avg_time_arr_length) for sample_idx in range(dataset.num_samples): # Estimate time remaining with 5 slowest times start_time = time.time() last_times = np.roll(last_times, -1) last_times[-1] = start_time avg_time = np.mean(np.sort(np.diff(last_times))[-5:]) samples_remaining = dataset.num_samples - sample_idx est_time_left = avg_time * samples_remaining # Print progress and time remaining estimate sys.stdout.write('\rSaving {} / {}, Avg Time: {:.3f}s, ' 'Time Remaining: {:.2f}s'.format( sample_idx + 1, dataset.num_samples, avg_time, est_time_left)) sys.stdout.flush() sample_name = dataset.sample_names[sample_idx] img_idx = int(sample_name) ############################## # Proposals ############################## if draw_proposals_separate or draw_overlaid: # Load proposals from files proposals_file_path = proposals_and_scores_dir + \ "/{}/{}.txt".format(global_step, sample_name) if not os.path.exists(proposals_file_path): print('Sample {}: No proposals, skipping'.format(sample_name)) continue print('Sample {}: Drawing proposals'.format(sample_name)) proposals_and_scores = np.loadtxt(proposals_file_path) proposal_boxes_3d = proposals_and_scores[:, 0:7] proposal_scores = proposals_and_scores[:, 7] # Apply score mask to proposals score_mask = proposal_scores > rpn_score_threshold proposal_boxes_3d = proposal_boxes_3d[score_mask] proposal_scores = proposal_scores[score_mask] proposal_objs = \ [box_3d_encoder.box_3d_to_object_label(proposal, obj_type='Proposal') for proposal in proposal_boxes_3d] ############################## # Predictions ############################## if draw_predictions_separate or draw_overlaid: predictions_file_path = predictions_and_scores_dir + \ "/{}/{}.txt".format(global_step, sample_name) if not os.path.exists(predictions_file_path): continue # Load predictions from files predictions_and_scores = np.loadtxt( predictions_and_scores_dir + "/{}/{}.txt".format(global_step, sample_name)) prediction_boxes_3d = predictions_and_scores[:, 0:7] prediction_scores = predictions_and_scores[:, 7] prediction_class_indices = predictions_and_scores[:, 8] # process predictions only if we have any predictions left after # masking if len(prediction_boxes_3d) > 0: # Apply score mask avod_score_mask = prediction_scores >= avod_score_threshold prediction_boxes_3d = prediction_boxes_3d[avod_score_mask] prediction_scores = prediction_scores[avod_score_mask] prediction_class_indices = \ prediction_class_indices[avod_score_mask] # # Swap l, w for predictions where w > l # swapped_indices = \ # prediction_boxes_3d[:, 4] > prediction_boxes_3d[:, 3] # prediction_boxes_3d = np.copy(prediction_boxes_3d) # prediction_boxes_3d[swapped_indices, 3] = \ # prediction_boxes_3d[swapped_indices, 4] # prediction_boxes_3d[swapped_indices, 4] = \ # prediction_boxes_3d[swapped_indices, 3] ############################## # Ground Truth ############################## # Get ground truth labels if dataset.has_labels: gt_objects = obj_utils.read_labels(dataset.label_dir, img_idx) else: gt_objects = [] # Filter objects to desired difficulty filtered_gt_objs = dataset.kitti_utils.filter_labels( gt_objects, classes=gt_classes) boxes2d, _, _ = obj_utils.build_bbs_from_objects( filtered_gt_objs, class_needed=gt_classes) image_path = dataset.get_rgb_image_path(sample_name) image = Image.open(image_path) image_size = image.size # Read the stereo calibration matrix for visualization stereo_calib = calib_utils.read_calibration(dataset.calib_dir, img_idx) calib_p2 = stereo_calib.p2 ############################## # Reformat and prepare to draw ############################## if draw_proposals_separate or draw_overlaid: proposals_as_anchors = box_3d_encoder.box_3d_to_anchor( proposal_boxes_3d) proposal_boxes, _ = anchor_projector.project_to_image_space( proposals_as_anchors, calib_p2, image_size) num_of_proposals = proposal_boxes_3d.shape[0] prop_fig, prop_2d_axes, prop_3d_axes = \ vis_utils.visualization(dataset.rgb_image_dir, img_idx, display=False) draw_proposals(filtered_gt_objs, calib_p2, num_of_proposals, proposal_objs, proposal_boxes, prop_2d_axes, prop_3d_axes, draw_orientations_on_prop) if draw_proposals_separate: # Save just the proposals filename = prop_out_dir + '/' + sample_name + '.png' plt.savefig(filename) if not draw_overlaid: plt.close(prop_fig) if draw_overlaid or draw_predictions_separate: if len(prediction_boxes_3d) > 0: # Project the 3D box predictions to image space image_filter = [] final_boxes_2d = [] for i in range(len(prediction_boxes_3d)): box_3d = prediction_boxes_3d[i, 0:7] img_box = box_3d_projector.project_to_image_space( box_3d, calib_p2, truncate=True, image_size=image_size, discard_before_truncation=False) if img_box is not None: image_filter.append(True) final_boxes_2d.append(img_box) else: image_filter.append(False) final_boxes_2d = np.asarray(final_boxes_2d) final_prediction_boxes_3d = prediction_boxes_3d[image_filter] final_scores = prediction_scores[image_filter] final_class_indices = prediction_class_indices[image_filter] num_of_predictions = final_boxes_2d.shape[0] # Convert to objs final_prediction_objs = \ [box_3d_encoder.box_3d_to_object_label( prediction, obj_type='Prediction') for prediction in final_prediction_boxes_3d] for (obj, score) in zip(final_prediction_objs, final_scores): obj.score = score else: if save_empty_images: pred_fig, pred_2d_axes, pred_3d_axes = \ vis_utils.visualization(dataset.rgb_image_dir, img_idx, display=False, fig_size=fig_size) filename = pred_out_dir + '/' + sample_name + '.png' plt.savefig(filename) plt.close(pred_fig) continue if draw_overlaid: # Overlay prediction boxes on image draw_predictions(filtered_gt_objs, calib_p2, num_of_predictions, final_prediction_objs, final_class_indices, final_boxes_2d, prop_2d_axes, prop_3d_axes, draw_score, draw_iou, gt_classes, draw_orientations_on_pred) filename = overlaid_out_dir + '/' + sample_name + '.png' plt.savefig(filename) plt.close(prop_fig) if draw_predictions_separate: # Now only draw prediction boxes on images # on a new figure handler if draw_projected_2d_boxes: pred_fig, pred_2d_axes, pred_3d_axes = \ vis_utils.visualization(dataset.rgb_image_dir, img_idx, display=False, fig_size=fig_size) draw_predictions(filtered_gt_objs, calib_p2, num_of_predictions, final_prediction_objs, final_class_indices, final_boxes_2d, pred_2d_axes, pred_3d_axes, draw_score, draw_iou, gt_classes, draw_orientations_on_pred) else: pred_fig, pred_3d_axes = \ vis_utils.visualize_single_plot( dataset.rgb_image_dir, img_idx, display=False) draw_3d_predictions(filtered_gt_objs, calib_p2, num_of_predictions, final_prediction_objs, final_class_indices, final_boxes_2d, pred_3d_axes, draw_score, draw_iou, gt_classes, draw_orientations_on_pred) filename = pred_out_dir + '/' + sample_name + '.png' plt.savefig(filename) plt.close(pred_fig) print('\nDone')
def main(_): parser = argparse.ArgumentParser() # Example usage # --checkpoint_name='avod_exp_example' # --data_split='test' # --ckpt_indices=50 100 112 # Optional arg: # --device=0 # --additional_cls=False parser.add_argument('--checkpoint_name', type=str, dest='checkpoint_name', required=True, help='Checkpoint name must be specified as a str\ and must match the experiment config file name.') parser.add_argument('--base_dir', type=str, dest='base_dir', required=True, help='Base data directory must be specified') parser.add_argument('--ckpt_indices', type=int, nargs='+', dest='ckpt_indices', required=True, help='Checkpoint indices must be a set of \ integers with space in between -> 0 10 20 etc') parser.add_argument('--device', type=str, dest='device', default='0', help='CUDA device id') parser.add_argument('--additional_cls', dest='additional_cls', action='store_true', default=False, help='If detections are from an additional class\ i.e. another class has already been pre-processed.') args = parser.parse_args() if len(sys.argv) == 1: parser.print_help() sys.exit(1) experiment_config = args.checkpoint_name + '.config' # Read the config from the experiment folder experiment_config_path = avod.root_dir() + '/data/outputs/' +\ args.checkpoint_name + '/' + experiment_config model_config, _, eval_config, dataset_config = \ config_builder.get_configs_from_pipeline_file( experiment_config_path, is_training=False) os.environ['CUDA_VISIBLE_DEVICES'] = args.device inference(model_config, eval_config, dataset_config, args.base_dir, args.ckpt_indices, args.additional_cls)
def __init__(self, dataset): self._dataset = dataset self._mini_batch_sampler = \ balanced_positive_negative_sampler.BalancedPositiveNegativeSampler() ############################## # Parse KittiUtils config ############################## self.kitti_utils_config = dataset.config.kitti_utils_config self._area_extents = self.kitti_utils_config.area_extents self._anchor_strides = np.reshape( self.kitti_utils_config.anchor_strides, (-1, 2)) ############################## # Parse MiniBatchUtils config ############################## self.config = self.kitti_utils_config.mini_batch_config self._density_threshold = self.config.density_threshold # RPN mini batches rpn_config = self.config.rpn_config if (rpn_config.ByteSize() != 0): rpn_iou_type = rpn_config.WhichOneof('iou_type') if rpn_iou_type == 'iou_2d_thresholds': self.rpn_iou_type = '2d' self.rpn_iou_thresholds = rpn_config.iou_2d_thresholds elif rpn_iou_type == 'iou_3d_thresholds': self.rpn_iou_type = '3d' self.rpn_iou_thresholds = rpn_config.iou_3d_thresholds self.rpn_neg_iou_range = [self.rpn_iou_thresholds.neg_iou_lo, self.rpn_iou_thresholds.neg_iou_hi] self.rpn_pos_iou_range = [self.rpn_iou_thresholds.pos_iou_lo, self.rpn_iou_thresholds.pos_iou_hi] self.rpn_mini_batch_size = rpn_config.mini_batch_size # AVOD mini batches avod_config = self.config.avod_config self.avod_iou_type = '2d' self.avod_iou_thresholds = avod_config.iou_2d_thresholds self.avod_neg_iou_range = [self.avod_iou_thresholds.neg_iou_lo, self.avod_iou_thresholds.neg_iou_hi] self.avod_pos_iou_range = [self.avod_iou_thresholds.pos_iou_lo, self.avod_iou_thresholds.pos_iou_hi] self.avod_mini_batch_size = avod_config.mini_batch_size # Setup paths if (rpn_config.ByteSize() != 0): self.mini_batch_dir = avod.root_dir() + '/data/mini_batches/' + \ 'iou_{}/'.format(self.rpn_iou_type) + \ dataset.name + '/' + dataset.cluster_split + '/' + \ dataset.bev_source else: self.mini_batch_dir = avod.root_dir() + '/data/mini_batches/' + \ 'iou_{}/'.format(self.avod_iou_type) + \ dataset.name + '/' + dataset.cluster_split + '/' + \ dataset.bev_source # Array column indices for saving to files self.col_length = 9 self.col_anchor_indices = 0 self.col_ious = 1 self.col_offsets_lo = 2 self.col_offsets_hi = 8 self.col_class_idx = 8
def main(checkpoint_name): """This demo shows RPN proposals and AVOD predictions in 3D and 2D in image space. Given certain thresholds for proposals and predictions, it selects and draws the bounding boxes on the image sample. It goes through the entire proposal and prediction samples for the given dataset split. The proposals, overlaid, and prediction images can be toggled on or off separately in the options section. The prediction score and IoU with ground truth can be toggled on or off as well, shown as (score, IoU) above the detection. """ # checkpoint_name =='pyramid_cars_with_aug_example' dataset_config = DatasetBuilder.copy_config(DatasetBuilder.KITTI_VAL) ############################## # Options ############################## dataset_config.data_split = 'val' fig_size = (10, 6.1) rpn_score_threshold = 0.1 avod_score_threshold = 0.002 #0.1 #0.009 # <== final threshold sample_names = [90] + list(range( 98, 104)) + [138, 224, 270, 290, 310, 330, 520] # Convert to string with correct format (don't change) sample_names = ['{:06d}'.format(x) for x in sample_names] # gt_classes = ['Car'] gt_classes = ['Pedestrian', 'Cyclist'] # gt_classes = ['Car', 'Pedestrian', 'Cyclist'] img_dir = '/home/jhuang/repo/avod/input' # Overwrite this to select a specific checkpoint global_step = None # Drawing Toggles draw_proposals_separate = False draw_overlaid = False draw_predictions_separate = True # Show orientation for both GT and proposals/predictions draw_orientations_on_prop = False draw_orientations_on_pred = False # Draw 2D bounding boxes draw_projected_2d_boxes = True # Save images for samples with no detections save_empty_images = True draw_score = True draw_iou = True ############################## # End of Options ############################## # Get the dataset dataset = None data_split = 'val' # Setup Paths predictions_dir = avod.root_dir() + \ '/data/outputs/' + checkpoint_name + '/predictions' proposals_and_scores_dir = predictions_dir + \ '/proposals_and_scores/' + data_split predictions_and_scores_dir = predictions_dir + \ '/final_predictions_and_scores/' + data_split # Output images directories output_dir_base = predictions_dir + '/images_2d' # Get checkpoint step steps = os.listdir(proposals_and_scores_dir) steps.sort(key=int) print('Available steps: {}'.format(steps)) # Use latest checkpoint if no index provided if global_step is None: global_step = steps[-1] if draw_proposals_separate: prop_out_dir = output_dir_base + '/proposals/{}/{}/{}'.format( data_split, global_step, rpn_score_threshold) if not os.path.exists(prop_out_dir): os.makedirs(prop_out_dir) print('Proposal images saved to:', prop_out_dir) if draw_overlaid: overlaid_out_dir = output_dir_base + '/overlaid/{}/{}/{}'.format( data_split, global_step, avod_score_threshold) if not os.path.exists(overlaid_out_dir): os.makedirs(overlaid_out_dir) print('Overlaid images saved to:', overlaid_out_dir) if draw_predictions_separate: pred_out_dir = output_dir_base + '/predictions/{}/{}/{}'.format( data_split, global_step, avod_score_threshold) if not os.path.exists(pred_out_dir): os.makedirs(pred_out_dir) print('Prediction images saved to:', pred_out_dir) # Rolling average array of times for time estimation avg_time_arr_length = 10 last_times = np.repeat(time.time(), avg_time_arr_length) + \ np.arange(avg_time_arr_length) num_samples = len(sample_names) for sample_idx in range(num_samples): # Estimate time remaining with 5 slowest times start_time = time.time() last_times = np.roll(last_times, -1) last_times[-1] = start_time avg_time = np.mean(np.sort(np.diff(last_times))[-5:]) samples_remaining = num_samples - sample_idx est_time_left = avg_time * samples_remaining # Print progress and time remaining estimate sys.stdout.write('\rSaving {} / {}, Avg Time: {:.3f}s, ' 'Time Remaining: {:.2f}s\n'.format( sample_idx + 1, num_samples, avg_time, est_time_left)) sys.stdout.flush() sample_name = sample_names[sample_idx] img_idx = int(sample_name) ############################## # Predictions ############################## if draw_predictions_separate or draw_overlaid: predictions_file_path = predictions_and_scores_dir + \ "/{}/{}.txt".format(global_step, sample_name) if not os.path.exists(predictions_file_path): continue # Load predictions from files predictions_and_scores = np.loadtxt( predictions_and_scores_dir + "/{}/{}.txt".format(global_step, sample_name)) prediction_boxes_3d = predictions_and_scores[:, 0:7] prediction_scores = predictions_and_scores[:, 7] print("scores=", prediction_scores) prediction_class_indices = predictions_and_scores[:, 8] # process predictions only if we have any predictions left after # masking if len(prediction_boxes_3d) > 0: # Apply score mask avod_score_mask = prediction_scores >= avod_score_threshold prediction_boxes_3d = prediction_boxes_3d[avod_score_mask] print("len(prediction_boxes_3d)=", len(prediction_boxes_3d)) prediction_scores = prediction_scores[avod_score_mask] prediction_class_indices = \ prediction_class_indices[avod_score_mask] # # Swap l, w for predictions where w > l # swapped_indices = \ # prediction_boxes_3d[:, 4] > prediction_boxes_3d[:, 3] # prediction_boxes_3d = np.copy(prediction_boxes_3d) # prediction_boxes_3d[swapped_indices, 3] = \ # prediction_boxes_3d[swapped_indices, 4] # prediction_boxes_3d[swapped_indices, 4] = \ # prediction_boxes_3d[swapped_indices, 3] ############################## # Ground Truth ############################## # Get ground truth labels gt_objects = [] image_path = get_rgb_image_path(img_dir, img_idx, 'img_') image = Image.open(image_path) image_size = image.size # Read the stereo calibration matrix for visualization calib_dir = img_dir stereo_calib = load_calib(calib_dir, img_idx, 'calib.txt') calib_p2 = stereo_calib.p2 if draw_overlaid or draw_predictions_separate: num_of_predictions = 0 if len(prediction_boxes_3d) > 0: # Project the 3D box predictions to image space image_filter = [] final_boxes_2d = [] for i in range(len(prediction_boxes_3d)): box_3d = prediction_boxes_3d[i, 0:7] img_box = box_3d_projector.project_to_image_space( box_3d, calib_p2, truncate=True, image_size=image_size, discard_before_truncation=False) if img_box is not None: image_filter.append(True) final_boxes_2d.append(img_box) else: image_filter.append(False) final_boxes_2d = np.asarray(final_boxes_2d) final_prediction_boxes_3d = prediction_boxes_3d[image_filter] final_scores = prediction_scores[image_filter] final_class_indices = prediction_class_indices[image_filter] num_of_predictions = final_boxes_2d.shape[0] # Convert to objs final_prediction_objs = \ [box_3d_encoder.box_3d_to_object_label( prediction, obj_type='Prediction') for prediction in final_prediction_boxes_3d] for (obj, score) in zip(final_prediction_objs, final_scores): obj.score = score # else: # if save_empty_images: # pred_fig, pred_2d_axes, pred_3d_axes = \ # vis_utils.visualization(dataset.rgb_image_dir, # img_idx, # display=False, # fig_size=fig_size) # filename = pred_out_dir + '/' + sample_name + '.png' # plt.savefig(filename) # plt.close(pred_fig) # continue if draw_predictions_separate and num_of_predictions > 0: # Now only draw prediction boxes on images # on a new figure handler if draw_projected_2d_boxes: pred_fig, pred_2d_axes, pred_3d_axes = \ vis_utils.visualization_jhuang(img_dir, img_idx, 'img_', display=False, fig_size=fig_size) draw_predictions([], calib_p2, num_of_predictions, final_prediction_objs, final_class_indices, final_boxes_2d, pred_2d_axes, pred_3d_axes, draw_score, draw_iou, gt_classes, draw_orientations_on_pred) else: pred_fig, pred_3d_axes = \ vis_utils.visualize_single_plot( dataset.rgb_image_dir, img_idx, display=False) draw_3d_predictions([], calib_p2, num_of_predictions, final_prediction_objs, final_class_indices, final_boxes_2d, pred_3d_axes, draw_score, draw_iou, gt_classes, draw_orientations_on_pred) filename = pred_out_dir + '/' + sample_name + '.png' plt.savefig(filename) plt.close(pred_fig) print('\nDone')
def __init__(self, dataset): self._dataset = dataset self._mini_batch_sampler = \ balanced_positive_negative_sampler.BalancedPositiveNegativeSampler() ############################## # Parse KittiUtils config ############################## self.kitti_utils_config = dataset.config.kitti_utils_config self._area_extents = self.kitti_utils_config.area_extents self._anchor_strides = np.reshape( self.kitti_utils_config.anchor_strides, (-1, 2)) ############################## # Parse MiniBatchUtils config ############################## self.config = self.kitti_utils_config.mini_batch_config self._density_threshold = self.config.density_threshold self.use_retinanet = self.config.use_retinanet if not self.use_retinanet: # RPN mini batches rpn_config = self.config.rpn_config rpn_iou_type = rpn_config.WhichOneof('iou_type') if rpn_iou_type == 'iou_2d_thresholds': self.rpn_iou_type = '2d' self.rpn_iou_thresholds = rpn_config.iou_2d_thresholds elif rpn_iou_type == 'iou_3d_thresholds': self.rpn_iou_type = '3d' self.rpn_iou_thresholds = rpn_config.iou_3d_thresholds self.rpn_neg_iou_range = [ self.rpn_iou_thresholds.neg_iou_lo, self.rpn_iou_thresholds.neg_iou_hi ] self.rpn_pos_iou_range = [ self.rpn_iou_thresholds.pos_iou_lo, self.rpn_iou_thresholds.pos_iou_hi ] self.rpn_mini_batch_size = rpn_config.mini_batch_size # AVOD mini batches avod_config = self.config.avod_config self.avod_iou_type = '2d' self.avod_iou_thresholds = avod_config.iou_2d_thresholds self.avod_neg_iou_range = [ self.avod_iou_thresholds.neg_iou_lo, self.avod_iou_thresholds.neg_iou_hi ] self.avod_pos_iou_range = [ self.avod_iou_thresholds.pos_iou_lo, self.avod_iou_thresholds.pos_iou_hi ] self.avod_mini_batch_size = avod_config.mini_batch_size # Setup paths self.mini_batch_dir = avod.root_dir() + '/data/mini_batches/' + \ 'iou_{}/'.format(self.rpn_iou_type) + \ dataset.name + '/' + dataset.cluster_split + '/' + \ dataset.bev_source # Array column indices for saving to files self.col_length = 9 self.col_anchor_indices = 0 self.col_ious = 1 self.col_offsets_lo = 2 self.col_offsets_hi = 8 self.col_class_idx = 8 else: #use retinanet retinanet_config = self.config.retinanet_config self.retinanet_pyramid_levels = retinanet_config.pyramid_levels self.retinanet_iou_type = retinanet_config.iou_type self.retinanet_iou_thresholds = retinanet_config.iou_2d_thresholds self.retinanet_neg_iou_range = [ self.retinanet_iou_thresholds.neg_iou_lo, self.retinanet_iou_thresholds.neg_iou_hi ] self.retinanet_pos_iou_range = [ self.retinanet_iou_thresholds.pos_iou_lo, self.retinanet_iou_thresholds.pos_iou_hi ] self.mini_batch_dir = avod.root_dir() + '/data/mini_batches/' + \ 'retinanet/' + 'iou_{}/'.format(self.retinanet_iou_type) + \ dataset.name + '/' + dataset.cluster_split #[x_bev, y_bev, w_bev, h_bev, angle_bev, h_img, angle_cls] #[2:9] is all offset cols. self.col_length = 12 #11 self.col_anchor_indices = 0 self.col_ious = 1 self.col_offsets_lo = 2 self.col_offsets_hi = 10 #9 self.col_class_idx = 10 #9 anchor_strides = [2**(int(l[-1])) for l in \ self.retinanet_pyramid_levels] input_bev_dims_h = retinanet_config.input_bev_dims_h input_bev_dims_w = retinanet_config.input_bev_dims_w self.retinanet_bev_shape = (input_bev_dims_h, input_bev_dims_w) image_shapes = [(int(np.ceil(input_bev_dims_h/s)), int(np.ceil(input_bev_dims_w/s)))\ for s in anchor_strides] anchor_base_sizes = [2**(int(l[-1])+2) for l in \ self.retinanet_pyramid_levels] self.retinanet_anchor_params = {\ 'anchor_strides': np.reshape(anchor_strides, (-1, 1)), \ 'anchor_base_sizes': anchor_base_sizes, \ 'anchor_scales': retinanet_config.anchor_scales,\ 'anchor_ratios': retinanet_config.anchor_ratios,\ 'anchor_init_ry_type': retinanet_config.anchor_init_ry_type,\ 'image_shapes': image_shapes, }
def main(dataset=None): """Generates anchors info which is used for mini batch sampling. Processing on 'Cars' can be split into multiple processes, see the Options section for configuration. Args: dataset: KittiDataset (optional) If dataset is provided, only generate info for that dataset. If no dataset provided, generates info for all 3 classes. """ if dataset is not None: do_preprocessing(dataset, None) return car_dataset_config_path = avod.root_dir() + \ '/configs/mb_preprocessing/rpn_cars.config' ped_dataset_config_path = avod.root_dir() + \ '/configs/mb_preprocessing/rpn_pedestrians.config' cyc_dataset_config_path = avod.root_dir() + \ '/configs/mb_preprocessing/rpn_cyclists.config' ppl_dataset_config_path = avod.root_dir() + \ '/configs/mb_preprocessing/rpn_people.config' ############################## # Options ############################## # Serial vs parallel processing in_parallel = True process_car = True # Cars process_ped = False # Pedestrians process_cyc = False # Cyclists process_ppl = True # People (Pedestrians + Cyclists) # Number of child processes to fork, samples will # be divided evenly amongst the processes (in_parallel must be True) num_car_children = 8 num_ped_children = 8 num_cyc_children = 8 num_ppl_children = 8 ############################## # Dataset setup ############################## if process_car: car_dataset = DatasetBuilder.load_dataset_from_config( car_dataset_config_path) if process_ped: ped_dataset = DatasetBuilder.load_dataset_from_config( ped_dataset_config_path) if process_cyc: cyc_dataset = DatasetBuilder.load_dataset_from_config( cyc_dataset_config_path) if process_ppl: ppl_dataset = DatasetBuilder.load_dataset_from_config( ppl_dataset_config_path) ############################## # Serial Processing ############################## if not in_parallel: if process_car: do_preprocessing(car_dataset, None) if process_ped: do_preprocessing(ped_dataset, None) if process_cyc: do_preprocessing(cyc_dataset, None) if process_ppl: do_preprocessing(ppl_dataset, None) print('All Done (Serial)') ############################## # Parallel Processing ############################## else: # List of all child pids to wait on all_child_pids = [] # Cars if process_car: car_indices_split = split_indices(car_dataset, num_car_children) split_work( all_child_pids, car_dataset, car_indices_split, num_car_children) # Pedestrians if process_ped: ped_indices_split = split_indices(ped_dataset, num_ped_children) split_work( all_child_pids, ped_dataset, ped_indices_split, num_ped_children) # Cyclists if process_cyc: cyc_indices_split = split_indices(cyc_dataset, num_cyc_children) split_work( all_child_pids, cyc_dataset, cyc_indices_split, num_cyc_children) # People (Pedestrians + Cyclists) if process_ppl: ppl_indices_split = split_indices(ppl_dataset, num_ppl_children) split_work( all_child_pids, ppl_dataset, ppl_indices_split, num_ppl_children) # Wait to child processes to finish print('num children:', len(all_child_pids)) for i, child_pid in enumerate(all_child_pids): os.waitpid(child_pid, 0) print('All Done (Parallel)')
split_work(all_child_pids, ped_dataset, ped_indices_split, num_ped_children) # Cyclists if process_cyc: cyc_indices_split = split_indices(cyc_dataset, num_cyc_children) split_work(all_child_pids, cyc_dataset, cyc_indices_split, num_cyc_children) # People (Pedestrians + Cyclists) if process_ppl: ppl_indices_split = split_indices(ppl_dataset, num_ppl_children) split_work(all_child_pids, ppl_dataset, ppl_indices_split, num_ppl_children) # Wait to child processes to finish print('num children:', len(all_child_pids)) for i, child_pid in enumerate(all_child_pids): os.waitpid(child_pid, 0) print('All Done (Parallel)') if __name__ == '__main__': # main() cars_people_dataset_config_path = avod.root_dir() + \ '/configs/mb_preprocessing/rpn_cars_people.config' cars_people_dataset = DatasetBuilder.load_dataset_from_config( cars_people_dataset_config_path) do_preprocessing(cars_people_dataset, None)