Python - Extraction et enregistrement de cadres vidéo


135

J'ai donc suivi ce tutoriel mais il ne semble rien faire. Rien du tout. Il attend quelques secondes et ferme le programme. Quel est le problème avec ce 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

En outre, dans les commentaires, il est dit que cela limite les images à 1000? Pourquoi?

EDIT: J'ai essayé de faire d' success = Trueabord mais cela n'a pas aidé. Il n'a créé qu'une seule image de 0 octet.


1
Quelle est la valeur de success?
101

2
Quelle est la valeur ? Le type peut être booléen, mais est-ce Trueou False?
That1Guy

1
Oui, mais quelle est votre valeur? Il peut être faux, auquel cas votre programme "attendra quelques secondes et se fermera". En d'autres termes, ajoutez un print successquelque part.
101

1
Cela n'a pas de sens de forcer success; si c'est faux, cela signifie que la lecture de la vidéo a échoué pour une raison quelconque. Vous devez d'abord faire fonctionner ce petit morceau.
101

1
Votre lecture échoue. Avez-vous construit opencv avec python et ffmpeg comme indiqué dans le didacticiel? brew install opencv --python27 --ffmpegsi vous utilisez une version différente de Python, vous devrez la changer pour votre version.
Knells

Réponses:


228

De là, téléchargez cette vidéo afin que nous ayons le même fichier vidéo pour le test. Assurez-vous d'avoir ce fichier mp4 dans le même répertoire de votre code python. Ensuite, assurez-vous également d'exécuter l'interpréteur python à partir du même répertoire.

Puis modifiez le code, fossé waitKeyqui perd du temps également sans fenêtre, il ne peut pas capturer les événements du clavier. Nous imprimons également la successvaleur pour nous assurer qu'elle lit correctement les images.

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

Comment ça se passe?


4
Cela permet d' économiser un fichier vide jpeg, et il retourneRead a new frame: False

3
Cela signifie qu'opencv ne peut pas lire la vidéo. Très probablement, il ne peut pas accéder à ffmpeg. quel système d'exploitation utilisez-vous?
fireant


3
Google les instructions pour votre version spécifique d'opencv et suivez précisément comment faire fonctionner ffmpeg et opencv-python sous Windows.
fireant

3
J'ai donc utilisé cette question pour résoudre mon problème de compatibilité. J'ai dû renommer la DLL en opencv_ffmpeg300.dll (car l'installation Python d'OpenCV2 était 3.0.0). Je l'ai placé dans mon répertoire Python (C: \ Python27). Je n'avais pas besoin d'installer la version Windows de ffmpeg ni d'opencv, mais j'avais besoin de la DLL fournie avec OpenCV, mais j'ai supprimé le reste d'OpenCV après cela. Quoi qu'il en soit, je vais sélectionner ceci comme réponse, mais quiconque lit ceci doit connaître cette DLL ESSENTIELLE.

37

Pour prolonger cette question (& réponse par @ user2700065) pour un cas légèrement différent, si quelqu'un ne veut pas extraire chaque image mais veut extraire une image toutes les secondes. Ainsi, une vidéo d'une minute donnera 60 images (images).

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)

J'utilise opencv-2.4.9, donc au lieu de cv2.CAP_PROP_POS_MSECje devais utilisercv2.cv.CAP_PROP_POS_MSEC
Pratik Kumar

1
Comment changer le code si je veux des images toutes les 5 secondes?
Soumya Boral

1
@SoumyaBoralcount = count + 5
Bhushan Babar

@BhushanBabar ne devrait-il pas y avoir un cv2.imwrite()au début de la boucle puisque vous avez appelé cv2.imread()avant la boucle?
mLstudent33

@ mLstudent33 désolé, ne vous comprenez pas, veuillez préciser.
Bhushan Babar

12

Ceci est un ajustement de la réponse précédente pour python 3.x de @GShocked, je le posterais dans le commentaire, mais je n'ai pas assez de réputation

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

