PageRenderTime 79ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/facept.c

https://github.com/cledersonbd/trab1_multimidia
C | 375 lines | 283 code | 75 blank | 17 comment | 80 complexity | 5bc52be37748ca80bd41daf087ab1a77 MD5 | raw file
  1. #include "cv.h"
  2. #include "highgui.h"
  3. #include <stdio.h>
  4. #include <ctype.h>
  5. #include <math.h>
  6. #include <float.h>
  7. #include <limits.h>
  8. #include <time.h>
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #define FACE_DETECT_STEP 3
  12. #define WINSIZEX 780.0
  13. #define WINSIZEY 380.0
  14. #define MOV_LIMIT 5
  15. #define LIM_LOST_PTS 8
  16. #define handle_error_en(en, msg) \
  17. do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
  18. const char* cascade_name = "haarcascade_frontalface_alt.xml";
  19. struct face_s {
  20. IplImage *img;
  21. CvPoint pt1, pt2;
  22. float area;
  23. int detected;
  24. int num_frames;
  25. };
  26. CvMemStorage* storage = 0;
  27. CvHaarClassifierCascade* cascade = 0;
  28. IplImage *image = 0, *grey = 0, *prev_grey = 0, *pyramid = 0, *prev_pyramid = 0, *swap_temp;
  29. int win_size = 10;
  30. const int MAX_COUNT = 500;
  31. CvPoint2D32f* points[2] = {0,0}, *swap_points;
  32. char* status = 0;
  33. int count = 0;
  34. int flags = 0;
  35. int add_remove_pt = 0;
  36. CvPoint pt[30];
  37. int midx=0,midy=0,oldmidx=0,oldmidy=0,minx=0,miny=0,maxx=0,maxy=0;
  38. float zscale=1.0,area=0;
  39. double distancias[10];
  40. double distmed,distmedold=-1;
  41. void * detect_face(void *param) {
  42. struct face_s *face;
  43. int scale = 1;
  44. IplImage *img;
  45. face = (struct face_s *) param;
  46. if(face->img == NULL)
  47. return NULL;
  48. img = cvCreateImage( cvGetSize(face->img), 8, 3 );
  49. cvCopy( face->img, img, 0 );
  50. CvSeq* faces = cvHaarDetectObjects( img, cascade, storage,
  51. 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(40, 40) );
  52. cvReleaseImage(&img);
  53. if(faces->total > 0) {
  54. face->detected =1;
  55. CvRect* r = (CvRect*)cvGetSeqElem( faces, 0 );
  56. //Find the dimensions of the face,and scale it if necessary
  57. face->pt1.x = r->x*scale;
  58. face->pt2.x = (r->x+r->width)*scale;
  59. face->pt1.y = r->y*scale;
  60. face->pt2.y = (r->y+r->height)*scale;
  61. face->area = (face->pt2.x - face->pt1.x) * (face->pt2.y - face->pt1.y);
  62. } else {
  63. face->detected=0;
  64. }
  65. /* Se detectou a face, adiciona pontos no centro e arredores para tracking */
  66. if(count < LIM_LOST_PTS && face->detected == 1) {
  67. add_remove_pt=0;
  68. if(count + add_remove_pt < 16)
  69. pt[add_remove_pt++] = cvPoint( (face->pt1.x+face->pt2.x)/2, (face->pt1.y+face->pt2.y)/2);
  70. if(count + add_remove_pt < 16)
  71. pt[add_remove_pt++] = cvPoint( pt[0].x+4 , pt[0].y);
  72. if(count + add_remove_pt < 16)
  73. pt[add_remove_pt++] = cvPoint( pt[0].x-4 , pt[0].y);
  74. if(count + add_remove_pt < 16)
  75. pt[add_remove_pt++] = cvPoint( pt[0].x , pt[0].y+4);
  76. if(count + add_remove_pt < 16)
  77. pt[add_remove_pt++] = cvPoint( pt[0].x , pt[0].y-4);
  78. if(count + add_remove_pt < 16)
  79. pt[add_remove_pt++] = cvPoint( pt[0].x+8 , pt[0].y);
  80. if(count + add_remove_pt < 16)
  81. pt[add_remove_pt++] = cvPoint( pt[0].x-8 , pt[0].y);
  82. if(count + add_remove_pt < 16)
  83. pt[add_remove_pt++] = cvPoint( pt[0].x , pt[0].y+8);
  84. if(count + add_remove_pt < 16)
  85. pt[add_remove_pt++] = cvPoint( pt[0].x , pt[0].y-8);
  86. if(count + add_remove_pt < 16)
  87. pt[add_remove_pt++] = cvPoint( pt[0].x+4 , pt[0].y+4);
  88. if(count + add_remove_pt < 16)
  89. pt[add_remove_pt++] = cvPoint( pt[0].x-4 , pt[0].y-4);
  90. if(count + add_remove_pt < 16)
  91. pt[add_remove_pt++] = cvPoint( pt[0].x+4 , pt[0].y+4);
  92. if(count + add_remove_pt < 16)
  93. pt[add_remove_pt++] = cvPoint( pt[0].x-4 , pt[0].y-4);
  94. if(count + add_remove_pt < 16)
  95. pt[add_remove_pt++] = cvPoint( pt[0].x+8 , pt[0].y+4);
  96. if(count + add_remove_pt < 16)
  97. pt[add_remove_pt++] = cvPoint( pt[0].x-8 , pt[0].y-4);
  98. if(count + add_remove_pt < 16)
  99. pt[add_remove_pt++] = cvPoint( pt[0].x+8 , pt[0].y+4);
  100. if(count + add_remove_pt < 16)
  101. pt[add_remove_pt++] = cvPoint( pt[0].x-8 , pt[0].y-4);
  102. }
  103. return NULL;
  104. } //end detect_face
  105. void on_mouse( int event, int x, int y, int flags, void* param )
  106. {
  107. if( !image )
  108. return;
  109. if( image->origin )
  110. y = image->height - y;
  111. if( event == CV_EVENT_LBUTTONDOWN )
  112. {
  113. pt[0] = cvPoint(x,y);
  114. add_remove_pt = 1;
  115. }
  116. }
  117. int main( int argc, char** argv ) {
  118. CvCapture* capture = 0;
  119. IplImage *foto,*wind;
  120. int i,k,c;
  121. struct face_s face = { .detected = 0, .img = NULL, .num_frames = 0 };
  122. CvSize foto_size,cam;
  123. foto = cvLoadImage(argv[1], -1);
  124. foto_size = cvGetSize(foto);
  125. /* Init points array */
  126. for(i=0;i<30;i++) {
  127. pt[i].x = 0;
  128. pt[i].y = 0;
  129. }
  130. cvNamedWindow( "foto", 1 );
  131. if( argc == 2 )
  132. capture = cvCaptureFromCAM( 0 );
  133. else if( argc == 3 )
  134. capture = cvCaptureFromAVI( argv[2] );
  135. if( !capture ) {
  136. fprintf(stderr,"Could not initialize capturing...\n");
  137. return -1;
  138. }
  139. storage = cvCreateMemStorage(0);
  140. cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
  141. cvClearMemStorage( storage );
  142. if( !cascade ) {
  143. fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
  144. return -1;
  145. }
  146. cvNamedWindow( "Window", 1 );
  147. foto = cvLoadImage(argv[1], -1);
  148. for(;;) {
  149. IplImage* frame = 0;
  150. frame = cvQueryFrame( capture );
  151. cam = cvGetSize(frame);
  152. if( !frame ) break;
  153. if( !image ) {
  154. /* allocate all the buffers */
  155. image = cvCreateImage( cvGetSize(frame), 8, 3 );
  156. image->origin = frame->origin;
  157. grey = cvCreateImage( cvGetSize(frame), 8, 1 );
  158. prev_grey = cvCreateImage( cvGetSize(frame), 8, 1 );
  159. pyramid = cvCreateImage( cvGetSize(frame), 8, 1 );
  160. prev_pyramid = cvCreateImage( cvGetSize(frame), 8, 1 );
  161. points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
  162. points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
  163. status = (char*)cvAlloc(MAX_COUNT);
  164. flags = 0;
  165. }
  166. cvCopy( frame, image, 0 );
  167. cvCvtColor( image, grey, CV_BGR2GRAY );
  168. face.img = image;
  169. /* If there are 6 points or less, detect face */
  170. if(count < LIM_LOST_PTS && face.num_frames % 8 == 0)
  171. detect_face(&face);
  172. if( count > 0 ) {
  173. /* Find medium value of the points
  174. * Also calculate the area using the edge points */
  175. midx = midy = 0;
  176. minx = maxx = points[1][0].x;
  177. miny = maxy = points[1][0].y;
  178. for( i = 0; i < count; i++ ) {
  179. midx += points[1][i].x;
  180. midy += points[1][i].y;
  181. if(points[1][i].x < minx) minx = points[1][i].x;
  182. if(points[1][i].x > maxx) maxx = points[1][i].x;
  183. if(points[1][i].y < miny) miny = points[1][i].y;
  184. if(points[1][i].y > maxy) maxy = points[1][i].y;
  185. }
  186. midx /= count;
  187. midy /= count;
  188. distmed = 0.0;
  189. int numdist = 0;
  190. for( i = 0; i < count; i++ ) {
  191. for( k = i; k < count; k++ ) {
  192. if(i==k || status[i] == 0) continue;
  193. double dist = sqrt( pow(points[1][i].x-points[1][k].x, 2) + pow(points[1][i].y-points[1][k].y, 2) );
  194. if(!isnan(dist)) {
  195. distmed += dist;
  196. numdist++;
  197. } else {
  198. printf("deu nan: %d(i %d) %d(k %d) - %d(i %d) %d(k %d)\n", (int)points[1][i].x,i,(int)points[1][k].x,k, (int)points[1][i].y,i,(int)points[1][k].y,k);
  199. }
  200. }
  201. }
  202. distmed /= numdist;
  203. /* If the middle point moved few pixels DO NOT move window */
  204. if( abs(midx-oldmidx) < 4) midx=oldmidx;
  205. if( abs(midy-oldmidy) < 4) midy=oldmidy;
  206. /* Draw middle point in window */
  207. IplImage *tmp = cvCreateImage(foto_size, IPL_DEPTH_8U, 3);
  208. cvCopy(foto, tmp, NULL);
  209. double scale;
  210. if(distmed > 0.1) {
  211. // Valores empiricos
  212. scale = pow((distmed/140.0+0.7),4);
  213. // Controle do calculo da escala
  214. if(scale < 0.1) scale=0.1;
  215. if(scale > 1.0) scale=1;
  216. cvSetImageROI(tmp, cvRect( (foto_size.width - foto_size.width*(scale))/2, (foto_size.height - foto_size.height*(scale))/2 , foto_size.width*(scale) , foto_size.height*(scale) ));
  217. }
  218. IplImage *tmp2 = cvCreateImage(foto_size, IPL_DEPTH_8U, 3);
  219. cvResize(tmp, tmp2, CV_INTER_LINEAR);
  220. cvReleaseImage(&tmp);
  221. wind = cvCreateImage(foto_size, IPL_DEPTH_8U, 3);
  222. cvCopy(tmp2, wind, NULL);
  223. cvReleaseImage(&tmp2);
  224. /* Margin X of the foto will be (Number of pixels per one percent)*(Percent of middle point in camera) */
  225. int pixx = foto_size.width/100*( 99.0 - (float)( (float)midx/cam.width*100.0) ) - WINSIZEX*zscale/2;
  226. int pixy = foto_size.height/100*( 99.0 - (float)( (float)midy/cam.height*100.0) ) - WINSIZEY*zscale/2;
  227. /* If we reach the border of the image, DO NOT let move outside */
  228. if(pixx < 0) pixx = 0;
  229. if(pixx +WINSIZEX*zscale > foto_size.width ) pixx = foto_size.width - WINSIZEX*zscale;
  230. if(pixy +WINSIZEY*zscale > foto_size.height ) pixy = foto_size.height - WINSIZEY*zscale;
  231. if(pixy < 0 ) pixy = 0;
  232. /* ROI of window */
  233. cvSetImageROI(wind, cvRect( pixx, pixy , WINSIZEX*zscale , WINSIZEY*zscale ));
  234. int vfar = 50;
  235. if(scale > 0.7) vfar = 120;
  236. /* Remove points too far of the medium point */
  237. for( i = k = 0; i < count; i++ ) {
  238. if( (int) points[1][i].x-midx > vfar || (int)points[1][i].x-midx < -vfar)
  239. continue;
  240. if( (int) points[1][i].y-midy > vfar || (int)points[1][i].y-midy < -vfar)
  241. continue;
  242. points[1][k++] = points[1][i];
  243. }
  244. count = k;
  245. cvCalcOpticalFlowPyrLK( prev_grey, grey, prev_pyramid, pyramid,
  246. points[0], points[1], count, cvSize(win_size,win_size), 5, status, 0,
  247. cvTermCriteria(CV_TERMCRIT_ITER,20,0.03), flags );
  248. flags |= CV_LKFLOW_PYR_A_READY;
  249. /* Remove untracked points and draw the remaining */
  250. for( i = k = 0; i < count; i++ ) {
  251. if( !status[i] )
  252. continue;
  253. points[1][k++] = points[1][i];
  254. cvCircle( image, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
  255. }
  256. count = k;
  257. cvCircle( image, cvPoint(midx,midy), 9, CV_RGB(0,0,255), -1, 8,0);
  258. IplImage *tmp3 = cvCreateImage( cvSize(WINSIZEX, WINSIZEY), IPL_DEPTH_8U, 3);
  259. cvCopy(wind, tmp3, NULL);
  260. cvSetImageROI(tmp3, cvRect(0,0,200,150));
  261. cvResize(image, tmp3, CV_INTER_LINEAR);
  262. cvResetImageROI(tmp3);
  263. cvShowImage( "foto", tmp3 );
  264. cvReleaseImage(&tmp3);
  265. cvReleaseImage(&wind);
  266. }
  267. /* Adiciona pontos para tracking */
  268. if( add_remove_pt && count < MAX_COUNT ) {
  269. int i;
  270. count = 0;
  271. for(i=0;i<add_remove_pt;i++)
  272. points[1][count++] = cvPointTo32f(pt[i]);
  273. cvFindCornerSubPix( grey, points[1] + count - 1, 1,
  274. cvSize(win_size,win_size), cvSize(-1,-1),
  275. cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
  276. add_remove_pt = 0;
  277. }
  278. if( face.detected == 1) {
  279. cvRectangle( image, face.pt1, face.pt2, CV_RGB(255,0,0), 3, 8, 0 );
  280. }
  281. CV_SWAP( prev_grey, grey, swap_temp );
  282. CV_SWAP( prev_pyramid, pyramid, swap_temp );
  283. CV_SWAP( points[0], points[1], swap_points );
  284. cvShowImage( "Window", image );
  285. face.num_frames++;
  286. c = cvWaitKey(10);
  287. if( (char)c == 27 ) break;
  288. switch( (char) c ) {
  289. case 'c':
  290. count = 0;
  291. detect_face(&face);
  292. break;
  293. default:
  294. ;
  295. }
  296. }
  297. cvReleaseCapture( &capture );
  298. cvDestroyWindow("Window");
  299. return 0;
  300. }