process_model.py 5.39 KB
Newer Older
1 2
# This class makes the training of the model possible

3
import argparse
4
import glob
tihmels's avatar
tihmels committed
5
import logging
Arne Gerdes's avatar
Arne Gerdes committed
6 7
import random
import cv2
tihmels's avatar
tihmels committed
8
import cv2.face
Arne Gerdes's avatar
Arne Gerdes committed
9
import numpy as np
10 11
import sys

12 13 14 15
from email_service import sendMail

logfile = 'logs/process_model.log'

16
# Creates and configures the logger
17
logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)-8s %(message)s',
tihmels's avatar
tihmels committed
18
                    datefmt='%m-%d %H:%M',
19
                    filename=logfile)
20

21
# Argument parser allows to specify program parameters
22
parser = argparse.ArgumentParser(description='Process Model Application')
tihmels's avatar
tihmels committed
23 24 25 26 27 28 29 30
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
31
                    help='path to dataset')
tihmels's avatar
tihmels committed
32
parser.add_argument('-i' '--iterations', action='store', dest='iterations', type=int, default=1,
33
                    help='number of iterations')
tihmels's avatar
tihmels committed
34
parser.add_argument('-p', '--properties', nargs='*', dest='properties', help='pre-processing steps for logging')
35 36 37
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')
38 39 40
arguments = parser.parse_args()
logging.debug(arguments)

41 42 43
if not arguments.emotions:
    print('No emotions declared')
    sys.exit()
44 45

logging.info('Fisherface training started')
46 47 48

def _get_faces_from_emotion(emotion):
    """
49 50 51
    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
52
    """
53
    files = glob.glob(arguments.dataset + '{}/*'.format(emotion))
54
    random.shuffle(files)
55

56
    # Mix the dataset in training and comparison images in the ratio 80 to 20
57 58 59
    training = files[:int(len(files) * 0.8)]
    prediction = files[-int(len(files) * 0.2):]

60 61
    return training, prediction

62

63 64
def image_preprocessing(image):
    """
65 66
    Preprocessing of the files
     : param item: picture
67 68 69
    """
    img = cv2.imread(image)  # open image
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # convert to grayscale
tihmels's avatar
tihmels committed
70 71 72
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    face = clahe.apply(gray)
    return face
73

74

75
def make_sets():
76 77 78 79
    """
    Creates the training set
    :return: The created training data
    """
80 81 82 83
    training_data = []
    training_labels = []
    prediction_data = []
    prediction_labels = []
84
    for emotion in arguments.emotions:
85
        training, prediction = _get_faces_from_emotion(emotion)
86 87
        # Append data to training and prediction list, and generate labels 0-7
        for item in training:
tihmels's avatar
tihmels committed
88
            img = image_preprocessing(item)
89 90
            # append image array to training data list
            training_data.append(img)
91
            training_labels.append(arguments.emotions.index(emotion))
92

93 94
        # repeat above process for prediction set
        for item in prediction:
tihmels's avatar
tihmels committed
95 96
            img = image_preprocessing(item)
            prediction_data.append(img)
97
            prediction_labels.append(arguments.emotions.index(emotion))
98 99 100

    return training_data, training_labels, prediction_data, prediction_labels

101

102
def run_recognizer():
103 104 105 106
    """
    Performs the actual training with Fisherfaces and Logged the results
    :return: The correctly recognized faces in percent
    """
107 108
    training_data, training_labels, prediction_data, prediction_labels = make_sets()

tihmels's avatar
tihmels committed
109
    logging.debug('Training...')
110 111 112 113 114
    fishface.train(training_data, np.asarray(training_labels))

    cnt = 0
    correct = 0
    incorrect = 0
tihmels's avatar
tihmels committed
115
    logging.debug('Prediction...')
116 117 118 119 120 121 122 123
    for image in prediction_data:
        pred, conf = fishface.predict(image)
        if pred == prediction_labels[cnt]:
            correct += 1
            cnt += 1
        else:
            incorrect += 1
            cnt += 1
124
    return (100 * correct) / (correct + incorrect)
125

Arne Gerdes's avatar
Arne Gerdes committed
126

127
# Emotions list
tihmels's avatar
tihmels committed
128
fishface = cv2.face.FisherFaceRecognizer_create()
129
metascore = []
tihmels's avatar
tihmels committed
130

131
# Argument parser
132
for i in range(1, arguments.iterations + 1):
133
    correct = run_recognizer()
134
    logging.info("{} : {}%".format(i, int(correct)))
135
    metascore.append(correct)
136

137
# Argument parser
138 139
if arguments.csv:
    file = open("resources/csv/{}.csv".format('_'.join(arguments.properties).lower()), "w")
140 141 142 143 144 145 146
    for entry in metascore:
        file.write("{}\n".format(int(entry)))

    file.close()

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

147
# Argument parser
148
if not arguments.test:
tihmels's avatar
tihmels committed
149
    fishface.write('resources/models/detection_model.xml')
150

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