Créez diverses vidéos Photoshop avec Python + OpenCV ④ Traitez les problèmes

0. Introduction

J'ai pu créer une vidéo Photoshop diverse la dernière fois (Partie ③ Créer une vidéo Photoshop diverse), mais ce n'est pas encore pratique. En règle générale, il existe les problèmes suivants. A. S'il y a plusieurs personnes, superposition sur le visage de chacun (vous ne pouvez pas sélectionner uniquement une personne spécifique) B.Méconnaissance de quelque chose qui n'est pas un visage (précision de la reconnaissance) C. Le visage peut ne pas être reconnu (précision de la reconnaissance) Nous visons à résoudre ces problèmes.

1. Politique

Tout d'abord, à propos de A et B. Le but de la création de Photoshop divers cette fois est "d'écraser le visage d'une autre personne uniquement sur le visage d'une personne spécifique". Cependant, il semble impossible de sélectionner automatiquement une personne spécifique parmi les visages reconnus, nous allons donc utiliser des mains humaines ici. Le chemin est ・ Sortie vidéo en attribuant un identifiant au visage reconnu ・ Vérifiez visuellement l'ID du visage que vous souhaitez écraser ・ Entrez l'ID Il est réalisé par la méthode. Cependant, si vous attribuez simplement des identifiants à tous les visages trouvés, le nombre d'identifiants à saisir sera très important, donc Je voudrais traiter de cela avec la solution de C. Afin de réduire le nombre d'ID, les cadres avant et arrière sont utilisés pour déterminer si les faces sont continues à partir de la position et de la taille, et si elles sont continues, le même ID est attribué. De plus, dans le cadre qui continue de X → Y → Z, si un visage est reconnu en X et Z, mais que la reconnaissance n'est pas reconnue en Y, il est complété car Y a également ce visage.

2. Implémentation de classe (FacePostion, FaceFrame)

Cette fois, nous allons créer une classe pour la première fois pour l'implémentation. Toutes les classes sont créées dans un fichier appelé frame_manager.py. Commencez par créer la classe ** FacePosition **. Bien que ce soit appelé une classe, il s'agit simplement d'une structure qui contient les coordonnées et l'ID du visage.

frame_manager.py(FacePosition)


class FacePosition:
    '''
Classe pour tenir la position du visage et l'ID comme un ensemble
Juste une structure avec ID et coordonnées comme coordonnées et taille de face
    '''

    def __init__(self, id, coordinate):
        self.id = id
        self.coordinate = coordinate

Utilisez-le pour conserver les informations sur le visage.

Ensuite, créez une classe ** FaceFrame ** pour contenir les informations sur le cadre et les faces qui y existent. Si vous passez les coordonnées du cadre et du visage, l'ID initial sera attribué au visage et stocké. Comptez les ID attribués jusqu'à présent dans la variable pour l'accès statique afin que l'ID initial ne soit pas couvert.

frame_manager.py(FaceFrame)


class FaceFrame:
    '''
Classe pour tenir le visage reconnu dans chaque cadre
Étant donné que faceCount est une variable pour compter le nombre d'identifiants utilisés afin que les identifiants ne soient pas couverts par l'ensemble de l'application,
Utilisez toujours FaceFrame.Accès avec faceCount
    '''
    
    faceCount = 0

    def __init__(self, frame, coordinates):

        '''
Passez les coordonnées et la taille du visage reconnu comme cadre.
Créer des instances de classe FacePoint pour le nombre de faces
        coodinates:Une gamme de résultats de reconnaissance faciale. Cascade.Transmettez le résultat de detectMultiScale tel quel
        '''
        
        #Fixez un arrangement pour quelques minutes du visage
        self.faces = [None]*len(coordinates)
        self.frame = frame

        #Créez une instance de FacePosition en attribuant un identifiant à chaque face transmise
        for i in range(0, len(coordinates)):
            self.faces[i] = FacePosition(FaceFrame.faceCount, coordinates[i])
            FaceFrame.faceCount += 1

    #Fonction pour ajouter des faces dans le cadre ultérieurement
    def append(self, faceId, coordinate):
        self.faces.append(FacePosition(faceId, coordinate))

