Guest User

OpenCV Optical Flow Demo

a guest
May 28th, 2011
854
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.18 KB | None | 0 0
  1. /* --Sparse Optical Flow Demo Program--
  2. * Written by David Stavens ([email protected])
  3. */
  4.  
  5. #include <stdio.h>
  6. #include <cv.h>
  7. #include <highgui.h>
  8. #include <math.h>
  9.  
  10. #define NO_FEATURES 400
  11. #define MIN_VECT_COMP 2000
  12.  
  13. static const double pi = 3.14159265358979323846;
  14.  
  15. inline static double square(int a)
  16. {
  17. return a * a;
  18. }
  19.  
  20. /* This is just an inline that allocates images. I did this to reduce clutter in the
  21. * actual computer vision algorithmic code. Basically it allocates the requested image
  22. * unless that image is already non-NULL. It always leaves a non-NULL image as-is even
  23. * if that image's size, depth, and/or channels are different than the request.
  24. */
  25. inline static void allocateOnDemand(IplImage **img, CvSize size, int depth, int channels) {
  26. if (*img != NULL)
  27. return;
  28.  
  29. *img = cvCreateImage(size, depth, channels);
  30. if (*img == NULL) {
  31. fprintf(stderr, "Error: Couldn't allocate image. Out of memory?\n");
  32. exit(-1);
  33. }
  34. }
  35.  
  36. int main(void)
  37. {
  38. /* Create an object that decodes the input video stream. */
  39. CvCapture *input_video = cvCaptureFromCAM(0);
  40.  
  41. if (input_video == NULL)
  42. {
  43. /* Either the video didn't exist OR it uses a codec OpenCV
  44. * doesn't support.
  45. */
  46. fprintf(stderr, "Error: Can't open video.\n");
  47. return -1;
  48. }
  49.  
  50. /* Read the video's frame size. */
  51. CvSize frame_size;
  52. frame_size.height = (int) cvGetCaptureProperty(input_video, CV_CAP_PROP_FRAME_HEIGHT);
  53. frame_size.width = (int) cvGetCaptureProperty(input_video, CV_CAP_PROP_FRAME_WIDTH);
  54.  
  55. /* Create three windows called "N", "N+1", and "Optical Flow"
  56. * for visualizing the output. Have those windows automatically change their
  57. * size to match the output.
  58. */
  59. cvNamedWindow("N", CV_WINDOW_AUTOSIZE);
  60. cvNamedWindow("N+1", CV_WINDOW_AUTOSIZE);
  61. cvNamedWindow("Optical Flow", CV_WINDOW_AUTOSIZE);
  62.  
  63. /* Color filters. */
  64. CvScalar hsv_min = cvScalar(0, 30, 80, 0);
  65. CvScalar hsv_max = cvScalar(50, 100, 255, 0);
  66.  
  67. long current_frame = 0;
  68. int key_pressed = 0;
  69.  
  70. while(key_pressed != 27) {
  71. static IplImage *frame = NULL, *frame1 = NULL, *frame1_1C = NULL, *frame2_1C = NULL, *eig_image = NULL, *temp_image = NULL, *pyramid1 = NULL, *pyramid2 = NULL;
  72.  
  73. /* Go to the frame we want. Important if multiple frames are queried in
  74. * the loop which they of course are for optical flow. Note that the very
  75. * first call to this is actually not needed. (Because the correct position
  76. * is set outsite the for() loop.)
  77. */
  78. // cvSetCaptureProperty(input_video, CV_CAP_PROP_POS_FRAMES, current_frame);
  79.  
  80. /* Get the next frame of the video.
  81. * IMPORTANT! cvQueryFrame() always returns a pointer to the _same_
  82. * memory location. So successive calls:
  83. * frame1 = cvQueryFrame();
  84. * frame2 = cvQueryFrame();
  85. * frame3 = cvQueryFrame();
  86. * will result in (frame1 == frame2 && frame2 == frame3) being true.
  87. * The solution is to make a copy of the cvQueryFrame() output.
  88. */
  89. frame = cvQueryFrame(input_video);
  90. if (frame == NULL)
  91. {
  92. /* Why did we get a NULL frame? We shouldn't be at the end. */
  93. fprintf(stderr, "Error: Hmm. The end came sooner than we thought.\n");
  94. return -1;
  95. }
  96.  
  97. /* Allocate necessary storage for skin detection. */
  98. allocateOnDemand(&temp_image, frame_size, IPL_DEPTH_8U, 3);
  99.  
  100. /* We'll make a full color backup of this frame so that we can draw on it.
  101. * (It's not the best idea to draw on the static memory space of cvQueryFrame().)
  102. */
  103. allocateOnDemand(&frame1, frame_size, IPL_DEPTH_8U, 3);
  104. cvConvertImage(frame, frame1);
  105.  
  106. /* Allocate another image if not already allocated.
  107. * Image has ONE challenge of color (ie: monochrome) with 8-bit "color" depth.
  108. * This is the image format OpenCV algorithms actually operate on (mostly).
  109. */
  110. allocateOnDemand(&frame1_1C, frame_size, IPL_DEPTH_8U, 1);
  111.  
  112. cvCvtColor(frame, temp_image, CV_BGR2HSV);
  113. cvInRangeS(temp_image, hsv_min, hsv_max, frame1_1C);
  114. cvSet(temp_image, cvScalar(0, 0, 0, 0));
  115. cvCopy(frame, temp_image, frame1_1C);
  116. cvConvertImage(temp_image, frame1_1C);
  117.  
  118. /* Convert whatever the AVI image format is into OpenCV's preferred format.
  119. * AND flip the image vertically. Flip is a shameless hack. OpenCV reads
  120. * in AVIs upside-down by default. (No comment :-))
  121. */
  122. // cvConvertImage(frame, frame1_1C);
  123.  
  124. /* Get the second frame of video. Sample principles as the first. */
  125. frame = cvQueryFrame(input_video);
  126. if (frame == NULL)
  127. {
  128. fprintf(stderr, "Error: Hmm. The end came sooner than we thought.\n");
  129. return -1;
  130. }
  131.  
  132. allocateOnDemand(&frame2_1C, frame_size, IPL_DEPTH_8U, 1);
  133.  
  134. cvCvtColor(frame, temp_image, CV_BGR2HSV);
  135. cvInRangeS(temp_image, hsv_min, hsv_max, frame2_1C);
  136. cvSet(temp_image, cvScalar(0, 0, 0, 0));
  137. cvCopy(frame, temp_image, frame2_1C);
  138. cvConvertImage(temp_image, frame2_1C);
  139.  
  140. // cvConvertImage(frame, frame2_1C);
  141.  
  142. /* Shi and Tomasi Feature Tracking! */
  143. /* Preparation: Allocate the necessary storage. */
  144. allocateOnDemand(&eig_image, frame_size, IPL_DEPTH_32F, 3);
  145. allocateOnDemand(&temp_image, frame_size, IPL_DEPTH_32F, 3);
  146.  
  147. /* Preparation: This array will contain the features found in frame 1. */
  148. CvPoint2D32f frame1_features[NO_FEATURES];
  149.  
  150. /* Preparation: BEFORE the function call this variable is the array size
  151. * (or the maximum number of features to find). AFTER the function call
  152. * this variable is the number of features actually found.
  153. */
  154. int number_of_features;
  155.  
  156. /* I'm hardcoding this at NO_FEATURES. But you should make this a #define so that you can
  157. * change the number of features you use for an accuracy/speed tradeoff analysis.
  158. */
  159. number_of_features = NO_FEATURES;
  160.  
  161. /* Actually run the Shi and Tomasi algorithm!!
  162. * "frame1_1C" is the input image.
  163. * "eig_image" and "temp_image" are just workspace for the algorithm.
  164. * The first ".01" specifies the minimum quality of the features (based on the eigenvalues).
  165. * The second ".01" specifies the minimum Euclidean distance between features.
  166. * "NULL" means use the entire input image. You could point to a part of the image.
  167. * WHEN THE ALGORITHM RETURNS:
  168. * "frame1_features" will contain the feature points.
  169. * "number_of_features" will be set to a value <= NO_FEATURES indicating the number of feature points found.
  170. */
  171. cvGoodFeaturesToTrack(frame1_1C, eig_image, temp_image, frame1_features, &number_of_features, .05, .001, NULL);
  172.  
  173. /* Pyramidal Lucas Kanade Optical Flow! */
  174. /* This array will contain the locations of the points from frame 1 in frame 2. */
  175. CvPoint2D32f frame2_features[NO_FEATURES];
  176.  
  177. /* The i-th element of this array will be non-zero if and only if the i-th feature of
  178. * frame 1 was found in frame 2.
  179. */
  180. char optical_flow_found_feature[NO_FEATURES];
  181.  
  182. /* The i-th element of this array is the error in the optical flow for the i-th feature
  183. * of frame1 as found in frame 2. If the i-th feature was not found (see the array above)
  184. * I think the i-th entry in this array is undefined.
  185. */
  186. float optical_flow_feature_error[NO_FEATURES];
  187.  
  188. /* This is the window size to use to avoid the aperture problem (see slide
  189. "Optical Flow: Overview"). */
  190. CvSize optical_flow_window = cvSize(3, 3);
  191.  
  192. /* This termination criteria tells the algorithm to stop when it has either done 20 iterations or when
  193. * epsilon is better than .3. You can play with these parameters for speed vs. accuracy but these values
  194. * work pretty well in many situations.
  195. */
  196. CvTermCriteria optical_flow_termination_criteria = cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .1);
  197.  
  198. /* This is some workspace for the algorithm.
  199. * (The algorithm actually carves the image into pyramids of different resolutions.)
  200. */
  201. allocateOnDemand(&pyramid1, frame_size, IPL_DEPTH_8U, 1);
  202. allocateOnDemand(&pyramid2, frame_size, IPL_DEPTH_8U, 1);
  203.  
  204. /* Actually run Pyramidal Lucas Kanade Optical Flow!!
  205. * "frame1_1C" is the first frame with the known features.
  206. * "frame2_1C" is the second frame where we want to find the first frame's features.
  207. * "pyramid1" and "pyramid2" are workspace for the algorithm.
  208. * "frame1_features" are the features from the first frame.
  209. * "frame2_features" is the (outputted) locations of those features in the second frame.
  210. * "number_of_features" is the number of features in the frame1_features array.
  211. * "optical_flow_window" is the size of the window to use to avoid the aperture problem.
  212. * "5" is the maximum number of pyramids to use. 0 would be just one level.
  213. * "optical_flow_found_feature" is as described above (non-zero iff feature found by the flow).
  214. * "optical_flow_feature_error" is as described above (error in the flow for this feature).
  215. * "optical_flow_termination_criteria" is as described above (how long the algorithm should look).
  216. * "0" means disable enhancements. (For example, the second aray isn't pre-initialized with guesses.)
  217. */
  218. cvCalcOpticalFlowPyrLK(frame1_1C, frame2_1C, pyramid1, pyramid2, frame1_features, frame2_features,
  219. number_of_features, optical_flow_window, 5, optical_flow_found_feature,
  220. optical_flow_feature_error, optical_flow_termination_criteria, 0);
  221.  
  222.  
  223. double xt = 0, yt = 0;
  224.  
  225. /* For fun (and debugging :)), let's draw the flow field. */
  226. for(int i = 0; i < number_of_features; i++)
  227. {
  228. /* If Pyramidal Lucas Kanade didn't really find the feature, skip it. */
  229. if (optical_flow_found_feature[i] == 0)
  230. continue;
  231.  
  232. CvPoint p,q;
  233. p.x = (int) frame1_features[i].x;
  234. p.y = (int) frame1_features[i].y;
  235. q.x = (int) frame2_features[i].x;
  236. q.y = (int) frame2_features[i].y;
  237.  
  238. double hypotenuse;
  239. hypotenuse = sqrt(square(p.y - q.y) + square(p.x - q.x));
  240.  
  241. if (hypotenuse < 10 || hypotenuse > 100)
  242. continue;
  243.  
  244. int line_thickness;
  245. line_thickness = 1;
  246.  
  247. cvCircle(frame1, p, 2, CV_RGB(0, 0, 255), line_thickness, CV_AA);
  248. cvCircle(frame1, q, 2, CV_RGB(0, 255, 0), line_thickness, CV_AA);
  249.  
  250. cvLine(frame1, p, q, CV_RGB(255, 0, 255), line_thickness, CV_AA);
  251.  
  252. xt += (p.x - q.x);
  253. yt += (p.y - q.y);
  254. }
  255.  
  256. CvPoint o, p;
  257. o.x = frame_size.width / 2;
  258. o.y = frame_size.height / 2;
  259. p.x = o.x + xt;
  260. p.y = o.y + yt;
  261.  
  262. double angle;
  263. double hypotenuse;
  264. angle = atan2(yt, xt);
  265. hypotenuse = sqrt(square(yt) + square(xt));
  266.  
  267. int line_thickness;
  268. line_thickness = 1;
  269.  
  270. /* Here we lengthen the arrow by a factor of three. */
  271. p.x = (int) (o.x - hypotenuse * cos(angle));
  272. p.y = (int) (o.y - hypotenuse * sin(angle));
  273.  
  274. /* Now we draw the main line of the arrow. */
  275. /* "frame1" is the frame to draw on.
  276. * "p" is the point where the line begins.
  277. * "q" is the point where the line stops.
  278. * "CV_AA" means antialiased drawing.
  279. * "0" means no fractional bits in the center cooridinate or radius.
  280. */
  281. cvLine(frame1, o, p, CV_RGB(255, 0, 0), line_thickness, CV_AA, 0);
  282.  
  283. /* Compute relevant direction. */
  284. xt = (abs(xt) > MIN_VECT_COMP) ? (50 * (xt > 0 ? -1 : 1)) : 0;
  285. yt = (abs(yt) > MIN_VECT_COMP) ? (50 * (yt > 0 ? -1 : 1)) : 0;
  286.  
  287. p.x = o.x + xt;
  288. p.y = o.y + yt;
  289.  
  290. line_thickness = 5;
  291.  
  292. cvLine(frame1, o, p, CV_RGB(255, 255, 0), line_thickness, CV_AA, 0);
  293.  
  294. /* Now draw the tips of the arrow. I do some scaling so that the
  295. * tips look proportional to the main line of the arrow.
  296. */
  297. o.x = (int) (p.x + 9 * cos(angle + pi / 4));
  298. o.y = (int) (p.y + 9 * sin(angle + pi / 4));
  299. cvLine(frame1, o, p, CV_RGB(255, 255, 0), line_thickness, CV_AA, 0);
  300.  
  301. o.x = (int) (p.x + 9 * cos(angle - pi / 4));
  302. o.y = (int) (p.y + 9 * sin(angle - pi / 4));
  303. cvLine(frame1, o, p, CV_RGB(255, 255, 0), line_thickness, CV_AA, 0);
  304.  
  305. printf("%f %f %d\n", xt, yt, number_of_features);
  306.  
  307. /* Now display the image we drew on. Recall that "Optical Flow" is the name of
  308. * the window we created above.
  309. */
  310. cvShowImage("Optical Flow", frame1);
  311. cvShowImage("N", frame1_1C);
  312. cvShowImage("N+1", frame2_1C);
  313.  
  314. /* And wait for the user to press a key (so the user has time to look at the image).
  315. * If the argument is 0 then it waits forever otherwise it waits that number of milliseconds.
  316. * The return value is the key the user pressed.
  317. */
  318. key_pressed = cvWaitKey(10);
  319. }
  320. }
Advertisement
Add Comment
Please, Sign In to add comment