Python - Extrahieren und Speichern von Videobildern


132

Also habe ich dieses Tutorial befolgt, aber es scheint nichts zu tun. Einfach nichts. Es wartet einige Sekunden und schließt das Programm. Was ist los mit diesem Code?

import cv2
vidcap = cv2.VideoCapture('Compton.mp4')
success,image = vidcap.read()
count = 0
success = True
while success:
  success,image = vidcap.read()
  cv2.imwrite("frame%d.jpg" % count, image)     # save frame as JPEG file
  if cv2.waitKey(10) == 27:                     # exit if Escape is hit
      break
  count += 1

Auch in den Kommentaren heißt es, dass dies die Frames auf 1000 begrenzt? Warum?

EDIT: Ich habe es success = Truezuerst versucht, aber das hat nicht geholfen. Es wurde nur ein Bild mit 0 Byte erstellt.


1
Was ist der Wert von success?
101

2
Was ist der Wert ? Der Typ kann boolesch sein, aber ist es Trueoder False?
That1Guy

1
Ja, aber was ist Ihr Wert? Es könnte falsch sein. In diesem Fall würde Ihr Programm einfach "einige Sekunden warten und schließen". Mit anderen Worten, fügen Sie print successirgendwo ein hinzu.
101

1
Es macht keinen Sinn zu zwingen success; Wenn es falsch ist, bedeutet dies, dass das Lesen des Videos aus irgendeinem Grund fehlgeschlagen ist. Sie müssen das Bit zuerst zum Laufen bringen.
101

1
Ihr Readh schlägt fehl. Haben Sie opencv mit Python und ffmpeg erstellt, wie im Tutorial beschrieben? brew install opencv --python27 --ffmpegWenn Sie eine andere Version von Python verwenden, müssen Sie diese in Ihre Version ändern.
Knells

Antworten:


225

Laden Sie dieses Video von hier herunter, damit wir dieselbe Videodatei für den Test haben. Stellen Sie sicher, dass sich diese mp4-Datei im selben Verzeichnis wie Ihr Python-Code befindet. Stellen Sie dann auch sicher, dass Sie den Python-Interpreter aus demselben Verzeichnis ausführen.

Ändern Sie dann den Code, ein Graben waitKey, der auch ohne Fenster Zeit verschwendet und die Tastaturereignisse nicht erfassen kann. Außerdem drucken wir den successWert, um sicherzustellen, dass die Frames erfolgreich gelesen werden.

import cv2
vidcap = cv2.VideoCapture('big_buck_bunny_720p_5mb.mp4')
success,image = vidcap.read()
count = 0
while success:
  cv2.imwrite("frame%d.jpg" % count, image)     # save frame as JPEG file      
  success,image = vidcap.read()
  print('Read a new frame: ', success)
  count += 1

Wie geht das


4
Das spart eine leere JPEG - Datei, und es gibtRead a new frame: False

3
Das bedeutet, dass opencv das Video nicht lesen kann. Höchstwahrscheinlich kann es nicht auf ffmpeg zugreifen. Welches Betriebssystem verwenden Sie?
Feuerwehrmann


3
Google die Anweisungen für Ihre spezifische Version von opencv und befolgen Sie genau, wie Sie ffmpeg und opencv-python unter Windows zum Laufen bringen.
Feuerwehrmann

3
Also habe ich diese Frage benutzt, um mein Problem mit der Kompatibilität zu lösen. Ich musste die DLL in opencv_ffmpeg300.dll umbenennen (da die Python-Installation von OpenCV2 3.0.0 war). Ich habe es in mein Python-Verzeichnis gelegt (C: \ Python27). Ich musste weder die Windows-Version von ffmpeg noch opencv installieren, aber ich brauchte die mit OpenCV gelieferte DLL, aber danach habe ich den Rest von OpenCV gelöscht. Wie auch immer, ich werde dies als Antwort auswählen, aber jeder, der dies liest, muss über diese ESSENTIAL DLL Bescheid wissen.

37

Um diese Frage (& Antwort von @ user2700065) für etwas andere Fälle zu erweitern, wenn jemand nicht jeden Frame extrahieren möchte, sondern Frame jede Sekunde extrahieren möchte. Ein 1-minütiges Video liefert also 60 Bilder.

import sys
import argparse

import cv2
print(cv2.__version__)

def extractImages(pathIn, pathOut):
    count = 0
    vidcap = cv2.VideoCapture(pathIn)
    success,image = vidcap.read()
    success = True
    while success:
        vidcap.set(cv2.CAP_PROP_POS_MSEC,(count*1000))    # added this line 
        success,image = vidcap.read()
        print ('Read a new frame: ', success)
        cv2.imwrite( pathOut + "\\frame%d.jpg" % count, image)     # save frame as JPEG file
        count = count + 1

if __name__=="__main__":
    a = argparse.ArgumentParser()
    a.add_argument("--pathIn", help="path to video")
    a.add_argument("--pathOut", help="path to images")
    args = a.parse_args()
    print(args)
    extractImages(args.pathIn, args.pathOut)