C'est une fonction qui convertira la plupart des formats vidéo en nombre d'images présentes dans la vidéo. Cela fonctionne Python3avecOpenCV 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)

Il prend en charge .mtset les fichiers normaux comme .mp4et .avi. Essayé et testé sur des .mtsfichiers. Fonctionne comme un charme.


8

Après de nombreuses recherches sur la façon de convertir des images en vidéo, j'ai créé cette fonction, j'espère que cela vous aidera. Nous avons besoin d'opencv pour cela:

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)

changer la valeur de fps (images par seconde), le chemin du dossier d'entrée et le chemin du dossier de sortie en fonction de vos propres emplacements locaux


files.sort (key = lambda x: int (x [5: -4])) AJOUT DE LA LIGNE CI-DESSUS qui permet de trier les cadres en fonction du nombre et non de la chaîne par exemple: initialement frame1.jpg était suivi de frame10.jpg pas frame2.jpg, la ligne ci-dessus trie les fichiers en fonction des numéros qu'ils contiennent.
Puja Sharma

3
La question était de vidéo en image
Santhosh Dhaipule Chandrakanth

ne pas enregistrer la vidéo pour moi pour une raison quelconque
Raksha

7

Les réponses précédentes ont perdu la première image. Et ce sera bien de stocker les images dans un dossier.

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

À propos, vous pouvez vérifier le taux de trame par VLC. Allez dans Windows -> informations sur les médias -> détails du codec


Existe-t-il un moyen d'augmenter la fréquence d'images lors de l'extraction?
Pratik Khadloya

Non. Lorsqu'une vidéo est réalisée, la fréquence d'images est fixe. Vous ne pouvez pas extraire plus que cela.
Yuchao Jiang

Quelle réponse incroyable. A parfaitement fonctionné pour moi. Y aurait-il un moyen de modifier la boucle dans le code afin que je n'obtienne que des images d'une certaine plage, comme les images 120 - 160? Merci!
Bowen Liu le

Vous pouvez utiliser la variable count pour spécifier les images que vous souhaitez extraire.
Yuchao Jiang

que dois-je faire si je veux extraire de la vidéo, disons 15 images qui sont positionnées à équidistance dans le temps du début à la fin de la vidéo? J'ai découvert que je devais utiliser cv.CAP_PROP_POS_AVI_RATIO, mais je ne sais pas comment. tnx
NeStack

7

Ce code extrait les images de la vidéo et enregistre les images au format .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

J'utilise Python via le logiciel Spyder d'Anaconda. En utilisant le code original listé dans la question de ce fil par @Gshocked, le code ne fonctionne pas (le python ne lira pas le fichier mp4). J'ai donc téléchargé OpenCV 3.2 et copié "opencv_ffmpeg320.dll" et "opencv_ffmpeg320_64.dll" à partir du dossier "bin". J'ai collé ces deux fichiers dll dans le dossier "Dlls" d'Anaconda.

Anaconda a aussi un dossier "pckgs" ... J'ai copié et collé le dossier "OpenCV 3.2" entier que j'ai téléchargé dans le dossier "pckgs" d'Anaconda.

Enfin, Anaconda a un dossier "Library" qui a un sous-dossier "bin". J'ai collé les fichiers «opencv_ffmpeg320.dll» et «opencv_ffmpeg320_64.dll» dans ce dossier.

Après avoir fermé et redémarré Spyder, le code a fonctionné. Je ne sais pas laquelle des trois méthodes a fonctionné, et je suis trop paresseux pour revenir en arrière et le comprendre. Mais ça marche, bravo!


4

Cette fonction extrait les images de la vidéo avec 1 fps, EN PLUS, elle identifie la dernière image et arrête également la lecture:

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

Le script suivant extraira les images toutes les demi-secondes de toutes les vidéos du dossier. (Fonctionne sur 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)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.