Les manipulations expérimentées ici s'inspirent de la façon dont on
fabriquait autrefois les dessins animés :
- réalisation d'une succession de dessins (ici des images)
- création du film par enchaînement rapide de ces images (ici un fichier vidéo)
Le fait de procéder en deux temps permet d'isoler les difficultés.
Par exemple : une fois que l'on aura trouvé une manière de faire pratique et efficace pour
enchaîner les images, on pourra concentrer toute son attention sur la réalisation
de celles-ci.
Au début, j'ai commencé par créer les images une à une en utilisant gimp, ImageMagick...
Puis j'ai tenté d'automatiser à l'ide d'un script Bash.
La suite des tentatives s'est faite en remplaçant Bash par de petits programmes
en langage Python.
Un copain m'a suggéré le remplacement d'ImageMagick par la bibliothèque Pil.
Un autre d'utiliser Pygame.
Ce qui suit est le regroupement de mes notes (rapides), transmises initialement par mail à la liste Armada, avant qu'elles ne soient égarées ou que je n'oublie le contexte d'expérimentation.
Remarque méthodologique :
Comme chaque manipulation va générer un grand nombre d'images intermédiaires,
il est judicieux de se placer dans un répertoire vide.
Si l'on utilise une (ou plusieurs) image initiale
il est "astucieux" de lui choisir un format différent de celles que l'on va générer.
Par exemple image-initiale.png pour générer des images.jpg.
Consulter en ligne :
Quelques essais avec ImageMagick
1. Dans un répertoire, j'ai rangé une série d'images de dimensions et d'extensions identiques et je veux en faire une séquence vidéo.
- je me positionne dans le répertoire
- convert -delay 20 *.png animation.mpg
Cela va plus vite qu'à la souris :-)
2. Je veux découper dans image1 une portion qui sera sauvegardée dans image2.
convert image1.png -crop 200x120+100+100 image2.png
-crop pour couper
200x120 largeur et hauteur de l'image résultant de la découpe
+100+100 valeurs x et y définissant la coordonnée de l'origine de la découpe
ImageMagick et bash
Point de départ : une vidéo capturée sous Youtube.
1. Cette vidéo est transformée en une succession d'images au format .png
(pour faire vite j'ai utilisé EKD, ayant oublié la syntaxe en ligne de commande et voulant gagner du temps : la "manip" n'est pas "purement ligne de commande". !Arg...).
Le son n'est pas récupéré.
Exemple de la première image :
http://lerautal.lautre.net/journal/video/image_000000001.png
2. Un rectangle de 200 de large sur 120 de haut est découpé dans chacune
de ces images, à un point de coordonnée y= 80 et un x qui va varier
selon l=l+1 en passant d'une image à une autre
On utilise un script bash (pourri : je suis ignare en bash) que voici :
#!/bin/bash let "l=1" for i in *.png; do let "l=l+1" j="${i%.jpg}" convert "$j" "-crop" 200x120+$l+80 "$j.jpg" done
3. On a obtenu ainsi une suite d'image .jpg que l'on va fondre dans une séquence
vidéo par :
convert -delay 20 *.jpg animation.mpg
Le résultat, stupéfiant pour moi... :
http://lerautal.lautre.net/journal/video/animation.mpg
ImageMagick et autre chose que Bash = Python
La question était "comment lancer un appel à imagemagick,
(avec passage de paramètres bien-sûr), avec Python" ?
Voici une réponse qui paraît simple.
Elle fait appel à la bibliothèque "os" (en langage approximatif = qui permet
de lancer des commandes au système).
Voici un exemple de programme :
1-# -*- coding:Utf-8 -*- 2- import os 3- commande="convert image1.png -crop 200x120+100+100 coupe.png" 4- os.system(commande)
Commentaires (à partir des numéros de lignes) :
1- choix le la page de code = le texte source est en UTF-8
2- on demande l'accès à l'OS
3- création d'une variable qui contient le texte des la commande à passer
4- exécution de la commande.
Remarque : la chaîne qui contient la commande peut être constituée
par concaténations successives. Sous réserve de mettre tout cela dans une boucle,
on doit pouvoir faire la même chose (en mieux) qu'avec mon script bash.
Autre piste (merci xxx) : la librairie Python dédiée à l'image, appelée Pil.
La documentation en ligne est ici
http://www.pythonware.com/library/pil/handbook/index.htm
Un appel à http://translate.google.fr/# peut aider si votre anglais n'y est pas.
Ceci étant, la librairie pil permet de se passer d'imagemagick...
et je sors de mon propos initial.
Essai de zoom avec Python et ImageMagick
Donc voici un nouveau zoom dans le radeau de la Méduse.
http://lerautal.lautre.net/journal/video/resul.mp4
Le but de la manip était de tester la faisabilité d'appels répétés à imagemagick
via Python.
De ce point de vue, c'est réussi.
Quant au reste...
Voici le programme, d'un débutant en Python.
Commentaires :
La taille de l'image initiale est fixée à 600x400
La boucle de zoom s'arrêtera quand la largeur de l'image ne sera plus > 300
while larg>300:
Les nombres sont convertis en chaines :
nom=str(nb) sx=str(x)...
Je prends un nombre de 4 chiffres pour avoir des noms de fichiers
tels que 1111.jpg 1112.jpg 1113.jpg
J'augmente y de 3 quand x a été augmenté de 3 (par la fonction modulo) :
if x%3==0:
y=y+2
la conséquence est un effet de tremblements.
Code du programme :
# -*- coding:Utf-8 -*- import os larg,haut=600,400 x=y=0 nb=1111 nom=str(nb) slarg=str(larg) shaut=str(haut) sx=str(x) sy=str(y) commande="convert radeau.png -crop "+slarg+"x"+shaut+"+"+sx+"+"+sy+ " cible.jpg" os.system(commande)< commande2="convert cible.jpg -resize 300x200 -strip -quality 50 -interlace line "+nom+".jpg" os.system(commande2) while larg>300: x=x+1 if x%3==0: y=y+2 larg=larg-(x) haut=haut-(y) nb=nb+1 nom=str(nb) slarg=str(larg) shaut=str(haut) sx=str(x) sy=str(y) commande="convert radeau.png -crop "+slarg+"x"+shaut+"+"+sx+"+"+sy+ " cible.jpg" os.system(commande) commande2="convert cible.jpg -resize 300x200 -strip -quality 50 -interlace line "+nom+".jpg" os.system(commande2)
Balayage latéral avec Python et ImageMagick
Cette fois-ci, on déplace un rectangle qui a la hauteur de l'image.
On fait varier x = x+1.
Pas de sauts ici : les dimensions sont fixes et le "pas" est petit (1 pixel).
400 images cela donnait une plus grosse vidéo.
Afin d'accélérer le temps de chargement, le fichier a été ensuite réduit en dimension et
recodé en utilisant ffmpeg.
La syntaxe étant
ffmpeg -i travers.mpg -cropbottom qcif travers2.mp4
Le résultat est ici :
http://lerautal.lautre.net/journal/video/travers2.mp4
Le code Python, plus simple est ici.
Le code du programme :
# -*- coding:Utf-8 -*- import os larg=200 haut=400 x=y=0 nb=1111 nom=str(nb) slarg=str(larg) shaut=str(haut) sx=str(x) sy=str(y) commande="convert radeau.png -crop "+slarg+"x"+shaut+"+"+sx+"+"+sy+" "+nom+".jpg" os.system(commande) while x<400: x=x+1 nb=nb+1 nom=str(nb) sx=str(x) sy=str(y) commande="convert radeau.png -crop "+slarg+"x"+shaut+"+"+sx+"+"+sy+" "+nom+".jpg" os.system(commande)
Animation avec Python et Pil
J'ai utilisé deux images fournies ici :
http://nadiana.com/pil-tutorial-how-create-button-generator
Le résultat est ici :
http://lerautal.lautre.net/journal/video/papillon.mp4
L'image unique du papillon a été remplacée par deux images utilisées en alternance.
Le code du programme :
# -*- coding:Utf-8 -*- import Image nb=1111 nom=str(nb) i=-10 y=10 flower=Image.open('flower.png') papi1=Image.open('papi1.png') papi2=Image.open('papi2.png') flower=Image.open('flower.png') while i<128: fleur=flower.copy() y=y+1 test=i%2 if test==0: fleur.paste(papi1,(i,y),papi1) else: fleur.paste(papi2,(i,y),papi2) nomfich=str(nb)+".jpg" fleur.save(nomfich) nb=nb+1 i=i+5
Cela vaut ce que ça vaut : une animation comme on aimait en faire il y a 20 ans...
mais enregistrée dans un fichier mpeg
Avec plein de petits bouts on peut imaginer faire un petit film.
Ceci étant, on est loin de la réactivité de SDL ou du côté à la mode des animations Blender.
Ne nous leurons pas, donc...
Mise en évidence d'une portion d'image
L'idée est celle d'un parcours guidé dans une oeuvre d'art
pour attirer l'attention sur tel ou tel point jugé significatif.
Le test proposé ici permet d'obtenir une image avec un cadre conservé
en pleine luminosité alors que le reste de l'image est assombri.
Deux images de départ :
- la "belle" qui contient l'information qui va être mise en valeur
http://lerautal.lautre.net/journal/video/radeau1.png
- la "grise" qui est celle dans laquelle un "projecteur rectangulaire" va se déplacer
au fur et à mesure :
http://lerautal.lautre.net/journal/video/radeau2.png
Le programme suivant fait un découpage d'une zone "belle" pour la coller, à la bonne place, en zone "grise".
# -*- coding:Utf-8 -*- import Image nb=1111 nom=str(nb)+".jpg" box=(40,200,260,400) belle=Image.open('radeau1.png') grise=Image.open('radeau2.png') region=belle.crop(box) grise.paste(region,(40,200)) grise.save(nom)
Compte-tenu des information déjà rédigée, le code doit vous paraître compréhensible (sinon me demander des éclaircissement).
Le résultat est ici : http://lerautal.lautre.net/journal/video/1111.jpg
Il est peu spectaculaire.
Pourtant, le simple fait d'y parvenir ouvre la possibilité à plusieurs extensions.
Parmi lesquelles :
- déplacement progressif d'une zone à une autre (en changeant les coordonnées par programme)
- zoom dans une zone sombre pour obtenir en "pleine dimension" la zone "belle".
- succession d'images fixes permettant de réaliser un diaporama avec commentaires
sonores enregistrés (pour une expo ou une séquence didactique-tique -et élastic-tic :-))
Compte-tenu des maigres moyens mis en oeuvre...
Simuler le déplacement d'un train dans un paysage
Le point de départ a été un film célèbre des frères Lumière : http://www.youtube.com/watch?v=MsWYfb4uCzA
Après des essais laborieux et pas très convaincants, il a fallu reconnaître que la gestion du point de fuite (avec pour conséquence des calculs "trigonométriques") ne pouvait être éludée.
Un paysage simpliste mais contenant le tracé de lignes de fuite a été dessiné : http://lerautal.lautre.net/journal/video/paysage.png
Ensuite a été dessiné un véhicule géométrique, adaptaté à ce paysage : http://lerautal.lautre.net/journal/video/vehicule.png
Le programme utilise une fonction nouvelle : im.resize, qui permet de redimendionner l'image du "train" en fonction de sa position dans le paysage.
Ne voulant pas approfondir la gestion des variable locales/globales, j'ai utilisé des valeurs numériques à la place de variables. Ce n'est pas bien, je le sais.
A partir du schema suivant : http://lerautal.lautre.net/journal/video/distfuite.jpg Voici quelques explications, pour compenser :
Le paysage correspond au rectangle jaune (300x200).
L'image du train va aller successivement de la gauche (rectangle rouge)
vers la droite (point de fuite).
La distance au point de fuite est contenue dans la variable distfuite. Au départ,
elle vaut : largeur (300) +50+50 (voir dessin).
Le reste est affaire de "trigonométrie" élémentaire : rap1 et rap1 correspondent à la
tangente de deux triangles rectangles.
Pour éviter un trop grand nombre d'images, j'ai adopté un "pas" de 10
while x<340:
.... x=x+10
ce qui fait que le "film" saccade encore beaucoup.
http://lerautal.lautre.net/journal/video/train2.mp4
Quand j'en aurai le courage, je referai la manip avec une véritable image de train telle que celle-ci : http://lerautal.lautre.net/journal/video/train.png
Le code du programme :
# -*- coding:Utf-8 -*- import Image nb,x,y=2111,-50,0 nom=str(nb) h1=150 h2=50 distfuite=400 largeur,hauteur=50,200 rap1=150.0/400 rap2=50.0/400 def calcdistfuite(n): z=350-n return z def calcy(n): z=int(150-n) return z fond=Image.open('paysage.png') fondsv=fond.copy() train=Image.open('vehicule.png') while x<340: fondsv=fond.copy() nvtrain=train.resize((largeur,hauteur)) fondsv.paste(nvtrain,(x,y),nvtrain) nomfich=str(nb)+".jpg" fondsv.save(nomfich) x=x+10 nb=nb-1 distfuite=calcdistfuite(x) h1=distfuite*rap1 h2=distfuite*rap2 y=calcy(h1) hauteur=h1+h2 largeur=int((hauteur*50)/200)