Skip to content
Snippets Groups Projects
TP_Dance.md 5.61 KiB
Newer Older
  • Learn to ignore specific revisions
  • Alexandre MEYER's avatar
    Alexandre MEYER committed
    
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    ## TP : Synthèse de l'image d'une personne guidée par une posture
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    ** DRAFT **
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    Ce TP vise à implémenter avec PyTorch le transfert de mouvement d'une vidéo source vers une personne cible, en suivant un papier de Chan∗ etal présenté à ICCV 2019 : [Everybody Dance Now](https://openaccess.thecvf.com/content_ICCV_2019/papers/Chan_Everybody_Dance_Now_ICCV_2019_paper.pdf). Cette approche a été choisie pour faire une introduction au GAN, mais le sujet passe par diverses étapes. Pour comprendre le principe, le TP propose une approche qui recherche la donnée la plus proche dans le jeu de données initial (pas de réseau). Puis un réseau simple qui génére une image de la personne à partir du tableau des points d'un squelette de la personne. Et pour finir un réseau prenant en entrée une image "baton" de la personne, qui est "booster" par un discrimineur à la façon des GAN.
    
    Le papier propose différents points pour améliorer la continuité temporelle et les visages, que nous ne regarderons pas.
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    ### Principe général
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    
    En entrée, il faut une vidéo de la personne cible effectuant quelques mouvements. Remarque : des approches récentes peuvent se contenter d'une seule image, mais l'idée ici est de pratiquer, pas d'être sur le dernier papier existant.
    
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    À partir d'une 2e vidéo d'une personne source, l'objectif est de faire effectuer les mouvements de la personne source à la personne cible. Ceci se fait en produisant une nouvelle vidéo, image par image de la personne cible avec la pose/squelette extrait de la vidéo source. Pour extraire le squelette des vidéos, nous utilisons un réseau pré-entraîné de la bibliothèque [Mediapipe](https://mediapipe-studio.webapps.google.com/studio/demo/pose_landmarker). Le code donné fait déjà ce travail.
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    
    
    Le modèle de machine learning doit apprendre à partir des images de la vidéo comment produire une nouvelle image de cette personne dans une nouvelle posture donnée en paramètre. Si la vidéo de cette personne est suffisamment riche, et contient toutes les postures possibles, on pourrait simplement rechercher l'image dont le squelette est "similaire" (question 1). Ensuite, on va plutôt chercher à avoir un réseau qui va généraliser. Il sera capable de produire une image, même avec une posture qui n'a jamais vraiment été vue. Nous allons essayer un réseau direct, puis un GAN.
    
    
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    ### Le code de départ 
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    [Téléchargez l'archive du code initial ici]()
    Il faut installer les classiques (numpy, pytorch), mais aussi OpenCV (cv2) et mediapipe.
    
    Les différents fichiers sont les suivants.
    * `VideoReader`: des fonctions de bases pour lire une vidéo et récupérer les images (utilise cv2).
    * `Vec3` : des points 3D, basé sur un tableau numpy.
    * `Skeleton`: une class qui stocke les positions 3D d'un squelette. Il y a 33 articulations (joints) donnés par mediapipe donc 99 floats en tout. Il est possible de passer en mode réduit (`reduced=True` en paramètre de différentes fonctions pour n'avoir que 13 articulations en 2D, donc 26 floats.
    * `VideoSkeleton`: une classe qui associe un squelette à chaque image d'une vidéo. Le squelette est stocké en mémoire, mais l'image de la vidéo est représenté par le nom du fichier de l'image (stocker toutes les images d'une vidéo prendrait trop de mémoire si la vidéo est longue). Cette classe découpe une vidéo en images sauvée sur le disque.
    * `GenNearest`, `GenVanilla` et `GenGan`: les 3 générateurs d'images à écrire.
    * `DanceDemo` : classe pricipale qui exécute une démo de la dance. L'animation/posture de `self.source` est appliquée au personnage défini par `self.target` en utilisant `self.gen`.
    
    Dans les classes `GenXXX` le cœur du problème est la fonction
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    ```  def generator(self, ske): ```
    qui renvoie l'image de la personne cible avec comme posture le squelette `ske` recu en paramètre.
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    Cette génération se fait à partir du dataset comportant un ensemble de paire (image, squelette).
    ![Image alt](images/dance_dataset.png)
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    ### Préparer les données
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    Lancez d'abord le script `VideoSkeleton` qui va produire les images à partir d'une vidéo. Avec les paramètres par défaut, le script produit 1400 images de la vidéo `taichi.mp4` qui comporte 14000 images.
    
    Alexandre MEYER's avatar
    Alexandre MEYER committed
    
    ### Plus proche squelette
    
    La solution basique est de chercher dans le dataset qu'elle est l'image dont le squelette associé est le plus proche de celui recherché. Ce point se code dans la fonction `GenNearest::generate`. Cette solution n'est pas efficace : consommation, mémoire, recherche qui peut être longue.
    ![Image alt](images/dance_principe.png)
    
    
    
    ### Réseau direct
    
    L'idée ici est d'entraîner un réseau basique qui produit une image à partir du squelette. Le squelette est représenté par un tableau de nombres. Dans le code `Skeleton`, vous pouvez choisir d'extraire le squelette de taille réduite : 13 articulations en 2D. Le réseau peut donc prendre 26 nombres en entrée et produire une image.
    
    ![Image alt](images/dance_genske2im.png)
    
    
    ### Réseau produisant une image du squelette
    
    Le papier propose de travailler avec une image intermédiaire où le squelette est représenté avec des bâtons. Cette image est simple à obtenir. Dans la classe `Skeleton`, la fonction `draw_reduced` prédit une telle image. Changer le réseau précédent pour qu'il prenne en entrée l'image à la place du squelette.
    
    ![Image alt](images/dance_genske2imbaton2im.png)
    
    
    ### GAN
    
    Pour améliorer la qualité du générateur, le papier ajoute un réseau `discrimineur` qui détecte si l'image est une fausse image ou une vraie image. Ce principe est similaire au GAN, même si dans un GAN l'image d'entrée est du bruit.
    
    ![Image alt](images/dance_genGAN.png)