Разбор видео с более низкой частотой кадров - PullRequest
0 голосов
/ 02 ноября 2018

В настоящее время я работаю над проектом, в котором мне нужно проанализировать видео и пропустить его через несколько моделей. Видео приходят со скоростью 60 кадров в секунду. Мне не нужно запускать каждый кадр через модели. Я сталкиваюсь с некоторыми проблемами при попытке пропустить ненужные кадры. Я попробовал два метода, которые оба довольно медленные.

Фрагмент кода метода 1: Проблема в том, что я все еще читаю каждый кадр видео. Только каждый 4-й кадр проходит через мою модель.

  cap = cv2.VideoCapture(self.video)    
    while cap.isOpened():
                    success, frame = cap.read()

                    if count % 4 !=0:
                        count += 1
                        continue

                    if success:
                        ''Run frame through models''
                    else:
                        break

Фрагмент кода метода 2: Этот метод медленнее. Я пытаюсь избежать чтения ненужных кадров в этом случае.

cap = cv2.VideoCapture(video)
count=0

while True:

    if count % 4 != 0:
        cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
        count+=1
        success, frame = cap.read()

Буду очень признателен за любые советы о том, как добиться этого наиболее эффективным способом.

Ответы [ 3 ]

0 голосов
/ 03 ноября 2018

Получение и установка кадров путем изменения CV_CAP_PROP_POS_FRAMES не точны (и медленны) из-за того, как работает сжатие видео: с использованием ключевых кадров.

Это может помочь вообще не использовать функцию read (). Вместо этого используйте grab () и извлекайте () только необходимые кадры. Из документации : Методы / функции (для чтения) объединяют VideoCapture :: grab () и VideoCapture :: retrieve () в одном вызове.

grab () получает данные кадра, а retrieve () декодирует их (вычислительно тяжелая часть). Вам может потребоваться только захватывать кадры, которые вы хотите пропустить, но не извлекать их.

В зависимости от вашей системы и сборки opencv, вы также можете использовать ffmpeg для декодирования видео с аппаратным ускорением.

0 голосов
/ 04 ноября 2018

Вместо того, чтобы устанавливать пороговое значение для количества кадров, которое заставит opencv обрабатывать ВСЕ кадры (что вы правильно указали, замедляет обработку видео), лучше использовать CAP_PROP_POS_MSEC link и разгрузить это обработка до cv2. Используя эту опцию, вы можете настроить cv2 на выборку 1 кадра каждую n-ю миллисекунду. Таким образом, установка subsample_rate=1000 в vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count * subsample_rate)) будет производить выборку 1 кадра каждую 1 секунду (так как 1000 миллисекунд равны 1 секунде). Надеюсь, это повысит скорость обработки вашего видео.

def extractImagesFromVideo(path_in, subsample_rate, path_out, saveImage, resize=(), debug=False):
    vidcap = cv2.VideoCapture(path_in)
    if not vidcap.isOpened():
        raise IOError

    if debug:
        length = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_COUNT))
        width  = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_WIDTH))
        height = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_HEIGHT))
        fps    = vidcap.get(cv2.cv2.CAP_PROP_FPS)
        print 'Length: %.2f | Width: %.2f | Height: %.2f | Fps: %.2f' % (length, width, height, fps)

    success, image = vidcap.read() #extract first frame.
    frame_count = 0
    while success:
        vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count*subsample_rate))
        success, image = vidcap.read()
        if saveImage and np.any(image):
            cv2.imwrite(os.path.join(path_out, "%s_%d.png" % (frame_count)), image)
        frame_count = frame_count + 1
    return frame_count
0 голосов
/ 02 ноября 2018

Как я понял, вы пытаетесь обработать каждый четвертый кадр. Вы используете условие:

if count % 4 != 0

, который вместо этого запускает 3 из 4 кадров (вы обрабатываете кадры 1, 2, 3, 5, 6, 7 и т. Д.)! Используйте противоположное:

if count % 4 == 0

Кроме того, хотя фрагменты кода, кажется, что два метода не обрабатывают одинаковые кадры. Хотя в обоих случаях ваш счетчик увеличивается на 1 в каждом кадре, вы фактически указываете на 15-кратный кадр этого счетчика во втором случае (cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15).

Некоторые комментарии к вашему коду (возможно, я что-то неправильно понял):

Дело 1:

while cap.isOpened():
                success, frame = cap.read()
                if count % 4 !=0:
                    count += 1
                    continue

здесь вы, кажется, считаете только некоторые кадры (3 из 4, как упоминалось), поскольку кадры, кратные 4, пропускаются: условие count % 4 !=0 в этом случае не выполняется, и ваш счетчик не обновляется, хотя вы читаете кадр , Итак, у вас здесь неточный счетчик. Не показано, как и где вы обрабатываете ваши кадры, чтобы судить об этой части.

Дело 2:

while True:
    if count % 4 != 0:
        cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
        count+=1
        success, frame = cap.read()

здесь вы читаете фреймы, только если условие выполнено, поэтому в этом фрагменте кода вы фактически не читаете ни одного фрейма, так как фрейм 0 не вызывает условие! Если вы обновите счетчик за пределами области действия if, это не ясно здесь. Но если вы делаете, вы также должны прочитать кадр там. Во всяком случае, нужно сказать больше кода, чтобы рассказать.

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

...