Есть ли способ вырезать кадры из видео, чтобы уменьшить его размер и продолжительность? - PullRequest
0 голосов
/ 07 марта 2020

У меня есть большой набор видео, которые мне нужно обработать, но процесс идет медленно, так как обработка включает в себя прохождение всего видео со скоростью около 0,6FPS, а в подавляющем большинстве кадров между ними мало изменений.

Можно ли как-нибудь сэмплировать видео, скажем, каждые две секунды и сохранить его как другое видео, сократив частоту кадров и длительность на две части? При этом я не беспокоюсь о потере информации, я бы с удовольствием сократил 10-минутное видео до нескольких сотен кадров. Мне нужно, чтобы это был видео файл, а не набор изображений.

1 Ответ

0 голосов
/ 08 марта 2020

Вы можете решить ее, используя cv2.VideoCapture и cv2.VideoWriter или FFmpeg .

В приведенном ниже решении используется ffmpeg- python.
Я опубликовал как решение OpenCV, так и решение FFmpeg.

Решение с использованием OpenCV:

  • Открытие входного видеофайла для чтения с использованием cv2.VideoCapture.
  • Открытие выходного видеофайла для записи с использованием cv2.VideoWriter.
  • Читать все кадры, но записывать только каждый 10-й кадр в выходной файл.

Решение с использованием FFmpeg:

Следующий пример «самодостаточен» - генерирует синтетический c входной видеофайл для тестирования и выполняет пропуск кадра в сгенерированном входном видео.

Вот код (пример с использованием ffmpeg-python внизу):

import ffmpeg  # Note: import ffmpeg is not a must, when using OpenCV solution.
import cv2
import sys

out_filename = 'out.mp4'

# Build synthetic video and read binary data into memory (for testing):
#########################################################################
in_filename = 'in.mp4'
width, height = 320, 240
fps = 1  # 1Hz (just for testing)

# Build synthetic video, for testing:
# ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -c:v libx264 -crf 18 -t 50 in.mp4
(
    ffmpeg
    .input('testsrc=size={}x{}:rate={}'.format(width, height, fps), f='lavfi')
    .output(in_filename, vcodec='libx264', crf=18, t=50)
    .overwrite_output()
    .run()
)
#########################################################################

# Open video file for reading
in_vid = cv2.VideoCapture(in_filename)

#Exit if video not opened.
if not in_vid.isOpened():
    print('Cannot open input video file')
    sys.exit()

# Read first image (for getting resolution).
ok, frame = in_vid.read()
if not ok:
    print('Cannot read video file')
    sys.exit()

width, height = frame.shape[1], frame.shape[0]

# Get frame rate of input video.
fps = in_vid.get(cv2.CAP_PROP_FPS)

# Create video writer
# 264 doesn't come by default with the default installation of OpenCV, but I preferred using H.264 (supposed to be better than XVID).
# https://stackoverflow.com/questions/41972503/could-not-open-codec-libopenh264-unspecified-error
# (I had to download openh264-1.8.0-win64.dll)
out_vid = cv2.VideoWriter(out_filename, cv2.VideoWriter_fourcc(*'H264'), fps, (width, height))


frame_counter = 0

while True:
    # Write every 10th frame to output video file.
    if ((frame_counter % 10) == 0):
        out_vid.write(frame)

    # Read a new frame
    ok, frame = in_vid.read()
    if not ok:
        break

    frame_counter += 1

out_vid.release()





# Selecting one every n frames from a video using FFmpeg:
# https://superuser.com/questions/1274661/selecting-one-every-n-frames-from-a-video-using-ffmpeg 
# ffmpeg -y -r 10 -i in.mp4 -vf "select=not(mod(n\,10))" -vsync vfr -vcodec libx264 -crf 18  1_every_10.mp4

out_filename = '1_every_10.mp4'

# Important: set input frame rate to fps*10
(
    ffmpeg
    .input(in_filename, r=str(fps*10))
    .output(out_filename, vf='select=not(mod(n\,10))', vsync='vfr', vcodec='libx264', crf='18')
    .overwrite_output()
    .run()
)
  • Примечание. Решение теряет часть качества видео из-за декодирования и перезаписи. -encoding.

Вы также можете попробовать FFmpeg десятичный фильтр , если вы ищете решение, которое пропускает кадры в соответствии с вычислением метрик.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...