Estimation de l'orientation de la tête avec Python et OpenCV + dlib

Estimation de la direction de la tête?

Estimation de la pose de la tête en anglais. Il s'agit d'un algorithme qui estime la direction dans laquelle le visage fait face et l'inclinaison de la tête à partir des informations d'image d'entrée et des données de caractéristiques du visage. Récemment, il a été largement utilisé pour le développement de Vtuber.

Méthode d'estimation de la direction de la tête

Qiita a déjà introduit plusieurs méthodes pour estimer la direction de la tête. Ceci est très bien organisé dans l'article de Qiita. Enquête sur l'estimation de l'orientation du visage

Je pense que c'est l'article auquel vous faites référence sur la méthode d'estimation de la tête utilisant Python et OpenCV + dlib. Head Pose Estimation using OpenCV and Dlib

Les algorithmes d'estimation de l'orientation du visage sont décrits en détail dans la section Comment fonctionnent les algorithmes d'estimation de pose? De cette page.

Un exemple de programme

Pour le moment, j'écrirai le programme présenté dans l'article. Vous pouvez télécharger le fichier dat pour la reconnaissance faciale à partir d'ici. [dlib.net] 68 points de données apprises pour la reconnaissance faciale [DL]

Module de charge

HeadPoseEstimation.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import cv2 #OpenCV:Bibliothèque de traitement d'image
import dlib #Bibliothèque d'apprentissage automatique
import imutils #Assistance OpenCV
from imutils import face_utils
import numpy as np

Nous importons OpenCV pour le traitement d'image, dlib pour la reconnaissance d'image et imutils comme aide à l'affichage à l'écran.

Paramètres de la caméra et du détecteur de visage

HeadPoseEstimation.py


DEVICE_ID = 0 #L'ID 0 de la caméra utilisée est une webcam standard
capture = cv2.VideoCapture(DEVICE_ID)#Lecture des données entraînées par dlib
predictor_path = ",,,/shape_predictor_68_face_landmarks.dat"
#Copiez le chemin du fichier dat appris

detector = dlib.get_frontal_face_detector() #Détecteur de visage d'appel. Seul le visage est détecté.
predictor = dlib.shape_predictor(predictor_path) #Sortez les repères tels que les yeux et le nez du visage

Veuillez vous référer ici pour les fonctions dlib détaillées. dlib documentation

Contenu de l'estimation de la direction de la tête

Il acquiert une image à la fois de la caméra et la traite.

HeadPoseEstimation.py


