alexylem / jarvis

Jarvis.sh is a simple configurable multi-lang assistant.
http://openjarvis.com
MIT License
810 stars 197 forks source link

Détection et reconnaissance Faciale avec apprentissage #56

Open alexylem opened 8 years ago

alexylem commented 8 years ago

Description

Donner la vue à jarvis: intégrer Jarvis avec l'un de mes autres projets sur opencv pour qu'il puisse détecter les visages, vous reconnaître s'il vous connaît déjà, et vous proposer de se souvenir de votre visage le cas échéant. L'idée principale serait d'avoir des notifications personnalisées en fonction de la personne qui passe devant les yeux de Jarvis, ex:

(Alex passe devant la caméra)
Jarvis: Oh bonjour Alex, tu as 2 emails non lus, veux-tu que je te les lise?
Smanar commented 8 years ago

Bon j'ai fait quelque test, c'est a la fois simple et complique. Il te faut decider des le depart quel algorithme tu veux utiliser car il n'y a pas moyen de convertir un LBPHFaceRecognizer en BasicFaceRecognizer.

Si tu veux utiliser LBPHFaceRecognizer il te suffit de remplacer les BasicFaceRecognizer par des LBPHFaceRecognizer

Ptrcv::face::LBPHFaceRecognizer learnCollectedFacesLBPH(const vector preprocessedFaces, const vector faceLabels, const string facerecAlgorithm) Ptrcv::face::LBPHFaceRecognizer model;

et ce dans 3 fichiers, recognition.h recognition.cpp et main.cpp

J'ai essayer de tout faire en doublon, mais ca double le code, impossible de garder un bout en commun.

physicien commented 8 years ago

Je viens d'essayer et le problème est qu'à la compilation, on retrouve un bon paquet d'erreurs que BasicFaceRecognizer avait corrigé.

Smanar commented 8 years ago

Tu as du deborder, en fait il faut modifier la fonction learnCollectedFaces, donc faut changer sa definition dans le fichier recognition.h et dans le fichier recognition.cpp puis la ligne Ptrcv::face::LBPHFaceRecognizer model; en debut de la fct dans le fichier recognitiuon.cpp Et evidement dans le fichier main.cpp pareil la ligne Ptrcv::face::LBPHFaceRecognizer model; en debut de fonction

et de memoire c'est tout.

physicien commented 8 years ago

@Smanar J'ai étrangement quelques erreurs encore, mais je vais tenter d'y réfléchir à tête reposé. Entre temps, j'ai grandement avancé du côté de la mémoire du module de reconnaissance faciale. Ce n'est pas encore complété et je dois encore résoudre une tonne d'erreurs, mais je partage mon avancement d'un nouveau main.cpp. Si ça dit à quelqu'un de l'essayer, juste faire attention au fait que j'ai mis de meilleurs classeurs pour la détections des yeux, et qu'ils sont disponible sur mon repository FaceRecognition.

Smanar commented 8 years ago

Si tu galeres encore donne moi la ligne ou ca deconne. Sinon suis pas un pro des licences, mais quand tu modifis un fichier ne t'appartenant pas, tu es sense le signaler en en-tete par exemple.

physicien commented 8 years ago

@Smanar oui, je suis aussi en train de voir pour les licences, je vais faire ça dès que j'ai 5 minutes. Sinon, j'ai réussi à faire fonctionner le code avec enregistrement des noms, mais j'ai encore un segmentation fault à la ligne 304 pour ce qui est de l'enregistrement de l'entraînement. Tout est sur le repo.

Smanar commented 8 years ago

J'ai fait un test rapide, mais comment tu fais pour sauvegarder ? Je peux juste apprendre de nouvelles tetes.

physicien commented 8 years ago

C'est en quittant que la sauvegarde est supposé se faire.

Smanar commented 8 years ago

Ok alors c'est pour ca que je galere. J'ai vu ecris qu'il fallait presser esc pr quitter, et c'est la que ca ne marche pas, mais faut dire que je teste sous windows pas unix.

