Algèbre linéaire et traitement des images

PROLONGEMENT : RÉALISATION D'UN CLIP VIDÉO

Étienne Coutant, Olivier Nocent, Frédéric Blanchard

Canon Cine Projector P-777, selector

Difficulté : *

Dans cette activité nous allons voir comment créer des vidéos, image par image. Nous allons réaliser un clip vidéo en enchaînant les effets, et les traitements.

1 Préparation

Vous aurez besoin d'une installation python 3, d'un éditeur et de ffmpeg. Il vous faudra aussi les modules numpy et matplotlib. Dans un terminal saisissez les instructions suivantes :

python3 -m pip install matplotlib
python3 -m pip install numpy

Nous aurons besoin de deux répertoires locaux :

import os

try:
   os.mkdir('input')
except:
    print('Le répertoire existe déjà')
try:
   os.mkdir('output')
except:
    print('Le répertoire existe déjà')

Vous pouvez ensuite placer les images initiales dans le répertoire input (ici, par leurs urls) :

import urllib.request

urllib.request.urlretrieve("https://iut-info.univ-reims.fr/users/coutant/img/solo-256px.png", "input/solo-256px.png")
urllib.request.urlretrieve("https://iut-info.univ-reims.fr/users/coutant/img/logo-starwars-256px.png", "input/logo-starwars-256px.png")

Voilà, les préparatifs sont faits. Vous pouvez, si vous le souhaitez, placer toutes ces instructions dans un script prepare.py :

#!/usr/bin/env python3
# encoding: utf8

import os, urllib.request

if __name__== "__main__":
    
    try:
       os.mkdir('input')
    except:
        print('Le répertoire existe déjà')
    try:
       os.mkdir('output')
    except:
        print('Le répertoire existe déjà')

    urllib.request.urlretrieve("https://iut-info.univ-reims.fr/users/coutant/img/solo-256px.png", "input/solo-256px.png")
    urllib.request.urlretrieve("https://iut-info.univ-reims.fr/users/coutant/img/logo-starwars-256px.png", "input/logo-starwars-256px.png")

2 Création des images puis de la video

On va maintenant enchaîner les traitements et générer une image à chaque étape. Les trois exemples qui suivent vont permettre de mieux comprendre le principe. Dans le premier, une rotation est réalisée sur une image. Chaque image de la séquence correspond à une rotation de l'image de départ, avec un angle différent dans le second, on déplace on conserve cette rotation, mais le centre de la rotation est modifié à chaque image. Enfin dans le troisième exemple, on modifie, en plus des changements précédents, la teinte de chaque image.

D'abord on importe les modules dont on a besoin.

import matplotlib.pyplot as plt
import numpy as np
from math import *

Ensuite, l'image dont on va se servir.

img = plt.imread("./input/solo-256px.png")

Maintenant nous allons générer les images une par une. Dans ce premier exemple, nous allons appliquer à notre image une rotation d'angle a en faisant varier a entre 0 et 2.\pi.

Si on souhaite générer 100 images, l'angle a va augmenter par pas de \frac{2.\pi}{100}, de 0 jusque 2.\pi (pour ces deux valeurs, l'image transformée est identique à l'image d'origine).

a = 0.0
nb_img = 100
centeri = floor(len(img) / 2)
centerj = floor(len(img[0]) / 2)
for i in range(nb_img):
    res = smartrotate(img, centeri, centerj, a)
    a += 2 * pi / nb_img
    plt.imsave(f"output/output{i:05}.png",res)
plt.imsave(f"output/output{nb_img:05}.png",img)

On peut alors construire la vidéo à partir des images générées :

import os

os.system('ffmpeg -framerate 5 -r 25 -i output/output%05d.png -pix_fmt yuv420p video1.mp4')

On obtient alors la vidéo suivante : video 1

Attention

N'oubliez pas de vider le dossier output après avoir généré la video.

0

On va maintenant modifier un peu la génération des images en faisant varier le centre de la rotation.

a = 0.0
nb_img = 100
centeri = 50 
centerj = 50
for i in range(nb_img):
    res = smartrotate(img, centeri, centerj, a)
    a += 2 * pi / nb_img
    centeri += 1
    centerj += 1
    plt.imsave(f"output/output{i:05}.png",res)
plt.imsave(f"output/output{nb_img:05}.png",img)
os.system('ffmpeg -framerate 5 -r 25 -i output/output%05d.png -pix_fmt yuv420p video2.mp4')
0

On obtient la vidéo suivante : video 2

Enfin, en plus de ces transformations, changeons maintenant la teinte de l'image :

a = 0.0
nb_img = 100
centeri = 50 
centerj = 50
for i in range(nb_img):
    res = colorize(smartrotate(img, centeri, centerj, a), a * 360 / (2*pi))
    a += 2 * pi / nb_img
    centeri += 1
    centerj += 1
    plt.imsave(f"output/output{i:05}.png",res)
plt.imsave(f"output/output{nb_img:05}.png",img)
os.system('ffmpeg -framerate 5 -r 25 -i output/output%05d.png -pix_fmt yuv420p video3.mp4')
0

On obtient la vidéo suivante : video 3

3 Exemple

Ce dernier exemple propose un mix progressif de deux images, avec des rotations.

# Lecture des images de départ

img1 = plt.imread("./input/solo-256px.png")
img2 = plt.imread("./input/logo-starwars-256px.png")
num = 1

factor = 0.0
angle = 0.0

for i in range(0, 50):
    factor += 0.02
    angle += 0.031416
    res = smartrotate(mix(img1, img2, factor),128,128,angle)
    plt.imsave(f"output/output{num:05}.png",res)
    num += 1

for i in range(0, 50):
    factor -= 0.02
    angle -= 0.031416
    res = smartrotate(mix(img1, img2, factor),128,128,angle)
    plt.imsave(f"output/output{num:05}.png",res)
    num += 1

factor = 0.0
angle = 0.0

for i in range(0, 50):
    factor += 0.02
    angle += 0.031416
    res = mix(smartrotate(img1,128,128,angle),smartrotate(img2,128,128,-angle), factor)
    plt.imsave(f"output/output{num:05}.png",res)
    num += 1

for i in range(0, 50):
    factor -= 0.02
    angle -= 0.031416
    res = mix(smartrotate(img1,128,128,angle),smartrotate(img2,128,128,-angle), factor)
    plt.imsave(f"output/output{num:05}.png",res)
    num += 1
import os

os.system('ffmpeg -r 20 -i output/output%05d.png -c:v libvpx-vp9 -b:v 2M video4.mp4')
0

Et on obtient finalement la vidéo suivante : video 4

4 À vous de jouer

Maintenant, c'est à vous de jouer :