Vous pouvez maintenant conserver la correspondance entre le cadre et le visage.

3. Implémentation de classe (FrameManager)

La classe ** FrameManager **, qui est le cœur du jeu. De l'extérieur, cette classe fonctionne comme suit. ■ Lorsque les informations de coordonnées du cadre et du visage sont transmises, les informations du cadre (Face Frame) qui attribuent l'ID et complètent l'échec de reconnaissance sont renvoyées.

Dans ce but, la trame reçue est temporairement stockée dans le tableau, et l'ID est attribué et la trame terminée est renvoyée. La longueur du tableau peut être modifiée en changeant LIST_SIZE, mais ici c'est 5. Le flux de traitement est le suivant. ・ Recevoir des informations sur les coordonnées du cadre et du visage -Stocker dans un tableau. À ce stade, l'élément le plus ancien du tableau est la valeur de retour. (・ Séparé par l'image précédente (frameFs) et l'image suivante (frameBs) avec l'image au milieu du tableau (frameC) comme limite) ・ Vérifiez la position et la taille des faces de frameF et frameC, et attribuez le même identifiant si elles sont considérées comme continues. -Comparez frameF et frameB, et s'il existe une face continue, mais qu'elle n'existe pas dans frameC, complétez-la avec frameC. ・ Répétez pour la combinaison de frameFs et frameBs. La tolérance pour juger que les faces sont continues est spécifiée par ALLOWED_GAP, mais cette fois, elle est définie sur 5%. (Étant donné que frameF et frameB ont plusieurs images, la présence ou l'absence de s indique s'il s'agit d'images individuelles ou de l'ensemble du groupe d'images.) Voici la source.

frame_manager.py(FrameManager)