physicien commented 8 years ago

Même moi sous Unix j'ai un segmentation fault en quittant. J'ai bien vérifié et c'est la ligne 304 du main. Je ne sais pas encore comment corriger le problème par contre.

Smanar commented 8 years ago

Nope, ce que je voulais dire c'est que la touche "esc" ne marchait pas, je ne devais pas avoir le focus sur la bne fenetre parce que now ca fonctionne.

Sinon pour le bug c'est normal. Tu es dans la fonction recognizeAndTrainUsingWebcam() ou model est defini, mais quand tu presses esc tu pars dans la fonction saveDatabase() et dans celle la model n'est pas definis. Donc plusieurs solutions

1 - Faire un pointeur model global pour le projet, non conseille. 2 - copier toute la fonction saveDatabase() a l'interieur de la fonction recognizeAndTrainUsingWebcam() 3 - passer model en parametre a la fonction saveDatabase() (meilleure solution) eg saveDatabase(model); avec void saveDatabase(Ptrcv::face::BasicFaceRecognizer model)

Par contre j'ai eu becaoup de mal avec les chemins d'acces.

physicien commented 8 years ago

Je viens d'essayer la 3e solution et ça semble en effet vouloir fonctionner, mais les chemins d'accès semblent être problématiques de mon côté aussi.

