smiledetect.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "opencv2/objdetect.hpp"
  2. #include "opencv2/highgui.hpp"
  3. #include "opencv2/imgproc.hpp"
  4. #include "opencv2/videoio.hpp"
  5. #include <iostream>
  6. using namespace std;
  7. using namespace cv;
  8. static void help(const char** argv)
  9. {
  10. cout << "\nThis program demonstrates the smile detector.\n"
  11. "Usage:\n" <<
  12. argv[0] << " [--cascade=<cascade_path> this is the frontal face classifier]\n"
  13. " [--smile-cascade=[<smile_cascade_path>]]\n"
  14. " [--scale=<image scale greater or equal to 1, try 2.0 for example. The larger the faster the processing>]\n"
  15. " [--try-flip]\n"
  16. " [video_filename|camera_index]\n\n"
  17. "Example:\n" <<
  18. argv[0] << " --cascade=\"data/haarcascades/haarcascade_frontalface_alt.xml\" --smile-cascade=\"data/haarcascades/haarcascade_smile.xml\" --scale=2.0\n\n"
  19. "During execution:\n\tHit any key to quit.\n"
  20. "\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
  21. }
  22. void detectAndDraw( Mat& img, CascadeClassifier& cascade,
  23. CascadeClassifier& nestedCascade,
  24. double scale, bool tryflip );
  25. string cascadeName;
  26. string nestedCascadeName;
  27. int main( int argc, const char** argv )
  28. {
  29. VideoCapture capture;
  30. Mat frame, image;
  31. string inputName;
  32. bool tryflip;
  33. help(argv);
  34. CascadeClassifier cascade, nestedCascade;
  35. double scale;
  36. cv::CommandLineParser parser(argc, argv,
  37. "{help h||}{scale|1|}"
  38. "{cascade|data/haarcascades/haarcascade_frontalface_alt.xml|}"
  39. "{smile-cascade|data/haarcascades/haarcascade_smile.xml|}"
  40. "{try-flip||}{@input||}");
  41. if (parser.has("help"))
  42. {
  43. help(argv);
  44. return 0;
  45. }
  46. cascadeName = samples::findFile(parser.get<string>("cascade"));
  47. nestedCascadeName = samples::findFile(parser.get<string>("smile-cascade"));
  48. tryflip = parser.has("try-flip");
  49. inputName = parser.get<string>("@input");
  50. scale = parser.get<int>("scale");
  51. if (!parser.check())
  52. {
  53. help(argv);
  54. return 1;
  55. }
  56. if (scale < 1)
  57. scale = 1;
  58. if( !cascade.load( cascadeName ) )
  59. {
  60. cerr << "ERROR: Could not load face cascade" << endl;
  61. help(argv);
  62. return -1;
  63. }
  64. if( !nestedCascade.load( nestedCascadeName ) )
  65. {
  66. cerr << "ERROR: Could not load smile cascade" << endl;
  67. help(argv);
  68. return -1;
  69. }
  70. if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
  71. {
  72. int c = inputName.empty() ? 0 : inputName[0] - '0' ;
  73. if(!capture.open(c))
  74. cout << "Capture from camera #" << c << " didn't work" << endl;
  75. }
  76. else if( inputName.size() )
  77. {
  78. inputName = samples::findFileOrKeep(inputName);
  79. if(!capture.open( inputName ))
  80. cout << "Could not read " << inputName << endl;
  81. }
  82. if( capture.isOpened() )
  83. {
  84. cout << "Video capturing has been started ..." << endl;
  85. cout << endl << "NOTE: Smile intensity will only be valid after a first smile has been detected" << endl;
  86. for(;;)
  87. {
  88. capture >> frame;
  89. if( frame.empty() )
  90. break;
  91. Mat frame1 = frame.clone();
  92. detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
  93. char c = (char)waitKey(10);
  94. if( c == 27 || c == 'q' || c == 'Q' )
  95. break;
  96. }
  97. }
  98. else
  99. {
  100. cerr << "ERROR: Could not initiate capture" << endl;
  101. help(argv);
  102. return -1;
  103. }
  104. return 0;
  105. }
  106. void detectAndDraw( Mat& img, CascadeClassifier& cascade,
  107. CascadeClassifier& nestedCascade,
  108. double scale, bool tryflip)
  109. {
  110. vector<Rect> faces, faces2;
  111. const static Scalar colors[] =
  112. {
  113. Scalar(255,0,0),
  114. Scalar(255,128,0),
  115. Scalar(255,255,0),
  116. Scalar(0,255,0),
  117. Scalar(0,128,255),
  118. Scalar(0,255,255),
  119. Scalar(0,0,255),
  120. Scalar(255,0,255)
  121. };
  122. Mat gray, smallImg;
  123. cvtColor( img, gray, COLOR_BGR2GRAY );
  124. double fx = 1 / scale;
  125. resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
  126. equalizeHist( smallImg, smallImg );
  127. cascade.detectMultiScale( smallImg, faces,
  128. 1.1, 2, 0
  129. //|CASCADE_FIND_BIGGEST_OBJECT
  130. //|CASCADE_DO_ROUGH_SEARCH
  131. |CASCADE_SCALE_IMAGE,
  132. Size(30, 30) );
  133. if( tryflip )
  134. {
  135. flip(smallImg, smallImg, 1);
  136. cascade.detectMultiScale( smallImg, faces2,
  137. 1.1, 2, 0
  138. //|CASCADE_FIND_BIGGEST_OBJECT
  139. //|CASCADE_DO_ROUGH_SEARCH
  140. |CASCADE_SCALE_IMAGE,
  141. Size(30, 30) );
  142. for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
  143. {
  144. faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
  145. }
  146. }
  147. for ( size_t i = 0; i < faces.size(); i++ )
  148. {
  149. Rect r = faces[i];
  150. Mat smallImgROI;
  151. vector<Rect> nestedObjects;
  152. Point center;
  153. Scalar color = colors[i%8];
  154. int radius;
  155. double aspect_ratio = (double)r.width/r.height;
  156. if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
  157. {
  158. center.x = cvRound((r.x + r.width*0.5)*scale);
  159. center.y = cvRound((r.y + r.height*0.5)*scale);
  160. radius = cvRound((r.width + r.height)*0.25*scale);
  161. circle( img, center, radius, color, 3, 8, 0 );
  162. }
  163. else
  164. rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
  165. Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
  166. color, 3, 8, 0);
  167. const int half_height=cvRound((float)r.height/2);
  168. r.y=r.y + half_height;
  169. r.height = half_height-1;
  170. smallImgROI = smallImg( r );
  171. nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
  172. 1.1, 0, 0
  173. //|CASCADE_FIND_BIGGEST_OBJECT
  174. //|CASCADE_DO_ROUGH_SEARCH
  175. //|CASCADE_DO_CANNY_PRUNING
  176. |CASCADE_SCALE_IMAGE,
  177. Size(30, 30) );
  178. // The number of detected neighbors depends on image size (and also illumination, etc.). The
  179. // following steps use a floating minimum and maximum of neighbors. Intensity thus estimated will be
  180. //accurate only after a first smile has been displayed by the user.
  181. const int smile_neighbors = (int)nestedObjects.size();
  182. static int max_neighbors=-1;
  183. static int min_neighbors=-1;
  184. if (min_neighbors == -1) min_neighbors = smile_neighbors;
  185. max_neighbors = MAX(max_neighbors, smile_neighbors);
  186. // Draw rectangle on the left side of the image reflecting smile intensity
  187. float intensityZeroOne = ((float)smile_neighbors - min_neighbors) / (max_neighbors - min_neighbors + 1);
  188. int rect_height = cvRound((float)img.rows * intensityZeroOne);
  189. Scalar col = Scalar((float)255 * intensityZeroOne, 0, 0);
  190. rectangle(img, Point(0, img.rows), Point(img.cols/10, img.rows - rect_height), col, -1);
  191. }
  192. imshow( "result", img );
  193. }