Animation simple de lèvres synchronisées au son pour Linux

Gazette Linux n°181 — décembre 2010

par Silas Brown (Copyright © 2010) <ssb22 AT cam DOT ac DOT uk>

traduction française de Gaël Montreuil (tous droits réservés) <g43l AT yahoo DOT fr>

Table des matières :

Certains programmes pour Windows tels que CrazyTalk vous permettent de transformer n'importe quelle image en une animation dans laquelle les lèvres sont synchronisées au son, afin de pouvoir créer des personnages parlants. Dans cet article, j'explique comment réaliser cela uniquement au moyen d'outils Linux libres. Le résultat est basique mais devrait être adéquat pour de nombreux usages.

1ère étape: Créer trois trames avec GIMP

Commencez avec l'image, au format PNG, que vous souhaitez animer, de préférence plutôt en basse résolution de sorte que le visage ne dépasse pas 100x100 pixels environ (cela vous évitera de devoir créer trop de trames). Le visage doit avoir la bouche fermée au départ, nommons l'image mouth-closed.png. Chargez la dans GIMP (gimp mouth-closed.png) et utilisez le menu déroulant d'échelle (sur la barre de statut) pour appliquer un zoom de 400% ou 800% afin de pouvoir travailler individuellement avec les pixels. Cadrez sur la zone de la bouche.

Activez l'outil de sélection à main levée de GIMP, soit en le trouvant dans la boite à outils ou en pressant la touche F. Cet outil permet de faire des sélections à main levée sur l'image que vous voulez éditer. Il est par exemple possible d'effacer une partie de l'arrière plan en dessinant une sélection de la zone à effacer et en pressant Control-X pour la découper. Mais dans notre cas, ce que l'on veut c'est décaler le bas de la bouche vers le bas d'un pixel, et probablement, nous voulons que l'ouverture de la bouche soit noire plutôt que blanche. C'est pourquoi il est important de sélectionner le noir pour la couleur d'arrière plan. Ce que vous pouvez faire en commutant couleur de premier plan et d'arrière plan dans la boite à outils de GIMP.

Tracez soigneusement une ligne là ou les lèvres se rejoignent, puis continuez vers le bas en entourant ainsi toute la partie inférieure de la bouche. Vous n'avez pas à vous soucier de rejoindre précisément le point d'où est partie la sélection car GIMP complétera tout seul le tracé en joignant les points de départ et de fin par une ligne droite. Si vous ratez, cliquez en dehors de votre sélection pour annuler puis réessayez.

Lorsque vous avez sélectionné la lèvre inférieure, appuyez sur Control-X pour l'envoyer dans le presse - papiers puis Control-V pour la coller à nouveau sur l'image, puis déplacez la sélection d'environ un pixel en dessous de sa position originale. La bouche devrait à présent se présenter comme entrouverte avec une ouverture d'une largeur d'environ un pixel (je dis « environ » car la ligne sera anti - crénelée par GIMP). Cliquez en dehors de la sélection pour tout déselectionner puis revenez à un affichage de 100% pour vous rendre compte du résultat. Puis sauvegardez l'image en mouthopen-1.png.

Répétez l'opération pour agrandir à nouveau d'un pixel l'ouverture de la bouche. Il est préférable cette fois - ci de ne pas sélectionner jusqu'aux coins de la bouche, car le milieu de la bouche s'abaisse plus que ses coins. Sauvegardez le résultat en mouthopen-1.png.

Si la résolution est suffisamment faible, alors il se peut que cela soit suffisant. Vous pouvez cependant ajouter d'autres trames, il suffit de les ajouter au script qui suit.

2ème étape: convertir l'amplitude du son en une séquence d'images

Ce n'est pas très professionnel car dans la réalité l'ouverture de la bouche dépend de la voyelle qui est prononcée et pas uniquement du volume du son, mais pour un usage pas trop exigeant vous serez surpris du résultat qu'on peut atteindre en n'utilisant que l'amplitude.