class FrameManager:
    
    '''
Une classe qui complète la continuité du visage et du visage manquant en fonction du cadre passé et du résultat de la reconnaissance faciale
Attribuez le même ID à des faces consécutives.
    '''
    #Spécifiez le nombre de FaceFrames pour vérifier la continuité du visage
    LIST_SIZE = 5
    CENTER_INDEX = int(LIST_SIZE/2)
    #Quelle différence de position et de taille doit être autorisée pour déterminer si les faces entre les cadres sont identiques.%Spécifié par
    ALLOWED_GAP = 5
        
    def __init__(self, height, width):
        '''
Spécifiez la hauteur et la largeur de la vidéo à traiter
        '''
        FrameManager.FRAME_HEIGHT = height
        FrameManager.FRAME_WIDTH = width

        self.__frames = [None]*self.LIST_SIZE
        
    
    def put(self, frame, coordinates):
        '''
Ajouter un cadre basé sur le cadre passé et le résultat de la reconnaissance faciale
Lors de l'ajout, attribuer un ID, vérifier la continuité, compléter les faces manquantes, LISTE_Renvoie l'occurrence SIZEth FaceFrame
Comme le traitement à la fin, après le traitement de toutes les trames, LISTE_Les cadres SIZE restent dans le gestionnaire de cadres, alors continuez à ajouter Aucun jusqu'à ce que vous ayez terminé de sortir les cadres restants.

        return:Une instance de FaceFrame. Cependant, LIST_Renvoie None s'il n'y a aucune occurrence de FaceFrame au niveau de SIZE th.
        '''
        #Puisque None est transmis lors de la sortie de la dernière image restante, dans ce cas, faceFrame est également défini sur None.
        if frame is None:
            faceFrame = None
        else:
            faceFrame = FaceFrame(frame, coordinates)

        #Faites avancer la liste une par une et ajoutez un cadre d'argument à la fin. Puisqu'il existe de nombreux accès aléatoires au traitement interne, je pense qu'il est souhaitable de les gérer dans un tableau.
        returnFrame = self.__frames[0]
        for i in range(0,len(self.__frames)-1):
            self.__frames[i] = self.__frames[i+1]
        self.__frames[FrameManager.LIST_SIZE-1] = faceFrame

        #Vérifier la continuité des cadres avant et arrière
        # CENTER_Avant cela avec INDEX comme limite(i)arrière(j)Vérifier la continuité du visage avec chaque combinaison
        for i in range(0, FrameManager.CENTER_INDEX):
            for j in range(FrameManager.CENTER_INDEX+1, FrameManager.LIST_SIZE):
                #Passer la partie Aucun
                if self.__frames[i] is not None and self.__frames[FrameManager.CENTER_INDEX] is not None and self.__frames[j] is not None:

                    #Vérifiez la continuité et complétez tous les cadres intermédiaires
                    for k in range(i+1, j):
                        self.connectFrame(self.__frames[i], self.__frames[k], self.__frames[j])

        return returnFrame
        
        
    def connectFrame(self, frameF, frameC, frameB):               
        # frameF.faces et cadreC.S'il y a des faces consécutives dans les faces, indiquez le même identifiant.
        #TODO Il est possible que le même identifiant puisse être attribué à plusieurs visages. En premier lieu, dans ce cas, le design actuel ne fonctionne pas, alors je l'ai mis en attente.
        frontFaceNum = len(frameF.faces)
        centerFaceNum = len(frameC.faces)
        backFaceNum = len(frameB.faces)
        for i in range(0, frontFaceNum):
            #Conserve si la i-ème face de l'image précédente correspond à l'une des faces de l'image C
            matched = False
            for j in range(0, centerFaceNum):
                #S'il est jugé qu'il s'agit du même visage, utilisez le même identifiant
                if self.compare(frameF.faces[i], frameC.faces[j]) == True:
                    frameC.faces[j].id = frameF.faces[i].id
                    matched = True
                    break
                
            #Même s'il n'est pas dans frameC, s'il est à la fois dans frameF et frameB, on suppose que le framC entre les deux a également cette face et est complété.
            if matched == False:
                for k in range(0, backFaceNum):
                    if self.compare(frameF.faces[i], frameB.faces[k]):
                        #Ajouter une face à la position / taille entre frameF et frameB
                        frameC.append(frameF.faces[i].id, ((frameF.faces[i].coordinate + frameB.faces[k].coordinate)/2).astype(np.int))
                        #Augmentez le nombre de faces de 1.(Au cas où un autre visage serait trouvé dans le processus ultérieur)
                        centerFaceNum += 1

                        #Prévention des boucles infinies
                        if(centerFaceNum>10):
                            break

       
    def compare(self, face1, face2):
        '''
Comparez si face1 et face2 sont continues.
        return:Vrai si pareil, Faux si différent
        '''
        result = True
        #Vérifiez si la différence de coordonnées et de taille de visage est dans la plage d'erreur, et toutes les erreurs(ALLOWED_GAP)Si c'est à l'intérieur, on juge qu'ils ont le même visage
        #Si les cadres TODO sont éloignés, il est préférable d'augmenter la tolérance en conséquence.
        for i in range(0,4):
            if i%2 == 0:
                gap = ((float(face1.coordinate[i])-float(face2.coordinate[i]))/FrameManager.FRAME_HEIGHT)*100
            else:
                gap = ((float(face1.coordinate[i])-float(face2.coordinate[i]))/FrameManager.FRAME_WIDTH)*100
            if (-1*FrameManager.ALLOWED_GAP < gap < FrameManager.ALLOWED_GAP) == False:
                result = False
                break
        return result

Pour l'utiliser avec cela, créez une instance de FrameManager et entrez les informations sur le cadre et la face. Il renverra un FaceFrame avec un ID.

De plus, lorsque je l'examine, je vérifie la continuité des identifiants plusieurs fois entre les mêmes trames, ce qui la rend redondante. Cependant, je ferme les yeux pour la raison décrite plus tard.

