Python - Estrazione e salvataggio di fotogrammi video


134

Quindi ho seguito questo tutorial ma non sembra fare nulla. Semplicemente niente. Attende alcuni secondi e chiude il programma. Cosa c'è di sbagliato in questo codice?

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

Inoltre nei commenti si dice che questo limita i frame a 1000? Perché?

EDIT: ho provato a fare success = Trueprima ma non ha aiutato. Ha creato solo un'immagine che era di 0 byte.


1
Qual è il valore di success?
101

2
Qual è il valore ? Il tipo può essere booleano, ma è Trueo False?
That1Guy

1
Sì, ma qual è il tuo valore? Potrebbe essere falso, nel qual caso il tuo programma dovrebbe semplicemente "attendere alcuni secondi e chiudere". In altre parole, aggiungi un file print successda qualche parte.
101

1
Non ha senso forzare success; se è falso, significa che la lettura del video non è riuscita per qualche motivo. Devi prima far funzionare quel bit.
101

1
Il tuo readh sta fallendo. Hai costruito opencv con python e ffmpeg come indicato nel tutorial? brew install opencv --python27 --ffmpegse stai usando una versione diversa di Python, dovrai cambiarla nella tua versione.
Knells

Risposte:


227

Da qui scarica questo video così avremo lo stesso file video per il test. Assicurati di avere quel file mp4 nella stessa directory del tuo codice Python. Quindi assicurati anche di eseguire l'interprete python dalla stessa directory.

Quindi modifica il codice, fosso waitKeyche fa perdere tempo anche senza finestra non può catturare gli eventi della tastiera. Inoltre stampiamo il successvalore per assicurarci che legga correttamente i frame.

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

Come va?


4
Questo salva un file jpeg vuoto e ritornaRead a new frame: False

3
Ciò significa che opencv non può leggere il video. Molto probabilmente non può accedere a ffmpeg. che sistema operativo stai usando?
fireant


3
Cerca su Google le istruzioni per la tua versione specifica di opencv e segui esattamente come far funzionare ffmpeg e opencv-python su Windows.
fireant

3
Quindi ho usato questa domanda per risolvere il mio problema con la compatibilità. Ho dovuto rinominare la DLL in opencv_ffmpeg300.dll (poiché l'installazione Python di OpenCV2 era 3.0.0). L'ho inserito nella mia directory Python (C: \ Python27). Non avevo bisogno di installare la versione per Windows di ffmpeg né opencv, ma avevo bisogno di quella DLL fornita con OpenCV, ma dopo ho cancellato il resto di OpenCV. Ad ogni modo, selezionerò questo come risposta, ma chiunque legga questo deve sapere di questa DLL ESSENZIALE.

37

Per estendere questa domanda (e risposta di @ user2700065) per casi leggermente diversi, se qualcuno non vuole estrarre ogni frame ma vuole estrarre frame ogni secondo. Quindi un video di 1 minuto darà 60 fotogrammi (immagini).

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)

Sto usando opencv-2.4.9, quindi invece di cv2.CAP_PROP_POS_MSECho dovuto usarecv2.cv.CAP_PROP_POS_MSEC
Pratik Kumar

1
Come cambiare il codice se voglio i frame ogni 5 secondi?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan Babar

@BhushanBabar non dovrebbe esserci un cv2.imwrite()all'inizio del ciclo dato che hai chiamato cv2.imread()prima del ciclo?
mLstudent33

@ mLstudent33 scusa, non capirti, per favore approfondisci.
Bhushan Babar

12

Questa è una modifica della risposta precedente per python 3.x da @GShocked, la pubblicherei nel commento, ma non ho abbastanza reputazione

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

Questa è la funzione che convertirà la maggior parte dei formati video nel numero di fotogrammi presenti nel video. FunzionaPython3 conOpenCV 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)

Supporta .mtse file normali come .mp4e .avi. Provato e testato su .mtsfile. Funziona come un fascino.


8

Dopo molte ricerche su come convertire i frame in video, ho creato questa funzione, spero che questo aiuti. Abbiamo bisogno di opencv per questo:

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)

modificare il valore di fps (fotogrammi al secondo), il percorso della cartella di input e il percorso della cartella di output in base alle proprie posizioni locali


files.sort (key = lambda x: int (x [5: -4])) AGGIUNTA DELLA RIGA SOPRA che aiuta a ordinare i frame in base al numero e non alla stringa es: inizialmente frame1.jpg era seguito da frame10.jpg non frame2.jpg, la riga sopra ordina i file in base ai numeri in essa contenuti.
Puja Sharma

3
La domanda era dal video al fotogramma
Santhosh Dhaipule Chandrakanth

non salvare il video per me per qualche motivo
Raksha

7

Le risposte precedenti hanno perso il primo frame. E sarà bello archiviare le immagini in una cartella.

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

A proposito, puoi controllare il frame rate di VLC. Vai a Windows -> Informazioni multimediali -> Dettagli codec


C'è un modo per aumentare il frame rate durante l'estrazione?
Pratik Khadloya

No. Quando viene realizzato un video, la frequenza dei fotogrammi è fissa. Non puoi estrarre più di quello.
Yuchao Jiang

Che risposta straordinaria. Ha funzionato perfettamente per me. Ci sarebbe un modo per modificare il loop nel codice in modo da ottenere solo frame da un certo intervallo, come frame 120-160? Grazie!
Bowen Liu

È possibile utilizzare la variabile count per specificare i frame che si desidera estrarre.
Yuchao Jiang

cosa devo fare se voglio estrarre dal video diciamo 15 frame che sono posizionati equidistanti nel tempo dall'inizio del video alla fine del video? Ho scoperto che devo usare cv.CAP_PROP_POS_AVI_RATIO, ma non so come. tnx
NeStack

7

Questo codice estrae i fotogrammi dal video e salva i fotogrammi in formato .jpg

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

Sto usando Python tramite il software Spyder di Anaconda. Utilizzando il codice originale elencato nella domanda di questo thread di @Gshocked, il codice non funziona (il python non leggerà il file mp4). Così ho scaricato OpenCV 3.2 e ho copiato "opencv_ffmpeg320.dll" e "opencv_ffmpeg320_64.dll" dalla cartella "bin". Ho incollato entrambi questi file dll nella cartella "Dlls" di Anaconda.

Anaconda ha anche una cartella "pckgs" ... Ho copiato e incollato l'intera cartella "OpenCV 3.2" che ho scaricato nella cartella "pckgs" di Anaconda.

Infine, Anaconda ha una cartella "Library" che ha una sottocartella "bin". Ho incollato i file "opencv_ffmpeg320.dll" e "opencv_ffmpeg320_64.dll" in quella cartella.

Dopo aver chiuso e riavviato Spyder, il codice ha funzionato. Non sono sicuro di quale dei tre metodi abbia funzionato e sono troppo pigro per tornare indietro e capirlo. Ma funziona così, salute!


4

Questa funzione estrae immagini dal video con 1 fps, INOLTRE identifica l'ultimo fotogramma e interrompe la lettura anche:

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

Lo script seguente estrarrà i frame ogni mezzo secondo di tutti i video nella cartella. (Funziona su 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.