2015-04-18 12 views
17

Desidero applicare una funzione scikit-image (in particolare la funzione di corrispondenza modello match_template) ai frame di un video mp4, codifica h264. È importante che la mia applicazione tenga traccia del tempo di ciascun fotogramma, ma conosco il framerate in modo che possa facilmente calcolare dal numero di fotogramma.Come leggere il video mp4 per essere elaborato da scikit-image?

prega di notare che sono in esecuzione a basso risorse, e vorrei mantenere le dipendenze sottile come possibile: numpy è necessario in ogni caso, e dal momento che ho intenzione di usare scikit-image, vorrei evitare di importare (e la compilazione) openCV solo per leggere il video.

Vedo in fondo alla pagina this che scikit-image può elaborare seamleassly il video memorizzato come un array numpy, ottenendo che sarebbe quindi l'ideale.

+0

Beh, ho provato OpenCV mentre lo sviluppo di un prototipo della mia applicazione su PC. Ma dato che distribuirò l'app su raspberry pi, sto valutando alternative più leggere, considerando anche lo sforzo e le dipendenze per compilare opencv su raspi. – gaggio

+3

Vedere anche [questa panoramica] (https://github.com/danielballan/scikit-image/blob/video-guide/doc/source/user_guide/video.txt) che stiamo preparando per la guida dell'utente. –

+0

@StefanvanderWalt: La panoramica è davvero molto utile, grazie. Potrebbe essere migliorato aggiungendo 'imageio', che risolve anche il problema dell'accesso a un numero di fotogramma specifico menzionato anche nella revisione. – gaggio

risposta

35

Imageio pacchetto python dovrebbe fare quello che vuoi. Ecco un frammento Python usando questo pacchetto:

import pylab 
import imageio 
filename = '/tmp/file.mp4' 
vid = imageio.get_reader(filename, 'ffmpeg') 
nums = [10, 287] 
for num in nums: 
    image = vid.get_data(num) 
    fig = pylab.figure() 
    fig.suptitle('image #{}'.format(num), fontsize=20) 
    pylab.imshow(image) 
pylab.show() 

enter image description here enter image description here

È inoltre possibile scorrere direttamente sopra le immagini del file (see the documentation):

for i, im in enumerate(vid): 
    print('Mean of frame %i is %1.1f' % (i, im.mean())) 

Per installare ImageIO è possibile utilizzare pip:

pip install imageio 

Un'altra soluzione sarebbe quella di utilizzare moviepy (che utilizza un codice simile per leggere il video), ma penso che imageio sia più leggero e faccia il lavoro.


risposta al primo commento

Al fine di verificare se il frame rate nominale è la stessa su tutto il file, è possibile contare il numero di frame nella iteratore:

count = 0 
try: 
    for _ in vid: 
     count += 1 
except RuntimeError: 
    print('something went wront in iterating, maybee wrong fps number') 
finally: 
    print('number of frames counted {}, number of frames in metada {}'.format(count, vid.get_meta_data()['nframes'])) 


In [10]: something went wront in iterating, maybee wrong fps number 
     number of frames counted 454, number of frames in metada 461 

per visualizzare il timestamp di ciascun frame:

try: 
    for num, image in enumerate(vid.iter_data()): 
     if num % int(vid._meta['fps']): 
      continue 
     else: 
      fig = pylab.figure() 
      pylab.imshow(image) 
      timestamp = float(num)/ vid.get_meta_data()['fps'] 
      print(timestamp) 
      fig.suptitle('image #{}, timestamp={}'.format(num, timestamp), fontsize=20) 
      pylab.show() 
except RuntimeError: 
    print('something went wrong') 
+0

Grazie per il link e l'esempio utili. Ciò che viene lasciato fuori da questo è solo il tempo corrispondente a ciascun fotogramma. Darò il via, il tempo potrebbe essere nei metadati del fotogramma, altrimenti deve essere calcolato dal numero di fotogramma, che va bene supponendo che il framerate nominale sia mantenuto correttamente durante la registrazione video. – gaggio

+0

Buona domanda, e su alcuni video il framerate nominale non viene mantenuto correttamente. Per controllarlo è possibile contare il numero di fotogrammi nell'iteratore e confrontarlo con il numero di fotogrammi nei metadati, se sono uguali è possibile calcolare il timestamp di ciascun fotogramma in base a frame_number/fps_rate. Ho aggiornato la mia risposta per confrontare i due numeri. – head7

+1

Questo funziona bene per me. Grazie mille. IMO molto più amichevole di ffmpeg/avconv/opencv/scikit-video. Vorrei averlo scoperto prima. – rd11

16

Si potrebbe utilizzare scikit-video, in questo modo:

from skvideo.io import VideoCapture 

cap = VideoCapture(filename) 
cap.open() 

while True: 
    retval, image = cap.read() 
    # image is a numpy array containing the next frame 
    # do something with image here 
    if not retval: 
     break 

Questo utilizza avconv o ffmpeg sotto il cofano. Le prestazioni sono abbastanza buone, con un piccolo overhead per spostare i dati in python rispetto alla semplice decodifica del video in avconv.

Il vantaggio di scikit-video è che l'API è esattamente la stessa dell'API di lettura/scrittura video di OpenCV; basta sostituire cv2.VideoCapture con skvideo.io.VideoCapture.