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.
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.
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.
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.
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()
Vous pouvez attribuer en toute sécurité un identifiant à votre visage,
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.
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