Commit 9f491647 authored by tihmels's avatar tihmels

Kommentare geschrieben

parent 53c5fa46
class RingBuffer: class RingBuffer:
"""
Simple fixed-size ringbuffer
"""
def __init__(self, size): def __init__(self, size):
self.data = [None for i in range(size)] self.data = [None for i in range(size)]
def append(self, x): def append(self, x):
"""
Append an element
:param x: the element
:return:
"""
self.data.pop(0) self.data.pop(0)
self.data.append(x) self.data.append(x)
def get(self): def get(self):
"""
return array with elements
:return: array with elements
"""
return self.data return self.data
...@@ -7,6 +7,14 @@ from email.mime.text import MIMEText ...@@ -7,6 +7,14 @@ from email.mime.text import MIMEText
def sendMail(subject, to='tjado.ihmels@uni-oldenburg.de', body='', filepath=''): def sendMail(subject, to='tjado.ihmels@uni-oldenburg.de', body='', filepath=''):
"""
For a longer runtime on a remote server emails serve as feedback
:param subject: subject
:param to: email adress
:param body: email text
:param filepath: optional attachment. For example a logfile
:return:
"""
fromaddr = "projectmood18@gmail.com" fromaddr = "projectmood18@gmail.com"
msg = MIMEMultipart() msg = MIMEMultipart()
......
""" """
Diese Klasse enthält Funktionen zum Bearbeiten von Bildern in OpenCV und PIL's Image. Utility Class for working with images in OpenCV
PIL => PIL ist die Python-Imaging-Bibliothek
""" """
import cv2 import cv2
import numpy as np import numpy as np
...@@ -9,28 +8,28 @@ from PIL import Image ...@@ -9,28 +8,28 @@ from PIL import Image
def image_as_nparray(image): def image_as_nparray(image):
""" """
Konvertiert PIL Image in ein Numpy Array Convert PIL Image to Numpy array
:param image: PIL's Image object. :param image: PIL's Image object.
:return: Numpy Array der Bilder. :return: Numpy Array
""" """
return np.asarray(image) return np.asarray(image)
def nparray_as_image(nparray, mode='RGB'): def nparray_as_image(nparray, mode='RGB'):
""" """
Konvertiert Numpy Array der Bilder in PIL Image Convert numpy array to PIL image
:param nparray: Numpy's array of image. :param nparray: Numpy's array of image.
:param mode: Modus der Umwandlung. Standardeinstellung ist "RGB". :param mode: transformation mode
:return: PIL Image mit dem Bild :return: PIL image
""" """
return Image.fromarray(np.asarray(np.clip(nparray, 0, 255), dtype='uint8'), mode) return Image.fromarray(np.asarray(np.clip(nparray, 0, 255), dtype='uint8'), mode)
def load_image(source_path): def load_image(source_path):
""" """
Lädt das RGB-Bild und konvertiert es in Graustufen. Load the RGB image and convert to grayscale
:param source_path: Quellpfad des Bildes. :param source_path: source path to image
:return: Bild wird vom Pfad geladen und in Graustufen konvertiert. :return: converted image
""" """
source_image = cv2.imread(source_path) source_image = cv2.imread(source_path)
return cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY) return cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY)
...@@ -38,24 +37,23 @@ def load_image(source_path): ...@@ -38,24 +37,23 @@ def load_image(source_path):
def draw_with_alpha(source_image, image_to_draw, coordinates): def draw_with_alpha(source_image, image_to_draw, coordinates):
""" """
Zeichnet ein teilweise transparentes Bild über ein anderes Bild. Draw a partially transparent image on another image
:param source_image: Bild zum Übermalen. :param source_image: Background image
:param image_to_draw: Bild zum Zeichnen. :param image_to_draw: Overdraw image
:param coordinates: : Koordinaten um ein Bild zu zeichnen. Tupel von x, y, Breite und Höhe. :param coordinates: : Coordinates to which the image should be drawn
""" """
x, y, w, h = coordinates x, y, w, h = coordinates
image_to_draw = image_to_draw.resize((h, w), Image.ANTIALIAS) image_to_draw = image_to_draw.resize((h, w), Image.ANTIALIAS)
image_array = image_as_nparray(image_to_draw) image_array = image_as_nparray(image_to_draw)
for c in range(0, 3): for c in range(0, 3):
source_image[y:y + h, x:x + w, c] = image_array[:, :, c] * (image_array[:, :, 3] / 255.0) \ source_image[y:y + h, x:x + w, c] = image_array[:, :, c] * (image_array[:, :, 3] / 255.0) + source_image[y:y + h, x:x + w, c] * (1.0 - image_array[:, :, 3] / 255.0)
+ source_image[y:y + h, x:x + w, c] * (1.0 - image_array[:, :, 3] / 255.0)
def draw_img(source_image, image_to_draw, coordinates): def draw_img(source_image, image_to_draw, coordinates):
""" """
Zeichnet ein teilweise transparentes Bild über ein anderes Bild. Draw an image to another image
:param source_image: Bild zum Übermalen. :param source_image: Background image
:param image_to_draw: Bild zum Zeichnen. :param image_to_draw: Overdraw image
:param coordinates: : Koordinaten um ein Bild zu zeichnen. Tupel von x, y, Breite und Höhe. :param coordinates: : Coordinates to which the image should be drawn
""" """
x, y, w, h = coordinates x, y, w, h = coordinates
image_to_draw = image_to_draw.resize((h, w), Image.ANTIALIAS) image_to_draw = image_to_draw.resize((h, w), Image.ANTIALIAS)
......
...@@ -5,7 +5,6 @@ import glob ...@@ -5,7 +5,6 @@ import glob
import logging import logging
import random import random
import cv2 import cv2
import cv2.face
import numpy as np import numpy as np
import sys import sys
......
...@@ -15,10 +15,8 @@ logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(name)-12s %(leve ...@@ -15,10 +15,8 @@ logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(name)-12s %(leve
datefmt='%m-%d %H:%M', datefmt='%m-%d %H:%M',
filename=logfile, filename=logfile,
filemode='w') filemode='w')
"""
Argument Parser erlaubt Parameter für die Verarbeitung anzugeben.
"""
# Argument Parser erlaubt Parameter für die Verarbeitung anzugeben.
parser = argparse.ArgumentParser(description='Dataset Preprocessor') parser = argparse.ArgumentParser(description='Dataset Preprocessor')
parser.add_argument('-0', action='append_const', dest='emotions', const='neutral', help='neutral') 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('-1', action='append_const', dest='emotions', const='happy', help='happy')
...@@ -41,6 +39,7 @@ parser.add_argument('-x', '--email', action='store_true', help='activate email n ...@@ -41,6 +39,7 @@ parser.add_argument('-x', '--email', action='store_true', help='activate email n
arguments = parser.parse_args() arguments = parser.parse_args()
logging.debug(arguments) logging.debug(arguments)
# if no emotions are declared, exit
if not arguments.emotions: if not arguments.emotions:
print('No emotions declared') print('No emotions declared')
sys.exit() sys.exit()
...@@ -54,6 +53,7 @@ minNeighbors = arguments.minNeighbors ...@@ -54,6 +53,7 @@ minNeighbors = arguments.minNeighbors
minSize = arguments.minSize minSize = arguments.minSize
email = arguments.email email = arguments.email
# check if files exist at destination path and ask the user to continue
if len(os.listdir(dataset_path)) > 0: if len(os.listdir(dataset_path)) > 0:
delete_data = input( delete_data = input(
'Im Dataset befinden sich Dateien. Durch diesen Vorgang werden die existierenden Daten gelöscht. Fortfahren (y/n): ') 'Im Dataset befinden sich Dateien. Durch diesen Vorgang werden die existierenden Daten gelöscht. Fortfahren (y/n): ')
...@@ -66,14 +66,20 @@ if len(os.listdir(dataset_path)) > 0: ...@@ -66,14 +66,20 @@ if len(os.listdir(dataset_path)) > 0:
print('process aborted by user') print('process aborted by user')
sys.exit() sys.exit()
# count some values for debugging
totalFiles: int = 0 totalFiles: int = 0
totalFaces: int = 0 totalFaces: int = 0
undetected: list = [] undetected: list = []
def detect_faces(emotion): def detect_faces(emotion):
""" """
Holt alle Dateien zu einer Emotion aus dem sorted_set 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:
""" """
# get all files from an emotion folder
files = glob.glob(source_path + '{}/*'.format(emotion)) files = glob.glob(source_path + '{}/*'.format(emotion))
global undetected global undetected
...@@ -84,15 +90,17 @@ def detect_faces(emotion): ...@@ -84,15 +90,17 @@ def detect_faces(emotion):
file_name_number = 0 file_name_number = 0
for f in files: for f in files:
frame = cv2.imread(f) # Open image frame = cv2.imread(f) # open image
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Convert image to grayscale gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # convert image to grayscale
# extract face coordinates via haarcascade
facefeatures = locate_faces(gray, scaleFactor, minNeighbors, (minSize, minSize)) facefeatures = locate_faces(gray, scaleFactor, minNeighbors, (minSize, minSize))
if facefeatures is '': if facefeatures is '':
logging.info('No face detected in ' + f) logging.info('No face detected in ' + f)
undetected.append(f) undetected.append(f)
if len(undetected) % 200 == 0 and email: if len(undetected) % 200 == 0 and email:
# could indicate that something went wrong, check the log
sendMail('Already ' + str(len(undetected)) + ' undetected faces', filepath=logfile) sendMail('Already ' + str(len(undetected)) + ' undetected faces', filepath=logfile)
else: else:
# Cut and save face # Cut and save face
...@@ -100,9 +108,10 @@ def detect_faces(emotion): ...@@ -100,9 +108,10 @@ def detect_faces(emotion):
totalFaces += 1 totalFaces += 1
gray = gray[y:y + h, x:x + w] # Cut the frame to size gray = gray[y:y + h, x:x + w] # Cut the frame to size
try: try:
save_file = dataset_path + '{}/{}{}.jpg'.format(emotion, arguments.prefix, file_name_number)
out = cv2.resize(gray, (resizeFactor, resizeFactor)) # Resize face so all images have same size out = cv2.resize(gray, (resizeFactor, resizeFactor)) # Resize face so all images have same size
success = cv2.imwrite(save_file, out) # Write image save_file = dataset_path + '{}/{}{}.jpg'.format(emotion, arguments.prefix,
file_name_number) # filepath + name
success = cv2.imwrite(save_file, out) # Write image to filesystem
if not success: if not success:
logging.error('Problem while writing file ' + str(f) + ' occurred...') logging.error('Problem while writing file ' + str(f) + ' occurred...')
if email: if email:
...@@ -118,11 +127,11 @@ def detect_faces(emotion): ...@@ -118,11 +127,11 @@ def detect_faces(emotion):
file_name_number += 1 file_name_number += 1
for emotion in emotions: for emotion in emotions:
# create emotion folder if not exist
if not os.path.exists(dataset_path + emotion): if not os.path.exists(dataset_path + emotion):
os.makedirs(dataset_path + emotion) os.makedirs(dataset_path + emotion)
detect_faces(emotion) # Call functional detect_faces(emotion) # sort faces into dataset
logging.info('{} faces in {} files found'.format(totalFaces, totalFiles)) logging.info('{} faces in {} files found'.format(totalFaces, totalFiles))
logging.info('In {} files no face could be detected'.format(totalFiles - totalFaces)) logging.info('In {} files no face could be detected'.format(totalFiles - totalFaces))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment