====== Présentation du projet ====== ====Ce que ce programme fait==== **hellEyes** est un programme permettant de changer chaque instance d’œil dans une image en un **flash lumineux rouge provenant directement du tréfonds des enfers©**, capable de vous faire passer pour **un véritable démon**, ou encore un agent des impôts.\\ L'image en question peut être donnée, prise, ou du temps réel sur n'importe quelle caméra supportant la librairie OpenCV.\\ Ce programme n'a pas de but autre que de divertir.\\ \\ Exemple d'exécution de ce programme:\\ {{:diy:projets:barack-obama.jpg?345|Avant}} {{:diy:projets:hell_eyes.jpg?345|Après}} ---- ====== Outils requis & Librairies Python====== ====Le programme==== Le programme se trouve en intégralité [[https://github.com/JsuisUnLama/BE-2018---PHILIBERT-Thomas/blob/master/code/hellEyes.py|ici]].\\ \\ ====Outils requis==== * Un classifier entraîné dans la détection du visage, comme [[https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xml|celui-ci]]. * Un classifier entraîné dans la détection d’œil, comme [[https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_eye.xml|celui-là]].\\ * Ce magnifique [[https://github.com/JsuisUnLama/BE-2018---PHILIBERT-Thomas/blob/master/images/begoneThotEyes.png|flash lumineux de la mort qui tue]]. Le tout à placer dans le même dossier que celui du programme.\\ \\ __Remarque:__ les deux classifiers donnés sont ceux utilisés par le programme. Vous pouvez les remplacer par n'importe quels autres classifiers remplissant les mêmes fonctions mais si vous le faites, n'oubliez pas de changer les noms des fichiers chargés ici:\\ # Load XML Classifiers face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml') //lignes 117 à 119//\\ \\ ====Librairies==== Ce programme utilise les librairies suivantes: # Libraries import cv2 import sys //lignes 1 à 3// * ''cv2'' référence la librairie [[https://opencv.org/|OpenCV]] (version 3.4.1) permettant de nombreuses opérations sur les images en Python et C++\\ * ''sys'' référence la librairie [[https://docs.python.org/3/library/sys.html|sys]] pour la gestion des paramètres en Python. ---- ====== Explication du programme====== ====Le contrôle d'erreur==== Il s'agit d'un pan entier de code contrôlant l'arbre d'argument suivant:\\ {{ :diy:projets:arbre_des_arguments_hell_eyes_1_.png |}} Ce n'est pas nécessairement excitant mais ça permet au programme de détecter différentes erreurs, de s'arrêter dans de meilleures conditions et en indiquant l'erreur en question. Si cela vous intéresse, le contrôle s'étend //lignes 55 à 112//.\\ ====Les fonctions==== Voilà qui est déjà un peu plus intéressant. Ce programme contient deux fonctions: * **hellEyes**(//image à traiter, flash rouge lumineux des enfers//). * **addHellEyes**(//image à traiter, flash rouge lumineux des enfers, axe, ordonnée, largeur, hauteur//). ===hellEyes=== # Functions def hellEyes(img,begone): # Detect faces gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5, minSize=(25,25)) for (x,y,w,h) in faces: roi_gray = gray[y:y+h, x:x+w] # Detect eyes and apply function to each eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5, minSize=(10,10)) for (ex,ey,ew,eh) in eyes: addHellEyes(img,begone,x+ex,y+ey,ew,eh) return img //lignes 9 à 22//.\\ \\ On prend l'image ''img'', on la transforme en niveaux de gris, on applique le //face classifier// dessus grâce à ''detectMultiScale''. Chaque visage ainsi détecté rejoins la liste ''faces'' sous la forme d'un tuple de 4 valeurs: * axe au point en haut à gauche du visage dans le référentiel du gris de **l'image de départ**. * ordonnée au point en haut à gauche du visage dans le référentiel du gris de **l'image de départ**. * Largeur du visage. * Hauteur du visage.\\ Pour chaque visage, on définit une sous image (ou **ROI**) à partir de celle en niveau de gris, de laquelle on applique le //eye classifier// toujours avec ''detectMultiScale''. Chaque œil ainsi détecté rejoins la liste ''eyes'' sous la forme d'un autre tuple de 4 points similaire à celui des visages, excepté qu'ici **l'image de départ** est le ROI du visage en traitement.\\ Enfin pour chaque œil on applique la fonction ''addHellEyes'' en passant **l'image de départ**, le flash rouge, la position (x,y) de l’œil dans le référentiel de **l'image de départ** ainsi que la largeur et la hauteur de l’œil qu'on traite .\\ ===addHellEyes=== def addHellEyes(img,begone,ex,ey,ew,eh): # ~0.017s # Datas add_w = 80 add_h = 120 centering_parameter_y = 0 centering_parameter_x = 10 # Preprocess new_h = eh+2*add_h new_w = ew+2*add_w resized_b = cv2.resize(begone,(new_h,new_w),interpolation = cv2.INTER_AREA) y1, y2 = ey-add_w+centering_parameter_y, ey+eh+add_w+centering_parameter_y x1, x2 = ex-add_h+centering_parameter_x, ex+ew+add_h+centering_parameter_x alpha = resized_b[:, :, 3] / 255.0 ctr_alpha = 1.0 - alpha # Treatment try: for c in range(0, 3): img[y1:y2, x1:x2, c] = (alpha * resized_b[:, :, c] + ctr_alpha * img[y1:y2, x1:x2, c]) except Exception as e: pass return img //lignes 26 à 51//.\\ \\ La partie ''#Data'' contient les données paramètres de "d'explosion" du **ROI** et de centrage, s'ajoutant aux calculs suivant pour center le flash sur les yeux et pour que le étendre le flash lumineux après son le ''resize''.\\ La partie ''#Preprocess'' contient le calcul de la taille du nouvel **ROI**, le changement de taille du flash lumineux, le calcul des nouvelles valeurs de départ et de fin dans **l'image de départ** et le calcul de la valeur de transparence.\\ La partie ''#Treatment'' pose //dans un ''try ... catch'' (voir [[https://wiki.ensfea.fr/doku.php?id=diy:projets:helleyes#problemes_et_ameliorations|Problèmes et améliorations]])// le flash lumineux sur l'image de départ pixel par pixel avant de la renvoyer.\\ Et voilà, vous êtes un contrôleur des impôts démon ! Il ne reste plus qu'à l'afficher. ====Le main==== Il s'agit là aussi d'un bout de code pas très passionnant. Il s'étend //lignes 115 jusqu'à la fin// et se résume à: * Chargement des //classifiers//. * Chargement du flash lumineux. * Débuter le traitement selon la méthode choisie, i.e: * Soit en appliquant la fonction puis en écrivant le résultat si le traitement est sur image fixe. * Soit en appliquant la fonction en continue et en l'affichant le résultat en temps réel jusqu'à pression de la touche ''Q''. * Quitter. ---- ======Problèmes et améliorations====== ====Problèmes==== Même si la scène ou l'image comporte un visage, le programme peut: - Ne pas détecter pas de visage et ne cherchera donc pas à détecter d'yeux. - Détecter un visage mais ne pas détecter d'yeux, pas assez... ou trop. - Ne pas afficher de flash lumineux même s'il détecte un visage et des yeux. ====Solutions possibles et améliorations==== En ce qui concerne les problèmes de détection (1 & 2), il suffirait de posséder des //classifiers// mieux entraînés, ou bien de faire le traitement (''detectMultiScale'') avec plusieurs //classifiers// et compiler les résultats dans une liste sans doublon.\\ Faire tourner plusieurs //classifiers// par image porterait un sacré coup sur le temps réel, mais est envisageable pour l'image fixe.\\ \\ Concernant l'absence d'affichage malgré détection (3), il s'agit d'un compromis.\\ Vous vous souvenez du traitement coincé dans un //''try ... catch''//? C'est de ça qu'il s'agit. Cela provient de "l'explosion" du **ROI** qui se fait sans contrôle de valeur aucun.\\ Une solution serait d'avoir un traitement plus rigoureux concernant les valeurs maximales de **l'image de départ**, définir une limite à ne pas franchir et ne superposer qu'une portion du flash lumineux d'une limite vers la fin, du début jusqu'à une limite, ou même d'une limite jusqu'à une limite.\\ Cette fois-ci, on peut considérer que cela n’entacherait pas le temps réel car il s'agit d'opérations de tests, peu coûteuses. Seulement, par soucis de temps, cette solution n'a pas été réalisée.\\ \\ Enfin, vis à vis des améliorations possibles, j'ai surtout en tête des améliorations de performance pour le temps réel sur une machine moins puissante (RaspBerry par exemple). Une amélioration évidente serait de paralléliser le programme, puisque la fonction s'applique indépendamment à chaque œil de chaque visage. \\ \\ \\ ---- //Merci pour votre attention.//\\ //[[thomas.philibert@univ-tlse3.fr|Philibert Thomas]]//