while(True): #Obtenez des images en continu de la caméra
    ret, frame = capture.read() #Capturez à partir de l'appareil photo et placez une image de données d'image dans le cadre
    
    frame = imutils.resize(frame, width=1000) #Ajuster la taille d'affichage de l'image du cadre
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #Convertir en échelle de gris
    rects = detector(gray, 0) #Détecter le visage du gris
    image_points = None
     
    for rect in rects:
        shape = predictor(gray, rect)
        shape = face_utils.shape_to_np(shape)
        
        for (x, y) in shape: #Tracez 68 points de repère sur tout le visage
            cv2.circle(frame, (x, y), 1, (255, 255, 255), -1)

        image_points = np.array([
                tuple(shape[30]),#Pointe du nez
                tuple(shape[21]),
                tuple(shape[22]),
                tuple(shape[39]),
                tuple(shape[42]),
                tuple(shape[31]),
                tuple(shape[35]),
                tuple(shape[48]),
                tuple(shape[54]),
                tuple(shape[57]),
                tuple(shape[8]),
                ],dtype='double')
    
    if len(rects) > 0:
        cv2.FONT_HERSHEY_PLAIN, 0.7, (0, 0, 255), 2)
        model_points = np.array([
                (0.0,0.0,0.0), # 30
                (-30.0,-125.0,-30.0), # 21
                (30.0,-125.0,-30.0), # 22
                (-60.0,-70.0,-60.0), # 39
                (60.0,-70.0,-60.0), # 42
                (-40.0,40.0,-50.0), # 31
                (40.0,40.0,-50.0), # 35
                (-70.0,130.0,-100.0), # 48
                (70.0,130.0,-100.0), # 54
                (0.0,158.0,-10.0), # 57
                (0.0,250.0,-50.0) # 8
                ])

        size = frame.shape

        focal_length = size[1]
        center = (size[1] // 2, size[0] // 2) #Coordonnées centrales du visage

        camera_matrix = np.array([
            [focal_length, 0, center[0]],
            [0, focal_length, center[1]],
            [0, 0, 1]
        ], dtype='double')

        dist_coeffs = np.zeros((4, 1))

        (success, rotation_vector, translation_vector) = cv2.solvePnP(model_points, image_points, camera_matrix,
                                                                      dist_coeffs, flags=cv2.SOLVEPNP_ITERATIVE)
        #Matrice rotative et jacobienne
        (rotation_matrix, jacobian) = cv2.Rodrigues(rotation_vector)
        mat = np.hstack((rotation_matrix, translation_vector))

        #yaw,pitch,Sortez le rouleau
        (_, _, _, _, _, _, eulerAngles) = cv2.decomposeProjectionMatrix(mat)
        yaw = eulerAngles[1]
        pitch = eulerAngles[0]
        roll = eulerAngles[2]
        
        print("yaw",int(yaw),"pitch",int(pitch),"roll",int(roll))#Extraction des données de posture de la tête

        cv2.putText(frame, 'yaw : ' + str(int(yaw)), (20, 10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 2)
        cv2.putText(frame, 'pitch : ' + str(int(pitch)), (20, 25), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 2)
        cv2.putText(frame, 'roll : ' + str(int(roll)), (20, 40), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 2)

        (nose_end_point2D, _) = cv2.projectPoints(np.array([(0.0, 0.0, 500.0)]), rotation_vector,
                                                         translation_vector, camera_matrix, dist_coeffs)
        #Tracé des points utilisés dans le calcul/Affichage du vecteur de direction du visage
        for p in image_points:
            cv2.drawMarker(frame, (int(p[0]), int(p[1])),  (0.0, 1.409845, 255),markerType=cv2.MARKER_CROSS, thickness=1)

        p1 = (int(image_points[0][0]), int(image_points[0][1]))
        p2 = (int(nose_end_point2D[0][0][0]), int(nose_end_point2D[0][0][1]))

        cv2.arrowedLine(frame, p1, p2, (255, 0, 0), 2)
    
    cv2.imshow('frame',frame) #Afficher l'image
    if cv2.waitKey(1) & 0xFF == ord('q'): #Appuyez sur q pour interrompre et quitter pendant
        break


capture.release() #Quitter la capture vidéo
cv2.destroyAllWindows() #Fermer la fenêtre

Si cela fonctionne correctement, ce sera comme ça. スクリーンショット 2019-11-24 23.32.58.png

Explications et remarques sur les paramètres

yaw,roll,pitch Les paramètres de posture de la tête: lacet, roulis, tangage sont comme ça. (Identique à un avion) IMG_0240.jpg

Caractéristiques du visage à utiliser

Veuillez vous référer ici pour la position de image_points définie cette fois. Le point utilisé cette fois est ・ À l'intérieur des sourcils (22,23) ・ Dans les yeux (40,43) ・ Pointe de nez (31) ・ Les deux côtés du nez (32,36) ・ Les deux extérieurs de la bouche (49,55) ・ Sous les lèvres (58) ・ Menton (9) C'est 11 points de. La direction de la tête peut être estimée avec 5 points de manière algorithmique, mais quand je l'ai essayé, lorsque le score était petit, la direction du vecteur au bout du nez s'est retournée, j'ai donc augmenté le score. (Est-ce parce que les données formées sont basées sur des occidentaux ...) Facial landmarks with dlib, OpenCV, and Python facial_landmarks_68markup-1024x825.jpg Plus vous utilisez les points à l'extérieur du visage, meilleure sera la précision, mais si les sourcils, etc. sont coupés lorsqu'ils sont tournés de côté, cela entraînera une mauvaise appréciation de la quantité de traits, alors essayez d'utiliser les points au centre du visage autant que possible. <img width = "638" alt = "IMG_18D234CF6CC9-1.jpeg " src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543519/9cc12aa3-958f-0940" -9737-84a999dfacbf.jpeg ">

Et le problème est model_points, c'est-à-dire que dois-je faire avec les coordonnées de position des parties de mon visage, mais je l'ai défini par la force à partir du programme suivant. Les données de coordonnées (x, y) du visage avec le bout du nez comme origine apparaîtront dans l'image, alors veuillez faire face à la caméra aussi droit que possible, étendez votre posture et lisez avec esprit. Je devine la coordonnée z. Trouvez la distance entre le bout de votre nez et la zone entre vos yeux et appliquez-la à la hauteur de votre nez. Accrochez-vous!

HPEcal.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import cv2 #OpenCV:Bibliothèque de traitement d'image
import dlib #Bibliothèque d'apprentissage automatique
import imutils #Assistance OpenCV
from imutils import face_utils
import numpy as np


#Obtient un objet VideoCapture
DEVICE_ID = 0 #L'ID 0 est une webcam standard
capture = cv2.VideoCapture(DEVICE_ID)#Lecture des données entraînées par dlib
predictor_path = "/shape_predictor_68_face_landmarks.dat"

print("[INFO] loading facial landmark predictor...")
detector = dlib.get_frontal_face_detector() #Détecteur de visage d'appel. Seul le visage est détecté.
predictor = dlib.shape_predictor(predictor_path) #Sortez les repères tels que les yeux et le nez du visage

while(True): #Obtenez des images en continu de la caméra
    ret, frame = capture.read() #Capturez à partir de l'appareil photo et placez une image de données d'image dans le cadre
    
    frame = imutils.resize(frame, width=2000) #Ajuster la taille d'affichage de l'image du cadre
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #Convertir en échelle de gris
    rects = detector(gray, 0) #Détecter le visage du gris
    image_points = None
     
    for rect in rects:
        shape = predictor(gray, rect)
        shape = face_utils.shape_to_np(shape)
        #print(shape[30])#Coordonnées du nez
        cal = shape-shape[30]
        print("######[X,Y]#######",
              "\n point18=",cal[17],
              "\n point22=",cal[21],
              "\n point37=",cal[36],
              "\n point40=",cal[39],
              "\n point28=",cal[27],
              "\n point31=",cal[30],
              "\n point32=",cal[31],
              "\n point49=",cal[48],
              "\n point58=",cal[57],
              "\n point9=",cal[8])
        
        for (x, y) in shape: #Tracez 68 points de repère sur tout le visage
            cv2.circle(frame, (x, y), 1, (255, 255, 255), -1)
            cv2.putText(frame,str((x, y)-shape[30]),(x,y), cv2.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 255), 2)

    
    cv2.imshow('frame',frame) #Afficher l'image
    if cv2.waitKey(1) & 0xFF == ord('q'): #Appuyez sur q pour interrompre et quitter pendant
        break

capture.release() #Quitter la capture vidéo
cv2.destroyAllWindows() #Fermer la fenêtre

finalement

Enfin, lancez tout le programme et terminez-le. Je vous remercie pour votre travail acharné.

programme

HeadPoseEstimation.py


import cv2 #OpenCV:Bibliothèque de traitement d'image
import dlib #Bibliothèque d'apprentissage automatique
import imutils #Assistance OpenCV
from imutils import face_utils
import numpy as np


#Obtient un objet VideoCapture
DEVICE_ID = 0 #L'ID 0 est une webcam standard
capture = cv2.VideoCapture(DEVICE_ID)#Lecture des données entraînées par dlib
predictor_path = ".../shape_predictor_68_face_landmarks.dat"

detector = dlib.get_frontal_face_detector() #Détecteur de visage d'appel. Seul le visage est détecté.
predictor = dlib.shape_predictor(predictor_path) #Sortez les repères tels que les yeux et le nez du visage

while(True): #Obtenez des images en continu de la caméra
    ret, frame = capture.read() #Capturez à partir de l'appareil photo et placez une image de données d'image dans le cadre
    
    frame = imutils.resize(frame, width=1000) #Ajuster la taille d'affichage de l'image du cadre
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #Convertir en échelle de gris
    rects = detector(gray, 0) #Détecter le visage du gris
    image_points = None
     
    for rect in rects:
        shape = predictor(gray, rect)
        shape = face_utils.shape_to_np(shape)

        for (x, y) in shape: #Tracez 68 points de repère sur tout le visage
            cv2.circle(frame, (x, y), 1, (255, 255, 255), -1)

        image_points = np.array([
                tuple(shape[30]),#Pointe du nez
                tuple(shape[21]),
                tuple(shape[22]),
                tuple(shape[39]),
                tuple(shape[42]),
                tuple(shape[31]),
                tuple(shape[35]),
                tuple(shape[48]),
                tuple(shape[54]),
                tuple(shape[57]),
                tuple(shape[8]),
                ],dtype='double')
    
    if len(rects) > 0:
        model_points = np.array([
                (0.0,0.0,0.0), # 30
                (-30.0,-125.0,-30.0), # 21
                (30.0,-125.0,-30.0), # 22
                (-60.0,-70.0,-60.0), # 39
                (60.0,-70.0,-60.0), # 42
                (-40.0,40.0,-50.0), # 31
                (40.0,40.0,-50.0), # 35
                (-70.0,130.0,-100.0), # 48
                (70.0,130.0,-100.0), # 54
                (0.0,158.0,-10.0), # 57
                (0.0,250.0,-50.0) # 8
                ])

        size = frame.shape

        focal_length = size[1]
        center = (size[1] // 2, size[0] // 2) #Coordonnées centrales du visage

        camera_matrix = np.array([
            [focal_length, 0, center[0]],
            [0, focal_length, center[1]],
            [0, 0, 1]
        ], dtype='double')

        dist_coeffs = np.zeros((4, 1))

        (success, rotation_vector, translation_vector) = cv2.solvePnP(model_points, image_points, camera_matrix,
                                                                      dist_coeffs, flags=cv2.SOLVEPNP_ITERATIVE)
        #Matrice rotative et jacobienne
        (rotation_matrix, jacobian) = cv2.Rodrigues(rotation_vector)
        mat = np.hstack((rotation_matrix, translation_vector))

        #yaw,pitch,Sortez le rouleau
        (_, _, _, _, _, _, eulerAngles) = cv2.decomposeProjectionMatrix(mat)
        yaw = eulerAngles[1]
        pitch = eulerAngles[0]
        roll = eulerAngles[2]
        
        print("yaw",int(yaw),"pitch",int(pitch),"roll",int(roll))#Extraction des données de posture de la tête

        cv2.putText(frame, 'yaw : ' + str(int(yaw)), (20, 10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 2)
        cv2.putText(frame, 'pitch : ' + str(int(pitch)), (20, 25), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 2)
        cv2.putText(frame, 'roll : ' + str(int(roll)), (20, 40), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 2)

        (nose_end_point2D, _) = cv2.projectPoints(np.array([(0.0, 0.0, 500.0)]), rotation_vector,
                                                         translation_vector, camera_matrix, dist_coeffs)
        #Tracé des points utilisés dans le calcul/Affichage du vecteur de direction du visage
        for p in image_points:
            cv2.drawMarker(frame, (int(p[0]), int(p[1])),  (0.0, 1.409845, 255),markerType=cv2.MARKER_CROSS, thickness=1)

        p1 = (int(image_points[0][0]), int(image_points[0][1]))
        p2 = (int(nose_end_point2D[0][0][0]), int(nose_end_point2D[0][0][1]))

        cv2.arrowedLine(frame, p1, p2, (255, 0, 0), 2)
    
    cv2.imshow('frame',frame) #Afficher l'image
    if cv2.waitKey(1) & 0xFF == ord('q'): #Appuyez sur q pour interrompre et quitter pendant
        break


capture.release() #Quitter la capture vidéo
cv2.destroyAllWindows() #Fermer la fenêtre

2020/4/2 PostScript

OpenCV ne fonctionne pas avec les erreurs liées à Qt!

J'ai récemment eu cette erreur

qt.qpa.plugin: Could not find the Qt platform plugin "cocoa" in ""
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Il semble que cette erreur apparaisse lorsque j'installe un nouvel openCV avec pip. Cela fonctionne lorsque la version est abaissée.

pip3 install opencv-python==4.1.2.30

Résumé de référence

Qiita Enquête sur l'estimation de l'orientation du visage

Externe

Head Pose Estimation using OpenCV and Dlib dlib documentation Facial landmarks with dlib, OpenCV, and Python

Recommended Posts

Estimation de l'orientation de la tête avec Python et OpenCV + dlib
Obtenez et estimez la forme de la tête en utilisant Dlib et OpenCV avec python
J'ai essayé la détection d'objets en utilisant Python et OpenCV
[Ubuntu] [Python] Comparaison de la détection de visage entre dlib et OpenCV
[Python] Utilisation d'OpenCV avec Python (basique)
Utiliser OpenCV avec Python @Mac
Tirez en accéléré à partir d'une caméra PC en utilisant Python, OpenCV
[Python] Accès et recadrage des pixels d'image à l'aide d'OpenCV (pour les débutants)
Construction d'environnement de python et opencv
Briller la vie avec Python et OpenCV
[Ubuntu] [Python] Suivi d'objets à l'aide de dlib
[Python] Utilisation d'OpenCV avec Python (filtrage d'image)
Réseau neuronal avec OpenCV 3 et Python 3
Authentification à l'aide de l'authentification des utilisateurs tweepy et de l'authentification d'application (Python)
[Python] Utilisation d'OpenCV avec Python (transformation d'image)
[Python] Utilisation d'OpenCV avec Python (détection des bords)
Clustering et visualisation à l'aide de Python et CytoScape
[Traitement d'image] Poo-san est nu par détection de bord en utilisant Python et OpenCV!
Créez et essayez un environnement OpenCV et Python en quelques minutes à l'aide de Docker
Alignement d'images numérisées de papier vidéo animé à l'aide d'OpenCV et de Python
Notes utilisant cChardet et python3-chardet dans Python 3.3.1.
De Python à l'utilisation de MeCab (et CaboCha)
Créer un environnement Python 3 et OpenCV sur Ubuntu 18.04
Utilisation de Python et MeCab avec Azure Databricks
[Ubuntu] [Python] Détection d'organes faciaux à l'aide de dlib
Détection de visage Dlib et compteur de clignotements par Python
Créez un Mario en utilisant Numpy et OpenCV
Capturer des images avec Pupil, python et OpenCV
Créer une lecture de feuille de notes avec Python OpenCV (Conseils pour bien lire)
Introduction facile de la série python3 et d'OpenCV3
J'utilise tox et Python 3.3 avec Travis-CI
Hello World et détection de visage avec OpenCV 4.3 + Python
J'ai essayé le web scraping en utilisant python et sélénium
Remarques sur l'installation de Python3 et l'utilisation de pip sous Windows7
Développer et déployer des API Python à l'aide de Kubernetes et Docker
Flux de développement Python avec Poetry, Git et Docker
Installez OpenCV 4.0 et Python 3.7 sur Windows 10 avec Anaconda
Créer une carte Web en utilisant Python et GDAL
[Python3] Génération automatique de texte avec janome et markovify
Essayez d'utiliser tensorflow ① Créez un environnement python et introduisez tensorflow
Correspondance des fonctionnalités avec OpenCV 3 et Python 3 (A-KAZE, KNN)
fonctions cv2 et types de données (liaison python OpenCV)
Essayez d'utiliser l'API ChatWork et l'API Qiita en Python
Python2.7 + CentOS7 + OpenCV3
Suivi d'objets à l'aide d'OpenCV3 et de Python3 (suivi des points caractéristiques spécifiés par la souris à l'aide de la méthode Lucas-Kanade)
Commencez à utiliser Python
Exemples OpenCV (Python)
[Remarque] openCV + python
Scraping à l'aide de Python
Paramètres initiaux pour l'utilisation de Python3.8 et pip sur CentOS8
Recherche de balises pixiv et enregistrement d'illustrations à l'aide de Python
Squelettes extensibles pour Vim utilisant Python, Click et Jinja2
Essayez de créer un fichier compressé en utilisant Python et zlib
Agréger les journaux Git à l'aide de Git Python et analyser les associations à l'aide d'Orange
Estimation de l'auteur à l'aide du réseau neuronal et de Doc2Vec (Aozora Bunko)
Essayez de projeter la conversion d'image en utilisant OpenCV avec Python
Envoyez et recevez Gmail via l'API Gmail en utilisant Python
Implémentation d'un générateur en utilisant Python> link> yield et next ()> yield