예제 #1
0
def save_video(project, split, label):
    project = urllib.parse.unquote(project)
    split = urllib.parse.unquote(split)
    label = urllib.parse.unquote(label)
    path = utils.lookup_project_path(project)

    # Read given video to a file
    input_stream = request.files['video']
    output_path = os.path.join(path, f'videos_{split}', label)
    temp_file_name = os.path.join(output_path, 'temp_video.webm')
    with open(temp_file_name, 'wb') as temp_file:
        temp_file.write(input_stream.read())

    # Find a video name that is not used yet
    existing_files = set(glob.glob(os.path.join(output_path, 'video_[0-9]*.mp4')))
    video_idx = 0
    output_file = os.path.join(output_path, f'video_{video_idx}.mp4')
    while output_file in existing_files:
        video_idx += 1
        output_file = os.path.join(output_path, f'video_{video_idx}.mp4')

    # Convert video to target frame rate and save to output name
    subprocess.call(f'ffmpeg -i "{temp_file_name}" -r 30 "{output_file}"', shell=True)

    # Remove temp video file
    os.remove(temp_file_name)

    return jsonify(success=True)
예제 #2
0
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'])
예제 #3
0
def prepare_annotation(project):
    """
    Prepare all files needed for annotating the videos in the given project.
    """
    project = urllib.parse.unquote(project)
    dataset_path = utils.lookup_project_path(project)

    # load feature extractor
    inference_engine, model_config = utils.load_feature_extractor(dataset_path)
    for split in SPLITS:
        print(f'\n\tPreparing videos in the {split}-set')

        for label in os.listdir(directories.get_videos_dir(
                dataset_path, split)):
            videos_dir = directories.get_videos_dir(dataset_path, split, label)
            frames_dir = directories.get_frames_dir(dataset_path, split, label)
            features_dir = directories.get_features_dir(dataset_path,
                                                        split,
                                                        model_config,
                                                        label=label)

            compute_frames_features(inference_engine=inference_engine,
                                    videos_dir=videos_dir,
                                    frames_dir=frames_dir,
                                    features_dir=features_dir)

    return redirect(url_for("project_details", project=project))
예제 #4
0
def show_video_list(project, split, label):
    """
    Show the list of videos for the given split, class label and project.
    If the necessary files for annotation haven't been prepared yet, this is done now.
    """
    project = urllib.parse.unquote(project)
    path = utils.lookup_project_path(project)
    split = urllib.parse.unquote(split)
    label = urllib.parse.unquote(label)
    frames_dir = join(path, f"frames_{split}", label)
    tags_dir = join(path, f"tags_{split}", label)
    logreg_dir = join(path, 'logreg', label)

    os.makedirs(logreg_dir, exist_ok=True)
    os.makedirs(tags_dir, exist_ok=True)

    # load feature extractor
    inference_engine = utils.load_feature_extractor(path)
    # compute the features and frames missing.
    compute_frames_features(inference_engine, split, label, path)

    videos = os.listdir(frames_dir)
    videos = natsorted(videos, alg=ns.IC)

    tagged_list = set(os.listdir(tags_dir))
    tagged = [f'{video}.json' in tagged_list for video in videos]

    video_list = zip(videos, tagged, list(range(len(videos))))
    return render_template('video_list.html', video_list=video_list, split=split, label=label, path=path,
                           project=project)
예제 #5
0
def download_file(project, split, label, video_name, img_file):
    """
    Load an image from the given path.
    """
    dataset_path = utils.lookup_project_path(project)
    img_dir = os.path.join(
        directories.get_frames_dir(dataset_path, split, label), video_name)
    return send_from_directory(img_dir, img_file, as_attachment=True)
예제 #6
0
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)
예제 #7
0
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))
예제 #8
0
def record_video(project, split, label):
    """
    Display the video recording screen.
    """
    project = urllib.parse.unquote(project)
    split = urllib.parse.unquote(split)
    label = urllib.parse.unquote(label)
    path = utils.lookup_project_path(project)

    countdown, recording = utils.get_timer_default(path)

    return render_template('video_recording.html', project=project, split=split, label=label, path=path,
                           countdown=countdown, recording=recording)
예제 #9
0
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))
예제 #10
0
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))
예제 #11
0
def prepare_annotation(project):
    """
    Prepare all files needed for annotating the videos in the given project.
    """
    project = urllib.parse.unquote(project)
    path = utils.lookup_project_path(project)

    # load feature extractor
    inference_engine = utils.load_feature_extractor(path)
    for split in utils.SPLITS:
        print("\n" + "-" * 10 + f"Preparing videos in the {split}-set" + "-" * 10)
        for label in os.listdir(join(path, f'videos_{split}')):
            compute_frames_features(inference_engine, split, label, path)

    return redirect(url_for("project_details", project=project))
예제 #12
0
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))
예제 #13
0
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))
예제 #14
0
 def inject_class_labels(project):
     path = utils.lookup_project_path(project)
     class_labels = utils.get_class_labels(path)
     return class_labels
예제 #15
0
 def inject_temporal_status(project):
     path = utils.lookup_project_path(project)
     temporal_status = utils.get_project_setting(path, 'temporal')
     return temporal_status
예제 #16
0
def download_file(project, split, label, video_name, img_file):
    """
    Load an image from the given path.
    """
    img_dir = utils.lookup_project_path(project) + f'/frames_{split}/{label}/{video_name}'
    return send_from_directory(img_dir, img_file, as_attachment=True)