Comment Extraire Une Image Dans Une Video Avec Python

Télécharger au format odt, pdf ou txt
Télécharger au format odt, pdf ou txt
Vous êtes sur la page 1sur 8

5 hours ago

Open options

Comment extraire des images d'une vidéo en Python


Comme vous le savez peut-être déjà, une vidéo est constituée d'une série
d'images. Ces images sont appelées images et sont lues en continu une par
une à une certaine vitesse qui sera reconnue comme un mouvement par
l'œil humain.

Dans ce didacticiel, vous apprendrez deux méthodes d'extraction d'images


à partir de fichiers vidéo en Python. Tout d'abord, nous verrons comment
nous pouvons le faire avec la célèbre bibliothèque OpenCV . Après cela,
nous explorerons l'autre méthode d'extraction d'images à l'aide de
la bibliothèque MoviePy.

Pour commencer, installons les bibliothèques :

$ pip install python-opencv moviepy

Méthode 1 : Extraction de cadres à l'aide d'OpenCV

Je vais créer un extract_frames_opencv.pyfichier et importer les modules


nécessaires :

from datetime import timedelta


import cv2
import numpy as np
import os

Étant donné que toutes les vidéos n'ont pas la même longueur et le
même FPS , nous allons définir un paramètre pour ajuster le nombre
d'images que nous voulons extraire et enregistrer par seconde :

# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
SAVING_FRAMES_PER_SECOND = 10
Nous utiliserons ce paramètre sur les deux méthodes. Par exemple, s'il est
défini sur 10 pour le moment, il n'enregistrera que 10 images par seconde
de la vidéo, même si le FPS vidéo est disons 24. Si la vidéo a une durée de
30 secondes, alors 300 images seront enregistrées au total. . Vous pouvez
également définir ce paramètre sur 0,5, ce qui économisera une image
toutes les 2 secondes, et ainsi de suite.

Ensuite, définissons deux fonctions d'assistance :

def format_timedelta(td):
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
omitting microseconds and retaining milliseconds"""
result = str(td)
try:
result, ms = result.split(".")
except ValueError:
return result + ".00".replace(":", "-")
ms = int(ms)
ms = round(ms / 1e4)
return f"{result}.{ms:02}".replace(":", "-")

def get_saving_frames_durations(cap, saving_fps):


"""A function that returns the list of durations where to save the frames"""
s = []
# get the clip duration by dividing number of frames by the number of frames per second
clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
# use np.arange() to make floating-point steps
for i in np.arange(0, clip_duration, 1 / saving_fps):
s.append(i)
return s

La format_timedelta()fonction accepte un objet timedelta et renvoie une belle


représentation sous forme de chaîne avec des millisecondes et en omettant
les microsecondes.

La get_saving_frames_durations()fonction accepte l' VideoCaptureobjet d'OpenCV


et le paramètre de sauvegarde dont nous avons parlé plus tôt et renvoie
une liste de points de durée sur lesquels nous devons enregistrer les
images.

Maintenant que nous avons ces fonctions d'assistance, définissons la


fonction principale et expliquons-la :

def main(video_file):
filename, _ = os.path.splitext(video_file)
filename += "-opencv"
# make a folder by the name of the video file
if not os.path.isdir(filename):
os.mkdir(filename)
# read the video file
cap = cv2.VideoCapture(video_file)
# get the FPS of the video
fps = cap.get(cv2.CAP_PROP_FPS)
# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
saving_frames_per_second = min(fps, SAVING_FRAMES_PER_SECOND)
# get the list of duration spots to save
saving_frames_durations = get_saving_frames_durations(cap, saving_frames_per_second)
# start the loop
count = 0
while True:
is_read, frame = cap.read()
if not is_read:
# break out of the loop if there are no frames to read
break
# get the duration by dividing the frame count by the FPS
frame_duration = count / fps
try:
# get the earliest duration to save
closest_duration = saving_frames_durations[0]
except IndexError:
# the list is empty, all duration frames were saved
break
if frame_duration >= closest_duration:
# if closest duration is less than or equals the frame duration,
# then save the frame
frame_duration_formatted = format_timedelta(timedelta(seconds=frame_duration))
cv2.imwrite(os.path.join(filename, f"frame{frame_duration_formatted}.jpg"), frame)
# drop the duration spot from the list, since this duration spot is already saved
try:
saving_frames_durations.pop(0)
except IndexError:
pass
# increment the frame count
count += 1

La fonction ci-dessus semble compliquée, mais ce n'est pas le cas, voici ce


que nous faisons :

 Tout d'abord, nous créons la variable de nom de fichier qui est


le nom du dossier dans lequel nous allons créer et enregistrer nos
cadres, nous l'ajoutons "-opencv"juste pour distinguer les
méthodes, mais vous pouvez le supprimer.
 Ensuite, nous créons le dossier en utilisant la os.mkdir()fonction
s'il n'est pas déjà créé.
 Après cela, nous lisons le fichier vidéo à l'aide
de cv2.VideoCapture, et récupérons le FPS à l'aide de
la cap.get()méthode et passons le code pour FPS, qui
est cv2.CAP_PROP_FPS.

 Nous définissons l'enregistrement d'images par seconde au


minimum du FPS vidéo réel et de notre paramètre. Nous nous
assurons donc que nous ne pouvons pas contourner un fps
d'économie plus élevé que les fps vidéo réels.
 Après avoir obtenu les durées d'enregistrement, nous entrons
dans la boucle de lecture des images et nous n'enregistrons que
lorsque nous sommes sûrs que la durée est dans
notre saving_frames_durationsliste. Nous sauvegardons le cadre à
l'aide de cv2.imwrite(), et définissons le nom du cadre sur la durée
réelle.

Définition du code principal :


if __name__ == "__main__":
import sys
video_file = sys.argv[1]
main(video_file)

Puisque nous transmettons le fichier vidéo à l'aide d'arguments de ligne de


commande, exécutons-le :

$ python extract_frames_opencv.py zoo.mp4

Après l'exécution de la commande ci-dessus, un nouveau dossier "zoo-


opencv"est créé et c'est ce qui y est inclus :

Comme vous pouvez le voir, les images sont enregistrées avec l'horodatage
dans le nom du fichier.

Méthode 2 : Extraction d'images à l'aide de MoviePy

Dans cette méthode, nous n'allons pas utiliser OpenCV, mais avec une autre
bibliothèque appelée MoviePy, je vais créer un fichier
appelé extract_frames_moviepy.pyet importer les modules nécessaires :

from moviepy.editor import VideoFileClip


import numpy as np
import os
from datetime import timedelta

Comme dans la première méthode, nous utiliserons également


le SAVING_FRAMES_PER_SECONDparamètre ici :

# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
SAVING_FRAMES_PER_SECOND = 10

Référez-vous à la première section de ce tutoriel pour savoir ce que cela


signifie exactement. Comme précédemment, nous avons également besoin
de la format_timedelta()fonction :
def format_timedelta(td):
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
omitting microseconds and retaining milliseconds"""
result = str(td)
try:
result, ms = result.split(".")
except ValueError:
return result + ".00".replace(":", "-")
ms = int(ms)
ms = round(ms / 1e4)
return f"{result}.{ms:02}".replace(":", "-")

