NVIDIA / NVIDIA/DALI

fn.readers.video--extract frames details

Open
#4,797 5 comments 0 reactions 1 assignee View on GitHub

@szalpal is already working on this.

Since Apr 20, 2023.

help wanted Video
Dominant language
C++
Stars
5.8k
Forks
678
Avg merge
3d 1h
Merged PRs (30d)
27

Description

import os.path
import numpy as np
import shutil
from PIL import Image
from nvidia.dali import pipeline_def
import nvidia.dali.fn as fn
import nvidia.dali.types as types

def get_opts(video_path):
    meta = get_video_meta_info(video_path)
    width = meta['width']
    height = meta['height']
    input_fps = meta['fps']
    duration = meta['duration']
    nb_frames = meta['nb_frames']

    if nb_frames == 0:
        print('error: the num of video frames is 0!')

    scale = 1
    video_uniform_len = min(int(duration), 60)
    sequence_length = 32
    video_read_interval = int((duration / video_uniform_len) / scale) * scale  # uniform extract frames
    if video_read_interval == 1:
        sequence_step = int(input_fps)
    else:
        sequence_step = nb_frames // 60
    opts = {
        'spatial_sequence_length': 1,
        'motion_sequence_length': sequence_length,
        'stride': 1,
        'step': sequence_step,
        'n_iter': video_uniform_len,
        'batch_size': 1,
        'num_threads': 4,
        'height': height,
        'width': width
    }
    return opts

def save_images(frames, seq_len, directory):
    for j in range(seq_len):
        im = Image.fromarray(frames[j])
        im.save(os.path.join(directory, str(j)) + '.png')

def extract_frames(filenames):
    data_dir = "/workspace/code/FAST-VQA-and-FasterVQA/vqa_dataset/output"

    opts = get_opts(video_filename)
    @pipeline_def
    def video_pipe(filenames):
        video = fn.readers.video(device="gpu", filenames=filenames, sequence_length=opts['motion_sequence_length'],
                                 stride=opts['stride'], step=opts['step'],
                                 skip_vfr_check=True)
        return video

    pipe = video_pipe(filenames=video_filename, batch_size=opts['batch_size'], num_threads=opts['num_threads'],
                      device_id=0)
    pipe.build()

    for i in range(opts['n_iter']):
        pipe_out = pipe.run()
        frames = np.array(pipe_out[0][0].as_cpu())
        print(frames.shape)
        label_dir = os.path.join(data_dir, str(i))
        os.makedirs(label_dir)
        save_images(frames, opts['motion_sequence_length'], label_dir)

video_filename = "test.mp4"
extract_frames(video_filename)

Uploading 000.mp4…

Hello, when I use this API to extract frames, if I input a video, the length of the video is less than 60s, suppose 15s, and FPS=24, I plan to set sequence_length=32, and I find that the first sequence is directly copied in the last sequence. I would like to ask if we can not copy the first sequence, but directly copy the 24 frames of the last sequence into 32 frames to form a sequence of (15, 32, 3, h, w)
2681681982272_ pic
@jantonguirao

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.