def project_details(project): """ Show the details for the selected project. """ project = urllib.parse.unquote(project) path = utils.lookup_project_path(project) config = utils.load_project_config(path) stats = {} for class_name, tags in config['classes'].items(): stats[class_name] = {} for split in SPLITS: videos_dir = directories.get_videos_dir(path, split, class_name) tags_dir = directories.get_tags_dir(path, split, class_name) stats[class_name][split] = { 'total': len(os.listdir(videos_dir)), 'tagged': len(os.listdir(tags_dir)) if os.path.exists(tags_dir) else 0, } return render_template('project_details.html', config=config, path=path, stats=stats, project=config['name'])
def project_config(): """ Provide the config for a given project. """ data = request.json name = data['name'] path = utils.lookup_project_path(name) # Get config config = utils.load_project_config(path) return jsonify(config)
def setup_project(): """ Add a new project to the config file. Can also be used for updating an existing project. """ data = request.form name = data['projectName'] path = data['path'] # Initialize project directory if not os.path.exists(path): os.mkdir(path) # Update project config try: # Check for existing config file config = utils.load_project_config(path) old_name = config['name'] config['name'] = name except FileNotFoundError: # Setup new project config config = { 'name': name, 'date_created': datetime.date.today().isoformat(), 'classes': {}, 'use_gpu': False, 'temporal': False, 'video_recording': { 'countdown': 3, 'recording': 5, }, } old_name = None utils.write_project_config(path, config) # Setup directory structure for split in SPLITS: videos_dir = directories.get_videos_dir(path, split) if not os.path.exists(videos_dir): os.mkdir(videos_dir) # Update overall projects config file projects = utils.load_project_overview_config() if old_name and old_name in projects: del projects[old_name] projects[name] = { 'path': path, } utils.write_project_overview_config(projects) return redirect(url_for('project_details', project=name))
def edit_class(project, class_name): """ Edit the class name and tags for an existing class in the given project. """ project = urllib.parse.unquote(project) class_name = urllib.parse.unquote(class_name) path = utils.lookup_project_path(project) # Get new class name and tags new_class_name, new_tag1, new_tag2 = utils.get_class_name_and_tags( request.form) # Update project config config = utils.load_project_config(path) del config['classes'][class_name] config['classes'][new_class_name] = [new_tag1, new_tag2] utils.write_project_config(path, config) # Update directory names data_dirs = [] for split in SPLITS: data_dirs.extend([ directories.get_videos_dir(path, split), directories.get_frames_dir(path, split), directories.get_tags_dir(path, split), ]) # Feature directories follow the format <dataset_dir>/<split>/<model>/<num_layers_to_finetune>/<label> features_dir = directories.get_features_dir(path, split) model_dirs = [ os.path.join(features_dir, model_dir) for model_dir in os.listdir(features_dir) ] data_dirs.extend([ os.path.join(model_dir, tuned_layers) for model_dir in model_dirs for tuned_layers in os.listdir(model_dir) ]) logreg_dir = directories.get_logreg_dir(path) data_dirs.extend([ os.path.join(logreg_dir, model_dir) for model_dir in os.listdir(logreg_dir) ]) for base_dir in data_dirs: class_dir = os.path.join(base_dir, class_name) if os.path.exists(class_dir): new_class_dir = os.path.join(base_dir, new_class_name) os.rename(class_dir, new_class_dir) return redirect(url_for('project_details', project=project))
def annotate(project, split, label, idx): """ For the given class label, show all frames for annotating the selected video. """ project = urllib.parse.unquote(project) path = utils.lookup_project_path(project) label = urllib.parse.unquote(label) split = urllib.parse.unquote(split) frames_dir = join(path, f"frames_{split}", label) features_dir = join(path, f"features_{split}", label) tags_dir = join(path, f"tags_{split}", label) logreg_dir = join(path, 'logreg', label) videos = os.listdir(frames_dir) videos.sort() features = np.load(join(features_dir, f'{videos[idx]}.npy')) features = features.mean(axis=(2, 3)) # Load logistic regression model if available logreg_path = join(logreg_dir, 'logreg.joblib') if os.path.isfile(logreg_path): logreg = load(logreg_path) classes = list(logreg.predict(features)) else: classes = [-1] * len(features) # The list of images in the folder images = [image for image in glob.glob(join(frames_dir, videos[idx], '*')) if utils.is_image_file(image)] # Natural sort images, so that they are sorted by number images = natsorted(images, alg=ns.IC) # Extract image file name (without full path) and include class label images = [(os.path.basename(image), _class) for image, _class in zip(images, classes)] # Load existing annotations annotations = [] annotations_file = join(tags_dir, f'{videos[idx]}.json') if os.path.exists(annotations_file): with open(annotations_file, 'r') as f: data = json.load(f) annotations = data['time_annotation'] # Read tags from config config = utils.load_project_config(path) tags = config['classes'][label] return render_template('frame_annotation.html', images=images, annotations=annotations, idx=idx, fps=16, n_images=len(images), video_name=videos[idx], split=split, label=label, path=path, tags=tags, project=project, n_videos=len(videos))
def remove_class(project, class_name): """ Remove the given class from the config file of the given project. No data will be deleted. """ project = urllib.parse.unquote(project) class_name = urllib.parse.unquote(class_name) path = utils.lookup_project_path(project) # Update project config config = utils.load_project_config(path) del config['classes'][class_name] utils.write_project_config(path, config) return redirect(url_for("project_details", project=project))
def add_class(project): """ Add a new class to the given project. """ project = urllib.parse.unquote(project) path = utils.lookup_project_path(project) # Get class name and tags class_name, tag1, tag2 = utils.get_class_name_and_tags(request.form) # Update project config config = utils.load_project_config(path) config['classes'][class_name] = [tag1, tag2] utils.write_project_config(path, config) # Setup directory structure for split in SPLITS: videos_dir = directories.get_videos_dir(path, split, class_name) if not os.path.exists(videos_dir): os.mkdir(videos_dir) return redirect(url_for("project_details", project=project))
def edit_class(project, class_name): """ Edit the class name and tags for an existing class in the given project. """ project = urllib.parse.unquote(project) class_name = urllib.parse.unquote(class_name) path = utils.lookup_project_path(project) # Get new class name and tags new_class_name, new_tag1, new_tag2 = utils.get_class_name_and_tags(request.form) # Update project config config = utils.load_project_config(path) del config['classes'][class_name] config['classes'][new_class_name] = [new_tag1, new_tag2] utils.write_project_config(path, config) # Update directory names prefixes = ['videos', 'features', 'frames', 'tags'] for split in utils.SPLITS: for prefix in prefixes: main_dir = os.path.join(path, f'{prefix}_{split}') class_dir = os.path.join(main_dir, class_name) if os.path.exists(class_dir): new_class_dir = os.path.join(main_dir, new_class_name) os.rename(class_dir, new_class_dir) logreg_dir = os.path.join(path, 'logreg') class_dir = os.path.join(logreg_dir, class_name) if os.path.exists(class_dir): new_class_dir = os.path.join(logreg_dir, new_class_name) os.rename(class_dir, new_class_dir) return redirect(url_for("project_details", project=project))