Ce notebook est une accrétion optionnelle, extraite de la conclusion de 01-1-Video-Operations-Basics pour rendre la lane principale plus claire. Il reprend intégralement le challenge qui figurait en fin du 01-1, sans modification du fond ni de la forme. Les étudiants qui veulent transformer les manipulations moviepy/imageio du 01-1 en produit livrable trouvent ici le terrain de jeu ; les autres passent directement au 01-2.
Contexte pédagogique
Le 01-1 a posé les fondamentaux :
Section 1 : création d’une vidéo de test à partir de frames générées avec PIL (Image.new, ImageDraw) et assemblage avec imageio.get_writer().append_data().
Sections 2-4 : manipulations moviepy (trim, concaténation, overlay texte), sonde ffmpeg-python, extraction rapide de frames avec decord.
Le challenge ci-dessous remet ces primitives au service d’un livrable fini : un slideshow 5 secondes @ 1 FPS avec cinq messages sur cinq fonds colorés différents. C’est la transition entre « savoir manipuler une vidéo » et « savoir produire un objet vidéo autonome ».
Prérequis
Avoir complété (ou parcouru) le notebook 01-1.
Packages : Pillow, imageio, imageio-ffmpeg (déjà listés dans requirements-video.txt à la racine de GenAI/).
FFmpeg installé sur le système (winget install FFmpeg ou apt install ffmpeg).
CHALLENGE BONUS - Générateur de Slideshow Vidéo
Points : 0.5 pts
Objectif
Créer une vidéo slideshow à partir de frames générées programmatiquement.
Ce que vous avez appris
La Section 1 montre: - Génération de frames avec PIL (Image.new, ImageDraw) - Assemblage avec imageio (get_writer, append_data)
Critères de succes
Frame 1: “Bienvenue”
Frame 2: “Voici le sujet”
Frame 3: “Point important”
Frame 4: “Conclusion”
Frame 5: “Merci”
Une couleur de fond différente (gradient ou palette cohérente)
Le texte centré
Contraintes techniques
Résolution: 640x480
Utiliser PIL pour les frames, imageio pour l’assemblage
FPS = 1 signifie chaque frame dure 1 seconde
Soumission : PR avec titre “Challenge #7 - [Votre Nom]”, aperçu des frames et vidéo générée
Espace de travail du challenge
Le challenge ci-dessus était resté sans endroit où répondre : ce notebook ajoute l’espace de travail. Deux exemples guidés rappellent les primitives posées dans 01-1 (une frame PIL centrée, un mini assemblage imageio) ; trois exercices portent le livrable complet. Tout tourne sur CPU (VRAM 0, conformément à l’en-tête) : Pillow pour les frames, imageio + imageio-ffmpeg (binaire ffmpeg embarqué) pour l’assemblage. Les artefacts sont écrits dans outputs/video_01_1b_slideshow/ (non versionné).
Exemple guidé 1 — Une frame PIL : fond coloré, message centré
La brique de base du slideshow. La fonction frame_demo crée une image RGB 640x480, remplit le fond, puis centre le texte en calculant sa boîte englobante :
Frame exemple sauvegardee : outputs\video_01_1b_slideshow\frame_demo.png ((640, 480))
Exemple guidé 2 — Mini assemblage : 2 frames @ 1 FPS
Le montage minimal : à 1 FPS, chaque frame dure une seconde. Deux frames donnent donc une vidéo de 2 secondes — le livrable du challenge est la même mécanique répétée 5 fois :
import numpy as npimport imageio.v2 as imageioframes_exemple = [ frame_demo("Demo A", (40, 60, 120)), frame_demo("Demo B", (120, 60, 40)),]video_exemple = OUTPUT_DIR /"mini_slideshow_exemple.mp4"with imageio.get_writer(video_exemple, fps=1) as writer:for f in frames_exemple: writer.append_data(np.asarray(f))print(f"Video exemple : {video_exemple.name} ({video_exemple.stat().st_size} octets, "f"{len(frames_exemple)} frames @ 1 FPS = {len(frames_exemple)} s)")
Video exemple : mini_slideshow_exemple.mp4 (2340 octets, 2 frames @ 1 FPS = 2 s)
Exercice 1 — Les 5 frames du challenge
Produire la liste des 5 frames imposées par les critères de succès : une par message, chacune sur un fond distinct (palette cohérente de votre choix), texte centré, résolution 640x480. Réutiliser frame_demo en variant la couleur, ou généraliser si vous préférez un dégradé.
# Exercice 1 (a completer) : les 5 frames du challengeMESSAGES = ["Bienvenue", "Voici le sujet", "Point important", "Conclusion", "Merci"]# TODO Etudiant : construire frames_challenge = liste de 5 PIL Images (640x480),# une par message de MESSAGES, chaque frame sur une couleur de fond distincte# (palette coherente), texte centre.frames_challenge =None# TODO etudiant : liste de 5 PIL.Imageprint("Exercice 1 a completer :",Noneif frames_challenge isNoneelsef"{len(frames_challenge)} frames generees")
Exercice 1 a completer : None
Exercice 2 — L’assemblage : 5 secondes @ 1 FPS
Assembler frames_challenge en vidéo slideshow 5 s @ 1 FPS (5 frames, une seconde chacune), exactement comme la vidéo exemple, et sauvegarder dans OUTPUT_DIR sous le nom slideshow_5s.mp4.
# Exercice 2 (a completer) : assembler le livrable video# TODO Etudiant : ecrire frames_challenge dans OUTPUT_DIR / 'slideshow_5s.mp4'# via imageio.get_writer(..., fps=1), comme la video exemple.video_challenge =None# TODO etudiant : Path du fichier slideshow_5s.mp4 produitprint("Exercice 2 a completer :", video_challenge)
Exercice 2 a completer : None
Exercice 3 — Vérifier le livrable
Un livrable se vérifie avant de se soumettre. Contrôler que slideshow_5s.mp4 existe, que sa taille est non nulle, et que ses métadonnées coïrent avec l’attendu : 5 frames, durée 5 secondes. Indices : imageio.get_reader(...) expose count_frames() et get_meta_data() (clés fps, duration).
# Exercice 3 (a completer) : verification du livrable# TODO Etudiant : construire verdict_livrable = {"existe": bool, "nframes": int|None,# "duree_s": float|None, "ok": bool} pour slideshow_5s.mp4, ou ok = existe ET# nframes == 5 ET duree_s == 5.0 (a tolerance pres).verdict_livrable =None# TODO etudiantprint("Exercice 3 a completer :", verdict_livrable)