sorted_set_facedetector.py 6.89 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
tihmels's avatar
tihmels committed
22

23
from email_service import sendMail
tihmels's avatar
tihmels committed
24
from face_detect import locate_faces
Arne Gerdes's avatar
Arne Gerdes committed
25

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

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

tihmels's avatar
tihmels committed
33
# Argument Parser erlaubt Parameter für die Verarbeitung anzugeben.
tihmels's avatar
tihmels committed
34 35 36 37 38 39 40 41 42
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/',
43
                    help='path to image source')
tihmels's avatar
tihmels committed
44
parser.add_argument('-d', '--dataset', action='store', dest='dataset', default='resources/img_data/dataset/',
Arne Gerdes's avatar
Arne Gerdes committed
45
                    help='path to dataset')
tihmels's avatar
tihmels committed
46 47
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
48 49 50 51
                    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
52
parser.add_argument('-x', '--email', action='store_true', help='activate email notifications')
53
arguments = parser.parse_args()
54 55
logging.debug(arguments)

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

61 62 63 64 65 66 67 68
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
69

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

tihmels's avatar
tihmels committed
75 76 77 78
    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))
79
    else:
tihmels's avatar
tihmels committed
80
        print('process aborted by user')
81
        sys.exit()
Arne Gerdes's avatar
Arne Gerdes committed
82

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

Arne Gerdes's avatar
Arne Gerdes committed
88
def detect_faces(emotion):
Arne Gerdes's avatar
Arne Gerdes committed
89
    """
tihmels's avatar
tihmels committed
90 91 92 93
    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
94
    """
tihmels's avatar
tihmels committed
95 96

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

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

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

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

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

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

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

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

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

150 151
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
152

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

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