4. FrameManager intégré

Incluez la classe FrameManager créée dans le fichier overlay_movie.py créé précédemment. Après la reconnaissance faciale, placez d'abord le visage reconnu dans FrameManager et écrivez l'ID sur le visage trouvé en fonction de l'occurrence FaceFrame de sortie.

overlay_movie2.py


# -*- coding:utf-8 -*-

import cv2
import datetime
import numpy as np
from PIL import Image

import frame_manager

def overlay_movie2():

    #Spécifiez la vidéo à entrer et le chemin de sortie.
    target = "target/test_input.mp4"
    result = "result/test_output2.m4v"  #.J'obtiens une erreur si je n'utilise pas m4v

    #Charger des vidéos et obtenir des informations sur la vidéo
    movie = cv2.VideoCapture(target) 
    fps    = movie.get(cv2.CAP_PROP_FPS)
    height = movie.get(cv2.CAP_PROP_FRAME_HEIGHT)
    width  = movie.get(cv2.CAP_PROP_FRAME_WIDTH)

    #Spécifiez MP4V comme format
    fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    
    #Ouvrez le fichier de sortie
    out = cv2.VideoWriter(result, int(fourcc), fps, (int(width), int(height)))

    #Acquérir la quantité de caractéristiques du classificateur en cascade
    cascade_path = "haarcascades/haarcascade_frontalface_alt.xml"
    cascade = cv2.CascadeClassifier(cascade_path)
    
    #Créer un FrameManager
    frameManager = frame_manager.FrameManager(height, width)

    #Spécifiez la couleur du rectangle qui entoure la face reconnue. Blanc ici.
    color = (255, 255, 255) 
    
    #Lire la première image
    if movie.isOpened() == True:
        ret,frame = movie.read()
    else:
        ret = False

    count = 0

    #Continuer à exporter des cadres tout en lisant avec succès les cadres
    while ret:
        
        #Convertir en échelle de gris
        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        #Effectuer la reconnaissance faciale
        facerecog = cascade.detectMultiScale(frame_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
            
        #Placer le visage reconnu dans FrameManager
        managedFrame = frameManager.put(frame, facerecog)

        #À partir de la 5e fois, les images seront renvoyées depuis Frame Manager, donc la sortie
        if managedFrame is not None:

            #Ajouter un numéro au visage reconnu
            for i in range(0,len(managedFrame.faces)):

                #Préparez les variables pour une manipulation facile
                tmpCoord = managedFrame.faces[i].coordinate
                tmpId = managedFrame.faces[i].id
                    
                print("Nombre de visages reconnus(ID) = "+str(tmpId))
                                        
                #Entourer un rectangle
                cv2.rectangle(managedFrame.frame, tuple(tmpCoord[0:2]),tuple(tmpCoord[0:2]+tmpCoord[2:4]), color, thickness=2)
                    
                #Écrire l'identifiant du visage
                cv2.putText(managedFrame.frame,str(tmpId),(tmpCoord[0],tmpCoord[1]),cv2.FONT_HERSHEY_TRIPLEX, 2, (100,200,255), thickness=2)
    
            out.write(managedFrame.frame)
        if count%10 == 0:
            date = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
            print(date + 'Nombre actuel d'images:'+str(count))
        
        count += 1
        ret,frame = movie.read()

        #Fin à mi-chemin
        if count > 200 :
            break

    print("Nombre de trames de sortie:"+str(count))

    
if __name__ == '__main__':
    overlay_movie2()

5. Résultat

Vous pouvez attribuer en toute sécurité un identifiant à votre visage, ID割り振り1人.JPG

Il est désormais possible d'identifier une personne spécifique de plusieurs personnes par ID, et il est désormais possible d'identifier des visages consécutifs par un ID. ID割り振り3人.JPG

6. Enfin

Tout ce que vous avez à faire est de saisir l'ID du visage que vous souhaitez écraser et écraser le visage correspondant. Je voudrais dire, mais ce n’était pas le cas. Je l'ai fait jusqu'à présent, mais ce programme ne peut pas remplir son objectif. La précision de reconnaissance du visage dans la vidéo à reconnaître est médiocre, et même si l'écart est complété, il ne peut pas être traité. (Je regardais ailleurs en me sentant mince) C'est pourquoi j'aimerais explorer une autre politique pour ce programme en tant que magasin. Il continuera au suivant.

Recommended Posts

Créez diverses vidéos Photoshop avec Python + OpenCV ④ Traitez les problèmes
Créez diverses vidéos Photoshop avec Python + OpenCV ③ Créez diverses vidéos Photoshop
Créez diverses vidéos Photoshop avec Python + OpenCV ② Créez une image fixe Photoshop
Créer un fichier au format Photoshop (.psd) avec python
Binarisation avec OpenCV / Python
"Traitement Apple" avec OpenCV3 + Python3
Édition d'image avec python OpenCV
Capture de caméra avec Python + OpenCV
Créer un gif 3D avec python3
[Python] Utilisation d'OpenCV avec Python (basique)
Détection de visage avec Python + OpenCV
Créer un répertoire avec python
Utiliser OpenCV avec Python @Mac
Créez un outil d'analyse vidéo simple avec python wxpython + openCV
Briller la vie avec Python et OpenCV
Créer une animation de tracé avec Python + Matplotlib
[Python] Utilisation d'OpenCV avec Python (filtrage d'image)
Créer Awaitable avec l'API Python / C
Réseau neuronal avec OpenCV 3 et Python 3
[Python] Utilisation d'OpenCV avec Python (transformation d'image)
[Python] Utilisation d'OpenCV avec Python (détection des bords)
Créez une illusion rayée avec correction gamma pour Python3 et openCV3
Créez un environnement virtuel avec Python!
Programmation facile Python + OpenCV avec Canopy
Essayez la reconnaissance faciale avec python + OpenCV
Découpez le visage avec Python + OpenCV
Reconnaissance faciale avec caméra avec opencv3 + python2.7
Charger une image gif avec Python + OpenCV
Trouver la similitude d'image avec Python + OpenCV
Utiliser OpenCV avec Python 3 dans Window
Dessinez une illustration avec Python + OpenCV
Faites en sorte que les vidéos floues ressemblent à des caméras à point fixe avec Python et OpenCV
Suivre les balles de baseball avec Python + OpenCV
Segmentation basée sur un graphique avec Python + OpenCV
Dessinez une flèche (vecteur) avec opencv / python
Etude de base d'OpenCV avec Python
Créez votre propre caméra virtuelle avec Python + OpenCV et appliquez des effets originaux
Créer un décorateur de fonction Python avec Class
Créez automatiquement la documentation de l'API Python avec Sphinx
Créez wordcloud à partir de votre tweet avec python3
Créez une image factice avec Python + PIL.
Enregistrer la vidéo image par image avec Python OpenCV
[Python] Créez un environnement virtuel avec Anaconda
Créons un groupe gratuit avec Python
Créez rapidement un fichier Excel avec Python #python
Capturer des images avec Pupil, python et OpenCV
J'ai essayé le rendu non réaliste avec Python + opencv
Traitement d'image avec Python et OpenCV [Tone Curve]
Créer un environnement Python + uWSGI + Nginx avec Docker
Créer et décrypter du code César avec python
Acquisition d'images depuis une caméra avec Python + OpenCV
[python, openCV] base64 Reconnaissance faciale dans les images
Créer un fichier Excel avec Python + matrice de similarité
Créer un compteur de fréquence de mots avec Python 3.4
Créer un environnement OpenCV3 + python3 sur OSX
[Python] Lire des images avec OpenCV (pour les débutants)
[Python] Créez rapidement une API avec Flask
Créez une application de mots anglais avec python