[PYTHON] Détection de sourire non supervisée à l'aide du SVM One Class

Aperçu

En tant que pratique de programmation, j'ai décidé de mettre en œuvre quelque chose et j'ai décidé de détecter les sourires. Le Deep Learning fait beaucoup de bruit aujourd'hui, mais il est implémenté de manière assez démodée. Puisqu'il s'agit d'un système approprié que j'ai créé avec mes propres idées, je vous serais reconnaissant si vous pouviez commenter si vous avez des suggestions.

Le flux de détection de sourire est le suivant.

  1. Obtenez une image avec une caméra WEB.
  2. Détectez le visage avec le classificateur en cascade OpenCV et coupez la plage.
  3. Obtenez les fonctionnalités HOG de l'image recadrée.
  4. Utilisez un SVM de classe unique pour déterminer «sourire (état normal)» ou «ne pas sourire (état anormal)».

Pour utiliser le classificateur en cascade, vous aurez besoin de haarcascade_frontalface_alt.xml depuis ici, veuillez donc le cloner.

À propos de One Class SVM

Une classe SVM est souvent utilisée pour les problèmes où il est difficile de collecter des données sur les enseignants. Cette fois, je vais l'utiliser comme un problème de détection d'anomalies. En d'autres termes, l'état de sourire est défini comme «normal» et les autres états sont définis comme «anormal».

Dans une SVM (Support Vector Machine) normale, un apprentissage supervisé est effectué pour trouver une frontière discriminante. Donc, en parlant du problème de détection de sourire, il s'agit d'une image de données d'apprentissage telles que «vrai visage» en plus de «sourire». D'autre part, One Class SVM effectue un apprentissage non supervisé et détermine s'il est "normal" ou "anormal". Par conséquent, si vous avez les données d'apprentissage de «sourire», vous pouvez distinguer «sourire» de «autre que cela».

la mise en oeuvre

Il y a trois phases.

  1. Collectez les données d'entraînement ("sourire (état normal)"). (Data_collect ())
  2. Apprenez une classe SVM en utilisant les données collectées. (Train ())
  3. Détectez les sourires à l'aide du SVM One Class formé. (Principale ())

main.py


import numpy as np
import cv2
from skimage.feature import hog
from sklearn.svm import OneClassSVM
from sklearn.decomposition import PCA
import pickle

n = 3
n_dim = 4
alpha = - 1.0e+6
th = 20 #3
nu = 0.2 #0.1 #Pourcentage de valeurs aberrantes dans les données d'entrée
font = cv2.FONT_HERSHEY_COMPLEX
train_data = "./dataset/train/train.csv"
weights = "./dataset/weights/weights.sav"
weights_pca = "./dataset/weights/weights_pca.sav"

f_ = cv2.CascadeClassifier()  # "./cascades/haarcascade_fullbody.xml"
f_.load(cv2.samples.findFile("./cascades/haarcascade_frontalface_alt.xml"))

def preprocess(image):
    frame = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    frame = cv2.equalizeHist(frame)
    return frame

def data_collect():
    feature = []
    capture = cv2.VideoCapture(0)

    while (True):
        ret, frame = capture.read()
        frame = preprocess(frame)
        face = f_.detectMultiScale(frame)  # ,scaleFactor=1.2

        for rect in face:
            cv2.rectangle(frame, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (255, 255, 0), thickness=2)
            face_frame = frame[rect[1]:rect[1] + rect[3], rect[0]:rect[0] + rect[2]]
            face_frame = cv2.resize(face_frame, (60, 60))
            hog_f_, im = hog(face_frame, visualise=True,transform_sqrt=True)
            feature = np.append(feature,hog_f_)
            np.savetxt(train_data,feature.reshape(-1,2025), delimiter=",")
            cv2.putText(frame, "please smile for collecting data!", (10, 100), font,
                             1, (255, 255, 0), 1, cv2.LINE_AA)
        cv2.waitKey(1)
        cv2.imshow("face", frame)

