00001 /*!@file Robots2/Beobot2/HumanRobotInteraction/FaceDetector.C Ice Module to 00002 detect faces */ 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Dicky Sihite <sihite@usc.edu> 00034 // $HeadURL: svn://ilab.usc.edu/trunk/saliency/src/Robots/Beobot2/HumanRobotInteaction/FaceDetector.C 00035 // $ $Id: FaceDetector.C 12962 2010-03-06 02:13:53Z irock $ 00036 ////////////////////////////////////////////////////////////////////// 00037 00038 #include "Robots/Beobot2/HumanRobotInteraction/FaceDetector.H" 00039 #include "Ice/BeobotEvents.ice.H" 00040 00041 #include "Raster/Raster.H" 00042 #include "Util/sformat.H" 00043 #include "Image/Image.H" 00044 #include "Ice/IceImageUtils.H" 00045 00046 #include <sys/stat.h> 00047 00048 //#define LOG_FOLDER "../data/logs/" 00049 00050 // ###################################################################### 00051 FaceDetector::FaceDetector(OptionManager& mgr, 00052 const std::string& descrName, const std::string& tagName) : 00053 RobotBrainComponent(mgr, descrName, tagName), 00054 itsOfs(new OutputFrameSeries(mgr)), 00055 itsTimer(1000000), 00056 itsCurrImgID(-1), 00057 itsPrevProcImgID(-1) 00058 { 00059 addSubComponent(itsOfs); 00060 } 00061 00062 // ###################################################################### 00063 FaceDetector::~FaceDetector() 00064 { } 00065 00066 // ###################################################################### 00067 void FaceDetector::start1() 00068 { 00069 // set start time 00070 itsTimer.reset(); 00071 } 00072 00073 00074 // ###################################################################### 00075 void FaceDetector::registerTopics() 00076 { 00077 // subscribe to all sensor data 00078 this->registerSubscription("CameraMessageTopic"); 00079 00080 this->registerPublisher("FacesMessageTopic"); 00081 } 00082 00083 // ###################################################################### 00084 void FaceDetector::evolve() 00085 { 00086 // check if the current image is updated 00087 its_Curr_Img_mutex.lock(); 00088 bool newImageFlag = (itsPrevProcImgID < itsCurrImgID); 00089 its_Curr_Img_mutex.unlock(); 00090 00091 // if so, process 00092 if(newImageFlag) 00093 { 00094 itsTimer.reset(); 00095 00096 its_Curr_Img_mutex.lock(); 00097 itsProcImg = itsCurrImg; 00098 itsPrevProcImgID = itsCurrImgID; 00099 its_Curr_Img_mutex.unlock(); 00100 00101 // find faces 00102 Image<PixRGB<byte> > res = findFaces(itsProcImg); 00103 00104 // display the image 00105 itsOfs->writeRGB(res, "display"); 00106 itsOfs->updateNext(); 00107 LINFO("time: %15.3f", itsTimer.get()/1000.0); 00108 00109 // publish FacesMessage 00110 BeobotEvents::FacesMessagePtr msg = 00111 new BeobotEvents::FacesMessage; 00112 msg->RequestID = itsPrevProcImgID; 00113 00114 its_Curr_Res_mutex.lock(); 00115 LINFO("Number of faces detected : %"ZU, itsCurrentFacesFound.size()); 00116 for(uint i = 0; i < itsCurrentFacesFound.size(); i++) 00117 { 00118 ImageIceMod::RectangleIce rect; 00119 rect.tl.i = itsCurrentFacesFound[i].top(); 00120 rect.tl.j = itsCurrentFacesFound[i].left(); 00121 rect.br.i = itsCurrentFacesFound[i].bottomO(); 00122 rect.br.j = itsCurrentFacesFound[i].rightO(); 00123 msg->faces.push_back(rect); 00124 LINFO("[%3d,%3d,%3d,%3d]", rect.tl.i,rect.tl.j,rect.br.i,rect.br.j ); 00125 } 00126 its_Curr_Res_mutex.unlock(); 00127 00128 // publish the message 00129 LINFO("[%6d] Publishing Faces Message", itsCurrMessageID++); 00130 publish("FacesMessageTopic", msg); 00131 } 00132 } 00133 00134 // ###################################################################### 00135 void FaceDetector::updateMessage(const RobotSimEvents::EventMessagePtr& eMsg, 00136 const Ice::Current&) 00137 { 00138 // reset the timer 00139 // itsTimer.reset(); 00140 // camera message 00141 if(eMsg->ice_isA("::BeobotEvents::CameraMessage")) 00142 { 00143 // store the image 00144 BeobotEvents::CameraMessagePtr cameraMsg = 00145 BeobotEvents::CameraMessagePtr::dynamicCast(eMsg); 00146 00147 int currRequestID = cameraMsg->RequestID; 00148 LINFO("Got a CameraMessage with Request ID = %d", 00149 currRequestID); 00150 Image<PixRGB<byte> > ima = Ice2Image<PixRGB<byte> >(cameraMsg->image); 00151 00152 // this line was to find face, moved up to evolve 00153 its_Curr_Img_mutex.lock(); 00154 itsCurrImg = ima; 00155 itsCurrImgID = cameraMsg->RequestID; 00156 its_Curr_Img_mutex.unlock(); 00157 00158 LINFO("time: %15.3f", itsTimer.get()/1000.0); 00159 } 00160 } 00161 00162 // ###################################################################### 00163 Image<PixRGB<byte> > FaceDetector::findFaces(Image<PixRGB<byte> > ima) 00164 { 00165 Image<PixRGB<byte> > res; 00166 IplImage *img = img2ipl(ima); 00167 00168 00169 int scale = 1; 00170 00171 // Create a string that contains the cascade name 00172 const char* cascade_name = 00173 "haarcascade_frontalface_alt.xml"; 00174 00175 // Load a HaarClassifierCascde 00176 CvHaarClassifierCascade* cascade = 00177 (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); 00178 00179 // Check whether the cascade has loaded successfully. 00180 // Else report and error and quit 00181 if( !cascade ) 00182 LFATAL("ERROR: Could not load classifier cascade"); 00183 00184 // Create a new image based on the input image 00185 IplImage* temp = 00186 cvCreateImage( cvSize(img->width/scale,img->height/scale), 8, 3 ); 00187 00188 // Create two points to represent the face locations 00189 CvPoint pt1, pt2; 00190 int i; 00191 00192 // Clear the memory storage which was used before 00193 CvMemStorage* storage = 0; 00194 storage = cvCreateMemStorage(0); 00195 cvClearMemStorage( storage ); 00196 00197 std::vector<Rectangle> tempResults; 00198 00199 // Find whether the cascade is loaded, to find the faces. If yes, then: 00200 if( cascade ) 00201 { 00202 00203 // There can be more than one face in an image. 00204 // So create a growable sequence of faces. 00205 // Detect the objects and store them in the sequence 00206 CvSeq* faces = cvHaarDetectObjects( img, cascade, storage, 00207 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, 00208 cvSize(40, 40) ); 00209 00210 // Loop the number of faces found. 00211 for( i = 0; i < (faces ? faces->total : 0); i++ ) 00212 { 00213 // Create a new rectangle for drawing the face 00214 CvRect* r = (CvRect*)cvGetSeqElem( faces, i ); 00215 00216 // Find the dimensions of the face,and scale it if necessary 00217 pt1.x = r->x*scale; 00218 pt2.x = (r->x+r->width)*scale; 00219 pt1.y = r->y*scale; 00220 pt2.y = (r->y+r->height)*scale; 00221 00222 // Draw the rectangle in the input image 00223 cvRectangle( img, pt1, pt2, CV_RGB(255,0,0), 3, 8, 0 ); 00224 00225 // store rectangle to publish later 00226 tempResults.push_back 00227 (Rectangle::tlbrO(pt1.y,pt1.x,pt2.y,pt2.x)); 00228 } 00229 } 00230 00231 // Release the temp image created. 00232 cvReleaseImage( &temp ); 00233 00234 // storing data 00235 its_Curr_Res_mutex.lock(); 00236 itsCurrentFacesFound.clear(); 00237 itsCurrentFacesFound = tempResults; 00238 // for (uint j = 0; j < tempResults.size(); j++) 00239 // { 00240 // // itsCurrentFacesFound 00241 // } 00242 its_Curr_Res_mutex.unlock(); 00243 00244 res = ipl2rgb(img); 00245 return res; 00246 } 00247 00248 // ###################################################################### 00249 /* So things look consistent in everyone's emacs... */ 00250 /* Local Variables: */ 00251 /* indent-tabs-mode: nil */ 00252 /* End: */