sorted_set_facedetector.py 6.88 KB
Newer Older
tihmels's avatar
tihmels committed
1
2
3
4
5
6
7
8
9
10
11
12
13
# ***************************************************
# * 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/
# ***************************************************/

Arne Gerdes's avatar
Arne Gerdes committed
14
import argparse
Arne Gerdes's avatar
Arne Gerdes committed
15
import glob
16
import logging
Arne Gerdes's avatar
Arne Gerdes committed
17
import os
18
19
20
import shutil
import sys

Arne Gerdes's avatar
Arne Gerdes committed
21
import cv2
22
from email_service import sendMail
tihmels's avatar
tihmels committed
23
from face_detect import locate_faces
Arne Gerdes's avatar
Arne Gerdes committed
24

25
26
27
logfile = 'logs/sorted_set_facedetector.log'

logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
28
                    datefmt='%m-%d %H:%M',
29
                    filename=logfile,
30
                    filemode='w')
31

tihmels's avatar
tihmels committed
32
# Argument Parser erlaubt Parameter für die Verarbeitung anzugeben.
tihmels's avatar
tihmels committed
33
34
35
36
37
38
39
40
41
parser = argparse.ArgumentParser(description='Dataset Preprocessor')
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('-s', '--source', action='store', dest='img_source', default='resources/img_data/sorted_set/',
42
                    help='path to image source')
tihmels's avatar
tihmels committed
43
parser.add_argument('-d', '--dataset', action='store', dest='dataset', default='resources/img_data/dataset/',
Arne Gerdes's avatar
Arne Gerdes committed
44
                    help='path to dataset')
tihmels's avatar
tihmels committed
45
46
parser.add_argument('-r', '--resize', action='store', dest='resize', default=250, type=int, help='resize factor')
parser.add_argument('-c', '--scale', action='store', dest='scaleFactor', default=1.1, type=float,
tihmels's avatar
tihmels committed
47
48
49
50
                    help='scale factor (ViolaJ)')
parser.add_argument('-n', '--minneighbors', action='store', dest='minNeighbors', default=6, type=int, help='min neighbors (ViolaJ)')
parser.add_argument('-m', '--minsize', action='store', dest='minSize', default=50, type=int, help='min size (ViolaJ)')
parser.add_argument('-p', '--prefix', action='store', dest='prefix', default='', help='prefix for files')
tihmels's avatar
tihmels committed
51
parser.add_argument('-x', '--email', action='store_true', help='activate email notifications')
52
arguments = parser.parse_args()
53
54
logging.debug(arguments)

tihmels's avatar
tihmels committed
55
# if no emotions are declared, exit
56
57
58
59
if not arguments.emotions:
    print('No emotions declared')
    sys.exit()

60
61
62
63
64
65
66
67
source_path = arguments.img_source
dataset_path = arguments.dataset
resizeFactor = arguments.resize
emotions = arguments.emotions
scaleFactor = arguments.scaleFactor
minNeighbors = arguments.minNeighbors
minSize = arguments.minSize
email = arguments.email
68

tihmels's avatar
tihmels committed
69
# check if files exist at destination path and ask the user to continue
tihmels's avatar
tihmels committed
70
71
if len(os.listdir(dataset_path)) > 0:
    delete_data = input(
72
        'Im Dataset befinden sich Dateien. Durch diesen Vorgang werden die existierenden Daten gelöscht. Fortfahren (y/n): ')
73

tihmels's avatar
tihmels committed
74
75
76
77
    if delete_data == 'y':
        dir = [f for f in os.listdir(dataset_path) if os.path.isdir(os.path.join(dataset_path, f))]
        for d in dir:
            shutil.rmtree(os.path.join(dataset_path, d))
78
    else:
tihmels's avatar
tihmels committed
79
        print('process aborted by user')
80
        sys.exit()
Arne Gerdes's avatar
Arne Gerdes committed
81

tihmels's avatar
tihmels committed
82
# count some values for debugging
tihmels's avatar
tihmels committed
83
84
85
86
totalFiles: int = 0
totalFaces: int = 0
undetected: list = []

