Как узнать общее количество кадров в файле (.avi) через Python с помощью открытого модуля cv.
Если возможно, что вся информация (разрешение, fps, продолжительность и т.д.) мы можем получить через видеофайл.
Как узнать общее количество кадров в файле (.avi) через Python с помощью открытого модуля cv.
Если возможно, что вся информация (разрешение, fps, продолжительность и т.д.) мы можем получить через видеофайл.
С новой версией 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_*
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)
см. здесь для получения дополнительной информации.
также, все это с зерном соли, не все эти реквизиты являются обязательными, некоторые могут быть недоступны с вашим кодеком захвата/видео
Вот как это работает с Python 3.6.5 (на Anaconda) и OpenCV 3.4.2. [Примечание]: вам нужно удалить "CV_" из "CV_CAP_PROP_xx" для любого свойства, указанного на официальном сайте OpenCV website.
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 )
Другое решение, не зависящее от иногда багги CV_CAP_PROP
, состоит в том, чтобы пересечь весь ваш видеофайл в цикле
Сбор информации о разрешении сложнее, потому что некоторые кодеки поддерживают разрешение переменной (аналогично VBR в аудиофайлах, где бит-бит не является константой, а вместо этого охватывает некоторый предопределенный диапазон).
FPS можно рассчитать, но здесь у вас есть та же проблема, что и с константой разрешения - константы (CFR) и переменной (VFR). Это скорее проблема чересстрочной резьбы omho. Лично я использовал бы счетчик кадров, который увеличивался после каждого действительного кадра, а с интервалом в 1 секунду таймер (работает в фоновом потоке) запускал бы сохранение текущего значения счетчика и затем его сброс. Вы можете сохранить значения в списке, чтобы рассчитать среднюю/постоянную частоту кадров в конце, когда вы также узнаете общее количество кадров, которые есть в видео.
Недостатком этого довольно упрощенного способа делать вещи является то, что вам нужно пройти весь файл, который - в случае его нескольких часов - определенно будет заметен пользователем. В этом случае вы можете быть в курсе и делать это в фоновом режиме, позволяя пользователю делать что-то еще, пока ваше приложение собирает эту информацию о загруженном видеофайле.
Преимущество заключается в том, что независимо от того, какой видеофайл у вас есть, пока OpenCV может читать из него, вы получите довольно точные результаты, в отличие от CV_CAP_PROP
, которые могут работать или не работать так, как вы ожидаете.
Существует два метода определения количества кадров в видеофайле
Метод № 1 быстрый и основан на функциональных возможностях видео OpenCV video property functionality, которые почти мгновенно определяют количество кадров в видеофайле. Тем не менее, существует компромисс между точностью, поскольку он зависит от версий 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. Поэтому, если вам нужна скорость, но вы готовы пожертвовать точностью, используйте метод № 1. В ситуациях, когда у вас все хорошо с задержкой, но нужно точное количество кадров, используйте метод № 2