OpenCV Error: Unspecified error (File can't be opened for writing!) in save, file /home/esteban/OpenCV/opencv_contrib/modules/face/src/facerec.cpp, line 70
terminate called after throwing an instance of 'cv::Exception'
  what():  /home/esteban/OpenCV/opencv_contrib/modules/face/src/facerec.cpp:70: error: (-2) File can't be opened for writing! in function save
Smanar commented 8 years ago

De memoire le pire etait le chemin d'acces du fichier de sauvegarde, un truc du style "data/____.xml", vu qu'il n y a pas de repertoire data. Suffit de garder que le nom, sans le sous repertoire.

physicien commented 8 years ago

J'ai tout simplement envoyé le tout dans ../data/nom_du_fichier et j'ai créé un répertoire data au bon endroit. Je réussi donc à enregistrer le modèle. Par contre, quand je relance le programme je n'ai pas l'impression qu'il arrive à load le dit modèle. Je viens de mettre à jour le répertoire avec mes modifications.

physicien commented 8 years ago

C'est corrigé, j'avais simplement oublié une ligne de code :laughing:

Il ne reste plus qu'à convertir le code pour qu'il utilise LBPH. Je ne sais pas quel va être le niveau de difficulté, mais c'est déjà ça d'être rendu là :smile:

EDIT: Il y a encore quelques petits bugs quand je load le modèle déjà entraîné, et je ne saurais pas vraiment décrire ces bugs, mais je ne pense pas qu'ils seront vraiment difficile à corriger. Je les mentionne ici simplement pour la forme.

Smanar commented 8 years ago

Mais c'est quoi l'utilite en fait, ca va marcher en meme temps avec LBPH et un autre mode, ou il va falloir choisir ? Pkoi ne pas s'en tenir a un seul mode ?

physicien commented 8 years ago

Pour faire simple, LBPH est moins sujet à l'erreur lors de conditions de luminosités différentes et surtout, il permet d'améliorer un entraînement déjà effectué en ajoutant de nouvelles photos du visage, sans pour autant recommencer l'entraînement au complet. Et pour ta première question, il faut choisir un algorithme à utiliser (malgré qu'il existe des systèmes hybrides, mais c'est un peu trop avancé pour ce que nous voulons), donc autant prendre celui qui ne nous limitera pas à moyen-terme.

Smanar commented 8 years ago

Dans ce cas fait le tourner uniquement en LBPH, tres peu de modifs (6/8 lignes max) avec la modif dont j'ai parle un peu plus tot.

physicien commented 8 years ago

Ce sera donc comme ça. J'ai commencé et je ne suis pas certain si c'est si simple ou si c'est moi qui fait quoi que ce soit de mal, car j'ai des problèmes avec la modif que tu as mentionné plus haut. Elle semble avoir des problèmes avec la fonction showTrainingDebugData et je ne suis pas certain de changer tout ce qu'il faut. As-tu essayé la modif de ton côté? Aussi, je pense que si nous passons à LBPH, il va falloir regarder si des modifications sont nécessaires dans l'entraînement suite à l'ajout de nouvelles données pour un visage déjà connu.

Michelgard commented 8 years ago

Bonsoir depuis quelque je bricole en python sur la reconnaissance faciale. Pour détecter un visage ou des visage dans une vidéo pas de soucis avec un jolie carré dessus tout va bien. Mais quand il faut mettre un nom dessus là c'est plus compliqué pour moi. Alors j'ai bien un nom mais soit toujours le même soit toujours un mauvais ou avec un indice très mauvais ou pire un visage inconnu d'un magasine avec un meilleur indice que moi en original. J'ai essayé plusieurs méthode avec des positif avec négatif Bof. Que des positifs dans un répertoire différent suivant la personne Bof. En faisant un fichier XML ou en direct. rien de bien concluant... Je vois qu'alex obtient 4125 avec son visage et 4426 sur un inconnu la différence n'est pas énorme comme indice suivant le curseur on pourrais avoir l'inverse. Vous utilisez quoi comme solution ? createFisherFaceRecognizer, createLBPHFaceRecognizer ... Avec des négatif et positif ? Combien d'image ? Merci de vos conseils. Je suis en python 2.7 et opencv 3.1

physicien commented 8 years ago

Pour l'instant, on utilise EigenFace qui ne nécessite pas d'avoir nécessairement plusieurs personnes dans le modèle, mais on souhaite passer à LBPH quand le courage de repasser dans le code y sera.

Si tu veux essayer, nous avons remis à jour un code en C++ disponible sur ce répertoire.

Michelgard commented 8 years ago

De mon coté en python j'ai essayé les trois :createEigenFaceRecognizer(),createFisherFaceRecognizer(),createLBPHFaceRecognizer() Et il y a une chose de sur c'est que j'ai le même résultat avec les trois... mais des résultats pas souvent justes il y a trop peu de différence d'indice entre une personne connue et une personne non connue. Même des fois l'indice est meilleur avec une personne inconnue !!! Mais comme je suis persévérant je vais continuer je passe peut être à coté de quelque chose. Merci

HoLengZai commented 8 years ago

Hello,

FYI, don't know if this article can help to speed up this functionality since we use Bing Voice recognition? https://msdn.microsoft.com/en-us/magazine/mt742868.aspx?wt.mc_id=AID529260_EML_4624092

So an idea could be that a ip camera / webcam save your picture on motion detection and jarvis is called to check the pic and to recognize our face and to do an action.?

wikijm commented 7 years ago

Est-ce que vos recherches sont suffisamment avancées pour en générer un plugin ?

physicien commented 7 years ago

Je pense bien que nos recherches ont donné de bons résultats. Dans mon cas c'était fonctionnel, mais le GUI avais encore des bugs. Mais bon, pour résumer, vaut mieux utiliser LBPH que EigenFace ou FisherFace.

wikijm commented 7 years ago

@physicien Pourrais-tu nous faire un résumé des actions à mener pour arriver à ton résultat "from scratch" ?

physicien commented 7 years ago

Mon résumé sera assez sommaire, car j'ai principalement pris un vieux code que j'ai mis à jour (ce qui ne fut pas évident). Mais avant tout, voici quelques fonctions qui sont nécessaires.

Pour ce qui est de la boucle principale, elle fonctionne ainsi:

// Main loop that runs forever, until the user hits Escape to quit.{
    // Since we have already initialized everything, lets start in Detection mode.
    // Run forever, until the user hits Escape to "break" out of this loop.
    while (true) {
        // Grab the next camera frame. Note that you can't modify camera frames.
        // Get a copy of the camera frame that we can draw onto.
        // Run the face recognition system on the camera image. It will draw some things onto the given image, so make sure it is not read-only memory!
        // Find a face and preprocess it to have a standard size and contrast & brightness.
GUI     // Draw an anti-aliased rectangle around the detected face.
        if (m_mode == MODE_DETECTION) {
            // Don't do anything special.
        }
        else if (m_mode == MODE_COLLECT_FACES) {
            // Check if we have detected a face.
            if (gotFaceAndEyes) {
                // Check if this face looks somewhat different from the previously collected face.
                // Also record when it happened.
                // Only process the face if it is noticeably different from the previous frame and there has 
                    // Also add the mirror image to the training set, so we have more training data, as well as to deal with faces looking to the left or right.
                    // Add the face images to the list of detected faces.
                    // Keep a reference to the latest face of each person.
GUI                 // Show the number of collected faces. But since we also store mirrored faces, just show how many the user thinks they stored.
GUI                 // Make a white flash on the face, so the user knows a photo has been taken.
                    // Keep a copy of the processed face, to compare on next iteration.
        }
        else if (m_mode == MODE_TRAINING) {
            // Check if there is enough data to train from. For Eigenfaces or LBPH, we can learn just one person if we want, 
            // but for Fisherfaces, we need atleast 2 people otherwise it will crash!
            if (haveEnoughData) {
                // Start training from the collected faces using Eigenfaces or a similar algorithm.
                // Now that training is over, we can start recognizing!
                // Since there isn't enough training data, go back to the face collection mode!
        }
        else if (m_mode == MODE_RECOGNITION) {
                // Generate a face approximation by back-projecting the eigenvectors & eigenvalues.
                // Verify whether the reconstructed face looks like the preprocessed face, otherwise it is 
                if (similarity < UNKNOWN_PERSON_THRESHOLD) {
                    // Identify who the person is in the preprocessed face image.
                }
                else {
                    // Since the confidence is low, assume it is an unknown person.
                }
GUI             // Show the confidence rating for the recognition in the mid-top of the display.
GUI             // Draw a gray line showing the threshold for an "unknown" person.
GUI             // Crop the confidence rating between 0.0 to 1.0, to show in the bar.
GUI             // Show the light-blue confidence bar.
GUI             // Show the gray border of the bar.
        else if (m_mode == MODE_DELETE_ALL) {
            // Restart everything!
            // Restart in Detection mode.
GUI     // Show the help, while also showing the number of collected faces. Since we also collect mirrored faces, we should just
GUI     // Tell the user how many faces they think we saved (ignoring the mirrored faces), hence divide by 2.
GUI     // Show the current mode.
GUI     // Show the current preprocessed face in the top-center of the display.
GUI     // Draw an anti-aliased border around the face, even if it is not shown.
GUI     // Draw the GUI buttons into the main image.
GUI     // Show the most recent face for each of the collected people, on the right side of the display.
GUI     // Highlight the person being collected, using a red rectangle around their face.
GUI     // Highlight the person that has been recognized, using a green rectangle around their face.
GUI     // Show the camera frame on the screen.
GUI     // If the user wants all the debug data, show it to them!
GUI     // IMPORTANT: Wait for at least 20 milliseconds, so that the image can be displayed on the 
GUI     // Also checks if a key was pressed in the GUI window. Note that it should be a "char" to 
    }//end while
}

C'est du pseudo-code, et j'ai laissé les étapes de GUI facilement identifiables pour ne garder que l'essentiel.

QuentinCG commented 7 years ago

Bonjour à tous,

Vous semblez arriver à faire pas mal de choses au niveau de la reconnaissance de visage mais le plugin ne semble pas se créer... Une raison?

Manque de motivation pour le faire? Idées pas assez mûres? Des obstacles?

Dans tous les cas, un plugin permettant d'installer/configurer/utiliser "facilement" OpenCV (ou autre) pour la détection de visage et créer des events Jarvis en conséquence serait vraiment cool.

Je suis des votre si il y a besoin d'aide sur le sujet (je n'y connais pas grand chose en OpenCV mais c'est l'occasion de découvrir). J'attends d'abord de mieux comprendre ce qui bloque et ce qui peut fonctionner avant d'aider =P

physicien commented 7 years ago

De mon côté, c'est surtout que je suis très occupé dans mes recherches (je suis en physique mathématique après tout), donc je continue de surveiller les posts, mais je suis un peu moins actifs.

QuentinCG commented 7 years ago

Ca marche.

Je ne vois pas forcement d'obstacle à cette feature car je vois pas mal de libs (python/C++/...) qui permettent d'utiliser la reconnaissance facial sans trop de soucis.

Je vais faire des tests de mon coté et voir si des choses peuvent se faire et me lancer si j'ai le courage (un plugin "beta" à potentiellement remanier une fois que l'on aura trouvé la meilleur solution et que Jarvis intégrera le multi-users).

Fruit de mes recherches sur ce qui me semble le plus simple pour notre cas: https://github.com/ageitgey/face_recognition

QuentinCG commented 7 years ago

Bonjour,

J'ai fait une EBAUCHE de plugin pour Jarvis avec reconnaissance faciale qui se base sur la lib python https://github.com/ageitgey/face_recognition (qui se base elle meme sur OpenCV).

Voici le plugin: https://github.com/QuentinCG/jarvis-face-recognition

Pour le moment, le plugin fonctionne de la manière suivante lors du lancement de Jarvis:

Voici un aperçu des logs en lançant le plugin en mode Keyboard (j'ai laissé délibérément les logs sur le terminal): _DEBUG:root:Enabling PiCamera DEBUG:root:Loading known face image(s) DEBUG:root:Loading image of 'Barack Obama' ('plugins_installed/jarvis-face-recognition/example/barack_obama.jpg') DEBUG:root:Loading image of 'Hillary Clinton' ('plugins_installed/jarvis-face-recognition/example/hillaryclinton.jpg') DEBUG:root:Capturing image DEBUG:root:Trying to find faces DEBUG:root:Found 0 face in image DEBUG:root:Waiting 2sec DEBUG:root:Capturing image DEBUG:root:Trying to find faces DEBUG:root:Found 1 face in image DEBUG:root:Comparing found faces with registered faces DEBUG:root:I see someone named 'Unknown user' Jarvis: J'ai détécté Unknown user

Les + de ce plugin :

Les - de ce plugin et Jarvis (améliorable):

Les - de ce plugin (non améliorable):

physicien commented 7 years ago

@QuentinCG Quel FaceRecognizer utilises-tu? Et je suis surpris que l'analyse prenne 5 secondes, car c'était beaucoup plus rapide dans le code que j'ai partagé.

QuentinCG commented 7 years ago

@physicien J'ai juste suivi ce tuto https://gist.github.com/ageitgey/1ac8dbe8572f3f533df6269dab35df65 et testé la lib python (c'est ultra simple à mettre en place).

L'idée est plus de poser un plugin de base quitte à la modifier complétement par la suite en utilisant complètement autre chose ;)

Je vais tester ta solution qui semble plus fluide ;) Comment vois tu l'intégration de ce que tu as fais dans un plugin de reconnaissance faciale pour Jarvis? (peux tu regarder vite fait ce que j'ai fait et faire une comparaison me donner une idée de ce qu'il y a à réaliser pour utiliser ton code pour Jarvis?)

physicien commented 7 years ago

@QuentinCG J'aimerais savoir qu'est-ce qui prend combien de temps dans la partie analyse d'une image. Je lis l'article expliquant comment la library fait les différentes étapes, et je crois que le problème est peut-être là, car la détection d'un visage se fait avec HOG et l'identification avec face landmark estimation. Ces méthodes me semblent beaucoup plus précises, mais probablement beaucoup plus lourdes sur un RP3. Je t'invite aussi de ton côté à regarder le pseudo code que j'ai laissé sur mon post du 29 mars. Dans mon code, j'utilise directement OpenCV et la traduction en python est certainement la prochaine étape (avec le débogage du GUI).

matt496 commented 7 years ago

Bonjour, j'ai regardé cette conversation mais je ne voie pas trop comment installer tout ca ^^^ Merci de me guidé.

alexylem commented 7 years ago

@matt496 le plugin est en cours de développement. Regarde le dernier post de @QuentinCG.

@QuentinCG

Ajouter le multiuser sur Jarvis car pour le moment, ce plugin n'a pas d’intérêt réel avec la façon dont Jarvis fonctionne... : A voir avec @alexylem sur la façon d’intégrer le multi-user (pour ma part, un "jarvis.sh -x "User is now XXXX" serait parfait... à voir sur la faisabilité).

Voir #190 notamment ma proposition d'implémentation. Si tu es d'accord je peux m'y mettre assez rapidement. Mais c'est un gros dev.

Détecter TOUTES les personnes de la photo

Dépend aussi du ticket référencé ci-dessus. Mais je ne vois pas trop l'intérêt dans une utilisation normale. Moi je m'arrêterais à la première personne connue.

Intégrer des capteurs de présence pour prendre une photo uniquement quand quelqu'un est détecté: Cela permettra d'éviter d'utiliser trop de CPU

Sur mon proto j'ai séparé la détection de visage de la reconnaissance de visage. La détection prend bcp moins de resource et ne cherche à reconnaitre que si un visage n'est détecté, mais tu as peut-être fait la même chose.

L'installation de ce plugin prend environ 4h

Normal, et encore ca c'est pour un Raspberry Pi 3 j'imagine. Sur mon 1 ca avait pris 24h 😄

QuentinCG commented 7 years ago

@alexylem

Si tu es d'accord je peux m'y mettre assez rapidement. Mais c'est un gros dev.

Je regarderais ca la semaine prochaine ;) (mais je pense que tu es le plus à même d'avoir une idée de ce qui peut etre implémenté coté Jarvis.

Moi je m'arrêterais à la première personne connue.

Ca me semble cohérent. C'était plus une réflexion sur ce qui est possible et voir si cela a une utilité.

Sur mon proto j'ai séparé la détection de visage de la reconnaissance de visage. La détection prend bcp moins de resource et ne cherche à reconnaitre que si un visage n'est détecté, mais tu as peut-être fait la même chose.

Oui j'ai fait pareil mais la lib que j'utilise semble très gourmande lors de la détection des visages (je vais essayer avec vos protos ;)

Normal, et encore ca c'est pour un Raspberry Pi 3 j'imagine. Sur mon 1 ca avait pris 24h 😄

Outch...

stefanekz commented 7 years ago

Bonjour, J'ai installé OpenCv sur ma raspberry pi3 (2017-08-16-raspbian-stretch) en suivant étape par étape ce tutoriel. http://www.pyimagesearch.com/2017/09/04/raspbian-stretch-install-opencv-3-python-on-your-raspberry-pi/ La compilation s'est bien passée.

Lorsque je lance un simple programme, voiçi ce qu'il me renvoi :

(cv) pi@raspberrypi:~ $ sudo modprobe bcm2835-v4l2 (cv) pi@raspberrypi:~ $ python script.py Unable to init server: Could not connect: Connection refused

(video test:1029): Gtk-WARNING **: cannot open display: (cv) pi@raspberrypi:~ $

Ce programme fonctionne très bien sur mon pc avec LinuxMint.

Merci pour vos réponses.

Stéphane.

ghost commented 6 years ago

Salut les gars, j'aimerai savoir ou en ai votre reconnaissance facial compatible avec Jarvis. Je suis super intéressé a ce projet et je connais plusieurs personne qui le sont comme moi. Cordialement, Alan

tag: @alexylem @physicien @Smanar

ghost commented 6 years ago

If you want I can pass you something that is worth gold, ie my steps of installation and compilation of openCV, it is the result of several days, what do I say, weeks of fierce battle , interested?

@alexylem can you share me? I'm very much interested

Thank you