[PYTHON] Unüberwachte Lächelnerkennung mit One Class SVM

Überblick

Als Programmierpraxis habe ich beschlossen, etwas zu implementieren und ein Lächeln zu erkennen. Deep Learning macht heute viel Lärm, wird aber ziemlich altmodisch implementiert. Da es sich um ein geeignetes System handelt, das ich mit meinen eigenen Ideen erstellt habe, würde ich es begrüßen, wenn Sie Kommentare abgeben könnten, wenn Sie Vorschläge haben.

Der Ablauf der Lächelnerkennung ist wie folgt.

  1. Holen Sie sich ein Bild mit einer WEB-Kamera.
  2. Erkennen Sie das Gesicht mit dem OpenCV-Kaskadenklassifikator und schneiden Sie den Bereich aus.
  3. Holen Sie sich die HOG-Funktionen des zugeschnittenen Bildes.
  4. Verwenden Sie SVM einer Klasse, um "Lächeln (normaler Zustand)" oder "Nicht lächeln (abnormaler Zustand)" zu bestimmen.

Um den Kaskadenklassifikator verwenden zu können, benötigen Sie haarcascade_frontalface_alt.xml von hier. Klonen Sie ihn daher bitte.

Über eine Klasse SVM

SVM einer Klasse wird häufig bei Problemen verwendet, bei denen es schwierig ist, Lehrerdaten zu erfassen. Dieses Mal werde ich es als Problem bei der Erkennung von Anomalien verwenden. Mit anderen Worten, der Zustand des Lächelns wird als "normal" definiert, und die anderen Zustände werden als "abnormal" definiert.

In einer normalen SVM (Support Vector Machine) wird überwachtes Lernen durchgeführt, um eine Diskriminanzgrenze zu finden. Wenn man also vom Problem der Lächelnerkennung spricht, ist es ein Bild von Lerndaten wie "wahres Gesicht" zusätzlich zu "Lächeln". Andererseits führt One Class SVM unbeaufsichtigtes Lernen durch und bestimmt, ob es "normal" oder "abnormal" ist. Wenn Sie also die Lerndaten "Lächeln" haben, können Sie "Lächeln" von "Anders als das" unterscheiden.

Implementierung

Es gibt drei Phasen.

  1. Sammeln Sie Trainingsdaten ("Lächeln (Normalzustand)"). (Data_collect ())
  2. Lernen Sie SVM einer Klasse anhand der gesammelten Daten. (Zug ())
  3. Erkennen Sie ein Lächeln mit dem trainierten One Class SVM. (Main ())

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 #Prozentsatz der Ausreißer in den Eingabedaten
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)#Regentag v,Spezifiziert von u

if __name__ == '__main__':
    data_collect() #Sammeln Sie zunächst Lächeln-Daten, indem Sie nur mit dieser Funktion drehen
    #train() #Daten lächeln(csv)Lesen und lernen Sie svm
    #main() #Lächelnerkennung mit dem erlernten Modell

(Die genaue Implementierung finden Sie unter hier. Eine Klasse SVM verwendete die Implementierung von Scicit-Learn. Wenn Sie es tatsächlich verwenden, erstellen Sie ein Verzeichnis wie unten gezeigt. Ich würde mich freuen, wenn Sie auf Fehler im Code hinweisen könnten. OneClassSVM/  ├ dataset/  │ └ train/  │ └ weights/  ├ cascades/    └ main.py

Implementierungsergänzung

Nach dem Ausschneiden des Gesichtsbilds mit dem Kaskadenklassifikator wird die Größe auf 60 x 60 geändert. (Die Größe wurde entsprechend festgelegt.) Vor dem Erlernen von SVM reduziert PCA die Dimension der HOG-Funktionen. Der Grund dafür ist, dass ich mir Sorgen um den Fluch gemacht habe, weil die Dimension von HOG 2000 überschreitet. Sie können die Anzahl der Dimensionen nach der Reduzierung mit n_dim angeben. Diesmal wurde es auf 4 gesetzt. Beim Erlernen von One Class SVM dauerte es einige Zeit, um die Hyperparameter anzupassen. Das Fit-Argument von OneClass SVM enthält Nu und Gamma. Es scheint, dass nu die Abnormalitätsrate in den Trainingsdaten ist und Gamma die Anzahl der Dimensionen von 1 / Merkmalsmenge. Da die Trainingsdaten jedoch in erster Linie keine abnormalen Werte enthalten, suchte ich nach einem guten Parameter, während ich main () drehte und train () ausführte. Schließlich ist nu = 0,3, gamma = 50 / Merkmalsmengen-Dimensionsnummer. Möglicherweise müssen Sie Nu und Gamma anpassen, wenn Sie es verwenden.

Experiment

Ich drehte main () und machte ein Experiment. Die Genauigkeit, wenn das Gesicht nach vorne zeigt, ist angemessen (ungefähr 80% werden wahrgenommen), aber da ich in den Trainingsdaten ein Lächeln auf der Ebene des Lächelns eingefügt habe, wurde es schwierig, die Grenze zwischen dem wahren Gesicht und dem Lächeln zu lernen. Es könnte getan worden sein.

Verweise

Gesichtserkennung durch OpenCV Haar-Cascade Erkennung abnormaler Werte mit One Class SVM

Recommended Posts

Unüberwachte Lächelnerkennung mit One Class SVM
Ausreißererkennung mit One Class SVM
SVM-Implementierung einer Klasse