faces.cpp

00001 
00002 /***************************************************************************
00003  *  faces.cpp - Faces classifier based on OpenCV
00004  *
00005  *  Created: Mon Dec 10 15:47:11 2007
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <classifiers/faces.h>
00025 
00026 #include <core/exception.h>
00027 #include <core/exceptions/software.h>
00028 #include <fvutils/color/colorspaces.h>
00029 #include <fvutils/color/conversions.h>
00030 #include <fvutils/adapters/iplimage.h>
00031 
00032 #include <opencv/cv.h>
00033 
00034 namespace firevision {
00035 #if 0 /* just to make Emacs auto-indent happy */
00036 }
00037 #endif
00038 
00039 /** @class FacesClassifier <classifiers/faces.h>
00040  * Faces classifier.
00041  * This class provides a classifier that uses OpenCV to detect images in the given
00042  * image. The faces are reported back as regions of interest. Each ROI is considered
00043  * to contain a face.
00044  *
00045  * This code is based on the OpenCV example provided and works with the Haar cascade
00046  * files that come with OpenCV. The code is based on investigations by Stefan Schiffer.
00047  *
00048  * @author Tim Niemueller
00049  */
00050 
00051 /** Constructor.
00052  * @param haarcascade_file Haar cascade file to use
00053  * @param pixel_width width of images that will be processed
00054  * @param pixel_height height of images that will be processed
00055  * @param image Optional image that is used by the classifier. If this image is NULL
00056  * an internal IplImage is created and the buffer converted. If you need the buffer
00057  * anyway pass a pointer to this image to do the conversion only once. In that case
00058  * the classifier assume that the image has already been converted!
00059  * @param haar_scale_factor Haar scale factor
00060  * @param min_neighbours minimum neighbours
00061  * @param flags flags, can only be CV_HAAR_DO_CANNY_PRUNING at the moment.
00062  */
00063 FacesClassifier::FacesClassifier(const char *haarcascade_file,
00064                                  unsigned int pixel_width, unsigned int pixel_height,
00065                                  IplImage *image,
00066                                  float haar_scale_factor, int min_neighbours, int flags)
00067   : Classifier("FacesClassifier")
00068 {
00069   __haar_scale_factor = haar_scale_factor;
00070   __min_neighbours = min_neighbours;
00071   __flags = flags;
00072 
00073   __cascade = (CvHaarClassifierCascade *) cvLoad(haarcascade_file);
00074   if ( ! __cascade ) {
00075     throw fawkes::Exception("Could not load Haar casca via OpenCV");
00076   }
00077 
00078   __storage = cvCreateMemStorage(0);
00079   if ( ! __storage ) {
00080     cvReleaseHaarClassifierCascade(&__cascade);
00081     throw fawkes::Exception("Could not initialize OpenCV memory");
00082   }
00083 
00084   if ( image ) {
00085     __image = image;
00086     __own_image = false;
00087   } else {
00088     __image = cvCreateImage(cvSize(pixel_width, pixel_height), IPL_DEPTH_8U, 3);
00089     __own_image = true;
00090   }
00091 }
00092 
00093 
00094 /** Destructor. */
00095 FacesClassifier::~FacesClassifier()
00096 {
00097   cvReleaseHaarClassifierCascade(&__cascade);
00098   cvReleaseMemStorage(&__storage);
00099   if ( __own_image ) {
00100     cvReleaseImage(&__image);
00101   }
00102 }
00103 
00104 
00105 std::list< ROI > *
00106 FacesClassifier::classify()
00107 {
00108   std::list< ROI > *rv = new std::list< ROI >();
00109 
00110   if ( __own_image ) {
00111     IplImageAdapter::convert_image_bgr(_src, __image);
00112   }
00113 
00114   CvSeq *face_seq = cvHaarDetectObjects(__image, __cascade, __storage,
00115                                         __haar_scale_factor, __min_neighbours, __flags);
00116 
00117   for ( int i = 0; i < face_seq->total; ++i) {
00118     CvAvgComp el = *(CvAvgComp*)cvGetSeqElem(face_seq, i);
00119     ROI r(el.rect.x, el.rect.y, el.rect.width, el.rect.height, _width, _height);
00120     r.num_hint_points = el.rect.width * el.rect.height;
00121     rv->push_back(r);
00122   }
00123 
00124   // sort, smallest first, we define num_hint_points as area enclosed by the ROI
00125   rv->sort();
00126 
00127   return rv;
00128 }
00129 
00130 } // end namespace firevision