process_model.py 6.26 KB
Newer Older
tihmels's avatar
tihmels committed
1
2
3
4
5
6
7
8
9
10
11
12
# ***************************************************
# * Copyright © 2010-2011 Tjado Ihmels <tjado.ihmels@uni-oldenburg.de>
# *
# * This file is part of whiteboard-project-matcher.
# *
# * whiteboard-project-matcher can not be copied and/or distributed without the express
# * permission of Tjado Ihmels
# *
# * Parts of this program are legally copied and adapted from
# * van Gent, P. (2016). Emotion Recognition With Python, OpenCV and a Face Dataset. A tech blog about fun things with Python and embedded electronics. Retrieved from:
# * http://www.paulvangent.com/2016/04/01/emotion-recognition-with-python-opencv-and-a-face-dataset/
# ***************************************************/
13

14
import argparse
Arne Gerdes's avatar
Arne Gerdes committed
15
import glob
tihmels's avatar
tihmels committed
16
import logging
Arne Gerdes's avatar
Arne Gerdes committed
17
18
19
import random
import cv2
import numpy as np
20
21
import sys

22
23
from email_service import sendMail

tihmels's avatar
tihmels committed
24
25
# This program takes the pictures from the dataset and generates a trained model

26
27
logfile = 'logs/process_model.log'

28
# Creates and configures the logger
29
logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)-8s %(message)s',
tihmels's avatar
tihmels committed
30
                    datefmt='%m-%d %H:%M',
31
                    filename=logfile)
32

33
# Argument parser allows to specify program parameters
34
parser = argparse.ArgumentParser(description='Process Model Application')
tihmels's avatar
tihmels committed
35
36
37
38
39
40
41
42
parser.add_argument('-0', action='append_const', dest='emotions', const='neutral', help='neutral')
parser.add_argument('-1', action='append_const', dest='emotions', const='happy', help='happy')
parser.add_argument('-2', action='append_const', dest='emotions', const='sadness', help='sadness')
parser.add_argument('-3', action='append_const', dest='emotions', const='surprise', help='surprise')
parser.add_argument('-4', action='append_const', dest='emotions', const='fear', help='fear')
parser.add_argument('-5', action='append_const', dest='emotions', const='disgust', help='disgust')
parser.add_argument('-6', action='append_const', dest='emotions', const='anger', help='anger')
parser.add_argument('-d', '--dataset', action='store', dest='dataset', default='resources/img_data/dataset/',
Arne Gerdes's avatar
Arne Gerdes committed
43
                    help='path to dataset')
tihmels's avatar
tihmels committed
44
parser.add_argument('-r', '--ratio', action='store', dest='ratio', help='the relative size of the training set in float [0.1,1]', default=1, type=float)
tihmels's avatar
tihmels committed
45
parser.add_argument('-i' '--iterations', action='store', dest='iterations', type=int, default=1,
46
                    help='number of iterations')
tihmels's avatar
tihmels committed
47
parser.add_argument('-p', '--properties', nargs='*', dest='properties', help='pre-processing steps for logging')
48
49
50
parser.add_argument('-t', '--test', action='store_true', dest='test', help='prevent writing new model to classifier')
parser.add_argument('-c', '--csv', action='store_true', dest='csv', help='activate csv output')
parser.add_argument('-x', '--email', action='store_true', dest='email', help='activate email notifications')
51
52
53
arguments = parser.parse_args()
logging.debug(arguments)

54
55
56
if not arguments.emotions:
    print('No emotions declared')
    sys.exit()
57
58

logging.info('Fisherface training started')
59
60
61

def _get_faces_from_emotion(emotion):
    """
62
63
64
    Get all the files to an emotion from the dataset, mix them, and split them into a training and test set.
     : param emotion: The emotion
     : return: training, prediction
65
    """
66
    files = glob.glob(arguments.dataset + '{}/*'.format(emotion))
Arne Gerdes's avatar
Arne Gerdes committed
67
    random.shuffle(files)
Arne Gerdes's avatar
Arne Gerdes committed
68

tihmels's avatar
tihmels committed
69
70
71
    # Mix the dataset in training and comparison images in the given ratio
    training = files[:int(len(files) * arguments.ratio)]
    prediction = files[-int(len(files) * (1 - arguments.ratio)):]
Arne Gerdes's avatar
Arne Gerdes committed
72

Arne Gerdes's avatar
Arne Gerdes committed
73
74
    return training, prediction

