php中文网 | cnphp.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 415|回复: 0

Camshift算法原理及其Opencv实现

[复制链接]

3138

主题

3148

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

UID
1
威望
0
积分
7946
贡献
0
注册时间
2021-4-14
最后登录
2024-11-21
在线时间
763 小时
QQ
发表于 2024-1-6 20:30:47 | 显示全部楼层 |阅读模式
  1. //对运动物体的跟踪:
  2. //如果背景固定,可用帧差法 然后在计算下连通域 将面积小的去掉即可
  3. //如果背景单一,即你要跟踪的物体颜色和背景色有较大区别 可用基于颜色的跟踪 如CAMSHIFT 鲁棒性都是较好的
  4. //如果背景复杂,如背景中有和前景一样的颜色 就需要用到一些具有预测性的算法 如卡尔曼滤波等 可以和CAMSHIFT结合

  5. #ifdef _CH_
  6. #pragma package <opencv>
  7. #endif

  8. #ifndef _EiC
  9. #include "cv.h"
  10. #include "highgui.h"
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #endif

  14. IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *backproject = 0, *histimg = 0;
  15. //用HSV中的Hue分量进行跟踪
  16. CvHistogram *hist = 0;
  17. //直方图类
  18. int backproject_mode = 0;
  19. int select_object = 0;
  20. int track_object = 0;
  21. int show_hist = 1;
  22. CvPoint origin;
  23. CvRect selection;
  24. CvRect track_window;
  25. CvBox2D track_box;
  26. //Meanshift跟踪算法返回的Box类
  27. //typedef struct CvBox2D{
  28. //CvPoint2D32f center; /* 盒子的中心 */
  29. //CvSize2D32f size; /* 盒子的长和宽 */
  30. //float angle; /* 水平轴与第一个边的夹角,用弧度表示*/
  31. //}CvBox2D;
  32. CvConnectedComp track_comp;
  33. //连接部件
  34. //typedef struct CvConnectedComp{
  35. //double area; /* 连通域的面积 */
  36. //float value; /* 分割域的灰度缩放值 */
  37. //CvRect rect; /* 分割域的 ROI */
  38. //} CvConnectedComp;
  39. int hdims = 16;
  40. //划分直方图bins的个数,越多越精确
  41. float hranges_arr[] = {0,180};
  42. //像素值的范围
  43. float* hranges = hranges_arr;
  44. //用于初始化CvHistogram类
  45. int vmin = 10, vmax = 256, smin = 30;
  46. //用于设置滑动条

  47. void on_mouse( int event, int x, int y, int flags, void* param )
  48. //鼠标回调函数,该函数用鼠标进行跟踪目标的选择
  49. {
  50.     if( !image )
  51.         return;

  52.     if( image->origin )
  53.         y = image->height - y;
  54.     //如果图像原点坐标在左下,则将其改为左上
  55.        
  56.     if( select_object )
  57.     //select_object为1,表示在用鼠标进行目标选择
  58.     //此时对矩形类selection用当前的鼠标位置进行设置
  59.     {
  60.         selection.x = MIN(x,origin.x);
  61.         selection.y = MIN(y,origin.y);
  62.         selection.width = selection.x + CV_IABS(x - origin.x);
  63.         selection.height = selection.y + CV_IABS(y - origin.y);
  64.         
  65.         selection.x = MAX( selection.x, 0 );
  66.         selection.y = MAX( selection.y, 0 );
  67.         selection.width = MIN( selection.width, image->width );
  68.         selection.height = MIN( selection.height, image->height );
  69.         selection.width -= selection.x;
  70.         selection.height -= selection.y;
  71.     }

  72.     switch( event )
  73.     {
  74.     case CV_EVENT_LBUTTONDOWN:
  75.             //鼠标按下,开始点击选择跟踪物体
  76.         origin = cvPoint(x,y);
  77.         selection = cvRect(x,y,0,0);
  78.         select_object = 1;
  79.         break;
  80.     case CV_EVENT_LBUTTONUP:
  81.             //鼠标松开,完成选择跟踪物体
  82.         select_object = 0;
  83.         if( selection.width > 0 && selection.height > 0 )
  84.                 //如果选择物体有效,则打开跟踪功能
  85.             track_object = -1;
  86.         break;
  87.     }
  88. }


  89. CvScalar hsv2rgb( float hue )
  90. //用于将Hue量转换成RGB量
  91. {
  92.     int rgb[3], p, sector;
  93.     static const int sector_data[][3]=
  94.         {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
  95.     hue *= 0.033333333333333333333333333333333f;
  96.     sector = cvFloor(hue);
  97.     p = cvRound(255*(hue - sector));
  98.     p ^= sector & 1 ? 255 : 0;

  99.     rgb[sector_data[sector][0]] = 255;
  100.     rgb[sector_data[sector][1]] = 0;
  101.     rgb[sector_data[sector][2]] = p;

  102.     return cvScalar(rgb[2], rgb[1], rgb[0],0);
  103. }

  104. int main( int argc, char** argv )
  105. {
  106.     CvCapture* capture = 0;
  107.    
  108.     if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
  109.             //打开摄像头
  110.         capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
  111.     else if( argc == 2 )
  112.             //打开avi
  113.         capture = cvCaptureFromAVI( argv[1] );

  114.     if( !capture )
  115.     //打开视频流失败
  116.     {
  117.         fprintf(stderr,"Could not initialize capturing...\n");
  118.         return -1;
  119.     }

  120.     printf( "Hot keys: \n"
  121.         "\tESC - quit the program\n"
  122.         "\tc - stop the tracking\n"
  123.         "\tb - switch to/from backprojection view\n"
  124.         "\th - show/hide object histogram\n"
  125.         "To initialize tracking, select the object with mouse\n" );
  126.         //打印程序功能列表
  127.        
  128.     cvNamedWindow( "Histogram", 1 );
  129.     //用于显示直方图
  130.     cvNamedWindow( "CamShiftDemo", 1 );
  131.     //用于显示视频
  132.     cvSetMouseCallback( "CamShiftDemo", on_mouse, 0 );
  133.     //设置鼠标回调函数
  134.     cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0 );
  135.     cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0 );
  136.     cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 );
  137.     //设置滑动条

  138.     for(;;)
  139.     //进入视频帧处理主循环
  140.     {
  141.         IplImage* frame = 0;
  142.         int i, bin_w, c;

  143.         frame = cvQueryFrame( capture );
  144.         if( !frame )
  145.             break;

  146.         if( !image )
  147.         //image为0,表明刚开始还未对image操作过,先建立一些缓冲区
  148.         {
  149.             image = cvCreateImage( cvGetSize(frame), 8, 3 );
  150.             image->origin = frame->origin;
  151.             hsv = cvCreateImage( cvGetSize(frame), 8, 3 );
  152.             hue = cvCreateImage( cvGetSize(frame), 8, 1 );
  153.             mask = cvCreateImage( cvGetSize(frame), 8, 1 );
  154.             //分配掩膜图像空间
  155.             backproject = cvCreateImage( cvGetSize(frame), 8, 1 );
  156.             //分配反向投影图空间,大小一样,单通道
  157.             hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 );
  158.             //分配直方图空间
  159.             histimg = cvCreateImage( cvSize(320,200), 8, 3 );
  160.             //分配用于直方图显示的空间
  161.             cvZero( histimg );
  162.             //置背景为黑色
  163.         }

  164.         cvCopy( frame, image, 0 );
  165.         cvCvtColor( image, hsv, CV_BGR2HSV );
  166.         //把图像从RGB表色系转为HSV表色系

  167.         if( track_object )
  168.         //track_object非零,表示有需要跟踪的物体
  169.         {
  170.             int _vmin = vmin, _vmax = vmax;

  171.             cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
  172.                         cvScalar(180,256,MAX(_vmin,_vmax),0), mask );
  173.             //制作掩膜板,只处理像素值为H:0~180,S:smin~256,V:vmin~vmax之间的部分
  174.             cvSplit( hsv, hue, 0, 0, 0 );
  175.                         //分离H分量
  176.                        
  177.             if( track_object < 0 )
  178.             //如果需要跟踪的物体还没有进行属性提取,则进行选取框类的图像属性提取
  179.             {
  180.                 float max_val = 0.f;
  181.                 cvSetImageROI( hue, selection );
  182.                 //设置原选择框为ROI
  183.                 cvSetImageROI( mask, selection );
  184.                 //设置掩膜板选择框为ROI
  185.                 cvCalcHist( &hue, hist, 0, mask );
  186.                 //得到选择框内且满足掩膜板内的直方图
  187.                 cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 );
  188.                 cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 );
  189.                 // 对直方图的数值转为0~255
  190.                 cvResetImageROI( hue );
  191.                 //去除ROI
  192.                 cvResetImageROI( mask );
  193.                 //去除ROI
  194.                 track_window = selection;
  195.                 track_object = 1;
  196.                                 //置track_object为1,表明属性提取完成
  197.                 cvZero( histimg );
  198.                 bin_w = histimg->width / hdims;
  199.                 for( i = 0; i < hdims; i++ )
  200.                 //画直方图到图像空间
  201.                 {
  202.                     int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 );
  203.                     CvScalar color = hsv2rgb(i*180.f/hdims);
  204.                     cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),
  205.                                  cvPoint((i+1)*bin_w,histimg->height - val),
  206.                                  color, -1, 8, 0 );
  207.                 }
  208.             }

  209.             cvCalcBackProject( &hue, backproject, hist );
  210.             //计算hue的反向投影图
  211.             cvAnd( backproject, mask, backproject, 0 );
  212.             //得到掩膜内的反向投影
  213.             cvCamShift( backproject, track_window,
  214.                         cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
  215.                         &track_comp, &track_box );
  216.             //使用MeanShift算法对backproject中的内容进行搜索,返回跟踪结果
  217.             track_window = track_comp.rect;
  218.             //得到跟踪结果的矩形框
  219.             
  220.             if( backproject_mode )
  221.                 cvCvtColor( backproject, image, CV_GRAY2BGR );
  222.                
  223.             if( image->origin )
  224.                 track_box.angle = -track_box.angle;
  225.             cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );
  226.             //画出跟踪结果的位置
  227.         }
  228.         
  229.         if( select_object && selection.width > 0 && selection.height > 0 )
  230.         //如果正处于物体选择,画出选择框
  231.         {
  232.             cvSetImageROI( image, selection );
  233.             cvXorS( image, cvScalarAll(255), image, 0 );
  234.             cvResetImageROI( image );
  235.         }

  236.         cvShowImage( "CamShiftDemo", image );
  237.         cvShowImage( "Histogram", histimg );

  238.         c = cvWaitKey(10);
  239.         if( (char) c == 27 )
  240.             break;
  241.         switch( (char) c )
  242.         //按键切换功能
  243.         {
  244.         case 'b':
  245.             backproject_mode ^= 1;
  246.             break;
  247.         case 'c':
  248.             track_object = 0;
  249.             cvZero( histimg );
  250.             break;
  251.         case 'h':
  252.             show_hist ^= 1;
  253.             if( !show_hist )
  254.                 cvDestroyWindow( "Histogram" );
  255.             else
  256.                 cvNamedWindow( "Histogram", 1 );
  257.             break;
  258.         default:
  259.             ;
  260.         }
  261.     }

  262.     cvReleaseCapture( &capture );
  263.     cvDestroyWindow("CamShiftDemo");

  264.     return 0;
  265. }

  266. #ifdef _EiC
  267. main(1,"camshiftdemo.c");
  268. #endif
复制代码

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|php中文网 | cnphp.com ( 赣ICP备2021002321号-2 )

GMT+8, 2024-11-21 21:45 , Processed in 0.790882 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

申明:本站所有资源皆搜集自网络,相关版权归版权持有人所有,如有侵权,请电邮(fiorkn@foxmail.com)告之,本站会尽快删除。

快速回复 返回顶部 返回列表