00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <ros/ros.h>
00028 #include <actionlib/server/simple_action_server.h>
00029 #include <face_recognition/FaceRecognitionAction.h>
00030 #include <image_transport/image_transport.h>
00031 #include <cv_bridge/cv_bridge.h>
00032 #include <sensor_msgs/image_encodings.h>
00033 #include <opencv2/imgproc/imgproc.hpp>
00034 #include <opencv2/highgui/highgui.hpp>
00035 #include <vector>
00036 #include <cvaux.h>
00037 #include <cxcore.hpp>
00038 #include <sys/stat.h>
00039 #include <termios.h>
00040
00041 #include <unistd.h>
00042 #include "face_recognition_lib.cpp"
00043
00044 using namespace std;
00045
00046 class FaceRecognition
00047 {
00048 public:
00049
00050 FaceRecognition(std::string name) :
00051 frl(),
00052 it_(nh_),
00053 pnh_("~"),
00054 as_(nh_, name, boost::bind(&FaceRecognition::executeCB, this, _1), false)
00055 {
00056
00057 pnh_.param<double>("confidence_value", confidence_value, 0.88);
00058
00059 pnh_.param<bool>("show_screen_flag", show_screen_flag, true);
00060 ROS_INFO("show_screen_flag: %s", show_screen_flag ? "true" : "false");
00061
00062 pnh_.param<int>("add_face_number", add_face_number, 25);
00063 add_face_number = 25;
00064
00065 person_number=0;
00066
00067 as_.start();
00068
00069
00070 if (show_screen_flag) {
00071 cvNamedWindow("Input", CV_WINDOW_AUTOSIZE);
00072 cvInitFont(&font,CV_FONT_HERSHEY_PLAIN, 1.0, 4.0, 2,2,CV_AA);
00073 textColor = CV_RGB(0,255,255);
00074 }
00075 goal_id_ = -99;
00076
00077 if(calcNumTrainingPerson("train.txt")!=frl.nPersons)
00078 {
00079 frl.database_updated=false;
00080
00081 ROS_WARN("Alert: Database is not updated. Please delete \"facedata.xml\" and re-run!");
00082 }
00083
00084 image_sub_ = it_.subscribe("/camera/image_raw", 1, &FaceRecognition::imageCB, this);
00085 }
00086
00087 ~FaceRecognition(void)
00088 {
00089 if (show_screen_flag) {
00090 cvDestroyWindow("Input");
00091 }
00092 }
00093
00094
00095 void executeCB(const face_recognition::FaceRecognitionGoalConstPtr &goal)
00096 {
00097
00098 if( as_.isPreemptRequested() || ros::isShuttingDown() )
00099 {
00100 as_.setPreempted();
00101 return;
00102 }
00103
00104 if(goal->order_id == 2 && goal->order_argument.empty() )
00105 {
00106 ROS_INFO("No name has been provided for the add_person_images goal");
00107 as_.setPreempted();
00108 return;
00109 }
00110 ros::Rate r(4);
00111
00112 goal_argument_ = goal->order_argument;
00113 result_.order_id = goal->order_id;
00114 feedback_.order_id = goal->order_id;
00115 result_.names.clear();
00116 result_.confidence.clear();
00117 feedback_.names.clear();
00118 feedback_.confidence.clear();
00119 goal_id_ = goal->order_id;
00120 switch(goal_id_)
00121 {
00122
00123 case 4: ROS_INFO("exit request");
00124 as_.setSucceeded(result_);
00125 r.sleep();
00126 ros::shutdown();
00127 break;
00128 case 3:
00129
00130 if(frl.retrainOnline())
00131 as_.setSucceeded(result_);
00132 else
00133 as_.setAborted(result_);
00134 break;
00135
00136 case 0:
00137
00138 case 1:
00139
00140 case 2:
00141
00142 {
00143 if(goal_id_ == 2)
00144 add_face_count=0;
00145
00146
00147 while( as_.isActive() && !as_.isPreemptRequested() && !ros::isShuttingDown() )
00148 r.sleep();
00149 mutex_.lock();
00150 if(as_.isActive())
00151 {
00152 as_.setPreempted();
00153 ROS_INFO("Goal %d is preempted",goal_id_);
00154 }
00155 goal_id_ = -99;
00156 mutex_.unlock();
00157 break;
00158 }
00159
00160 }
00161 goal_id_ = -99;
00162 }
00163
00164 int calcNumTrainingPerson(const char * filename)
00165 {
00166 FILE * imgListFile = 0;
00167 char imgFilename[512];
00168 int iFace, nFaces=0;
00169 int person_num=0;
00170
00171 if( !(imgListFile = fopen(filename, "r")) )
00172 {
00173 fprintf(stderr, "Can\'t open file %s\n", filename);
00174 return 0;
00175 }
00176
00177 while( fgets(imgFilename, 512, imgListFile) ) ++nFaces;
00178 rewind(imgListFile);
00179
00180 for(iFace=0; iFace<nFaces; iFace++)
00181 {
00182 char personName[256];
00183 int personNumber;
00184
00185 fscanf(imgListFile, "%d %s %s", &personNumber, personName, imgFilename);
00186 if (personNumber > person_num)
00187 person_num = personNumber;
00188 }
00189 fclose(imgListFile);
00190 return (person_num);
00191 }
00192 void imageCB(const sensor_msgs::ImageConstPtr& msg)
00193 {
00194
00195
00196 if (!as_.isActive() || goal_id_ > 2) return;
00197 if(!mutex_.try_lock()) return;
00198 if(as_.isPreemptRequested())
00199 {
00200 ROS_INFO("Goal %d is preempted",goal_id_);
00201 as_.setPreempted();
00202 mutex_.unlock(); return;
00203 }
00204
00205
00206 ros::param::getCached("~show_screen_flag", show_screen_flag);
00207
00208 cv_bridge::CvImagePtr cv_ptr;
00209
00210 try
00211 {
00212 cv_ptr = cv_bridge::toCvCopy(msg, "bgr8");
00213 }
00214 catch (cv_bridge::Exception& e)
00215 {
00216 ROS_ERROR("cv_bridge exception: %s", e.what());
00217 as_.setPreempted();
00218 ROS_INFO("Goal %d is preempted",goal_id_);
00219 mutex_.unlock();
00220 return;
00221 }
00222 ros::Rate r(4);
00223 IplImage img_input = cv_ptr->image;
00224 IplImage *img= cvCloneImage(&img_input);
00225 IplImage *greyImg;
00226 IplImage *faceImg;
00227 IplImage *sizedImg;
00228 IplImage *equalizedImg;
00229 CvRect faceRect;
00230
00231 greyImg = frl.convertImageToGreyscale(img);
00232
00233 faceRect = frl.detectFaceInImage(greyImg,frl.faceCascade);
00234
00235 if (faceRect.width < 1)
00236 {
00237 ROS_INFO("No face was detected in the last frame");
00238 if(show_screen_flag)
00239 {
00240 cvPutText(img, text_image.str().c_str(), cvPoint(10, faceRect.y + 50), &font, textColor);
00241 cvShowImage("Input", img);
00242 cvWaitKey(1);
00243 }
00244 cvReleaseImage( &greyImg );cvReleaseImage(&img);
00245 r.sleep();
00246 mutex_.unlock(); return;
00247 }
00248 if (show_screen_flag) {
00249 cvRectangle(img, cvPoint(faceRect.x, faceRect.y), cvPoint(faceRect.x + faceRect.width-1, faceRect.y + faceRect.height-1), CV_RGB(0,255,0), 1, 8, 0);
00250 }
00251 faceImg = frl.cropImage(greyImg, faceRect);
00252
00253 sizedImg = frl.resizeImage(faceImg, frl.faceWidth, frl.faceHeight);
00254
00255 equalizedImg = cvCreateImage(cvGetSize(sizedImg), 8, 1);
00256 cvEqualizeHist(sizedImg, equalizedImg);
00257 cvReleaseImage( &greyImg );cvReleaseImage( &faceImg );cvReleaseImage( &sizedImg );
00258
00259 if(as_.isPreemptRequested())
00260 {
00261 ROS_INFO("Goal %d is preempted",goal_id_);
00262 cvReleaseImage(&equalizedImg);cvReleaseImage(&img);
00263 as_.setPreempted();
00264 ROS_INFO("Goal %d is preempted",goal_id_);
00265 mutex_.unlock(); return;
00266 }
00267
00268 if( goal_id_==2 )
00269 {
00270 if(add_face_count==0)
00271 {
00272
00273 person_number = calcNumTrainingPerson("train.txt")+1;
00274 }
00275 char cstr[256];
00276 sprintf(cstr, "data/%d_%s%d.pgm", person_number, &goal_argument_[0], add_face_count+1);
00277 ROS_INFO("Storing the current face of '%s' into image '%s'.", &goal_argument_[0], cstr);
00278
00279 cvSaveImage(cstr, equalizedImg, NULL);
00280
00281 trainFile = fopen("train.txt", "a");
00282 fprintf(trainFile, "%d %s %s\n", person_number, &goal_argument_[0], cstr);
00283 fclose(trainFile);
00284 if(add_face_count==0)
00285 {
00286
00287 ros::param::getCached("~add_face_number", add_face_number);
00288 if(add_face_number<=0)
00289 {
00290 ROS_INFO("add_face_number parameter is Zero, it is Invalid. One face was added anyway!");
00291 add_face_number=1;
00292 }
00293 frl.database_updated = false;
00294 }
00295 if (show_screen_flag) {
00296 text_image.str("");
00297 text_image <<"A picture of "<< &goal_argument_[0]<< "was added" <<endl;
00298 cvPutText(img, text_image.str().c_str(), cvPoint( 10, 50), &font, textColor);
00299 }
00300
00301 if(++add_face_count==add_face_number)
00302 {
00303
00304 result_.names.push_back(goal_argument_);
00305 as_.setSucceeded(result_);
00306 if (show_screen_flag)
00307 {
00308 cvShowImage("Input", img);
00309 cvWaitKey(1);
00310 }
00311 cvReleaseImage(&equalizedImg); cvReleaseImage(&img);
00312 mutex_.unlock(); return;
00313 }
00314 feedback_.names.clear();
00315 feedback_.confidence.clear();
00316 feedback_.names.push_back(goal_argument_);
00317
00318 as_.publishFeedback(feedback_);
00319 }
00320
00321 if( goal_id_<2 )
00322 {
00323 int iNearest, nearest;
00324 float confidence;
00325 float * projectedTestFace=0;
00326 if(!frl.database_updated)
00327
00328 ROS_WARN("Alert: Database is not updated. Please delete \"facedata.xml\" and re-run!");
00329 if(frl.nEigens < 1)
00330 {
00331 ROS_INFO("NO database available, goal is Aborted");
00332 cvReleaseImage(&equalizedImg);cvReleaseImage(&img);
00333 ROS_INFO("Goal %d is Aborted",goal_id_);
00334 as_.setAborted();
00335 mutex_.unlock(); return;
00336 }
00337
00338 projectedTestFace = (float *)cvAlloc( frl.nEigens*sizeof(float) );
00339
00340 cvEigenDecomposite(equalizedImg,frl.nEigens,frl.eigenVectArr,0, 0,frl.pAvgTrainImg,projectedTestFace);
00341
00342 iNearest = frl.findNearestNeighbor(projectedTestFace, &confidence);
00343 nearest = frl.trainPersonNumMat->data.i[iNearest];
00344
00345 ros::param::getCached("~confidence_value", confidence_value);
00346 cvFree(&projectedTestFace);
00347 if(confidence<confidence_value)
00348 {
00349 ROS_INFO("Confidence is less than %f was %f, detected face is not considered.",(float)confidence_value, (float)confidence);
00350 if (show_screen_flag) {
00351 text_image.str("");
00352 text_image << "Confidence is less than "<< confidence_value;
00353 cvPutText(img, text_image.str().c_str(), cvPoint(faceRect.x, faceRect.y + faceRect.height + 25), &font, textColor);
00354 }
00355 }
00356 else
00357 {
00358 if (show_screen_flag) {
00359 text_image.str("");
00360 text_image << frl.personNames[nearest-1].c_str()<<" is recognized";
00361 cvPutText(img, text_image.str().c_str(), cvPoint(faceRect.x, faceRect.y + faceRect.height + 25), &font, textColor);
00362 }
00363
00364 if(goal_id_==0)
00365 {
00366 result_.names.push_back(frl.personNames[nearest-1].c_str());
00367 result_.confidence.push_back(confidence);
00368 as_.setSucceeded(result_);
00369 }
00370
00371 else
00372 {
00373 ROS_INFO("detected %s confidence %f ", frl.personNames[nearest-1].c_str(),confidence);
00374 feedback_.names.clear();
00375 feedback_.confidence.clear();
00376 feedback_.names.push_back(frl.personNames[nearest-1].c_str());
00377 feedback_.confidence.push_back(confidence);
00378 as_.publishFeedback(feedback_);
00379 }
00380
00381 }
00382
00383 }
00384 if (show_screen_flag)
00385 {
00386 cvShowImage("Input", img);
00387 cvWaitKey(1);
00388 }
00389 cvReleaseImage(&equalizedImg); cvReleaseImage(&img);
00390 r.sleep();
00391 mutex_.unlock();
00392 return;
00393 }
00394
00395
00396 protected:
00397
00398 boost::mutex mutex_;
00399 std::string goal_argument_;
00400 int goal_id_;
00401 face_recognition::FaceRecognitionFeedback feedback_;
00402 face_recognition::FaceRecognitionResult result_;
00403 int add_face_count;
00404 FILE *trainFile;
00405 double confidence_value;
00406 bool show_screen_flag;
00407 int add_face_number;
00408 CvFont font;
00409 CvScalar textColor;
00410 ostringstream text_image;
00411 ros::NodeHandle nh_, pnh_;
00412 FaceRecognitionLib frl;
00413 image_transport::ImageTransport it_;
00414 image_transport::Subscriber image_sub_;
00415 actionlib::SimpleActionServer<face_recognition::FaceRecognitionAction> as_;
00416 int person_number;
00417 };
00418
00419
00420 int main(int argc, char** argv)
00421 {
00422 ros::init(argc, argv, "face_recognition");
00423 FaceRecognition face_recognition(ros::this_node::getName());
00424 ros::spin();
00425 return 0;
00426 }
00427