facedetect.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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 use of cv::CascadeClassifier class to detect objects (Face + eyes). You can use Haar or LBP features.\n"
  11. "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
  12. "It's most known use is for faces.\n"
  13. "Usage:\n"
  14. << argv[0]
  15. << " [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
  16. " [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
  17. " [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
  18. " [--try-flip]\n"
  19. " [filename|camera_index]\n\n"
  20. "example:\n"
  21. << argv[0]
  22. << " --cascade=\"data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"data/haarcascades/haarcascade_eye_tree_eyeglasses.xml\" --scale=1.3\n\n"
  23. "During execution:\n\tHit any key to quit.\n"
  24. "\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
  25. }
  26. void detectAndDraw( Mat& img, CascadeClassifier& cascade,
  27. CascadeClassifier& nestedCascade,
  28. double scale, bool tryflip );
  29. string cascadeName;
  30. string nestedCascadeName;
  31. int main( int argc, const char** argv )
  32. {
  33. VideoCapture capture;
  34. Mat frame, image;
  35. string inputName;
  36. bool tryflip;
  37. CascadeClassifier cascade, nestedCascade;
  38. double scale;
  39. cv::CommandLineParser parser(argc, argv,
  40. "{help h||}"
  41. "{cascade|data/haarcascades/haarcascade_frontalface_alt.xml|}"
  42. "{nested-cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|}"
  43. "{scale|1|}{try-flip||}{@filename||}"
  44. );
  45. if (parser.has("help"))
  46. {
  47. help(argv);
  48. return 0;
  49. }
  50. cascadeName = parser.get<string>("cascade");
  51. nestedCascadeName = parser.get<string>("nested-cascade");
  52. scale = parser.get<double>("scale");
  53. if (scale < 1)
  54. scale = 1;
  55. tryflip = parser.has("try-flip");
  56. inputName = parser.get<string>("@filename");
  57. if (!parser.check())
  58. {
  59. parser.printErrors();
  60. return 0;
  61. }
  62. if (!nestedCascade.load(samples::findFileOrKeep(nestedCascadeName)))
  63. cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
  64. if (!cascade.load(samples::findFile(cascadeName)))
  65. {
  66. cerr << "ERROR: Could not load classifier cascade" << endl;
  67. help(argv);
  68. return -1;
  69. }
  70. if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
  71. {
  72. int camera = inputName.empty() ? 0 : inputName[0] - '0';
  73. if(!capture.open(camera))
  74. {
  75. cout << "Capture from camera #" << camera << " didn't work" << endl;
  76. return 1;
  77. }
  78. }
  79. else if (!inputName.empty())
  80. {
  81. image = imread(samples::findFileOrKeep(inputName), IMREAD_COLOR);
  82. if (image.empty())
  83. {
  84. if (!capture.open(samples::findFileOrKeep(inputName)))
  85. {
  86. cout << "Could not read " << inputName << endl;
  87. return 1;
  88. }
  89. }
  90. }
  91. else
  92. {
  93. image = imread(samples::findFile("lena.jpg"), IMREAD_COLOR);
  94. if (image.empty())
  95. {
  96. cout << "Couldn't read lena.jpg" << endl;
  97. return 1;
  98. }
  99. }
  100. if( capture.isOpened() )
  101. {
  102. cout << "Video capturing has been started ..." << endl;
  103. for(;;)
  104. {
  105. capture >> frame;
  106. if( frame.empty() )
  107. break;
  108. Mat frame1 = frame.clone();
  109. detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
  110. char c = (char)waitKey(10);
  111. if( c == 27 || c == 'q' || c == 'Q' )
  112. break;
  113. }
  114. }
  115. else
  116. {
  117. cout << "Detecting face(s) in " << inputName << endl;
  118. if( !image.empty() )
  119. {
  120. detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
  121. waitKey(0);
  122. }
  123. else if( !inputName.empty() )
  124. {
  125. /* assume it is a text file containing the
  126. list of the image filenames to be processed - one per line */
  127. FILE* f = fopen( inputName.c_str(), "rt" );
  128. if( f )
  129. {
  130. char buf[1000+1];
  131. while( fgets( buf, 1000, f ) )
  132. {
  133. int len = (int)strlen(buf);
  134. while( len > 0 && isspace(buf[len-1]) )
  135. len--;
  136. buf[len] = '\0';
  137. cout << "file " << buf << endl;
  138. image = imread( buf, IMREAD_COLOR );
  139. if( !image.empty() )
  140. {
  141. detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
  142. char c = (char)waitKey(0);
  143. if( c == 27 || c == 'q' || c == 'Q' )
  144. break;
  145. }
  146. else
  147. {
  148. cerr << "Aw snap, couldn't read image " << buf << endl;
  149. }
  150. }
  151. fclose(f);
  152. }
  153. }
  154. }
  155. return 0;
  156. }
  157. void detectAndDraw( Mat& img, CascadeClassifier& cascade,
  158. CascadeClassifier& nestedCascade,
  159. double scale, bool tryflip )
  160. {
  161. double t = 0;
  162. vector<Rect> faces, faces2;
  163. const static Scalar colors[] =
  164. {
  165. Scalar(255,0,0),
  166. Scalar(255,128,0),
  167. Scalar(255,255,0),
  168. Scalar(0,255,0),
  169. Scalar(0,128,255),
  170. Scalar(0,255,255),
  171. Scalar(0,0,255),
  172. Scalar(255,0,255)
  173. };
  174. Mat gray, smallImg;
  175. cvtColor( img, gray, COLOR_BGR2GRAY );
  176. double fx = 1 / scale;
  177. resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
  178. equalizeHist( smallImg, smallImg );
  179. t = (double)getTickCount();
  180. cascade.detectMultiScale( smallImg, faces,
  181. 1.1, 2, 0
  182. //|CASCADE_FIND_BIGGEST_OBJECT
  183. //|CASCADE_DO_ROUGH_SEARCH
  184. |CASCADE_SCALE_IMAGE,
  185. Size(30, 30) );
  186. if( tryflip )
  187. {
  188. flip(smallImg, smallImg, 1);
  189. cascade.detectMultiScale( smallImg, faces2,
  190. 1.1, 2, 0
  191. //|CASCADE_FIND_BIGGEST_OBJECT
  192. //|CASCADE_DO_ROUGH_SEARCH
  193. |CASCADE_SCALE_IMAGE,
  194. Size(30, 30) );
  195. for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
  196. {
  197. faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
  198. }
  199. }
  200. t = (double)getTickCount() - t;
  201. printf( "detection time = %g ms\n", t*1000/getTickFrequency());
  202. for ( size_t i = 0; i < faces.size(); i++ )
  203. {
  204. Rect r = faces[i];
  205. Mat smallImgROI;
  206. vector<Rect> nestedObjects;
  207. Point center;
  208. Scalar color = colors[i%8];
  209. int radius;
  210. double aspect_ratio = (double)r.width/r.height;
  211. if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
  212. {
  213. center.x = cvRound((r.x + r.width*0.5)*scale);
  214. center.y = cvRound((r.y + r.height*0.5)*scale);
  215. radius = cvRound((r.width + r.height)*0.25*scale);
  216. circle( img, center, radius, color, 3, 8, 0 );
  217. }
  218. else
  219. rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
  220. Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
  221. color, 3, 8, 0);
  222. if( nestedCascade.empty() )
  223. continue;
  224. smallImgROI = smallImg( r );
  225. nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
  226. 1.1, 2, 0
  227. //|CASCADE_FIND_BIGGEST_OBJECT
  228. //|CASCADE_DO_ROUGH_SEARCH
  229. //|CASCADE_DO_CANNY_PRUNING
  230. |CASCADE_SCALE_IMAGE,
  231. Size(30, 30) );
  232. for ( size_t j = 0; j < nestedObjects.size(); j++ )
  233. {
  234. Rect nr = nestedObjects[j];
  235. center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale);
  236. center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale);
  237. radius = cvRound((nr.width + nr.height)*0.25*scale);
  238. circle( img, center, radius, color, 3, 8, 0 );
  239. }
  240. }
  241. imshow( "result", img );
  242. }