def train():
    x_train = np.loadtxt(train_data,delimiter=",")
    pca = PCA(n_components=n_dim)
    clf = OneClassSVM(nu=nu, gamma=40/n_dim)#1/n_dim
    z_train = pca.fit_transform(x_train)
    clf.fit(z_train)

    pickle.dump(pca, open(weights_pca, "wb"))
    pickle.dump(clf,open(weights,"wb"))

def main():
    clf = pickle.load(open(weights,"rb"))
    pca = pickle.load(open(weights_pca, "rb"))
    capture = cv2.VideoCapture(0)

    while(True):
        ret,frame = capture.read()
        frame = preprocess(frame)
        face = f_.detectMultiScale(frame)

        for rect in face:
            cv2.rectangle(frame,tuple(rect[0:2]),tuple(rect[0:2]+rect[2:4]),(255,255,0),thickness=2)
            face_frame = frame[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
            face_frame = cv2.resize(face_frame,(60,60))
            feature , _ = hog(face_frame,visualise=True,transform_sqrt=True)
            z_feature = pca.transform(feature.reshape(1,2025))
            score = clf.predict(z_feature.reshape(1,n_dim))
            if score[0]== 1:
                cv2.putText(frame, "smile!", (10, 100), font,
                             1, (255, 255, 0), 1, cv2.LINE_AA)
        cv2.waitKey(1)
        cv2.imshow("face",frame)#Jour de pluie v,Spécifié par u

if __name__ == '__main__':
    data_collect() #Tout d'abord, collectez des données de sourire en tournant uniquement avec cette fonction
    #train() #Données de sourire(csv)Lire et apprendre svm
    #main() #Détection de sourire avec le modèle appris

(Veuillez vous référer à ici pour l'implémentation exacte. Une classe SVM a utilisé l'implémentation de scicit-learn. Lorsque vous l'utilisez réellement, créez un répertoire comme suit. Je vous serais reconnaissant si vous pouviez signaler toute erreur dans le code. OneClassSVM/  ├ dataset/  │ └ train/  │ └ weights/  ├ cascades/    └ main.py

Supplément de mise en œuvre

Après avoir coupé l'image du visage avec le classificateur en cascade, elle est redimensionnée à 60x60. (La taille a été décidée de manière appropriée.) Avant d'apprendre SVM, PCA réduit la dimension des fonctionnalités HOG. La raison en est que je m'inquiétais de la malédiction car la dimension de HOG dépasse 2000. Vous pouvez spécifier le nombre de dimensions après réduction avec n_dim. Cette fois, il était réglé sur 4. De plus, lors de l'apprentissage du SVM One Class, il a fallu un certain temps pour ajuster les hyper paramètres. Il y a nu et gamma dans l'argument fit de OneClass SVM. Il semble que nu soit le taux d'anomalie dans les données d'apprentissage et gamma le nombre de dimensions de 1 / quantité de caractéristique. Cependant, comme il n'y a pas de valeurs anormales dans les données d'entraînement en premier lieu, en raison de m'inquiéter de ce qu'il faut faire, j'ai fini par chercher un bon paramètre en tournant main () et en faisant train (). Enfin, nu = 0,3, gamma = 50 / numéro de dimension de quantité d'entités. Vous devrez peut-être ajuster nu et gamma lors de son utilisation.

Expérience

J'ai tourné main () et j'ai fait une expérience. La précision lorsque le visage fait face à l'avant est raisonnable (environ 80% perçu), mais comme j'ai mis un sourire au niveau du sourire dans les données d'entraînement, il est devenu difficile d'apprendre la frontière entre le vrai visage et le sourire. Cela a peut-être été fait.

Les références

Détection de visage par OpenCV Haar-Cascade Détection de valeur anormale à l'aide de One Class SVM

Recommended Posts

Détection de sourire non supervisée à l'aide du SVM One Class
Détection des valeurs aberrantes à l'aide d'un SVM de classe
Implémentation SVM à une classe