Passons maintenant à la fonction principale :

def main(video_file):
# load the video clip
video_clip = VideoFileClip(video_file)
# make a folder by the name of the video file
filename, _ = os.path.splitext(video_file)
filename += "-moviepy"
if not os.path.isdir(filename):
os.mkdir(filename)

# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
saving_frames_per_second = min(video_clip.fps, SAVING_FRAMES_PER_SECOND)
# if SAVING_FRAMES_PER_SECOND is set to 0, step is 1/fps, else
1/SAVING_FRAMES_PER_SECOND
step = 1 / video_clip.fps if saving_frames_per_second == 0 else 1 / saving_frames_per_second
# iterate over each possible frame
for current_duration in np.arange(0, video_clip.duration, step):
# format the file name and save it
frame_duration_formatted = format_timedelta(timedelta(seconds=current_duration)).replace(":", "-")
frame_filename = os.path.join(filename, f"frame{frame_duration_formatted}.jpg")
# save the frame with the current duration
video_clip.save_frame(frame_filename, current_duration)

Comme vous l'avez peut-être déjà remarqué, cette méthode nécessite


moins de code. Tout d'abord, nous chargeons notre clip vidéo à l'aide de
la VideoFileClip()classe, nous créons notre dossier et nous nous assurons
que le fps enregistré est inférieur ou égal au fps vidéo.

Nous définissons ensuite notre pas de bouclage, qui est de 1 divisé par le
fps d'enregistrement, si nous définissons le SAVING_FRAMES_PER_SECONDà 10, alors
le pas serait de 0,1 (c'est-à-dire l'enregistrement d'une image toutes les 0,1
secondes).

La différence ici est que l' VideoFileClipobjet a la save_frame()méthode, qui


accepte deux arguments : le nom de fichier de l'image et la durée de
l'image que vous souhaitez enregistrer. Donc, ce que nous avons fait, c'est
boucler en utilisant np.arange()(version à virgule flottante de
la range()fonction régulière ) pour prendre des mesures sur chaque image
que nous voulons, et appeler la save_frame()méthode en conséquence.

Voici le code principal :

if __name__ == "__main__":
import sys
video_file = sys.argv[1]
main(video_file)

Testons-le :

$ python extract_frames_moviepy.py zoo.mp4

Après quelques secondes, le zoo-moviepydossier est créé et les images ont été
enregistrées dans ce dossier.

Conclusion

Après avoir utilisé les deux méthodes dans mon cas, je remarque que la
première méthode (utilisant OpenCV) est plus rapide en termes de temps
d'exécution mais enregistre des images plus grandes que MoviePy.

Dans le cas de cette vidéo de démonstration, la taille de 190 images était de


2,8 Mo en utilisant la deuxième méthode (en utilisant MoviePy) et de 5,46
Mo en utilisant OpenCV. Cependant, la durée de la méthode MoviePy était
de 2,3 secondes, alors que l'OpenCV prenait environ 0,6 seconde.

Ceci étant dit, j'ai mis entre vos mains deux méthodes d'extraction d'images
de vidéos en Python, à vous de choisir quelle méthode vous convient le
mieux.

Vous aimerez peut-être aussi