Як дізнатися загальну кількість фреймів у файлі з cv2 у python


80

Як дізнатися загальну кількість фреймів у файлі (.avi) через Python за допомогою відкритого модуля cv.

Якщо можливо, яку всю інформацію (роздільна здатність, fps, тривалість тощо) ми можемо отримати з відеофайлу за допомогою цього.

Відповіді:


120

У новішій версії OpenCV (я використовую 3.1.0) це працює так:

import cv2

cap = cv2.VideoCapture("video.mp4")
length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print( length )

І подібне для інших властивостей відео cv2.CAP_PROP_*


3
Об'єкт 'module' не має атрибута 'CAP_PROP_FRAME_COUNT'
Джон Ктеджік,

1
Ви впевнені, що використовуєте OpenCV версії 3+? Я щойно перевірив версію 3.3.1 і все ще працює.
fev8

Будь-яка ідея, в чому складність cap.get()?

Я протестував це зараз, для мене він працює також із відеофайлами .avi. Зараз я використовую версію 4.0.1-dev на машині Ubuntu 18.04. Ви впевнені, що ваш відеофайл не зламаний?
phev8

Або, як натякали на це деякі інші коментатори, це залежить від того, що знаходиться у вашому контейнері avi ... Мабуть, іноді він просто недоступний - ви можете спробувати використовувати інший кодер для вашого відеофайлу.
fev8,

40
import cv2

cap = cv2.VideoCapture(fn)

if not cap.isOpened(): 
    print "could not open :",fn
    return

length = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))
width  = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT))
fps    = cap.get(cv2.cv.CV_CAP_PROP_FPS)

дивіться тут для отримання додаткової інформації.

Крім того, все це з достатньою кількістю солі, не всі ці реквізити є обов’язковими, деякі можуть бути недоступні з вашим захопленням / відеокодеком


1
CAP_PROP_FRAME_COUNT дає 0 значень, ось код імпорту cv2 # - - кодування: utf-8 - - ім'я файлу = "test.avi" cap = cv2.VideoCapture (ім'я файлу) fps = cap.get (cv2.cv.CV_CAP_PROP_FPS) print 'fps =' + str (fps) Frames = cap.get (cv2.cv.CV_CAP_PROP_FRAME_COUNT) print 'Frames =' + str (Frames) Чи можете ви сказати, де я роблю неправильно?
Niraj

ви, мабуть, не робите нічого поганого. знову ж таки, avi - це просто контейнер, в ньому може бути що завгодно , і деякі кодеки просто не підтримують запити певних властивостей.
берак

Привіт Берак, Вибачте за пізній повтор, будь ласка, дайте мені ще трохи натяку на це.
Niraj

14

Ось як це працює з Python 3.6.5 (на Anaconda) та OpenCV 3.4.2. [Примітка]: Вам потрібно вилучити "CV_" з "CV_CAP_PROP_xx" для будь-якого майна, як вказано на офіційному веб-сайті OpenCV .

import cv2
cap = cv2.VideoCapture("video.mp4")
property_id = int(cv2.CAP_PROP_FRAME_COUNT) 
length = int(cv2.VideoCapture.get(cap, property_id))
print( length )

2
Це чудово! Ви також можете отримати за допомогоюlength = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
Scratch'N'Purr

10

Існує два методи визначення кількості кадрів у відеофайлі

  • Спосіб №1: Використовуйте вбудовані властивості OpenCV для доступу до метаданих відеофайлів, які є швидкого та ефективного але неточних
  • Спосіб №2: Проведіть вручну кожен кадр у відеофайлі за допомогою лічильника, який є повільним та неефективним, але точним

Метод №1 швидкий і покладається на функціональність властивостей відео OpenCV, яка майже миттєво визначає кількість кадрів у відеофайлі. Однак існує компроміс з точністю, оскільки він залежить від версій OpenCV та відеокодеків. З іншого боку, підрахунок кожного кадру вручну буде 100% точним, хоча і буде значно повільнішим. Ось функція, яка намагається виконати метод №1 за замовчуванням, якщо вона не вдається, вона автоматично використовуватиме метод №2

def frame_count(video_path, manual=False):
    def manual_count(handler):
        frames = 0
        while True:
            status, frame = handler.read()
            if not status:
                break
            frames += 1
        return frames 

    cap = cv2.VideoCapture(video_path)
    # Slow, inefficient but 100% accurate method 
    if manual:
        frames = manual_count(cap)
    # Fast, efficient but inaccurate method
    else:
        try:
            frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        except:
            frames = manual_count(cap)
    cap.release()
    return frames

Тести

if __name__ == '__main__':
    import timeit
    import cv2

    start = timeit.default_timer()
    print('frames:', frame_count('fedex.mp4', manual=False))
    print(timeit.default_timer() - start, '(s)')

    start = timeit.default_timer()
    print('frames:', frame_count('fedex.mp4', manual=True))
    print(timeit.default_timer() - start, '(s)')

Результати методу №1

frames: 3671
0.018054921 (s)

Результати методу №2

frames: 3521
9.447095287 (s)

Зверніть увагу, що два методи відрізняються на 150 кадрів, а метод №2 значно повільніший, ніж метод №1 . Тому, якщо вам потрібна швидкість, але ви бажаєте пожертвувати точністю, використовуйте метод No1. У ситуаціях, коли у вас все добре із затримкою, але вам потрібна точна кількість кадрів, використовуйте метод No2


4

Іншим рішенням, яке не залежить від інколи помилкових помилок, CV_CAP_PROPє обхід всього вашого відеофайлу в циклі

  • Збільшуйте змінну лічильника кадрів щоразу, коли зустрічається дійсний кадр, і зупиняйтеся, коли з’являється невірний (кінець відеофайлу).
  • Збір інформації про роздільну здатність є складнішим, оскільки деякі кодеки підтримують змінну роздільну здатність (подібно до VBR в аудіофайлах, де бітрейт не є константою, а натомість охоплює певний заздалегідь визначений діапазон).

    • постійна роздільна здатність - для визначення роздільної здатності всього відеофайлу вам потрібен лише перший кадр, у цьому випадку обхід повного відео не потрібен
    • змінна роздільна здатність - вам потрібно отримати роздільну здатність кожного окремого кадру (ширина та висота) і розрахувати середнє значення, щоб отримати середню роздільну здатність відео
  • FPS можна розрахувати, проте тут у вас така ж проблема, як і з роздільною здатністю - константа (CFR) проти змінної (VFR). Це більше проблема мульти-потоків omho. Особисто я б використовував лічильник кадрів, який збільшувався після кожного дійсного кадру, тоді як з інтервалом в 1 секунду таймер (що працює у фоновому потоці) запускав би збереження поточного значення лічильника, а потім його скидання. Ви можете зберігати значення у списку, щоб підрахувати середню / постійну частоту кадрів в кінці, коли ви також будете знати загальну кількість кадрів у відео.

Недоліком цього досить спрощеного способу здійснення є те, що вам доведеться пройти весь файл, який - у випадку, якщо це триватиме кілька годин - обов’язково буде помітний користувачеві. У цьому випадку ви можете бути розумними і робити це у фоновому режимі, дозволяючи користувачеві робити щось інше, поки ваша програма збирає цю інформацію про завантажений відеофайл.

Перевага полягає в тому, що незалежно від того, який відеофайл у вас є, якщо OpenCV може з нього читати, ви отримаєте досить точні результати, на відміну від тих, CV_CAP_PROPякі можуть працювати, а можуть і не працювати, як ви очікуєте.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.