Ich benutze opencv-2.4.9, also anstatt cv2.CAP_PROP_POS_MSECich musstecv2.cv.CAP_PROP_POS_MSEC
Pratik Kumar

1
Wie ändere ich den Code, wenn ich alle 5 Sekunden Frames haben möchte?
Soumya Boral

1
@ SoumyaBoralcount = count + 5
Bhushan Babar

@ BhushanBabar sollte es cv2.imwrite()am Anfang der Schleife keine geben, da Sie cv2.imread()vor der Schleife aufgerufen haben?
mLstudent33

@ mLstudent33 Entschuldigung, verstehe nicht, bitte erläutern Sie.
Bhushan Babar

12

Dies ist eine Optimierung der vorherigen Antwort für Python 3.x von @GShocked. Ich würde sie im Kommentar veröffentlichen, habe aber nicht genug Ruf

import sys
import argparse

import cv2
print(cv2.__version__)

def extractImages(pathIn, pathOut):
    vidcap = cv2.VideoCapture(pathIn)
    success,image = vidcap.read()
    count = 0
    success = True
    while success:
      success,image = vidcap.read()
      print ('Read a new frame: ', success)
      cv2.imwrite( pathOut + "\\frame%d.jpg" % count, image)     # save frame as JPEG file
      count += 1

if __name__=="__main__":
    print("aba")
    a = argparse.ArgumentParser()
    a.add_argument("--pathIn", help="path to video")
    a.add_argument("--pathOut", help="path to images")
    args = a.parse_args()
    print(args)
    extractImages(args.pathIn, args.pathOut)

11

Dies ist eine Funktion, mit der die meisten Videoformate in die Anzahl der im Video enthaltenen Frames konvertiert werden. Es funktioniert weiter Python3mitOpenCV 3+

import cv2
import time
import os

def video_to_frames(input_loc, output_loc):
    """Function to extract frames from input video file
    and save them as separate frames in an output directory.
    Args:
        input_loc: Input video file.
        output_loc: Output directory to save the frames.
    Returns:
        None
    """
    try:
        os.mkdir(output_loc)
    except OSError:
        pass
    # Log the time
    time_start = time.time()
    # Start capturing the feed
    cap = cv2.VideoCapture(input_loc)
    # Find the number of frames
    video_length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - 1
    print ("Number of frames: ", video_length)
    count = 0
    print ("Converting video..\n")
    # Start converting the video
    while cap.isOpened():
        # Extract the frame
        ret, frame = cap.read()
        # Write the results back to output location.
        cv2.imwrite(output_loc + "/%#05d.jpg" % (count+1), frame)
        count = count + 1
        # If there are no more frames left
        if (count > (video_length-1)):
            # Log the time again
            time_end = time.time()
            # Release the feed
            cap.release()
            # Print stats
            print ("Done extracting frames.\n%d frames extracted" % count)
            print ("It took %d seconds forconversion." % (time_end-time_start))
            break

if __name__=="__main__":

    input_loc = '/path/to/video/00009.MTS'
    output_loc = '/path/to/output/frames/'
    video_to_frames(input_loc, output_loc)

Es unterstützt .mtsund normale Dateien wie .mp4und .avi. Versucht und getestet auf .mtsDateien. Klappt wunderbar.


8

Nach vielen Recherchen zum Konvertieren von Frames in Videos habe ich diese Funktion erstellt. Ich hoffe, dies hilft. Dafür benötigen wir opencv:

import cv2
import numpy as np
import os

def frames_to_video(inputpath,outputpath,fps):
   image_array = []
   files = [f for f in os.listdir(inputpath) if isfile(join(inputpath, f))]
   files.sort(key = lambda x: int(x[5:-4]))
   for i in range(len(files)):
       img = cv2.imread(inputpath + files[i])
       size =  (img.shape[1],img.shape[0])
       img = cv2.resize(img,size)
       image_array.append(img)
   fourcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')
   out = cv2.VideoWriter(outputpath,fourcc, fps, size)
   for i in range(len(image_array)):
       out.write(image_array[i])
   out.release()


inputpath = 'folder path'
outpath =  'video file path/video.mp4'
fps = 29
frames_to_video(inputpath,outpath,fps)

Ändern Sie den Wert von fps (Frames pro Sekunde), den Eingabeordnerpfad und den Ausgabeordnerpfad entsprechend Ihren lokalen Speicherorten


files.sort (key = lambda x: int (x [5: -4])) HINZUFÜGEN DER OBEN GENANNTEN LINIE, um die Frames nach der Nummer und nicht nach der Zeichenfolge zu sortieren, z. B.: Anfangs folgte frame1.jpg frame10.jpg nicht frame2.jpg, die obige Zeile sortiert die Dateien nach den darin enthaltenen Nummern.
Puja Sharma

3
Die Frage war vom Video zum Bild
Santhosh Dhaipule Chandrakanth

Ich habe das Video aus irgendeinem Grund nicht für mich
gespeichert

7

Die vorherigen Antworten haben den ersten Frame verloren. Und es wird schön sein, die Bilder in einem Ordner zu speichern.

