Home | History | Annotate | Download | only in cpp
      1 #include "opencv2/objdetect.hpp"
      2 #include "opencv2/imgcodecs.hpp"
      3 #include "opencv2/videoio.hpp"
      4 #include "opencv2/highgui.hpp"
      5 #include "opencv2/imgproc.hpp"
      6 #include "opencv2/core/utility.hpp"
      7 
      8 #include "opencv2/videoio/videoio_c.h"
      9 #include "opencv2/highgui/highgui_c.h"
     10 
     11 #include <cctype>
     12 #include <iostream>
     13 #include <iterator>
     14 #include <stdio.h>
     15 
     16 using namespace std;
     17 using namespace cv;
     18 
     19 static void help()
     20 {
     21     cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n"
     22             "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
     23             "It's most known use is for faces.\n"
     24             "Usage:\n"
     25             "./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
     26                "   [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
     27                "   [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
     28                "   [--try-flip]\n"
     29                "   [filename|camera_index]\n\n"
     30             "see facedetect.cmd for one call:\n"
     31             "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3\n\n"
     32             "During execution:\n\tHit any key to quit.\n"
     33             "\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
     34 }
     35 
     36 void detectAndDraw( Mat& img, CascadeClassifier& cascade,
     37                     CascadeClassifier& nestedCascade,
     38                     double scale, bool tryflip );
     39 
     40 string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
     41 string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
     42 
     43 int main( int argc, const char** argv )
     44 {
     45     CvCapture* capture = 0;
     46     Mat frame, frameCopy, image;
     47     const string scaleOpt = "--scale=";
     48     size_t scaleOptLen = scaleOpt.length();
     49     const string cascadeOpt = "--cascade=";
     50     size_t cascadeOptLen = cascadeOpt.length();
     51     const string nestedCascadeOpt = "--nested-cascade";
     52     size_t nestedCascadeOptLen = nestedCascadeOpt.length();
     53     const string tryFlipOpt = "--try-flip";
     54     size_t tryFlipOptLen = tryFlipOpt.length();
     55     string inputName;
     56     bool tryflip = false;
     57 
     58     help();
     59 
     60     CascadeClassifier cascade, nestedCascade;
     61     double scale = 1;
     62 
     63     for( int i = 1; i < argc; i++ )
     64     {
     65         cout << "Processing " << i << " " <<  argv[i] << endl;
     66         if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
     67         {
     68             cascadeName.assign( argv[i] + cascadeOptLen );
     69             cout << "  from which we have cascadeName= " << cascadeName << endl;
     70         }
     71         else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
     72         {
     73             if( argv[i][nestedCascadeOpt.length()] == '=' )
     74                 nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
     75             if( !nestedCascade.load( nestedCascadeName ) )
     76                 cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
     77         }
     78         else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
     79         {
     80             if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
     81                 scale = 1;
     82             cout << " from which we read scale = " << scale << endl;
     83         }
     84         else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
     85         {
     86             tryflip = true;
     87             cout << " will try to flip image horizontally to detect assymetric objects\n";
     88         }
     89         else if( argv[i][0] == '-' )
     90         {
     91             cerr << "WARNING: Unknown option %s" << argv[i] << endl;
     92         }
     93         else
     94             inputName.assign( argv[i] );
     95     }
     96 
     97     if( !cascade.load( cascadeName ) )
     98     {
     99         cerr << "ERROR: Could not load classifier cascade" << endl;
    100         help();
    101         return -1;
    102     }
    103 
    104     if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
    105     {
    106         capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );
    107         int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ;
    108         if(!capture) cout << "Capture from CAM " <<  c << " didn't work" << endl;
    109     }
    110     else if( inputName.size() )
    111     {
    112         image = imread( inputName, 1 );
    113         if( image.empty() )
    114         {
    115             capture = cvCaptureFromAVI( inputName.c_str() );
    116             if(!capture) cout << "Capture from AVI didn't work" << endl;
    117         }
    118     }
    119     else
    120     {
    121         image = imread( "../data/lena.jpg", 1 );
    122         if(image.empty()) cout << "Couldn't read ../data/lena.jpg" << endl;
    123     }
    124 
    125     cvNamedWindow( "result", 1 );
    126 
    127     if( capture )
    128     {
    129         cout << "In capture ..." << endl;
    130         for(;;)
    131         {
    132             IplImage* iplImg = cvQueryFrame( capture );
    133             frame = cv::cvarrToMat(iplImg);
    134             if( frame.empty() )
    135                 break;
    136             if( iplImg->origin == IPL_ORIGIN_TL )
    137                 frame.copyTo( frameCopy );
    138             else
    139                 flip( frame, frameCopy, 0 );
    140 
    141             detectAndDraw( frameCopy, cascade, nestedCascade, scale, tryflip );
    142 
    143             if( waitKey( 10 ) >= 0 )
    144                 goto _cleanup_;
    145         }
    146 
    147         waitKey(0);
    148 
    149 _cleanup_:
    150         cvReleaseCapture( &capture );
    151     }
    152     else
    153     {
    154         cout << "In image read" << endl;
    155         if( !image.empty() )
    156         {
    157             detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
    158             waitKey(0);
    159         }
    160         else if( !inputName.empty() )
    161         {
    162             /* assume it is a text file containing the
    163             list of the image filenames to be processed - one per line */
    164             FILE* f = fopen( inputName.c_str(), "rt" );
    165             if( f )
    166             {
    167                 char buf[1000+1];
    168                 while( fgets( buf, 1000, f ) )
    169                 {
    170                     int len = (int)strlen(buf), c;
    171                     while( len > 0 && isspace(buf[len-1]) )
    172                         len--;
    173                     buf[len] = '\0';
    174                     cout << "file " << buf << endl;
    175                     image = imread( buf, 1 );
    176                     if( !image.empty() )
    177                     {
    178                         detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
    179                         c = waitKey(0);
    180                         if( c == 27 || c == 'q' || c == 'Q' )
    181                             break;
    182                     }
    183                     else
    184                     {
    185                         cerr << "Aw snap, couldn't read image " << buf << endl;
    186                     }
    187                 }
    188                 fclose(f);
    189             }
    190         }
    191     }
    192 
    193     cvDestroyWindow("result");
    194 
    195     return 0;
    196 }
    197 
    198 void detectAndDraw( Mat& img, CascadeClassifier& cascade,
    199                     CascadeClassifier& nestedCascade,
    200                     double scale, bool tryflip )
    201 {
    202     int i = 0;
    203     double t = 0;
    204     vector<Rect> faces, faces2;
    205     const static Scalar colors[] =  { CV_RGB(0,0,255),
    206         CV_RGB(0,128,255),
    207         CV_RGB(0,255,255),
    208         CV_RGB(0,255,0),
    209         CV_RGB(255,128,0),
    210         CV_RGB(255,255,0),
    211         CV_RGB(255,0,0),
    212         CV_RGB(255,0,255)} ;
    213     Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );
    214 
    215     cvtColor( img, gray, COLOR_BGR2GRAY );
    216     resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
    217     equalizeHist( smallImg, smallImg );
    218 
    219     t = (double)cvGetTickCount();
    220     cascade.detectMultiScale( smallImg, faces,
    221         1.1, 2, 0
    222         //|CASCADE_FIND_BIGGEST_OBJECT
    223         //|CASCADE_DO_ROUGH_SEARCH
    224         |CASCADE_SCALE_IMAGE
    225         ,
    226         Size(30, 30) );
    227     if( tryflip )
    228     {
    229         flip(smallImg, smallImg, 1);
    230         cascade.detectMultiScale( smallImg, faces2,
    231                                  1.1, 2, 0
    232                                  //|CASCADE_FIND_BIGGEST_OBJECT
    233                                  //|CASCADE_DO_ROUGH_SEARCH
    234                                  |CASCADE_SCALE_IMAGE
    235                                  ,
    236                                  Size(30, 30) );
    237         for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
    238         {
    239             faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
    240         }
    241     }
    242     t = (double)cvGetTickCount() - t;
    243     printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
    244     for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
    245     {
    246         Mat smallImgROI;
    247         vector<Rect> nestedObjects;
    248         Point center;
    249         Scalar color = colors[i%8];
    250         int radius;
    251 
    252         double aspect_ratio = (double)r->width/r->height;
    253         if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
    254         {
    255             center.x = cvRound((r->x + r->width*0.5)*scale);
    256             center.y = cvRound((r->y + r->height*0.5)*scale);
    257             radius = cvRound((r->width + r->height)*0.25*scale);
    258             circle( img, center, radius, color, 3, 8, 0 );
    259         }
    260         else
    261             rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),
    262                        cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
    263                        color, 3, 8, 0);
    264         if( nestedCascade.empty() )
    265             continue;
    266         smallImgROI = smallImg(*r);
    267         nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
    268             1.1, 2, 0
    269             //|CASCADE_FIND_BIGGEST_OBJECT
    270             //|CASCADE_DO_ROUGH_SEARCH
    271             //|CASCADE_DO_CANNY_PRUNING
    272             |CASCADE_SCALE_IMAGE
    273             ,
    274             Size(30, 30) );
    275         for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )
    276         {
    277             center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
    278             center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
    279             radius = cvRound((nr->width + nr->height)*0.25*scale);
    280             circle( img, center, radius, color, 3, 8, 0 );
    281         }
    282     }
    283     cv::imshow( "result", img );
    284 }
    285