Du fait que nous utiliserons un simple script en Python pour convertir l'amplitude en positions des lèvres, il est très important que le fichier audio n'ait absolument aucun bruit de fond. (si vous voulez un fond sonore dans le résultat final alors il faudra l'intégrer après avoir exécuté le script ci - dessous). Si le fichier audio a été généré par un synthétiseur vocal (espeak ou autre) alors cela devrait être parfait, mais si vous enregistrez le son vous même faites - le dans un environnement parfaitement calme.

Nous devons nous assurer que notre fichier vocal (appelons - le speech.wav se termine par environ 3 secondes de silence à la fin. Cela parce que nous allons utiliser MEncoder, et qu'un bogue de certaines versions peut provoquer la perte des 3 dernières secondes (cette étape peut être sautée si vous votre version de MEncoder n'est pas boguée, dans ce cas contentez vous de nommer le fichier padded.wav.)

sox speech.wav padded.wav pad 0.1 3

Vous devriez vous retrouver avec un fichier padded.wav finissant sur un silence. Puis, pour notre exercice, nous convertissons celui - ci en 8 bits non signés 4khz mono (mais n'effacez pas l'original!), pour pouvoir lire l'amplitude plus facilement avec un script.

sox padded.wav -1 -u -c 1 -r 4000 -t raw rawfile

Le résultat devrait être un fichier rawfile que le script python suivant peut convertir en une séquence d'images (en réalité, une séquence de liens symboliques vers vos trames). Le script Python exécutera MEncoder pour créer effectivement l'animation.

   1 framerate = 10 ; slice=4000/framerate
   2 dat = open("rawfile").read()
   3 frames = []
   4 import os
   5 for i in range(0,len(dat),slice):
   6     samples = map(lambda x:ord(x)-128,
   7                   dat[i:i+slice])
   8     frames.append(max(samples))
   9 
  10 pics = ["mouth-closed.png",
  11         "mouthopen-1.png",
  12         "mouthopen-2.png"]
  13 max_mouthOpen = len(pics)-1
  14 
  15 step = int(max(frames)/(max_mouthOpen*2))
  16 for i in range(len(frames)):
  17     mouth=min(int(frames[i]/step),max_mouthOpen)
  18     if i:
  19         if mouth>frames[i-1]+1:
  20             mouth=frames[i-1]+1
  21         elif mouth < frames[i-1]-1:
  22             mouth=frames[i-1]-1
  23     else: mouth=0
  24     frames[i] = mouth
  25     os.system("ln -s %s frame%09d.png" %
  26               (pics[mouth],i))
  27 
  28 os.system(("mencoder 'mf://frame0*.png' " +
  29           "-audiofile padded.wav -mf type=png " +
  30           "-mf fps=%d -oac mp3lame -ovc lavc " +
  31           "-o animation.avi && rm frame0*.png")
  32           % framerate)

Assurez vous qu'il n'y ait pas de fichier correspondant au masque frame0*.png dans le répertoire courant lorsque vous lancez ce script. le résultat est sauvegardé sous animation.avi, visible avec mplayer.

Limitations

Parce que cette méthode n'ouvre la bouche que de quelques pixels, il est probable qu'il soit difficile de redimensionner la vidéo. Plutôt que de changer la taille de la vidéo, il est préférable de bien dimensionner les trames dés le départ.

Par ailleurs, certaines versions de MEncoder/Mplayer auront du mal à conserver la synchronisation du son et de la vidéo sur de longues durées (plus de quelques secondes). Pour un meilleur résultat, utilisez un lecteur capable de forcer le taux d'images AVI en fonction de la bande sonore. Le convertisseur de téléchargement de Youtube ne posera pas de problème.


Adaptation française de la Gazette Linux

L'adaptation française de ce document a été réalisée dans le cadre du Projet de traduction de la Gazette Linux

Cet article est publié selon les termes de la Open Publication License. La Linux Gazette n'est ni produite, ni sponsorisée, ni avalisée par notre hébergeur principal, SSC, Inc.

Vous pourrez lire d'autres articles traduits et en apprendre plus sur ce projet en visitant notre site http://www.traduc.org/Gazette_Linux

Si vous souhaitez apporter votre contribution, n'hésitez pas à nous rejoindre, nous serons heureux de vous accueillir.