# create a folder to store extracted images
import os
folder = 'test'  
os.mkdir(folder)
# use opencv to do the job
import cv2
print(cv2.__version__)  # my version is 3.1.0
vidcap = cv2.VideoCapture('test_video.mp4')
count = 0
while True:
    success,image = vidcap.read()
    if not success:
        break
    cv2.imwrite(os.path.join(folder,"frame{:d}.jpg".format(count)), image)     # save frame as JPEG file
    count += 1
print("{} images are extacted in {}.".format(count,folder))

Übrigens können Sie die Framerate per VLC überprüfen . Gehen Sie zu Windows -> Medieninformationen -> Codec-Details


Gibt es eine Möglichkeit, die Bildrate während der Extraktion zu erhöhen?
Pratik Khadloya

Nein. Wenn ein Video erstellt wird, ist die Bildrate festgelegt. Mehr kann man nicht extrahieren.
Yuchao Jiang

Was für eine erstaunliche Antwort. Hat perfekt für mich funktioniert. Gibt es eine Möglichkeit, die Schleife im Code so zu optimieren, dass ich nur Frames aus einem bestimmten Bereich erhalte, z. B. Frame 120 - 160? Vielen Dank!
Bowen Liu

Mit der Variablenanzahl können Sie die Frames angeben, die Sie extrahieren möchten.
Yuchao Jiang

Was muss ich tun, wenn ich aus dem Video 15 Bilder extrahieren möchte, die zeitlich gleich weit vom Videoanfang bis zum Videoende positioniert sind? Ich habe herausgefunden, dass ich verwenden muss cv.CAP_PROP_POS_AVI_RATIO, aber ich weiß nicht wie. tnx
NeStack

7

Dieser Code extrahiert Frames aus dem Video und speichert die Frames im JPG-Format

import cv2
import numpy as np
import os

# set video file path of input video with name and extension
vid = cv2.VideoCapture('VideoPath')


if not os.path.exists('images'):
    os.makedirs('images')

#for frame identity
index = 0
while(True):
    # Extract images
    ret, frame = vid.read()
    # end of frames
    if not ret: 
        break
    # Saves images
    name = './images/frame' + str(index) + '.jpg'
    print ('Creating...' + name)
    cv2.imwrite(name, frame)

    # next frame
    index += 1

4

Ich verwende Python über die Spyder-Software von Anaconda. Unter Verwendung des Originalcodes, der in der Frage dieses Threads von @Gshocked aufgeführt ist, funktioniert der Code nicht (der Python liest die mp4-Datei nicht). Also habe ich OpenCV 3.2 heruntergeladen und "opencv_ffmpeg320.dll" und "opencv_ffmpeg320_64.dll" aus dem Ordner "bin" kopiert. Ich habe diese beiden DLL-Dateien in Anacondas Ordner "DLLs" eingefügt.

Anaconda hat auch einen "pckgs" -Ordner ... Ich habe den gesamten "OpenCV 3.2" -Ordner, den ich heruntergeladen habe, kopiert und in den Anaconda-Ordner "pckgs" eingefügt.

Schließlich hat Anaconda einen Ordner "Library", der einen Unterordner "bin" enthält. Ich habe die Dateien "opencv_ffmpeg320.dll" und "opencv_ffmpeg320_64.dll" in diesen Ordner eingefügt.

Nach dem Schließen und Neustarten von Spyder funktionierte der Code. Ich bin mir nicht sicher, welche der drei Methoden funktioniert hat, und ich bin zu faul, um zurück zu gehen und es herauszufinden. Aber es funktioniert so, Prost!


4

Diese Funktion extrahiert Bilder aus Videos mit 1 fps. Außerdem identifiziert sie das letzte Bild und hört auch auf zu lesen:

import cv2
import numpy as np

def extract_image_one_fps(video_source_path):

    vidcap = cv2.VideoCapture(video_source_path)
    count = 0
    success = True
    while success:
      vidcap.set(cv2.CAP_PROP_POS_MSEC,(count*1000))      
      success,image = vidcap.read()

      ## Stop when last frame is identified
      image_last = cv2.imread("frame{}.png".format(count-1))
      if np.array_equal(image,image_last):
          break

      cv2.imwrite("frame%d.png" % count, image)     # save frame as PNG file
      print '{}.sec reading a new frame: {} '.format(count,success)
      count += 1

0

Das folgende Skript extrahiert alle halbe Sekunde Frames aller Videos im Ordner. (Funktioniert mit Python 3.7)

import cv2
import os
listing = os.listdir(r'D:/Images/AllVideos')
count=1
for vid in listing:
    vid = r"D:/Images/AllVideos/"+vid
    vidcap = cv2.VideoCapture(vid)
    def getFrame(sec):
        vidcap.set(cv2.CAP_PROP_POS_MSEC,sec*1000)
        hasFrames,image = vidcap.read()
        if hasFrames:
            cv2.imwrite("D:/Images/Frames/image"+str(count)+".jpg", image) # Save frame as JPG file
        return hasFrames
    sec = 0
    frameRate = 0.5 # Change this number to 1 for each 1 second
    
    success = getFrame(sec)
    while success:
        count = count + 1
        sec = sec + frameRate
        sec = round(sec, 2)
        success = getFrame(sec)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.