分享

OpenCV学习——眼部识别算法实现

 oskycar 2011-10-10

论文下载地址:

http://www.cs./techreports/pdf/2005-012-blink-detection.pdf

 

程序介绍:

 

This system is the enhancement of my previous Eye Tracking system, where this system
automatically locate the user's eye by detecting eye blinks. Motion analysis
techniques are used in this stage, followed by online creation of the open eye template.
The open eye template is used to locate the user's eye in the subsequent frames with
template matching. Blink detection is performed using motion analysis techniques.

Since the operation requires extensive amount of computation, the search region is
restricted in a small search window around the user's eye. This method will drastically
reduces the computation needed thus making the system running smoothly in real time.

Author:  Nashruddin Amin <me@>
License: GPL
Website: http://

See the complete tutorial at:
http:///Real_Time_Eye_Tracking_and_Blink_Detection

Requirement
===========

This package requires the OpenCV library, freely available at:
http:///projects/opencvlibrary

Compiling
=========

Compile as usual. See the OpenCV wiki (http://opencv.) for info on how
to use various IDE with OpenCV.

Usage
=====
1. Run the program.
2. Blink your eyes. You will see 2 rectangles. The green rectangle labels
   the object being tracked (your eye) and the red rectangle is the search window.
3. Move your head to see the eye tracking.
4. If you blink, the program will display the text 'blink!' in the window.
5. Press 'r' to repeat eye detection.
6. Press 'q' to quit.

Contact the author
==================
Feel free to contact me@.

 

 

源程序:

 

  1. /** 
  2.  * Real Time Eye Tracking and Blink Detection with OpenCV 
  3.  * 
  4.  * @author  Nash <me@> 
  5.  * @license GPL 
  6.  * @website http:// 
  7.  * 
  8.  * See the tutorial at 
  9.  * http:///Real_Time_Eye_Tracking_and_Blink_Detection 
  10.  */  
  11. #include <stdio.h>   
  12. #include "cv.h"   
  13. #include "highgui.h"   
  14. #define FRAME_WIDTH        240   
  15. #define FRAME_HEIGHT    180   
  16. #define TPL_WIDTH         16   
  17. #define TPL_HEIGHT         12   
  18. #define WIN_WIDTH        TPL_WIDTH * 2   
  19. #define WIN_HEIGHT        TPL_HEIGHT * 2   
  20. #define TM_THRESHOLD    0.4   
  21. #define STAGE_INIT        1   
  22. #define STAGE_TRACKING    2   
  23. #define POINT_TL(r)        cvPoint(r.x, r.y)   
  24. #define POINT_BR(r)        cvPoint(r.x + r.width, r.y + r.height)   
  25. #define POINTS(r)        POINT_TL(r), POINT_BR(r)   
  26. #define DRAW_RECTS(f, d, rw, ro)                                /   
  27. {                                                                /  
  28.     cvRectangle(f, POINTS(rw), CV_RGB(255, 0, 0), 1, 8, 0);        /  
  29.     cvRectangle(f, POINTS(ro), CV_RGB(0, 255, 0), 1, 8, 0);        /  
  30.     cvRectangle(d, POINTS(rw), cvScalarAll(255),  1, 8, 0);        /  
  31.     cvRectangle(d, POINTS(ro), cvScalarAll(255),  1, 8, 0);        /  
  32. }  
  33. #define    DRAW_TEXT(f, t, d, use_bg)                                /   
  34. if (d)                                                            /  
  35. {                                                                /  
  36.     CvSize _size;                                                /  
  37.     cvGetTextSize(t, &font, &_size, NULL);                        /  
  38.     if (use_bg)                                                    /  
  39.     {                                                            /  
  40.         cvRectangle(f, cvPoint(0, f->height),                     /  
  41.                     cvPoint(_size.width + 5,                     /  
  42.                             f->height - _size.height * 2),        /  
  43.                     CV_RGB(255, 0, 0), CV_FILLED, 8, 0);        /  
  44.     }                                                            /  
  45.     cvPutText(f, t, cvPoint(2, f->height - _size.height / 2),    /  
  46.               &font, CV_RGB(255,255,0));                        /  
  47.     d--;                                                        /  
  48. }  
  49. CvCapture*        capture;  
  50. IplImage*        frame, * gray, * prev, * diff, * tpl;  
  51. CvMemStorage*    storage;  
  52. IplConvKernel*    kernel;  
  53. CvFont            font;  
  54. char*            wnd_name  = "video";  
  55. char*            wnd_debug = "diff";  
  56. int  get_connected_components(IplImage* img, IplImage* prev, CvRect window, CvSeq** comp);  
  57. int     is_eye_pair(CvSeq* comp, int num, CvRect* eye);  
  58. int  locate_eye(IplImage* img, IplImage* tpl, CvRect* window, CvRect* eye);  
  59. int     is_blink(CvSeq* comp, int num, CvRect window, CvRect eye);  
  60. void delay_frames(int nframes);  
  61. void init();  
  62. void exit_nicely(char* msg);  
  63. int  
  64. main(int argc, char** argv)  
  65. {  
  66.     CvSeq*    comp = 0;  
  67.     CvRect    window, eye;  
  68.     int        key, nc, found;  
  69.     int        text_delay, stage = STAGE_INIT;  
  70.     init();  
  71.     while (key != 'q')  
  72.     {  
  73.         frame = cvQueryFrame(capture);  
  74.         if (!frame)  
  75.             exit_nicely("cannot query frame!");  
  76.         frame->origin = 0;  
  77.         if (stage == STAGE_INIT)  
  78.             window = cvRect(0, 0, frame->width, frame->height);  
  79.         cvCvtColor(frame, gray, CV_BGR2GRAY);  
  80.         nc = get_connected_components(gray, prev, window, &comp);  
  81.         if (stage == STAGE_INIT && is_eye_pair(comp, nc, &eye))  
  82.         {  
  83.             delay_frames(5);  
  84.             cvSetImageROI(gray, eye);  
  85.             cvCopy(gray, tpl, NULL);  
  86.             cvResetImageROI(gray);  
  87.             stage = STAGE_TRACKING;  
  88.             text_delay = 10;  
  89.         }  
  90.         if (stage == STAGE_TRACKING)  
  91.         {  
  92.             found = locate_eye(gray, tpl, &window, &eye);  
  93.             if (!found || key == 'r')  
  94.                 stage = STAGE_INIT;  
  95.             if (is_blink(comp, nc, window, eye))  
  96.                 text_delay = 10;  
  97.             DRAW_RECTS(frame, diff, window, eye);  
  98.             DRAW_TEXT(frame, "blink!", text_delay, 1);  
  99.         }  
  100.         cvShowImage(wnd_name, frame);  
  101.         cvShowImage(wnd_debug, diff);  
  102.         prev = cvClone(gray);  
  103.         key  = cvWaitKey(15);  
  104.     }  
  105.     exit_nicely(NULL);  
  106. }  
  107. /** 
  108.  * This is the wrapper function for cvFindContours 
  109.  * 
  110.  * @param    IplImage* img      the current grayscaled frame 
  111.  * @param    IplImage* prev      previously saved frame 
  112.  * @param    CvRect    window  search within this window 
  113.  * @param    CvSeq**   comp    output parameter, will contain the connected components 
  114.  * @return    int                  the number of connected components 
  115.  */  
  116. int   
  117. get_connected_components(IplImage* img, IplImage* prev, CvRect window, CvSeq** comp)  
  118. {  
  119.     IplImage* _diff;  
  120.     cvZero(diff);  
  121.     /* apply search window to images */  
  122.     cvSetImageROI(img, window);  
  123.     cvSetImageROI(prev, window);  
  124.     cvSetImageROI(diff, window);  
  125.     /* motion analysis */  
  126.     cvSub(img, prev, diff, NULL);  
  127.     cvThreshold(diff, diff, 5, 255, CV_THRESH_BINARY);  
  128.     cvMorphologyEx(diff, diff, NULL, kernel, CV_MOP_OPEN, 1);  
  129.     /* reset search window */  
  130.     cvResetImageROI(img);  
  131.     cvResetImageROI(prev);  
  132.     cvResetImageROI(diff);  
  133.     _diff = cvClone(diff);  
  134.     /* get connected components */  
  135.     int nc = cvFindContours(_diff, storage, comp, sizeof(CvContour),  
  136.                             CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));  
  137.     cvClearMemStorage(storage);  
  138.     cvReleaseImage(&_diff);  
  139.     return nc;  
  140. }  
  141. /** 
  142.  * Experimentally-derived heuristics to determine whether 
  143.  * the connected components are eye pair or not. 
  144.  * 
  145.  * @param    CvSeq*  comp the connected components 
  146.  * @param    int     num  the number of connected components 
  147.  * @param   CvRect* eye  output parameter, will contain the location of the 
  148.  *                       first component 
  149.  * @return    int          '1' if eye pair, '0' otherwise 
  150.  */  
  151. int  
  152. is_eye_pair(CvSeq* comp, int num, CvRect* eye)  
  153. {  
  154.     if (comp == 0 || num != 2)  
  155.         return 0;  
  156.     CvRect r1 = cvBoundingRect(comp, 1);  
  157.     comp = comp->h_next;  
  158.     if (comp == 0)  
  159.         return 0;  
  160.     CvRect r2 = cvBoundingRect(comp, 1);  
  161.     /* the width of the components are about the same */  
  162.     if (abs(r1.width - r2.width) >= 5)  
  163.         return 0;  
  164.     /* the height f the components are about the same */  
  165.     if (abs(r1.height - r2.height) >= 5)  
  166.         return 0;  
  167.     /* vertical distance is small */  
  168.     if (abs(r1.y - r2.y) >= 5)  
  169.         return 0;  
  170.     /* reasonable horizontal distance, based on the components' width */  
  171.     int dist_ratio = abs(r1.x - r2.x) / r1.width;  
  172.     if (dist_ratio < 2 || dist_ratio > 5)  
  173.         return 0;  
  174.     /* get the centroid of the 1st component */  
  175.     CvPoint point = cvPoint(  
  176.         r1.x + (r1.width / 2),  
  177.         r1.y + (r1.height / 2)  
  178.     );  
  179.     /* return eye boundaries */  
  180.     *eye = cvRect(  
  181.         point.x - (TPL_WIDTH / 2),  
  182.         point.y - (TPL_HEIGHT / 2),  
  183.         TPL_WIDTH,  
  184.         TPL_HEIGHT  
  185.     );  
  186.     return 1;  
  187. }  
  188. /** 
  189.  * Locate the user's eye with template matching 
  190.  * 
  191.  * @param    IplImage* img     the source image 
  192.  * @param    IplImage* tpl     the eye template 
  193.  * @param    CvRect*   window  search within this window, 
  194.  *                            will be updated with the recent search window 
  195.  * @param    CvRect*   eye     output parameter, will contain the current 
  196.  *                            location of user's eye 
  197.  * @return    int               '1' if found, '0' otherwise 
  198.  */  
  199. int  
  200. locate_eye(IplImage* img, IplImage* tpl, CvRect* window, CvRect* eye)  
  201. {  
  202.     IplImage*    tm;  
  203.     CvRect        win;  
  204.     CvPoint        minloc, maxloc, point;  
  205.     double        minval, maxval;  
  206.     int            w, h;  
  207.     /* get the centroid of eye */  
  208.     point = cvPoint(  
  209.         (*eye).x + (*eye).width / 2,  
  210.         (*eye).y + (*eye).height / 2  
  211.     );  
  212.     /* setup search window 
  213.        replace the predefined WIN_WIDTH and WIN_HEIGHT above 
  214.        for your convenient */  
  215.     win = cvRect(  
  216.         point.x - WIN_WIDTH / 2,  
  217.         point.y - WIN_HEIGHT / 2,  
  218.         WIN_WIDTH,  
  219.         WIN_HEIGHT  
  220.     );  
  221.     /* make sure that the search window is still within the frame */  
  222.     if (win.x < 0)  
  223.         win.x = 0;  
  224.     if (win.y < 0)  
  225.         win.y = 0;  
  226.     if (win.x + win.width > img->width)  
  227.         win.x = img->width - win.width;  
  228.     if (win.y + win.height > img->height)  
  229.         win.y = img->height - win.height;  
  230.     /* create new image for template matching result where: 
  231.        width  = W - w + 1, and 
  232.        height = H - h + 1 */  
  233.     w  = win.width  - tpl->width  + 1;  
  234.     h  = win.height - tpl->height + 1;  
  235.     tm = cvCreateImage(cvSize(w, h), IPL_DEPTH_32F, 1);  
  236.     /* apply the search window */  
  237.     cvSetImageROI(img, win);  
  238.     /* template matching */  
  239.     cvMatchTemplate(img, tpl, tm, CV_TM_SQDIFF_NORMED);  
  240.     cvMinMaxLoc(tm, &minval, &maxval, &minloc, &maxloc, 0);  
  241.     /* release things */  
  242.     cvResetImageROI(img);  
  243.     cvReleaseImage(&tm);  
  244.     /* only good matches */  
  245.     if (minval > TM_THRESHOLD)  
  246.         return 0;  
  247.     /* return the search window */  
  248.     *window = win;  
  249.     /* return eye location */  
  250.     *eye = cvRect(  
  251.         win.x + minloc.x,  
  252.         win.y + minloc.y,  
  253.         TPL_WIDTH,  
  254.         TPL_HEIGHT  
  255.     );  
  256.     return 1;  
  257. }  
  258. int       
  259. is_blink(CvSeq* comp, int num, CvRect window, CvRect eye)  
  260. {  
  261.     if (comp == 0 || num != 1)  
  262.         return 0;  
  263.     CvRect r1 = cvBoundingRect(comp, 1);  
  264.     /* component is within the search window */  
  265.     if (r1.x < window.x)  
  266.         return 0;  
  267.     if (r1.y < window.y)  
  268.         return 0;  
  269.     if (r1.x + r1.width > window.x + window.width)  
  270.         return 0;  
  271.     if (r1.y + r1.height > window.y + window.height)  
  272.         return 0;  
  273.     /* get the centroid of eye */  
  274.     CvPoint pt = cvPoint(  
  275.         eye.x + eye.width / 2,  
  276.         eye.y + eye.height / 2  
  277.     );  
  278.     /* component is located at the eye's centroid */  
  279.     if (pt.x <= r1.x || pt.x >= r1.x + r1.width)  
  280.         return 0;  
  281.     if (pt.y <= r1.y || pt.y >= r1.y + r1.height)  
  282.         return 0;  
  283.     return 1;  
  284. }  
  285. /** 
  286.  * Delay for the specified frame count. I have to write this custom 
  287.  * delay function for these reasons: 
  288.  * - usleep() is not available in Windows 
  289.  * - usleep() and Sleep() will freeze the video for the given interval 
  290.  */  
  291. void  
  292. delay_frames(int nframes)  
  293. {  
  294.     int i;  
  295.     for (i = 0; i < nframes; i++)  
  296.     {  
  297.         frame = cvQueryFrame(capture);  
  298.         if (!frame)  
  299.             exit_nicely("cannot query frame");  
  300.         cvShowImage(wnd_name, frame);  
  301.         if (diff)  
  302.             cvShowImage(wnd_debug, diff);  
  303.         cvWaitKey(30);  
  304.     }  
  305. }  
  306. /** 
  307.  * Initialize images, memory, and windows 
  308.  */  
  309. void  
  310. init()  
  311. {  
  312.     char* msg[] = { "Blink Detection 1.0",  
  313.                     "Copyright (c) 2009",  
  314.                     "http://",  
  315.                     "Press 'q' to quit...",  
  316.                     "Press 'r' to restart...",  
  317.                     "Have fun!" };  
  318.     int delay, i;  
  319.     capture = cvCaptureFromCAM(0);  
  320.     if (!capture)  
  321.         exit_nicely("Cannot initialize camera!");  
  322.     cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH,  FRAME_WIDTH);  
  323.     cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT);  
  324.     frame = cvQueryFrame(capture);  
  325.     if (!frame)  
  326.         exit_nicely("cannot query frame!");  
  327.     cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.4, 0.4, 0, 1, 8);  
  328.     cvNamedWindow(wnd_name, 1);  
  329.     for (delay = 20, i = 0; i < 6; i++, delay = 20)  
  330.         while (delay)  
  331.         {  
  332.             frame = cvQueryFrame(capture);  
  333.             if (!frame)  
  334.                 exit_nicely("cannot query frame!");  
  335.             DRAW_TEXT(frame, msg[i], delay, 0);  
  336.             cvShowImage(wnd_name, frame);  
  337.             cvWaitKey(30);  
  338.         }  
  339.     storage = cvCreateMemStorage(0);  
  340.     if (!storage)  
  341.         exit_nicely("cannot allocate memory storage!");  
  342.     kernel = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_CROSS, NULL);  
  343.     gray   = cvCreateImage(cvGetSize(frame), 8, 1);  
  344.     prev   = cvCreateImage(cvGetSize(frame), 8, 1);  
  345.     diff   = cvCreateImage(cvGetSize(frame), 8, 1);  
  346.     tpl       = cvCreateImage(cvSize(TPL_WIDTH, TPL_HEIGHT), 8, 1);  
  347.     if (!kernel || !gray || !prev || !diff || !tpl)  
  348.         exit_nicely("system error.");  
  349.     gray->origin  = frame->origin;  
  350.     prev->origin  = frame->origin;  
  351.     diff->origin  = frame->origin;  
  352.     cvNamedWindow(wnd_debug, 1);  
  353. }  
  354. /** 
  355.  * This function provides a way to exit nicely 
  356.  * from the system 
  357.  * 
  358.  * @param char* msg error message to display 
  359.  */  
  360. void  
  361. exit_nicely(char* msg)  
  362. {  
  363.     cvDestroyAllWindows();  
  364.     if (capture)  
  365.         cvReleaseCapture(&capture);  
  366.     if (gray)  
  367.         cvReleaseImage(&gray);  
  368.     if (prev)  
  369.         cvReleaseImage(&prev);  
  370.     if (diff)  
  371.         cvReleaseImage(&diff);  
  372.     if (tpl)  
  373.         cvReleaseImage(&tpl);  
  374.     if (storage)  
  375.         cvReleaseMemStorage(&storage);  
  376.     if (msg != NULL)  
  377.     {  
  378.         fprintf(stderr, msg);  
  379.         fprintf(stderr, "/n");  
  380.         exit(1);  
  381.     }  
  382.     exit(0);  
  383. }

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多