import cv2, glob, random, math, numpy as np, dlib, itertools
from sklearn.svm import SVC
from sklearn.ensemble import BaggingClassifier, RandomForestClassifier
from sklearn.multiclass import OneVsRestClassifier
from sklearn import linear_model
from sklearn.neighbors import KNeighborsClassifier
emotions = ["Angry", "Disgust", "Fear", "Happy", "Neutral", "Sad", "Surprise"]
# "Happy", "Neutral", "Sad"] #Emotion list
# hist 均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("./shape_predictor_68_face_landmarks.dat")
clf = SVC(kernel='linear', probability=True, tol=1e-3) #SVM
# clf = RandomForestClassifier(min_samples_leaf=20) #随机森林
# knn = KNeighborsClassifier(n_neighbors=7) #KNN
# clf = linear_model.LogisticRegression(C=1e5) #逻辑回归
# n_estimators = 10
# clf = OneVsRestClassifier(BaggingClassifier(SVC(kernel='linear', probability=True, class_weight='balanced'), max_samples=1.0 / n_estimators, n_estimators=n_estimators),n_jobs=-1)
def get_files(emotion):
print("./data/%s/*" % emotion)
files = glob.glob("./data/%s/*" % emotion)
print(len(files))
random.shuffle(files)
training = files[:int(len(files)*0.8)] # get first 80% of file list
prediction = files[-int(len(files)*0.2):] # get last 20% of file list
return training, prediction
def get_landmarks(image):
detections = detector(image, 1)
for k,d in enumerate(detections): # For all detected face instances individually
shape = predictor(image, d) # Draw Facial Landmarks with the predictor class
xlist = []
ylist = []
for i in range(1, 68): # Store X and Y coordinates in two lists
xlist.append(float(shape.part(i).x))
ylist.append(float(shape.part(i).y))
xmean = np.mean(xlist) # Get the mean of both axes to determine centre of gravity
ymean = np.mean(ylist)
xcentral = [(x-xmean) for x in xlist] # get distance between each point and the central point in both axes
ycentral = [(y-ymean) for y in ylist]
if xlist[26] == xlist[29]:
# If x-coordinates of the set are the same, the angle is 0, catch to prevent 'divide by 0' error in function
anglenose = 0
else:
anglenose = int(math.atan((ylist[26]-ylist[29])/(xlist[26]-xlist[29]))*180/math.pi)
if anglenose < 0:
anglenose += 90
else:
anglenose -= 90
landmarks_vectorised = []
for x, y, w, z in zip(xcentral, ycentral, xlist, ylist):
landmarks_vectorised.append(x)
landmarks_vectorised.append(y)
meannp = np.asarray((ymean,xmean))
coornp = np.asarray((z,w))
dist = np.linalg.norm(coornp-meannp)
anglerelative = (math.atan((z-ymean)/(w-xmean))*180/math.pi) - anglenose
landmarks_vectorised.append(dist)
landmarks_vectorised.append(anglerelative)
if len(detections) < 1:
landmarks_vectorised = "error"
return landmarks_vectorised
def make_sets():
training_data = []
training_labels = []
prediction_data = []
prediction_labels = []
for emotion in emotions:
training, prediction = get_files(emotion)
for item in training:
image = cv2.imread(item) # open image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # convert to grayscale
clahe_image = clahe.apply(gray)
landmarks_vectorised = get_landmarks(clahe_image)
if landmarks_vectorised == "error":
pass
else:
training_data.append(landmarks_vectorised) # append image array to training data list
training_labels.append(emotions.index(emotion))
for item in prediction:
image = cv2.imread(item)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
clahe_image = clahe.apply(gray)
landmarks_vectorised = get_landmarks(clahe_image)
if landmarks_vectorised == "error":
pass
else:
prediction_data.append(landmarks_vectorised)
prediction_labels.append(emotions.index(emotion))
return training_data, training_labels, prediction_data, prediction_labels
accur_lin = [] # 10 random set generation
for i in range(0,10):
print("Making sets %s" % i) # Make sets by random sampling 80/20%
training_data, training_labels, prediction_data, prediction_labels = make_sets()
npar_train = np.array(training_data) # numpy array
npar_trainlabs = np.array(training_labels)
print("training model %s" % i) # train model
clf.fit(npar_train, training_labels)
print("getting accuracies %s" % i)
npar_pred = np.array(prediction_data)
pred_lin = clf.score(npar_pred, prediction_labels)
print ("Model: ", pred_lin)
accur_lin.append(pred_lin) # Store accuracy in a list
print("Mean value accuracy in Model: %.3f" %np.mean(accur_lin))