Arne Gerdes's avatar
Arne Gerdes committed
75

76
77
def image_preprocessing(image):
    """
78
79
    Preprocessing of the files
     : param item: picture
80
81
82
    """
    img = cv2.imread(image)  # open image
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # convert to grayscale
tihmels's avatar
tihmels committed
83
84
85
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    face = clahe.apply(gray)
    return face
Arne Gerdes's avatar
Arne Gerdes committed
86

Arne Gerdes's avatar
Arne Gerdes committed
87

Arne Gerdes's avatar
Arne Gerdes committed
88
def make_sets():
89
90
91
92
    """
    Creates the training set
    :return: The created training data
    """
Arne Gerdes's avatar
Arne Gerdes committed
93
94
95
96
    training_data = []
    training_labels = []
    prediction_data = []
    prediction_labels = []
97
    for emotion in arguments.emotions:
98
        training, prediction = _get_faces_from_emotion(emotion)
Arne Gerdes's avatar
Arne Gerdes committed
99
100
        # Append data to training and prediction list, and generate labels 0-7
        for item in training:
tihmels's avatar
tihmels committed
101
            img = image_preprocessing(item)
102
103
            # append image array to training data list
            training_data.append(img)
104
            training_labels.append(arguments.emotions.index(emotion))
Arne Gerdes's avatar
Arne Gerdes committed
105

106
107
        # repeat above process for prediction set
        for item in prediction:
tihmels's avatar
tihmels committed
108
109
            img = image_preprocessing(item)
            prediction_data.append(img)
110
            prediction_labels.append(arguments.emotions.index(emotion))
Arne Gerdes's avatar
Arne Gerdes committed
111
112
113

    return training_data, training_labels, prediction_data, prediction_labels

Arne Gerdes's avatar
Arne Gerdes committed
114

Arne Gerdes's avatar
Arne Gerdes committed
115
def run_recognizer():
116
117
118
119
    """
    Performs the actual training with Fisherfaces and Logged the results
    :return: The correctly recognized faces in percent
    """
Arne Gerdes's avatar
Arne Gerdes committed
120
121
    training_data, training_labels, prediction_data, prediction_labels = make_sets()

tihmels's avatar
tihmels committed
122
    logging.debug('Training...')
Arne Gerdes's avatar
Arne Gerdes committed
123
124
125
126
127
    fishface.train(training_data, np.asarray(training_labels))

    cnt = 0
    correct = 0
    incorrect = 0
tihmels's avatar
tihmels committed
128
    logging.debug('Prediction...')
Arne Gerdes's avatar
Arne Gerdes committed
129
130
131
132
133
134
135
136
    for image in prediction_data:
        pred, conf = fishface.predict(image)
        if pred == prediction_labels[cnt]:
            correct += 1
            cnt += 1
        else:
            incorrect += 1
            cnt += 1
137
    return (100 * correct) / (correct + incorrect)
Arne Gerdes's avatar
Arne Gerdes committed
138

Arne Gerdes's avatar
Arne Gerdes committed
139

140
# Emotions list
tihmels's avatar
tihmels committed
141
fishface = cv2.face.FisherFaceRecognizer_create()
Arne Gerdes's avatar
Arne Gerdes committed
142
metascore = []
tihmels's avatar
tihmels committed
143

144
# Argument parser
145
for i in range(1, arguments.iterations + 1):
Arne Gerdes's avatar
Arne Gerdes committed
146
    correct = run_recognizer()
147
    logging.info("{} : {}%".format(i, int(correct)))
Arne Gerdes's avatar
Arne Gerdes committed
148
    metascore.append(correct)
149

150
# Argument parser
151
152
if arguments.csv:
    file = open("resources/csv/{}.csv".format('_'.join(arguments.properties).lower()), "w")
153
154
155
156
157
158
159
    for entry in metascore:
        file.write("{}\n".format(int(entry)))

    file.close()

logging.info("Fisherface training finished - {}% average\n".format(np.mean(metascore)))

160
# Argument parser
161
if not arguments.test:
tihmels's avatar
tihmels committed
162
    fishface.write('resources/models/detection_model.xml')
Arne Gerdes's avatar
Arne Gerdes committed
163

164
# Argument parser
165
if arguments.email:
tihmels's avatar
tihmels committed
166
    sendMail('Fisherface training finished', body=str(arguments), filepath='resources/models/detection_model.xml')