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 /** @class FacesClassifier <classifiers/faces.h>
00035  * Faces classifier.
00036  * This class provides a classifier that uses OpenCV to detect images in the given
00037  * image. The faces are reported back as regions of interest. Each ROI is considered
00038  * to contain a face.
00039  *
00040  * This code is based on the OpenCV example provided and works with the Haar cascade
00041  * files that come with OpenCV. The code is based on investigations by Stefan Schiffer.
00042  *
00043  * @author Tim Niemueller
00044  */
00045 
00046 /** Constructor.
00047  * @param haarcascade_file Haar cascade file to use
00048  * @param pixel_width width of images that will be processed
00049  * @param pixel_height height of images that will be processed
00050  * @param image Optional image that is used by the classifier. If this image is NULL
00051  * an internal IplImage is created and the buffer converted. If you need the buffer
00052  * anyway pass a pointer to this image to do the conversion only once. In that case
00053  * the classifier assume that the image has already been converted!
00054  * @param haar_scale_factor Haar scale factor
00055  * @param min_neighbours minimum neighbours
00056  * @param flags flags, can only be CV_HAAR_DO_CANNY_PRUNING at the moment.
00057  */
00058 FacesClassifier::FacesClassifier(const char *haarcascade_file,
00059                                  unsigned int pixel_width, unsigned int pixel_height,
00060                                  IplImage *image,
00061                                  float haar_scale_factor, int min_neighbours, int flags)
00062   : Classifier("FacesClassifier")
00063 {
00064   __haar_scale_factor = haar_scale_factor;
00065   __min_neighbours = min_neighbours;
00066   __flags = flags;
00067
00068   __cascade = (CvHaarClassifierCascade *) cvLoad(haarcascade_file);
00069   if ( ! __cascade ) {
00070     throw fawkes::Exception("Could not load Haar casca via OpenCV");
00071   }
00072
00073   __storage = cvCreateMemStorage(0);
00074   if ( ! __storage ) {
00075     cvReleaseHaarClassifierCascade(&__cascade);
00076     throw fawkes::Exception("Could not initialize OpenCV memory");
00077   }
00078
00079   if ( image ) {
00080     __image = image;
00081     __own_image = false;
00082   } else {
00083     __image = cvCreateImage(cvSize(pixel_width, pixel_height), IPL_DEPTH_8U, 3);
00084     __own_image = true;
00085   }
00086 }
00087
00088 
00089 /** Destructor. */
00090 FacesClassifier::~FacesClassifier()
00091 {
00092   cvReleaseHaarClassifierCascade(&__cascade);
00093   cvReleaseMemStorage(&__storage);
00094   if ( __own_image ) {
00095     cvReleaseImage(&__image);
00096   }
00097 }
00098
00099
00100 std::list< ROI > *
00101 FacesClassifier::classify()
00102 {
00103   std::list< ROI > *rv = new std::list< ROI >();
00104
00105   if ( __own_image ) {
00106     IplImageAdapter::convert_image_bgr(_src, __image);
00107   }
00108
00109   CvSeq *face_seq = cvHaarDetectObjects(__image, __cascade, __storage,
00110                                         __haar_scale_factor, __min_neighbours, __flags);
00111
00112   for ( int i = 0; i < face_seq->total; ++i) {
00113     CvAvgComp el = *(CvAvgComp*)cvGetSeqElem(face_seq, i);
00114     ROI r(el.rect.x, el.rect.y, el.rect.width, el.rect.height, _width, _height);
00115     r.num_hint_points = el.rect.width * el.rect.height;
00116     rv->push_back(r);
00117   }
00118
00119   // sort, smallest first, we define num_hint_points as area enclosed by the ROI
00120   rv->sort();
00121
00122   return rv;
00123 }