FaceDetection.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, Ulrich Klank, Dejan Pangercic
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include "FaceDetection.h"
00031 #include "XMLTag.h"
00032 
00033 #include <iostream>
00034 #include <cstdio>
00035 
00036 /*  . */
00037 #include "IplImageReading.h"
00038 /* */
00039 #include "ImageSubscription.h"
00040 /* */
00041 #include "DetectedFace.h"
00042 
00043 #define XML_ATTRIBUTE_CASCADE_NAME "cascade_name"
00044 #define XML_ATTRIBUTE_NESTED_CASCADE_NAME "nested_cascade_name"
00045 #define XML_ATTRIBUTE_SCALE "scale"
00046 
00047 
00048 using namespace cop;
00049 
00050 FaceDetection::FaceDetection()
00051 {
00052   printf("FaceDetection created\n");
00053 }
00054 
00055 FaceDetection::~FaceDetection(void)
00056 {
00057 }
00058 
00059 XMLTag* FaceDetection::Save()
00060 {
00061   XMLTag* tag = new XMLTag(GetName());
00062   return tag;
00063 }
00064 
00065 
00066 void FaceDetection::SetData(XMLTag* tag)
00067 {
00068   if(tag != NULL)
00069   {
00070     cascade_name_ = tag->GetProperty(XML_ATTRIBUTE_CASCADE_NAME, "");
00071     nested_cascade_name_ = tag->GetProperty(XML_ATTRIBUTE_NESTED_CASCADE_NAME, "");
00072     scale_ = tag->GetPropertyDouble(XML_ATTRIBUTE_SCALE, 1.5);
00073 
00074    if( !nested_cascade_.load( nested_cascade_name_ ) )
00075       cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
00076 
00077     if( !cascade_.load( cascade_name_ ) )
00078     {
00079       cerr << "ERROR: Could not load classifier cascade" << endl;
00080       cerr << "Usage: facedetect [--cascade=\"<cascade_path>\"]\n"
00081         "   [--nested-cascade[=\"nested_cascade_path\"]]\n"
00082         "   [--scale[=<image scale>\n"
00083         "   [filename|camera_index]\n" ;
00084       //return -1;
00085     }
00086   }
00087 }
00088 
00089 double angle_two_pixel(double x1, double y1, double x2, double y2, MinimalCalibration& calib)
00090 {
00091   double X1 = (x1 - calib.proj_center_x)*calib.pix_size_x;
00092   double Y1 = (y1 - calib.proj_center_y)*calib.pix_size_y;
00093   double Z1 = calib.focal_length;
00094   double X2 = (x2 - calib.proj_center_x)*calib.pix_size_x;
00095   double Y2 = (y2 - calib.proj_center_y)*calib.pix_size_y;
00096   double Z2 = calib.focal_length;
00097 
00098   printf("in: x1 %f, y1 %f, x2 %f,y2 %f\n", x1, y1, x2, y2);
00099   printf("3d: x1 %f, y1 %f,z1 %f, x2 %f,y2 %f, z2 %f\n", X1, Y1, Z1, X2, Y2, Z2);
00100   double ret = (((X1 * X2) + (Y1 * Y2) + (Z1 * Z2)) / (sqrt( X1*X1 + Y1*Y1 + Z1*Z1) * sqrt(X2*X2 + Y2*Y2 + Z2*Z2)));
00101   printf("res: acos(%f)\n", ret);
00102   ret = acos(ret);
00103   printf("res: %f\n", ret);
00104   return ret;
00105 }
00106 
00107 RelPose* distance_to_3d(RelPose *sensor_pose, MinimalCalibration &calib, double length_min,
00108            double length_max, double x, double y, double cov_width, double cov_height)
00109 {
00110   printf("istance_to_3d with lmin %f  lmax %f x %f y %f co_w %f co_h%f\n ",
00111   length_min, length_max, x, y, cov_width, cov_height);
00112   Matrix m(4,4), cov(6,6);
00113   double X, Y, Z;
00114   X = (x - calib.proj_center_x)*calib.pix_size_x;
00115   Y = (y - calib.proj_center_y)*calib.pix_size_y;
00116   Z = calib.focal_length;
00117   double norm = sqrt( X*X + Y*Y + Z*Z);
00118 
00119   X *= (length_max + length_min)/(2*norm);
00120   Y *= (length_max + length_min)/(2*norm);
00121   Z *= (length_max + length_min)/(2*norm);
00122   /* TODO rotate the matrix*/
00123   m << 1.0 << 0.0 << 0.0 << X
00124     << 0.0 << 1.0 << 0.0 << Y
00125     << 0.0 << 0.0 << 1.0 << Z
00126     << 0.0 << 0.0 << 0.0 << 1.0;
00127 
00128   cov << cov_width / 2 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
00129       << 0.0 << cov_height / 2<< 0.0 << 0.0 << 0.0 << 0.0
00130       << 0.0 << 0.0 << (length_max - length_min)/2 << 0.0 << 0.0 << 0.0
00131       << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
00132       << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
00133       << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0;
00134   return RelPoseFactory::FRelPose(sensor_pose, m, cov);
00135 }
00136 
00137 
00138 
00139 // Public attribute accessor methods
00140 //
00141 std::vector<RelPose*> FaceDetection::Perform(std::vector<Sensor*> sensors, RelPose* pose, Signature& object, int &numOfObjects, double& qualityMeasure)
00142 {
00143   std::vector<RelPose*> results;
00144   int i = 0;
00145   double t = 0;
00146   vector<Rect> faces;
00147   DetectedFace* face_descr = (DetectedFace*)object.GetElement(0, DESCRIPTOR_DETECTEDFACE);
00148   try
00149   {
00150     ScopedCvMat_t image (sensors, ReadingType_IplImage);
00151 
00152     RelPose* sensor_pose = image.sensor_pose_at_capture_time;
00153 
00154     Mat gray, smallImg( cvRound ((*image).rows/scale_), cvRound((*image).cols/scale_), CV_8UC1 );
00155     cvtColor( (*image), gray, CV_BGR2GRAY );
00156     resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
00157     equalizeHist( smallImg, smallImg );
00158 
00159     t = (double)cvGetTickCount();
00160     cascade_.detectMultiScale( smallImg, faces,
00161                                 1.1, 2, 0
00162                                 //|CV_HAAR_FIND_BIGGEST_OBJECT
00163                                 //|CV_HAAR_DO_ROUGH_SEARCH
00164                                 |CV_HAAR_SCALE_IMAGE
00165                                 ,
00166                                 Size(30, 30) );
00167       t = (double)cvGetTickCount() - t;
00168       printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
00169       for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
00170       {
00171         Mat smallImgROI;
00172         vector<Rect> nestedObjects;
00173         Point center;
00174         int radius;
00175 
00176         printf("Enter inner loop\n");
00177 
00178         center.x = cvRound((r->x + r->width*0.5)*scale_);
00179         center.y = cvRound((r->y + r->height*0.5)*scale_);
00180         radius = cvRound((r->width + r->height)*0.25*scale_);
00181         /*circle( (*image), center, radius, color, 3, 8, 0 );*/
00182         if( nested_cascade_.empty() )
00183           continue;
00184         smallImgROI = smallImg(*r);
00185         nested_cascade_.detectMultiScale( smallImgROI, nestedObjects,
00186                                         1.1, 2, 0
00187                                         //|CV_HAAR_FIND_BIGGEST_OBJECT
00188                                         //|CV_HAAR_DO_ROUGH_SEARCH
00189                                         //|CV_HAAR_DO_CANNY_PRUNING
00190                                         |CV_HAAR_SCALE_IMAGE
00191                                         ,
00192                                         Size(30, 30) );
00193         double max_face_height = 0.30;
00194         double min_face_height = 0.20;
00195         double max_face_width  = 0.25;
00196         double min_face_width = 0.15;
00197         printf("After nested cascade\n");
00198 
00199         vector<Rect>::const_iterator nr = nestedObjects.begin();
00200         if(nr == nestedObjects.end())
00201         {
00202           /*angle in x*/
00203           double alpha = angle_two_pixel(r->x ,
00204                                          r->y + r->height*0.5,
00205                                          r->x + r->width,
00206                                          r->y + r->height*0.5, image.calib);
00207           /*angle in y*/
00208           double beta =  angle_two_pixel(r->x + r->width*0.5,
00209                                          r->y,
00210                                          r->x + r->width*0.5,
00211                                          r->y + r->height, image.calib);
00212           /*Assuming floor aligned camera (in the x axis) and face size*/
00213           double length_min = min_face_height / (2* tan(alpha));
00214           double length_max = max_face_height / (2* tan(alpha));
00215 
00216           length_min = max(length_min, min_face_width / (2* tan(beta)));
00217           length_max = min(length_max, max_face_width / (2* tan(beta)));
00218 
00219           RelPose* pose = distance_to_3d(sensor_pose, image.calib, length_min, length_max,
00220                                         center.x, center.y, max_face_width - min_face_width,
00221                                         max_face_height - min_face_height);
00222           pose->m_qualityMeasure = 1.0;
00223           qualityMeasure = 1.0;
00224           results.push_back(pose);
00225           std::vector<double> vec;
00226           vec.push_back(center.x);
00227           vec.push_back(center.y);
00228           vec.push_back((r->width + r->height)*0.25*scale_);
00229           face_descr->m_lastlyDetectedFaces[pose->m_uniqueID] = (vec);
00230           if(results.size() == (unsigned)numOfObjects)
00231             break;
00232         }
00233 
00234         for( ; nr != nestedObjects.end(); nr++ )
00235         {
00236 
00237           printf("Innerst loop\n");
00238 
00239           center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale_);
00240           center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale_);
00241 
00242           /*angle in x*/
00243           double alpha = angle_two_pixel(r->x + nr->x,
00244                                          r->y + nr->y + nr->height*0.5,
00245                                          r->x + nr->x + nr->width,
00246                                          r->y + nr->y + nr->height*0.5, image.calib);
00247           /*angle in y*/
00248           double beta =  angle_two_pixel(r->x + nr->x + nr->width*0.5,
00249                                          r->y + nr->y,
00250                                          r->x + nr->x + nr->width*0.5,
00251                                          r->y + nr->y + nr->height, image.calib);
00252           /*Assuming floor aligned camera (in the x axis) and face size*/
00253           double length_min = min_face_height / (2* tan(alpha));
00254           double length_max = max_face_height / (2* tan(alpha));
00255 
00256           length_min = max(length_min, min_face_width / (2* tan(beta)));
00257           length_max = min(length_max, max_face_width / (2* tan(beta)));
00258 
00259           RelPose* pose = distance_to_3d(sensor_pose, image.calib, length_min, length_max,
00260                                         center.x, center.y, max_face_width - min_face_width,
00261                                         max_face_height - min_face_height);
00262           pose->m_qualityMeasure = 1.0;
00263           qualityMeasure = 1.0;
00264           results.push_back(pose);
00265           std::vector<double> vec;
00266           vec.push_back(center.x);
00267           vec.push_back(center.y);
00268           vec.push_back((nr->width + nr->height)*0.25*scale_);
00269           face_descr->m_lastlyDetectedFaces[pose->m_uniqueID] = (vec);
00270           if(results.size() == (unsigned)numOfObjects)
00271             break;
00272         }
00273       }
00274   }
00275   catch(const char* exception)
00276   {
00277     printf("FaceDetection failed: %s\n", exception);
00278   }
00279   if(results.size() != (unsigned)numOfObjects)
00280     numOfObjects = results.size();
00281 
00282   return results;
00283 }
00284 
00285 double FaceDetection::CheckSignature(const Signature& object, const std::vector<Sensor*> &sensors)
00286 {
00287   printf("FaceDetection::CheckSignature\n");
00288   if(object.GetElement(0, DESCRIPTOR_DETECTEDFACE) != NULL)
00289   {
00290     for(size_t i = 0; i < sensors.size(); i++)
00291     {
00292       printf("Yes\n");
00293 
00294         return 1.0;
00295     }
00296   }
00297   printf("No\n");
00298   return 0.0;
00299 }
00300 


cop_ros_plugins
Author(s): U. Klank, Dejan Pangercic
autogenerated on Mon Oct 6 2014 10:51:04