ufacedetect.cpp 8.7 KB

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