空灵学院

 找回密码
 立即注册

扫一扫,访问微社区

搜索
查看: 1927|回复: 0

光流法程序

[复制链接]

1137

主题

1761

帖子

7558

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
7558
发表于 2016-2-2 10:36:30 | 显示全部楼层 |阅读模式
  1. /* --Sparse Optical Flow Demo Program--
  2. * Written by David Stavens (david.stavens@ai.stanford.edu)
  3. */
  4. #include
  5. #include
  6. #include
  7. #include

  8. static const double pi = 3.14159265358979323846;
  9. inline static double square(int a)
  10. {
  11. return a * a;
  12. }
  13. /*该函数目的:给img分配内存空间,并设定format,如位深以及channel数*/
  14. inline static void allocateOnDemand( IplImage **img, CvSize size,
  15. int depth, int channels )
  16. {
  17.    if ( *img != NULL ) return;
  18.      *img = cvCreateImage( size, depth, channels );
  19.    if ( *img == NULL )
  20.       {
  21.   fprintf(stderr, "Error: Couldn't allocate image.  Out of
  22. memory?/n");
  23.         exit(-1);
  24.       }
  25. }
  26. /*主函数,原程序是读取avi视频文件,然后处理,我简单改成从摄像头直接读取
  27. 数据*/
  28. int main(int argc, char *argv[])
  29. {
  30. /*创建CvCapture对象,用于操作摄像头*/
  31.   CvCapture *input_video = cvCreateCameraCapture(0);
  32.   usleep(500);
  33.   if (input_video == NULL)
  34.      {
  35. fprintf(stderr, "Error: Can't open video device./n");
  36. return -1;
  37.      }

  38. /*先读取一帧,以便得到帧的属性,如长、宽等*/
  39.   cvQueryFrame( input_video );

  40. /*读取帧的属性*/
  41.   CvSize frame_size;
  42.   frame_size.height=
  43. (int) cvGetCaptureProperty( input_video, CV_CAP_PROP_FRAME_HEIGHT );
  44.   frame_size.width=
  45. (int) cvGetCaptureProperty( input_video, CV_CAP_PROP_FRAME_WIDTH );
  46. /*********************************************************/

  47. /*创建一个名为optical flow的窗口,大小自动改变*/
  48.   cvNamedWindow("Optical Flow", CV_WINDOW_AUTOSIZE);

  49. /*用于把结果写到文件中去,非必要*/
  50.   CvVideoWriter *writer = 0;
  51.   int isColor = 1;
  52.   int fps     = 25;  // or 30
  53.   int frameW  = 640; // 744 for firewire cameras
  54.   int frameH  = 480; // 480 for firewire cameras
  55.   writer=cvCreateVideoWriter("out.avi",CV_FOURCC('P','I','M','1'),
  56.              fps,cvSize(frameW,frameH),isColor);
  57. /*开始光流法*/
  58.   while(true)
  59.   {
  60.     static IplImage *frame = NULL, *frame1 = NULL, *frame1_1C =NULL,
  61. *frame2_1C = NULL, *eig_image = NULL, *temp_image = NULL,
  62. *pyramid1= NULL, *pyramid2 = NULL;

  63. /*获取第一帧*/
  64.     frame = cvQueryFrame( input_video );
  65.     if (frame == NULL)
  66.      {
  67. fprintf(stderr, "Error: Hmm. The end came sooner than we
  68. thought./n");
  69. return -1;
  70.      }

  71. /*由于opencv的光流函数处理的是8位的灰度图,所以需要创建一个同样格式的
  72. IplImage的对象*/
  73. allocateOnDemand( &frame1_1C, frame_size, IPL_DEPTH_8U, 1 );

  74. /* 把摄像头图像格式转换成OpenCV惯常处理的图像格式*/
  75.     cvConvertImage(frame, frame1_1C, 0);

  76. /* 我们需要把具有全部颜色信息的原帧保存,以备最后在屏幕上显示用*/
  77.     allocateOnDemand( &frame1, frame_size, IPL_DEPTH_8U, 3 );
  78.     cvConvertImage(frame, frame1, 0);

  79. /* 获取第二帧 */
  80.     frame = cvQueryFrame( input_video );
  81.     if (frame == NULL)
  82.      {
  83. fprintf(stderr, "Error: Hmm. The end came sooner than we
  84. thought./n");
  85. return -1;
  86.      }

  87. /*原理同上*/
  88.     allocateOnDemand( &frame2_1C, frame_size, IPL_DEPTH_8U, 1 );
  89.     cvConvertImage(frame, frame2_1C, 0);

  90. /*********************************************************
  91. 开始shi-Tomasi算法,该算法主要用于feature selection,即一张图中哪些是我
  92. 们感兴趣需要跟踪的点(interest point)
  93. input:
  94. * "frame1_1C" 输入图像.
  95. * "eig_image" and "temp_image" 只是给该算法提供可操作的内存区域.
  96. * 第一个".01" 规定了特征值的最小质量,因为该算法要得到好的特征点,哪就
  97. 需要一个选择的阈值
  98. * 第二个".01" 规定了像素之间最小的距离,用于减少运算复杂度,当然也一定
  99. 程度降低了跟踪精度
  100. * "NULL" 意味着处理整张图片,当然你也可以指定一块区域
  101. output:
  102. * "frame1_features" 将会包含fram1的特征值
  103. * "number_of_features" 将在该函数中自动填充上所找到特征值的真实数目,
  104. 该值<= 400
  105. **********************************************************/

  106. /*开始准备该算法需要的输入*/

  107. /* 给eig_image,temp_image分配空间*/
  108.     allocateOnDemand( &eig_image, frame_size, IPL_DEPTH_32F, 1 );
  109.     allocateOnDemand( &temp_image, frame_size, IPL_DEPTH_32F, 1 );

  110. /* 定义存放frame1特征值的数组,400只是定义一个上限 */
  111.     CvPoint2D32f frame1_features[400];
  112.     number_of_features = 400;

  113. /*开始跑shi-tomasi函数*/
  114.     cvGoodFeaturesToTrack(frame1_1C, eig_image, temp_image,
  115. frame1_features, &number_of_features, .01, .01, NULL);

  116. /**********************************************************
  117. 开始金字塔Lucas Kanade光流法,该算法主要用于feature tracking,即是算出
  118. 光流,并跟踪目标。
  119. input:
  120. * "frame1_1C" 输入图像,即8位灰色的第一帧
  121. * "frame2_1C" 第二帧,我们要在其上找出第一帧我们发现的特征点在第二帧
  122. 的什么位置
  123. * "pyramid1" and "pyramid2" 是提供给该算法可操作的内存区域,计算中间
  124. 数据
  125. * "frame1_features" 由shi-tomasi算法得到的第一帧的特征点.
  126. * "number_of_features" 第一帧特征点的数目
  127. * "optical_flow_termination_criteria" 该算法中迭代终止的判别,这里是
  128. epsilon<0.3,epsilon是两帧中对应特征窗口的光度之差的平方,这个以后的文
  129. 章会讲
  130. * "0" 这个我不知道啥意思,反正改成1就出不来光流了,就用作者原话解释把
  131. means disable enhancements.  (For example, the second array isn't
  132. pre-initialized with guesses.)
  133. output:
  134. * "frame2_features" 根据第一帧的特征点,在第二帧上所找到的对应点
  135. * "optical_flow_window" lucas-kanade光流算法的运算窗口,具体lucas-kanade
  136. 会在下一篇详述
  137. * "5" 指示最大的金字塔层数,0表示只有一层,那就是没用金字塔算法
  138. * "optical_flow_found_feature" 用于指示在第二帧中是否找到对应特征值,
  139. 若找到,其值为非零
  140. * "optical_flow_feature_error" 用于存放光流误差
  141. **********************************************************/

  142. /*开始为pyramid lucas kanade光流算法输入做准备*/
  143.     CvPoint2D32f frame2_features[400];

  144. /* 该数组相应位置的值为非零,如果frame1中的特征值在frame2中找到 */
  145.     char optical_flow_found_feature[400];

  146. /* 数组第i个元素表对应点光流误差*/
  147.     float optical_flow_feature_error[400];

  148. /*lucas-kanade光流法运算窗口,这里取3*3的窗口,可以尝试下5*5,区别就是5*5
  149. 出现aperture problem的几率较小,3*3运算量小,对于feature selection即shi-tomasi算法来说足够了*/
  150.     CvSize optical_flow_window = cvSize(3,3);

  151. /* 终止规则,当完成20次迭代或者当epsilon<=0.3,迭代终止,可以尝试下别的值*/
  152.     CvTermCriteria optical_flow_termination_criteria
  153.   = cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3 );

  154. /*分配工作区域*/
  155.     allocateOnDemand( &pyramid1, frame_size, IPL_DEPTH_8U, 1 );
  156.     allocateOnDemand( &pyramid2, frame_size, IPL_DEPTH_8U, 1 );

  157. /*开始跑该算法*/
  158.     cvCalcOpticalFlowPyrLK(frame1_1C, frame2_1C, pyramid1, pyramid2,
  159. frame1_features, frame2_features, number_of_features,
  160. optical_flow_window, 5, optical_flow_found_feature,
  161. optical_flow_feature_error, optical_flow_termination_criteria, 0 );

  162. /*画光流场,具体画图过程我就不介绍了,只要知道画图是依据两帧对应的特征值,
  163. 这个特征值就是图像上我们感兴趣的点,如边缘上的点P(x,y)*/
  164.     for(int i = 0; i < number_of_features; i++)
  165.       {
  166.            /* 如果没找到对应特征点 */
  167.         if ( optical_flow_found_feature[i] == 0 )
  168.      continue;
  169. int line_thickness;
  170. line_thickness = 1;

  171. /* CV_RGB(red, green, blue) is the red, green, and blue components
  172. * of the color you want, each out of 255.
  173. */
  174. CvScalar line_color;
  175.         line_color = CV_RGB(255,0,0);

  176. /*画箭头,因为帧间的运动很小,所以需要缩放,不然看不见箭头,缩放因子为3*/
  177. CvPoint p,q;
  178. p.x = (int) frame1_features[i].x;
  179. p.y = (int) frame1_features[i].y;
  180. q.x = (int) frame2_features[i].x;
  181. q.y = (int) frame2_features[i].y;

  182. double angle;
  183. angle = atan2( (double) p.y - q.y, (double) p.x - q.x );
  184. double hypotenuse;
  185. hypotenuse = sqrt( square(p.y - q.y) + square(p.x - q.x) );

  186. /*执行缩放*/
  187. q.x = (int) (p.x - 3 * hypotenuse * cos(angle));
  188. q.y = (int) (p.y - 3 * hypotenuse * sin(angle));

  189. /*画箭头主线*/
  190. /* "frame1"要在frame1上作画.
  191. * "p" 线的开始点.
  192. * "q" 线的终止点.
  193. * "CV_AA" 反锯齿.
  194. * "0" 没有小数位.
  195. */
  196. cvLine( frame1, p, q, line_color, line_thickness, CV_AA, 0);

  197. /* 画箭的头部*/
  198. p.x = (int) (q.x + 9 * cos(angle + pi / 4));
  199. p.y = (int) (q.y + 9 * sin(angle + pi / 4));
  200. cvLine( frame1, p, q, line_color, line_thickness, CV_AA, 0);
  201. p.x = (int) (q.x + 9 * cos(angle - pi / 4));
  202. p.y = (int) (q.y + 9 * sin(angle - pi / 4));
  203. cvLine( frame1, p, q, line_color, line_thickness, CV_AA, 0);
  204.       }
  205. /*显示图像*/
  206. cvShowImage("Optical Flow", frame1);
  207. /*延时,要不放不了*/
  208. int key=cvWaitKey(20);
  209. /*写入到文件中去*/
  210. cvWriteFrame(writer,frame1);
  211.    }
  212. }
复制代码
分类:
图像处理

回复

使用道具 举报

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

本版积分规则

Archiver|空灵学院 ( 11033542 )

GMT+8, 2024-3-29 03:13 , Processed in 0.032930 second(s), 27 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

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