--- /dev/null
+#! /usr/bin/env octave
+
+printf("OpenCV Octave version of lkdemo\n");
+
+## import the necessary things for OpenCV
+cv;
+highgui;
+
+#############################################################################
+## some "constants"
+
+win_size = 10;
+MAX_COUNT = 500;
+
+#############################################################################
+## some "global" variables
+
+global g;
+
+g.image = [];
+g.pt = [];
+g.add_remove_pt = false;
+g.flags = 0;
+g.night_mode = false;
+g.need_to_init = true;
+
+g
+
+#############################################################################
+## the mouse callback
+
+## the callback on the trackbar
+function on_mouse (event, x, y, flags, param)
+ global g;
+ global cv;
+ global highgui;
+
+ if (swig_this(g.image) == 0)
+ ## not initialized, so skip
+ return;
+ endif
+
+ if (g.image.origin != 0)
+ ## different origin
+ y = g.image.height - y;
+ endif
+
+ if (event == highgui.CV_EVENT_LBUTTONDOWN)
+ ## user has click, so memorize it
+ pt = cv.cvPoint (x, y);
+ g.add_remove_pt = true;
+ endif
+endfunction
+
+#############################################################################
+## so, here is the main part of the program
+
+
+filename = "/home/x/work/sneaker/dvgrab-001.avi";
+if (size(argv, 1)>1)
+ filename=argv(){1};
+endif
+
+capture = highgui.cvCreateFileCapture (filename);
+
+## check that capture device is OK
+if (!swig_this(capture))
+ printf("Error opening capture device\n");
+ exit(1)
+endif
+
+## display a small howto use it
+printf("Hot keys: \n");
+printf("\tESC - quit the program\n");
+printf("\tr - auto-initialize tracking\n");
+printf("\tc - delete all the points\n");
+printf("\tn - switch the \"night\" mode on/off\n");
+printf("To add/remove a feature point click it\n");
+
+## first, create the necessary windows
+highgui.cvNamedWindow ('LkDemo', 1);
+
+## register the mouse callback
+highgui.cvSetMouseCallback ('LkDemo', @on_mouse, []);
+
+while (1)
+ ## do forever
+
+ ## 1. capture the current image
+ frame = highgui.cvQueryFrame (capture);
+ if (swig_this(frame) == 0)
+ ## no image captured... end the processing
+ break
+ endif
+
+ if (swig_this(g.image) == 0),
+ ## create the images we need
+ g.image = cv.cvCreateImage (cv.cvGetSize (frame), 8, 3);
+# g.image.origin = frame.origin;
+ g.grey = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1);
+ g.prev_grey = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1);
+ g.pyramid = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1);
+ g.prev_pyramid = cv.cvCreateImage (cv.cvGetSize (frame), 8, 1);
+ g.points = {[], []};
+ endif
+
+ ## copy the frame, so we can draw on it
+ cv.cvCopy (frame, g.image)
+
+ ## create a grey version of the image
+ cv.cvCvtColor (g.image, g.grey, cv.CV_BGR2GRAY)
+
+ if (g.night_mode)
+ ## night mode: only display the points
+ cv.cvSetZero (g.image);
+ endif
+
+ if (g.need_to_init)
+ ## we want to search all the good points
+
+ ## create the wanted images
+ eig = cv.cvCreateImage (cv.cvGetSize (g.grey), 32, 1);
+ temp = cv.cvCreateImage (cv.cvGetSize (g.grey), 32, 1);
+
+ ## the default parameters
+ quality = 0.01;
+ min_distance = 10;
+
+ ## search the good points
+ g.points {1} = cv.cvGoodFeaturesToTrack (g.grey, eig, temp,MAX_COUNT,quality, min_distance, [], 3, 0, 0.04);
+
+ ## refine the corner locations
+ cv.cvFindCornerSubPix (g.grey,g.points {1},cv.cvSize (win_size, win_size), cv.cvSize (-1, -1),cv.cvTermCriteria (cv.CV_TERMCRIT_ITER | cv.CV_TERMCRIT_EPS,20, 0.03));
+
+ elseif (size (g.points {1}, 2) > 0)
+ ## we have points, so display them
+
+ ## calculate the optical flow
+ [tmp, status] = cv.cvCalcOpticalFlowPyrLK (g.prev_grey, g.grey, g.prev_pyramid, g.pyramid,g.points {1}, size (g.points {1},2),cv.cvSize (win_size, win_size), 3,size (g.points {1}, 2),[],cv.cvTermCriteria (bitor(cv.CV_TERMCRIT_ITER,cv.CV_TERMCRIT_EPS),20, 0.03),g.flags);
+ g.points {2} = tmp;
+
+ ## initializations
+ point_counter = -1;
+ new_points = {};
+
+ for the_point = g.points {2},
+ the_point = the_point{1};
+ ## go trough all the points
+
+ ## increment the counter
+ point_counter += 1;
+
+ if (g.add_remove_pt)
+ ## we have a point to add, so see if it is close to
+ ## another one. If yes, don't use it
+ dx = pt.x - the_point.x;
+ dy = pt.y - the_point.y;
+ if (dx * dx + dy * dy <= 25)
+ ## too close
+ g.add_remove_pt = 0;
+ continue;
+ endif
+ endif
+
+ if (!status {point_counter+1})
+ ## we will disable this point
+ continue;
+ endif
+
+ ## this point is a correct point
+ new_points{end+1} = the_point;
+
+ ## draw the current point
+ cv.cvCircle (g.image, {the_point.x, the_point.y},3, cv.cvScalar (0, 255, 0, 0),-1, 8, 0);
+ endfor
+
+ ## set back the points we keep;
+ points {1} = new_points;
+ endif
+
+ if (g.add_remove_pt)
+ ## we want to add a point
+ points {1} = append (points {1}, cv.cvPointTo32f (pt));
+
+ ## refine the corner locations
+ g.points {1} = cv.cvFindCornerSubPix \
+ (g.grey, {points {1}}, cv.cvSize (win_size, win_size), cv.cvSize \
+ (-1, -1), cv.cvTermCriteria (bitor(cv.CV_TERMCRIT_ITER, cv.CV_TERMCRIT_EPS),20, 0.03));
+
+ ## we are no more in "add_remove_pt" mode
+ g.add_remove_pt = false
+ endif
+
+ ## swapping
+ tmp = g.prev_grey; g.prev_grey = g.grey; g.grey = tmp;
+ tmp = g.prev_pyramid; g.prev_pyramid = g.pyramid; g.pyramid = tmp;
+ tmp = g.points{1}; g.points{1} = g.points{2}; g.points{2} = tmp;
+ g.need_to_init = false;
+
+ ## we can now display the image
+ highgui.cvShowImage ('LkDemo', g.image)
+
+ ## handle events
+ c = highgui.cvWaitKey (10);
+
+ if (c == 27)
+ ## user has press the ESC key, so exit
+ break
+ endif
+
+ ## processing depending on the character
+ if (c == int32('r'))
+ g.need_to_init = true;
+ elseif (c == int32('c'))
+ g.points = {[], []};
+ elseif (c == int32('n'))
+ g.night_mode = !g.night_mode;
+ endif
+endwhile