Arne Gerdes's avatar
Arne Gerdes committed
87
def detect_faces(emotion):
Arne Gerdes's avatar
Arne Gerdes committed
88
    """
tihmels's avatar
tihmels committed
89
90
91
92
    This function iterates the presorted set from one emotion and generates the dataset for recognition
    Haarcascade locates the face and with the coordinates the pictures will be resized and converted to grayscale
    :param emotion: the emotion
    :return:
Arne Gerdes's avatar
Arne Gerdes committed
93
    """
tihmels's avatar
tihmels committed
94
95

    # get all files from an emotion folder
96
    files = glob.glob(source_path + '{}/*'.format(emotion))
97
98
99
100

    global undetected
    global totalFaces
    global totalFiles
Arne Gerdes's avatar
Arne Gerdes committed
101

102
    logging.info("Found {} {} files".format(len(files), emotion))
103

tihmels's avatar
tihmels committed
104
    file_name_number = 0
Arne Gerdes's avatar
Arne Gerdes committed
105
    for f in files:
tihmels's avatar
tihmels committed
106
107
        frame = cv2.imread(f)  # open image
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # convert image to grayscale
Arne Gerdes's avatar
Arne Gerdes committed
108

tihmels's avatar
tihmels committed
109
        # extract face coordinates via haarcascade
110
        facefeatures = locate_faces(gray, scaleFactor, minNeighbors, (minSize, minSize))
tihmels's avatar
tihmels committed
111
112

        if facefeatures is '':
tihmels's avatar
tihmels committed
113
            logging.info('No face detected in ' + f)
114
            undetected.append(f)
115
            if len(undetected) % 200 == 0 and email:
tihmels's avatar
tihmels committed
116
                # could indicate that something went wrong, check the log
tihmels's avatar
tihmels committed
117
                sendMail('Already ' + str(len(undetected)) + ' undetected faces', filepath=logfile)
118
119
120
121
122
123
        else:
            # Cut and save face
            for (x, y, w, h) in facefeatures:  # get coordinates and size of rectangle containing face
                totalFaces += 1
                gray = gray[y:y + h, x:x + w]  # Cut the frame to size
                try:
124
                    out = cv2.resize(gray, (resizeFactor, resizeFactor))  # Resize face so all images have same size
tihmels's avatar
tihmels committed
125
126
127
                    save_file = dataset_path + '{}/{}{}.jpg'.format(emotion, arguments.prefix,
                                                                    file_name_number)  # filepath + name
                    success = cv2.imwrite(save_file, out)  # Write image to filesystem
128
                    if not success:
tihmels's avatar
tihmels committed
129
                        logging.error('Problem while writing file ' + str(f) + ' occurred...')
130
                        if email:
Arne Gerdes's avatar
Arne Gerdes committed
131
                            sendMail('Problem while writing file',
tihmels's avatar
tihmels committed
132
                                     body=str(f) + ' to ' + save_file)
133
                except:
134
                    logging.error('Some error with ' + f)
135
                    if email:
tihmels's avatar
tihmels committed
136
                        sendMail('Some error occured', body=f, filepath=logfile)
137
                    pass  # If error, pass file
138

tihmels's avatar
tihmels committed
139
        totalFiles += 1  # Increment image number
tihmels's avatar
tihmels committed
140
        file_name_number += 1
141

142
for emotion in emotions:
tihmels's avatar
tihmels committed
143
    # create emotion folder if not exist
144
145
    if not os.path.exists(dataset_path + emotion):
        os.makedirs(dataset_path + emotion)
Arne Gerdes's avatar
Arne Gerdes committed
146

tihmels's avatar
tihmels committed
147
    detect_faces(emotion)  # sort faces into dataset
148

149
150
logging.info('{} faces in {} files found'.format(totalFaces, totalFiles))
logging.info('In {} files no face could be detected'.format(totalFiles - totalFaces))
tihmels's avatar
tihmels committed
151

152
for f in undetected:
153
154
    logging.info(f)

155
156
if email:
    sendMail('Facedetector finished notification', filepath=logfile)