honrisse | Nessie3 a écrit :
Le but est effectivement de détecter tous les visages sur une photo et de placer à coté de chaque visage un numéro différent sans aller plus loin (pas de reconnaissance faciale).
Visage n°1 --------> chiffre 1
...
Visage n°36 -------> chiffre 36
Picasa j'ai essayé mais je n'y suis pas arrivé.
Y aurait-il un informaticien prêt à développer le programme ?
Je suis prêt à le payer.
|
La détection de visages d'OpenCV n'est pas parfaite:
L'ordre des numéros n'est pas parfait non plus (sur cette photo c'est bon), et il peut y avoir des fausses détections pour les visages.
Voici le programme qui permet de le faire en ligne de commande. Et il faut aussi savoir programmer en C++ pour pouvoir compiler le source avec OpenCV.
Il y a des tutoriels sur le site d'OpenCV qui expliquent comment utiliser la librarie OpenCV.
Pour l'utiliser:
Code :
- -cascade <pour le chemin vers le fichier d'apprentissage pour la détection de visages>
- -image_list <chemin vers le fichier texte contenant les images à traiter, une ligne par chemin pour les images>
- -display <pour afficher le résultat en cours de traitement, appuyer sur une touche pour continuer quand la fenêtre est sélectionner>
|
Cela reste une preuve de faisabilité. Pour être vraiment utile, il faudrait rajouter toute l'interface autour du programme. Le programme détecte et labellise 95% des visages d'une photo, mais il faudrait une interface qui permettrait de supprimer les fausses détections, ajouter/éditer les numéros, etc.
Le code source:
Code :
- /**
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>
- **/
- #include <iostream>
- #include <algorithm>
- #include <fstream>
- #include <opencv2/opencv.hpp>
- #define DEBUG 0
- /**
- @author: Catree
- @date: 2015/07/11
- **/
- typedef struct face_info_t {
- cv::Point face_center;
- cv::Size face_size;
- cv::Point label_center;
- cv::Size img_size;
- face_info_t() : face_center(), face_size(), label_center(), img_size()
- {
- }
- face_info_t(const cv::Point ¢er, const cv::Size &size, const cv::Point &lbl_center, const cv::Size _img_size)
- : face_center(center), face_size(size), label_center(lbl_center), img_size(_img_size)
- {
- }
- bool operator<(const face_info_t& face_info) const
- {
- int top1 = (int) (face_center.y - face_size.height*0.5);
- int bottom1 = (int) (face_center.y + face_size.height*0.5);
- int top2 = (int) (face_info.face_center.y - face_info.face_size.height*0.5);
- int bottom2 = (int) (face_info.face_center.y + face_info.face_size.height*0.5);
- if( (top1 >= top2 && top1 <= bottom2) || (bottom1 >= top2 && bottom1 <= bottom2) ||
- (top2 >= top1 && top2 <= bottom1) || (bottom2 >= top1 && bottom2 <= bottom1) )
- {
- return (face_center.x < face_info.face_center.x);
- }
- return (face_center.y < face_info.face_center.y);
- }
- } face_info_t;
- std::vector<face_info_t> remove_same_faces(const std::vector<face_info_t> &vectorOfFaces)
- {
- std::vector<face_info_t> vectorOfUniqueFaces;
- std::vector<size_t> vectorOfDuplicateIndexes;
- for(size_t i = 0; i < vectorOfFaces.size(); i++)
- {
- int top = (int) (vectorOfFaces[i].face_center.x - vectorOfFaces[i].face_size.width*0.5);
- int left = (int) (vectorOfFaces[i].face_center.y - vectorOfFaces[i].face_size.height*0.5);
- cv::Rect r1(top, left, vectorOfFaces[i].face_size.width, vectorOfFaces[i].face_size.height);
- bool duplicate = false;
- for(size_t j = i+1; j < vectorOfFaces.size(); j++)
- {
- if(std::find(vectorOfDuplicateIndexes.begin(), vectorOfDuplicateIndexes.end(), j) == vectorOfDuplicateIndexes.end())
- {
- top = (int) (vectorOfFaces[j].face_center.x - vectorOfFaces[j].face_size.width*0.5);
- left = (int) (vectorOfFaces[j].face_center.y - vectorOfFaces[j].face_size.height*0.5);
- cv::Rect r2(top, left, vectorOfFaces[i].face_size.width, vectorOfFaces[i].face_size.height);
- cv::Rect r_intersection = r1 & r2;
- if(r_intersection.width > 0 && r_intersection.height > 0)
- {
- duplicate = true;
- vectorOfDuplicateIndexes.push_back(j);
- }
- }
- }
- if(!duplicate)
- {
- vectorOfUniqueFaces.push_back(vectorOfFaces[i]);
- }
- }
- return vectorOfUniqueFaces;
- }
- void display_number(cv::Mat &img, const int number, const cv::Point ¢er, const cv::Size &label_box_size=cv::Size(30,30),
- const cv::Scalar label_box_bcg_color=cv::Scalar(255,255,255))
- {
- cv::Mat label_box(label_box_size, CV_8UC3);
- label_box.setTo(label_box_bcg_color);
- std::stringstream ss;
- ss << number;
- double factor = label_box_size.width / 30.0;
- if(number < 10)
- {
- cv::putText(label_box, ss.str(), cv::Point(label_box.cols/2-6*factor, label_box.rows/2+5*factor), cv::FONT_HERSHEY_PLAIN, factor, cv::Scalar(0,0,0), 2);
- }
- else
- {
- cv::putText(label_box, ss.str(), cv::Point(label_box.cols/2-10*factor, label_box.rows/2+5*factor), cv::FONT_HERSHEY_PLAIN, factor, cv::Scalar(0,0,0), 2);
- }
- label_box.copyTo(img(cv::Rect(center.x, center.y, label_box.cols, label_box.rows)));
- }
- void detect_faces_and_display_labels(cv::Mat &img, cv::CascadeClassifier &face_cascade, const bool display_result=false)
- {
- std::vector<cv::Rect> faces;
- face_cascade.detectMultiScale(img, faces);
- int size = std::min(img.rows, img.cols) / 24;
- cv::Size label_box_size(size, size);
- std::vector<face_info_t> vectorOfFaces(faces.size());
- for (size_t i = 0; i < faces.size(); i++)
- {
- cv::Point center((int) (faces[i].x + faces[i].width*0.5), (int) (faces[i].y + faces[i].height*0.5));
- #if DEBUG
- ellipse(img, center, cv::Size(faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, cv::Scalar(255, 0, 255), 2);
- #endif
- cv::Point label_box(center.x - size/2, center.y + faces[i].height - size/2);
- vectorOfFaces[i] = face_info_t(center, faces[i].size(), label_box, img.size());
- }
- std::sort (vectorOfFaces.begin(), vectorOfFaces.end());
- vectorOfFaces = remove_same_faces(vectorOfFaces);
- int label = 1;
- for(std::vector<face_info_t>::const_iterator it = vectorOfFaces.begin(); it != vectorOfFaces.end(); ++it, label++)
- {
- display_number(img, label, it->label_center, label_box_size);
- }
- if(display_result)
- {
- cv::imshow("Image with tags", img);
- std::cout << "Press a key to continue..." << std::endl;
- cv::waitKey(0);
- }
- }
- cv::Mat read_image(const std::string &filepath)
- {
- cv::Mat img = cv::imread(filepath);
- return img;
- }
- void help()
- {
- std::cout << "Option: -h <print this help>" << std::endl;
- std::cout << "Option: -cascade <filepath for the cascade classifier learning file>" << std::endl;
- std::cout << "Option: -image_list <filepath for the text file containing the images to process>" << std::endl;
- std::cout << "Option: -display <display the result for each image>" << std::endl;
- }
- int main(int argc, char*argv[])
- {
- std::string casacade_filepath = "haarcascade_frontalface_alt2.xml";
- std::string image_list_filepath = "image_list.txt";
- bool display_result = false;
- for(int i = 1; i < argc; i++)
- {
- if(std::string(argv[i]) == "-h" )
- {
- help();
- }
- else if(std::string(argv[i]) == "-cascade" )
- {
- if(i+1 < argc)
- {
- casacade_filepath = argv[i+1];
- }
- }
- else if(std::string(argv[i]) == "-image_list" )
- {
- if(i+1 < argc)
- {
- image_list_filepath = argv[i+1];
- }
- }
- else if(std::string(argv[i]) == "-display" )
- {
- display_result = true;
- }
- }
- std::ifstream file(image_list_filepath.c_str());
- if(!file.is_open())
- {
- std::cerr << "Problem with the filepath for the learning file !" << std::endl;
- return -1;
- }
- std::string line;
- std::vector<std::string> vectorOfImageFilepaths;
- while(getline(file, line))
- {
- vectorOfImageFilepaths.push_back(line);
- }
- cv::CascadeClassifier face_cascade;
- if(!face_cascade.load(casacade_filepath))
- {
- std::cerr << "Problem with the filepath for cascade classifier learning file !" << std::endl;
- return -1;
- }
- for(std::vector<std::string>::const_iterator it = vectorOfImageFilepaths.begin(); it != vectorOfImageFilepaths.end(); ++it)
- {
- cv::Mat img = read_image(*it);
- if(!img.empty())
- {
- std::string filenama_tagged = (*it) + "_tagged.jpg";
- detect_faces_and_display_labels(img, face_cascade, display_result);
- std::cout << "Save image: " << filenama_tagged << std::endl;
- cv::imwrite(filenama_tagged, img);
- }
- else
- {
- std::cerr << "The image " << line << " cannot be read !" << std::endl;
- }
- }
- return 0;
- }
|
Message édité par honrisse le 11-07-2015 à 22:39:19
|