Ermitteln der Gesamtzahl der Frames in einer Datei mit cv2 in Python

77

Ermitteln der Gesamtzahl der Frames in einer Datei (.avi) über Python mithilfe des Open-CV-Moduls.

Wenn möglich, welche Informationen (Auflösung, fps, Dauer usw.) wir von einer Videodatei dadurch erhalten können.

Niraj
quelle

Antworten:

114

Mit einer neueren OpenCV-Version (ich verwende 3.1.0) funktioniert es folgendermaßen:

import cv2

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

Ähnliches gilt für andere Videoeigenschaften cv2.CAP_PROP_*

phev8
quelle
3
Das 'Modul'-Objekt hat kein Attribut' CAP_PROP_FRAME_COUNT '
John Ktejik
1
Sind Sie sicher, dass Sie OpenCV Version 3+ verwenden? Ich habe gerade mit Version 3.3.1 getestet und funktioniert immer noch.
Phev8
Irgendeine Idee, wie komplex das ist cap.get()?
Ich habe es gerade getestet, für mich funktioniert es auch mit .avi-Videodateien. Im Moment verwende ich Version 4.0.1-dev auf einem Ubuntu 18.04-Computer. Bist du sicher, dass deine Videodatei nicht kaputt ist?
Phev8
Oder wie einige andere Kommentatoren hier angedeutet haben, hängt es davon ab, was sich in Ihrem AVI-Container befindet ... Anscheinend ist es manchmal einfach nicht verfügbar - Sie könnten versuchen, einen anderen Encoder für Ihre Videodatei zu verwenden.
Phev8
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)

siehe hier für weitere Informationen.

Auch alles mit einem Körnchen Salz, nicht alle diese Requisiten sind obligatorisch, einige sind möglicherweise nicht mit Ihrem Capture / Video-Codec verfügbar

berak
quelle
1
CAP_PROP_FRAME_COUNT gibt 0 Werte an. Hier ist der Codeimport cv2 # - - Kodierung: utf-8 - - Dateiname = "test.avi" cap = cv2.VideoCapture (Dateiname) 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) Kannst du sagen, wo ich falsch mache?
Niraj
Sie machen wahrscheinlich nichts falsch. Auch hier ist avi nur ein Container, möglicherweise befindet sich etwas darin, und einige Codecs unterstützen das Abfragen bestimmter Eigenschaften einfach nicht.
Berak
Hallo berak, Entschuldigung für die späte Wiederholung, kannst du mir bitte ein bisschen mehr Hinweise dazu geben?
Niraj
12

So funktioniert es mit Python 3.6.5 (unter Anaconda) und OpenCV 3.4.2. [Hinweis]: Sie müssen das "CV_" aus dem "CV_CAP_PROP_xx" für jede Eigenschaft löschen, die auf der offiziellen OpenCV- Website angegeben ist .

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 )
MGLondon
quelle
2
Das ist toll! Sie können auch mitlength = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
Scratch'N'Purr
9

Es gibt zwei Methoden, um die Anzahl der Frames in einer Videodatei zu bestimmen

  • Methode 1: Verwenden Sie integrierte OpenCV-Eigenschaften, um auf Metadaten zu Videodateien zuzugreifen, die schnell und effizient, aber ungenau sind
  • Methode 2: Manuelles Durchlaufen jedes Frames in der Videodatei mit einem Zähler, der langsam und ineffizient, aber genau ist

Methode 1 ist schnell und relys auf OpenCV der Video Eigenschaft Funktionalität , die fast augenblicklich die Anzahl der Frames in einer Videodatei bestimmt. Es gibt jedoch einen Kompromiss bei der Genauigkeit, da dieser von Ihren OpenCV- und Video-Codec-Versionen abhängt. Andererseits ist das manuelle Zählen jedes Frames 100% genau, obwohl es erheblich langsamer ist. Hier ist eine Funktion, die standardmäßig versucht, Methode 1 auszuführen. Wenn dies fehlschlägt, wird automatisch Methode 2 verwendet

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

Benchmarks

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)')

Ergebnisse von Methode 1

frames: 3671
0.018054921 (s)

Ergebnisse von Methode 2

frames: 3521
9.447095287 (s)

Beachten Sie, dass sich die beiden Methoden um 150 Frames unterscheiden und Methode 2 erheblich langsamer ist als Methode 1 . Verwenden Sie daher Methode 1, wenn Sie Geschwindigkeit benötigen, aber bereit sind, auf Genauigkeit zu verzichten. Verwenden Sie in Situationen, in denen Sie eine Verzögerung haben, aber die genaue Anzahl der Frames benötigen, Methode 2

nathancy
quelle
4

Eine andere Lösung, die nicht von den manchmal fehlerhaften CV_CAP_PROPGettern abhängt, besteht darin, Ihre gesamte Videodatei in einer Schleife zu durchlaufen

  • Erhöhen Sie einen Frame-Zähler Zählervariable jedes Mal, wenn ein gültiger Frame gefunden wird, und stoppen Sie, wenn ein ungültiger Frame auftritt (Ende der Videodatei).
  • Das Sammeln von Informationen über die Auflösung ist schwieriger, da einige Codecs eine variable Auflösung unterstützen (ähnlich wie bei VBR in Audiodateien, bei denen die Bitrate keine Konstante ist, sondern einen vordefinierten Bereich abdeckt).

    • Konstante Auflösung - In diesem Fall benötigen Sie nur das erste Bild, um die Auflösung der gesamten Videodatei zu bestimmen, sodass das Durchlaufen des gesamten Videos nicht erforderlich ist
    • Variable Auflösung - Sie müssen die Auflösung jedes einzelnen Frames (Breite und Höhe) ermitteln und einen Durchschnitt berechnen, um die durchschnittliche Auflösung des Videos zu erhalten
  • FPS kann berechnet werden, aber hier haben Sie das gleiche Problem wie bei der Auflösung - Konstante (CFR) vs Variable (VFR). Dies ist eher ein Multithreading-Problem omho. Persönlich würde ich einen Frame-Zähler verwenden, der nach jedem gültigen Frame erhöht wird, während in einem Intervall von 1 Sekunde ein Timer (der in einem Hintergrund-Thread ausgeführt wird) das Speichern des aktuellen Zählerwerts und das anschließende Zurücksetzen auslöst. Sie können die Werte in einer Liste speichern, um die durchschnittliche / konstante Bildrate am Ende zu berechnen, wenn Sie auch die Gesamtzahl der Bilder im Video kennen.

Der Nachteil dieser eher simplen Vorgehensweise besteht darin, dass Sie die gesamte Datei durchlaufen müssen, was - falls sie mehrere Stunden lang ist - vom Benutzer definitiv bemerkt wird. In diesem Fall können Sie klug sein und dies in einem Hintergrundprozess tun, während der Benutzer etwas anderes tun kann, während Ihre Anwendung diese Informationen über die geladene Videodatei sammelt.

Der Vorteil ist, dass Sie unabhängig davon, welche Videodatei Sie haben, solange OpenCV daraus lesen kann, ziemlich genaue Ergebnisse erhalten, im Gegensatz zu CV_CAP_PROPdenen, die möglicherweise so funktionieren oder nicht, wie Sie es erwarten.

rbaleksandar
quelle