camshiftdemo.cpp的详细注释

来源:互联网 发布:个人理财产品 知乎 编辑:程序博客网 时间:2024/06/05 00:00
  1. #include "opencv2/video/tracking.hpp"  
  2. #include "opencv2/imgproc/imgproc.hpp"  
  3. #include "opencv2/highgui/highgui.hpp"  
  4.   
  5. #include <iostream>  
  6. #include <ctype.h>  
  7.   
  8. using namespace cv;  
  9. using namespace std;  
  10.   
  11. Mat image;  
  12.   
  13. bool backprojMode = false;  
  14. bool selectObject = false;//用来判断是否选中,当鼠标左键按下时为true,左键松开时为false  
  15. int trackObject = 0;  
  16. bool showHist = true;  
  17. Point origin;//选中的起点  
  18. Rect selection;//选中的区域  
  19. int vmin = 10, vmax = 256, smin = 30;//图像掩膜需要的边界常数  
  20.   
  21. //鼠标事件响应函数,这个函数从按下左键时开始响应直到左键释放  
  22. static void onMouse( int event, int x, int y, intvoid* )  
  23. {  
  24.     if( selectObject )  
  25.     {  
  26.         //选择区域的x坐标选起点与当前点的最小值,保证鼠标不管向右下角还是左上角拉动都正确选择  
  27.         selection.x = MIN(x, origin.x);  
  28.         selection.y = MIN(y, origin.y);  
  29.         //获得选择区域的宽和高  
  30.         selection.width = std::abs(x - origin.x);  
  31.         selection.height = std::abs(y - origin.y);  
  32.         //这条语句多余,注释掉不影响结果  
  33.     //  selection &= Rect(0, 0, image.cols, image.rows);  
  34.     }  
  35.   
  36.     switch( event )  
  37.     {  
  38.     case CV_EVENT_LBUTTONDOWN://按下鼠标时,捕获点origin  
  39.         origin = Point(x,y);  
  40.         selection = Rect(x,y,0,0);  
  41.         selectObject = true;//这时switch前面的if语句条件为true,执行该语句  
  42.         break;  
  43.     case CV_EVENT_LBUTTONUP://松开鼠标时,捕获width和height  
  44.         selectObject = false;  
  45.         if( selection.width > 0 && selection.height > 0 )  
  46.             trackObject = -1;//重新计算直方图  
  47.         break;  
  48.     }  
  49. }  
  50.   
  51. static void help()//打印控制按键说明  
  52. {  
  53.     cout << "\nThis is a demo that shows mean-shift based tracking\n"  
  54.             "You select a color objects such as your face and it tracks it.\n"  
  55.             "This reads from video camera (0 by default, or the camera number the user enters\n"  
  56.             "Usage: \n"  
  57.             "   ./camshiftdemo [camera number]\n";  
  58.   
  59.     cout << "\n\nHot keys: \n"  
  60.             "\tESC - quit the program\n"  
  61.             "\tc - stop the tracking\n"  
  62.             "\tb - switch to/from backprojection view\n"  
  63.             "\th - show/hide object histogram\n"  
  64.             "\tp - pause video\n"  
  65.             "To initialize tracking, select the object with mouse\n";  
  66. }  
  67.   
  68. const char* keys =  
  69. {  
  70.     "{1|  | 0 | camera number}"  
  71. };  
  72.   
  73. int main( int argc, const char** argv )  
  74. {  
  75.     help();  
  76.   
  77.     VideoCapture cap;  
  78.     Rect trackWindow;//要跟踪的窗口  
  79.     int hsize = 16;//创建直方图时要用的常量  
  80.     float hranges[] = {0,180};  
  81.     const float* phranges = hranges;  
  82.     CommandLineParser parser(argc, argv, keys);  
  83.     int camNum = parser.get<int>("1");//现在camNum = 0  
  84.   
  85.     cap.open(camNum);  
  86.     //摄像头画面捕捉不成功则退出程序  
  87.     if( !cap.isOpened() )  
  88.     {  
  89.         help();  
  90.         cout << "***Could not initialize capturing...***\n";  
  91.         cout << "Current parameter's value: \n";  
  92.         parser.printParams();//打印出cmd参数信息  
  93.         return -1;  
  94.     }  
  95.     //关于显示窗口的一些设置  
  96.     namedWindow( "Histogram", 0 );  
  97.     namedWindow( "CamShift Demo", 0 );  
  98.     //设置鼠标事件,把鼠标响应与onMouse函数关联起来  
  99.     setMouseCallback( "CamShift Demo", onMouse, 0 );  
  100.     //创建三个滑块条,特定条件用滑块条选择不同参数能获得较好的跟踪效果  
  101.     createTrackbar( "Vmin""CamShift Demo", &vmin, 256, 0 );  
  102.     createTrackbar( "Vmax""CamShift Demo", &vmax, 256, 0 );  
  103.     createTrackbar( "Smin""CamShift Demo", &smin, 256, 0 );  
  104.   
  105.     //创建Mat变量,frame, hsv, hue, mask, hist, histimg, backproj;其中histimg初始化为200*300的零矩阵  
  106.     Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;  
  107.     bool paused = false;  
  108.   
  109.     //主循环  
  110.     for(;;)  
  111.     {  
  112.         if( !paused )  
  113.         {  
  114.             cap >> frame;//从摄像头输入frame  
  115.             if( frame.empty() )//为空,跳出主循环  
  116.                 break;  
  117.         }  
  118.   
  119.         frame.copyTo(image);//frame存入image  
  120.   
  121.         if( !paused )  
  122.         {  
  123.             cvtColor(image, hsv, CV_BGR2HSV);//将BGR转换成HSV格式,存入hsv中,hsv是3通道  
  124.   
  125.             if( trackObject )//松开鼠标左键时,trackObject为-1,执行核心部分  
  126.             {  
  127.                 int _vmin = vmin, _vmax = vmax;  
  128.   
  129.                 //inRange用来检查元素的取值范围是否在另两个矩阵的元素取值之间,返回验证矩阵mask(0-1矩阵)  
  130.                 //这里用于制作掩膜板,只处理像素值为H:0~180,S:smin~256, V:vmin~vmax之间的部分。mask是要求的,单通道  
  131.                 inRange(hsv, Scalar(0, smin, MIN(_vmin,_vmax)),  
  132.                         Scalar(180, 256, MAX(_vmin, _vmax)), mask);  
  133.   
  134.                 int ch[] = {0, 0};  
  135.                 //type包含通道信息,例如CV_8UC3,而深度信息depth不包含通道信息,例如CV_8U.  
  136.                 hue.create(hsv.size(), hsv.depth());//hue是单通道  
  137.                 mixChannels(&hsv, 1, &hue, 1, ch, 1);//将H分量拷贝到hue中,其他分量不拷贝。  
  138.   
  139.                 if( trackObject < 0 )  
  140.                 {  
  141.                     //roi为选中区域的矩阵,maskroi为0-1矩阵  
  142.                     Mat roi(hue, selection), maskroi(mask, selection);  
  143.                     //绘制色调直方图hist,仅限于用户选定的目标矩形区域  
  144.                     calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);  
  145.                     normalize(hist, hist, 0, 255, CV_MINMAX);//必须是单通道,hist是单通道。归一化,范围为0-255  
  146.   
  147.                     trackWindow = selection;  
  148.                     trackObject = 1;//trackObject置1,接下来就不需要再执行这个if块了  
  149.                       
  150.                     histimg = Scalar::all(0);//用于显示直方图  
  151.                     //计算每个直方的宽度  
  152.                     int binW = histimg.cols / hsize;//hsize为16,共显示16个  
  153.                     Mat buf(1, hsize, CV_8UC3);//  
  154.   
  155.                     forint i = 0; i < hsize; i++ )  
  156.                         //直方图每一项的颜色是根据项数变化的  
  157.                         buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180./hsize), 255, 255);  
  158.                     cvtColor(buf, buf, CV_HSV2BGR);  
  159.                     //量化等级一共有16个等级,故循环16次,画16个直方块  
  160.                     forint i = 0; i < hsize; i++ )  
  161.                     {  
  162.                         int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);//获取直方图每一项的高  
  163.                         //画直方图。opencv中左上角为坐标原点  
  164.                         rectangle( histimg, Point(i*binW,histimg.rows),  
  165.                                    Point((i+1)*binW,histimg.rows - val),  
  166.                                    Scalar(buf.at<Vec3b>(i)), -1, 8 );  
  167.                     }  
  168.                 }  
  169.                 //根据直方图hist计算整幅图像的反向投影图backproj,backproj与hue相同大小  
  170.                 calcBackProject(&hue, 1, 0, hist, backproj, &phranges);  
  171.                 //计算两个矩阵backproj、mask的每个元素的按位与,返回backproj  
  172.                 backproj &= mask;  
  173.                 //调用最核心的camshift函数  
  174.                 //TermCriteria是算法完成的条件  
  175.                 RotatedRect trackBox = CamShift(backproj, trackWindow,  
  176.                                     TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));  
  177.                 if( trackWindow.area() <= 1 )  
  178.                 {  
  179.                     int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;  
  180.                     trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,  
  181.                                        trackWindow.x + r, trackWindow.y + r) &  
  182.                                   Rect(0, 0, cols, rows);  
  183.                 }  
  184.   
  185.                 if( backprojMode )//转换显示方式,将backproj显示出来  
  186.                     cvtColor( backproj, image, CV_GRAY2BGR );  
  187.                 //画出椭圆,第二个参数是一个矩形,画该矩形的内接圆  
  188.                 ellipse( image, trackBox, Scalar(0,0,255), 3, CV_AA );  
  189.             }  
  190.         }  
  191.         else if( trackObject < 0 )  
  192.             paused = false;  
  193.   
  194.         if( selectObject && selection.width > 0 && selection.height > 0 )  
  195.         {  
  196.             Mat roi(image, selection);  
  197.             bitwise_not(roi, roi);  
  198.         }  
  199.   
  200.         imshow( "CamShift Demo", image );  
  201.         imshow( "Histogram", histimg );  
  202.   
  203.         //每轮都要等待用户的按键控制  
  204.         char c = (char)waitKey(10);  
  205.         if( c == 27 )//"Esc"键,直接退出  
  206.             break;  
  207.         switch(c)  
  208.         {  
  209.         case 'b'://转换显示方式  
  210.             backprojMode = !backprojMode;  
  211.             break;  
  212.         case 'c'://停止追踪  
  213.             trackObject = 0;  
  214.             histimg = Scalar::all(0);  
  215.             break;  
  216.         case 'h'://隐藏或显示直方图  
  217.             showHist = !showHist;  
  218.             if( !showHist )  
  219.                 destroyWindow( "Histogram" );  
  220.             else  
  221.                 namedWindow( "Histogram", 1 );  
  222.             break;  
  223.         case 'p'://暂停  
  224.             paused = !paused;//frame停止从摄像头获取图像,只显示旧的图像  
  225.             break;  
  226.         default:  
  227.             ;  
  228.         }  
  229.     }  
  230.   
  231.     return 0;  
  232. }  
0 0
原创粉丝点击