aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rwxr-xr-xpix_opencv_lk-help.pd162
-rwxr-xr-xpix_opencv_lk.cc654
-rwxr-xr-xpix_opencv_lk.h116
4 files changed, 933 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 926369e..9b88ef7 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ endif
.SUFFIXES = $(EXTENSION)
-SOURCES = pix_opencv_edge.cc pix_opencv_laplace.cc pix_opencv_morphology.cc pix_opencv_distrans.cc pix_opencv_motempl.cc pix_opencv_haarcascade.cc pix_opencv_contours_boundingrect.cc pix_opencv_bgsubstract.cc pix_opencv_contours_convexity.cc pix_opencv_dft.cc
+SOURCES = pix_opencv_edge.cc pix_opencv_laplace.cc pix_opencv_morphology.cc pix_opencv_distrans.cc pix_opencv_motempl.cc pix_opencv_haarcascade.cc pix_opencv_contours_boundingrect.cc pix_opencv_bgsubstract.cc pix_opencv_contours_convexity.cc pix_opencv_dft.cc pix_opencv_lk.cc
all: $(SOURCES:.cc=.$(EXTENSION))
diff --git a/pix_opencv_lk-help.pd b/pix_opencv_lk-help.pd
new file mode 100755
index 0000000..4b67d7c
--- /dev/null
+++ b/pix_opencv_lk-help.pd
@@ -0,0 +1,162 @@
+#N canvas 288 90 1192 685 10;
+#X obj 396 -37 gemhead;
+#X obj 212 501 pix_texture;
+#X obj 212 529 square 2;
+#X obj 28 132 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577
+0;
+#N canvas 0 22 454 304 gemwin 0;
+#X obj 132 136 gemwin;
+#X obj 67 89 outlet;
+#X obj 67 10 inlet;
+#X obj 67 41 route create;
+#X msg 67 70 set destroy;
+#X msg 182 68 set create;
+#X msg 132 112 create \, 1;
+#X msg 238 112 destroy;
+#N canvas 87 154 247 179 Gem.init 0;
+#X obj 118 46 loadbang;
+#X msg 118 81 reset;
+#X obj 118 113 outlet;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X restore 289 80 pd Gem.init;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 3 0 6 0;
+#X connect 3 1 5 0;
+#X connect 3 1 7 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X restore 35 178 pd gemwin;
+#X msg 35 154 create;
+#X text 36 136 Create window and render;
+#X obj 213 404 pix_texture;
+#X obj 213 432 square 2;
+#X obj 325 71 translateXYZ -2 0 0;
+#X obj 326 100 separator;
+#X obj 340 179 cnv 15 600 400 empty empty empty 20 12 0 14 -24198 -66577
+0;
+#X obj 511 -66 bng 25 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 524 128 unpack 0 0 0;
+#X floatatom 514 151 5 0 0 3 length - -;
+#X floatatom 563 151 5 0 0 3 width - -;
+#X floatatom 613 151 5 0 0 3 height - -;
+#X obj 568 109 bng 15 250 50 0 empty empty end_reached 20 7 0 10 -262144
+-1 -1;
+#X floatatom 550 74 5 0 10000 1 frame# - -;
+#X obj 511 -37 openpanel;
+#X msg 511 -17 open \$1;
+#X obj 499 92 pix_film;
+#X msg 517 26 auto \$1;
+#X obj 517 8 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 326 126 translateXYZ 4 0 0;
+#X obj 580 26 loadbang;
+#X msg 528 50 colorspace RGBA;
+#X floatatom 488 416 5 0 0 0 - - -;
+#X text 523 415 window size;
+#X obj 553 262 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X msg 468 260 nightmode \$1;
+#X text 572 263 set nightmode;
+#X msg 463 234 quality \$1;
+#X floatatom 538 235 5 0 0 0 - - -;
+#X floatatom 546 210 5 0 0 0 - - -;
+#X msg 449 209 mindistance \$1;
+#X text 587 208 set distance ( default 10 );
+#X msg 442 181 init;
+#X text 511 181 init point detections;
+#X floatatom 631 235 5 0 0 0 - - -;
+#X obj 576 233 / 1000;
+#X msg 481 285 mark \$1 \$2;
+#X msg 492 311 delete \$1;
+#X text 563 311 delete a marker;
+#X msg 503 337 clear;
+#X text 551 338 delete all markers;
+#X msg 510 364 maxmove \$1;
+#X text 624 364 max movement of a marker ( default 5 pisels );
+#X floatatom 586 366 5 0 0 0 - - -;
+#X text 763 234 set quality ( default 100 );
+#X msg 671 233 100;
+#X obj 704 233 loadbang;
+#X obj 480 504 unpack f f;
+#X floatatom 481 529 5 0 0 0 - - -;
+#X floatatom 539 530 5 0 0 0 - - -;
+#X text 482 545 X;
+#X text 537 546 Y;
+#X obj 479 478 route 1 2 3 4 5 6 7 8 9 10;
+#X text 651 479 position of each marked point;
+#X obj 377 428 pix_opencv_lk;
+#X text 23 21 written by Lluis Gomez i Bigorda ( lluisgomez@hangar.org
+) and Yves Degoyon ( ydegoyon@gmail.com );
+#X text 23 9 pix_opencv_lk : contour most significant points detection
+;
+#X obj 952 123 gemmouse;
+#X obj 1008 230 f;
+#X obj 978 229 f;
+#X obj 1022 201 t b b;
+#X obj 978 257 pack f f;
+#X text 560 286 mark x y : mark a point to track ( max points : 10
+);
+#X obj 998 151 route 1;
+#X msg 1019 176 bang;
+#X connect 0 0 21 0;
+#X connect 1 0 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 4 0;
+#X connect 7 0 8 0;
+#X connect 9 0 7 0;
+#X connect 9 0 10 0;
+#X connect 10 0 24 0;
+#X connect 12 0 19 0;
+#X connect 13 0 14 0;
+#X connect 13 1 15 0;
+#X connect 13 2 16 0;
+#X connect 17 0 18 0;
+#X connect 18 0 21 1;
+#X connect 19 0 20 0;
+#X connect 20 0 21 0;
+#X connect 21 0 9 0;
+#X connect 21 1 13 0;
+#X connect 21 2 17 0;
+#X connect 22 0 21 0;
+#X connect 23 0 22 0;
+#X connect 24 0 59 0;
+#X connect 25 0 26 0;
+#X connect 26 0 21 0;
+#X connect 27 0 59 1;
+#X connect 29 0 30 0;
+#X connect 30 0 59 0;
+#X connect 32 0 59 0;
+#X connect 33 0 32 0;
+#X connect 34 0 35 0;
+#X connect 35 0 59 0;
+#X connect 37 0 59 0;
+#X connect 39 0 40 0;
+#X connect 40 0 33 0;
+#X connect 41 0 59 0;
+#X connect 42 0 59 0;
+#X connect 44 0 59 0;
+#X connect 46 0 59 0;
+#X connect 48 0 46 0;
+#X connect 50 0 39 0;
+#X connect 51 0 50 0;
+#X connect 52 0 53 0;
+#X connect 52 1 54 0;
+#X connect 57 0 52 0;
+#X connect 59 0 1 0;
+#X connect 59 1 57 0;
+#X connect 62 0 64 1;
+#X connect 62 1 63 1;
+#X connect 62 2 68 0;
+#X connect 63 0 66 1;
+#X connect 64 0 66 0;
+#X connect 65 0 64 0;
+#X connect 65 1 63 0;
+#X connect 66 0 41 0;
+#X connect 68 0 69 0;
+#X connect 69 0 65 0;
diff --git a/pix_opencv_lk.cc b/pix_opencv_lk.cc
new file mode 100755
index 0000000..a4a7acb
--- /dev/null
+++ b/pix_opencv_lk.cc
@@ -0,0 +1,654 @@
+////////////////////////////////////////////////////////
+//
+// GEM - Graphics Environment for Multimedia
+//
+// zmoelnig@iem.kug.ac.at
+//
+// Implementation file
+//
+// Copyright (c) 1997-2000 Mark Danks.
+// Copyright (c) Günther Geiger.
+// Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM
+// Copyright (c) 2002 James Tittle & Chris Clepper
+// For information on usage and redistribution, and for a DISCLAIMER OF ALL
+// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
+//
+/////////////////////////////////////////////////////////
+
+#include "pix_opencv_lk.h"
+#include <stdio.h>
+
+CPPEXTERN_NEW(pix_opencv_lk)
+
+/////////////////////////////////////////////////////////
+//
+// pix_opencv_lk
+//
+/////////////////////////////////////////////////////////
+// Constructor
+//
+/////////////////////////////////////////////////////////
+
+pix_opencv_lk :: pix_opencv_lk()
+{
+ int i;
+
+ comp_xsize=0;
+ comp_ysize=0;
+
+ inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("winsize"));
+
+ m_dataout = outlet_new(this->x_obj, &s_anything);
+ win_size = 10;
+
+ points[0] = 0;
+ points[1] = 0;
+ status = 0;
+ count = 0;
+ need_to_init = 1;
+ night_mode = 0;
+ flags = 0;
+ add_remove_pt = 0;
+ quality = 0.1;
+ min_distance = 10;
+ maxmove = 8;
+
+ for ( i=0; i<MAX_MARKERS; i++ )
+ {
+ x_xmark[i] = -1;
+ x_ymark[i] = -1;
+ }
+
+ // initialize font
+ cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 1.0, 1.0, 0, 1, 8 );
+
+ rgba = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 4 );
+ rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 );
+ grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ status = (char*)cvAlloc(MAX_COUNT);
+
+}
+
+/////////////////////////////////////////////////////////
+// Destructor
+//
+/////////////////////////////////////////////////////////
+pix_opencv_lk :: ~pix_opencv_lk()
+{
+ // Destroy cv_images
+ cvReleaseImage( &rgba );
+ cvReleaseImage( &rgb );
+ cvReleaseImage( &grey );
+ cvReleaseImage( &prev_grey );
+ cvReleaseImage( &pyramid );
+ cvReleaseImage( &prev_pyramid );
+}
+
+/////////////////////////////////////////////////////////
+// processImage
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_lk :: processRGBAImage(imageStruct &image)
+{
+ int i, k;
+ int im;
+
+ if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize))
+ {
+
+ this->comp_xsize=image.xsize;
+ this->comp_ysize=image.ysize;
+
+ rgba = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 4 );
+ rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 );
+ grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ status = (char*)cvAlloc(MAX_COUNT);
+
+ }
+
+ memcpy( rgba->imageData, image.data, image.xsize*image.ysize*4 );
+ cvCvtColor(rgba, grey, CV_BGRA2GRAY);
+
+ if( night_mode )
+ cvZero( rgba );
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ x_found[im] = 0;
+ }
+
+ if( need_to_init )
+ {
+ /* automatic initialization */
+ IplImage* eig = cvCreateImage( cvSize(grey->width,grey->height), 32, 1 );
+ IplImage* temp = cvCreateImage( cvSize(grey->width,grey->height), 32, 1 );
+
+ count = MAX_COUNT;
+ cvGoodFeaturesToTrack( grey, eig, temp, points[1], &count,
+ quality, min_distance, 0, 3, 0, 0.04 );
+ cvFindCornerSubPix( grey, points[1], count,
+ cvSize(win_size,win_size), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
+ cvReleaseImage( &eig );
+ cvReleaseImage( &temp );
+
+ add_remove_pt = 0;
+ }
+ else if( count > 0 )
+ {
+ cvCalcOpticalFlowPyrLK( prev_grey, grey, prev_pyramid, pyramid,
+ points[0], points[1], count, cvSize(win_size,win_size), 3, status, 0,
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03), flags );
+ flags |= CV_LKFLOW_PYR_A_READY;
+ for( i = k = 0; i < count; i++ )
+ {
+ if( add_remove_pt )
+ {
+ double dx = pt.x - points[1][i].x;
+ double dy = pt.y - points[1][i].y;
+
+ if( dx*dx + dy*dy <= 25 )
+ {
+ add_remove_pt = 0;
+ continue;
+ }
+ }
+
+ if( !status[i] )
+ continue;
+
+ points[1][k++] = points[1][i];
+ cvCircle( rgba, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // first marking
+ if ( x_xmark[im] != -1.0 )
+ {
+ if ( ( abs( points[1][i].x - x_xmark[im] ) <= maxmove ) && ( abs( points[1][i].y - x_ymark[im] ) <= maxmove ) )
+ {
+ char tindex[4];
+ sprintf( tindex, "%d", im+1 );
+ cvPutText( rgba, tindex, cvPointFrom32f(points[1][i]), &font, CV_RGB(255,255,255));
+ x_xmark[im]=points[1][i].x;
+ x_ymark[im]=points[1][i].y;
+ x_found[im]=1;
+ SETFLOAT(&x_list[0], im+1);
+ SETFLOAT(&x_list[1], x_xmark[im]);
+ SETFLOAT(&x_list[2], x_ymark[im]);
+ outlet_list( m_dataout, 0, 3, x_list );
+ }
+ }
+ }
+ }
+ count = k;
+ }
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( (x_xmark[im] != -1.0 ) && !x_found[im] )
+ {
+ x_xmark[im]=-1.0;
+ x_ymark[im]=-1.0;
+ SETFLOAT(&x_list[0], im+1);
+ SETFLOAT(&x_list[1], x_xmark[im]);
+ SETFLOAT(&x_list[2], x_ymark[im]);
+ // send a lost point message to the patch
+ outlet_list( m_dataout, 0, 3, x_list );
+ post( "pix_opencv_lk : lost point %d", im+1 );
+ }
+ }
+
+ if( add_remove_pt && count < MAX_COUNT )
+ {
+ points[1][count++] = cvPointTo32f(pt);
+ cvFindCornerSubPix( grey, points[1] + count - 1, 1,
+ cvSize(win_size,win_size), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
+ add_remove_pt = 0;
+ }
+
+ CV_SWAP( prev_grey, grey, swap_temp );
+ CV_SWAP( prev_pyramid, pyramid, swap_temp );
+ CV_SWAP( points[0], points[1], swap_points );
+ need_to_init = 0;
+
+ memcpy( image.data, rgba->imageData, image.xsize*image.ysize*4 );
+}
+
+void pix_opencv_lk :: processRGBImage(imageStruct &image)
+{
+ int i, k;
+ int im;
+
+ if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize))
+ {
+
+ this->comp_xsize=image.xsize;
+ this->comp_ysize=image.ysize;
+
+ rgba = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 4 );
+ rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 );
+ grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ status = (char*)cvAlloc(MAX_COUNT);
+
+ }
+
+ memcpy( rgb->imageData, image.data, image.xsize*image.ysize*3 );
+ cvCvtColor(rgb, grey, CV_BGRA2GRAY);
+
+ if( night_mode )
+ cvZero( rgb );
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ x_found[im] = 0;
+ }
+
+ if( need_to_init )
+ {
+ /* automatic initialization */
+ IplImage* eig = cvCreateImage( cvSize(grey->width,grey->height), 32, 1 );
+ IplImage* temp = cvCreateImage( cvSize(grey->width,grey->height), 32, 1 );
+
+ count = MAX_COUNT;
+ cvGoodFeaturesToTrack( grey, eig, temp, points[1], &count,
+ quality, min_distance, 0, 3, 0, 0.04 );
+ cvFindCornerSubPix( grey, points[1], count,
+ cvSize(win_size,win_size), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
+ cvReleaseImage( &eig );
+ cvReleaseImage( &temp );
+
+ add_remove_pt = 0;
+ }
+ else if( count > 0 )
+ {
+ cvCalcOpticalFlowPyrLK( prev_grey, grey, prev_pyramid, pyramid,
+ points[0], points[1], count, cvSize(win_size,win_size), 3, status, 0,
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03), flags );
+ flags |= CV_LKFLOW_PYR_A_READY;
+ for( i = k = 0; i < count; i++ )
+ {
+ if( add_remove_pt )
+ {
+ double dx = pt.x - points[1][i].x;
+ double dy = pt.y - points[1][i].y;
+
+ if( dx*dx + dy*dy <= 25 )
+ {
+ add_remove_pt = 0;
+ continue;
+ }
+ }
+
+ if( !status[i] )
+ continue;
+
+ points[1][k++] = points[1][i];
+ cvCircle( rgb, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // first marking
+ if ( x_xmark[im] != -1.0 )
+ {
+ if ( ( abs( points[1][i].x - x_xmark[im] ) <= maxmove ) && ( abs( points[1][i].y - x_ymark[im] ) <= maxmove ) )
+ {
+ char tindex[4];
+ sprintf( tindex, "%d", im+1 );
+ cvPutText( rgb, tindex, cvPointFrom32f(points[1][i]), &font, CV_RGB(255,255,255));
+ x_xmark[im]=points[1][i].x;
+ x_ymark[im]=points[1][i].y;
+ x_found[im]=1;
+ SETFLOAT(&x_list[0], im+1);
+ SETFLOAT(&x_list[1], x_xmark[im]);
+ SETFLOAT(&x_list[2], x_ymark[im]);
+ outlet_list( m_dataout, 0, 3, x_list );
+ }
+ }
+ }
+ }
+ count = k;
+ }
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( (x_xmark[im] != -1.0 ) && !x_found[im] )
+ {
+ x_xmark[im]=-1.0;
+ x_ymark[im]=-1.0;
+ SETFLOAT(&x_list[0], im+1);
+ SETFLOAT(&x_list[1], x_xmark[im]);
+ SETFLOAT(&x_list[2], x_ymark[im]);
+ // send a lost point message to the patch
+ outlet_list( m_dataout, 0, 3, x_list );
+ post( "pix_opencv_lk : lost point %d", im+1 );
+ }
+ }
+
+ if( add_remove_pt && count < MAX_COUNT )
+ {
+ points[1][count++] = cvPointTo32f(pt);
+ cvFindCornerSubPix( grey, points[1] + count - 1, 1,
+ cvSize(win_size,win_size), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
+ add_remove_pt = 0;
+ }
+
+ CV_SWAP( prev_grey, grey, swap_temp );
+ CV_SWAP( prev_pyramid, pyramid, swap_temp );
+ CV_SWAP( points[0], points[1], swap_points );
+ need_to_init = 0;
+
+ memcpy( image.data, rgb->imageData, image.xsize*image.ysize*3 );
+}
+
+void pix_opencv_lk :: processYUVImage(imageStruct &image)
+{
+}
+
+void pix_opencv_lk :: processGrayImage(imageStruct &image)
+{
+ int i, k;
+ int im;
+
+ if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize))
+ {
+
+ this->comp_xsize=image.xsize;
+ this->comp_ysize=image.ysize;
+
+ rgba = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 4 );
+ rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 );
+ grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_grey = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ prev_pyramid = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 );
+ points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
+ status = (char*)cvAlloc(MAX_COUNT);
+
+ }
+
+ memcpy( grey->imageData, image.data, image.xsize*image.ysize );
+
+ if( night_mode )
+ cvZero( grey );
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ x_found[im] = 0;
+ }
+
+ if( need_to_init )
+ {
+ /* automatic initialization */
+ IplImage* eig = cvCreateImage( cvSize(grey->width,grey->height), 32, 1 );
+ IplImage* temp = cvCreateImage( cvSize(grey->width,grey->height), 32, 1 );
+
+ count = MAX_COUNT;
+ cvGoodFeaturesToTrack( grey, eig, temp, points[1], &count,
+ quality, min_distance, 0, 3, 0, 0.04 );
+ cvFindCornerSubPix( grey, points[1], count,
+ cvSize(win_size,win_size), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
+ cvReleaseImage( &eig );
+ cvReleaseImage( &temp );
+
+ add_remove_pt = 0;
+ }
+ else if( count > 0 )
+ {
+ cvCalcOpticalFlowPyrLK( prev_grey, grey, prev_pyramid, pyramid,
+ points[0], points[1], count, cvSize(win_size,win_size), 3, status, 0,
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03), flags );
+ flags |= CV_LKFLOW_PYR_A_READY;
+ for( i = k = 0; i < count; i++ )
+ {
+ if( add_remove_pt )
+ {
+ double dx = pt.x - points[1][i].x;
+ double dy = pt.y - points[1][i].y;
+
+ if( dx*dx + dy*dy <= 25 )
+ {
+ add_remove_pt = 0;
+ continue;
+ }
+ }
+
+ if( !status[i] )
+ continue;
+
+ points[1][k++] = points[1][i];
+ cvCircle( grey, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // first marking
+ if ( x_xmark[im] != -1.0 )
+ {
+ if ( ( abs( points[1][i].x - x_xmark[im] ) <= maxmove ) && ( abs( points[1][i].y - x_ymark[im] ) <= maxmove ) )
+ {
+ char tindex[4];
+ sprintf( tindex, "%d", im+1 );
+ cvPutText( grey, tindex, cvPointFrom32f(points[1][i]), &font, CV_RGB(255,255,255));
+ x_xmark[im]=points[1][i].x;
+ x_ymark[im]=points[1][i].y;
+ x_found[im]=1;
+ SETFLOAT(&x_list[0], im+1);
+ SETFLOAT(&x_list[1], x_xmark[im]);
+ SETFLOAT(&x_list[2], x_ymark[im]);
+ outlet_list( m_dataout, 0, 3, x_list );
+ }
+ }
+ }
+ }
+ count = k;
+ }
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( (x_xmark[im] != -1.0 ) && !x_found[im] )
+ {
+ x_xmark[im]=-1.0;
+ x_ymark[im]=-1.0;
+ SETFLOAT(&x_list[0], im+1);
+ SETFLOAT(&x_list[1], x_xmark[im]);
+ SETFLOAT(&x_list[2], x_ymark[im]);
+ // send a lost point message to the patch
+ outlet_list( m_dataout, 0, 3, x_list );
+ post( "pix_opencv_lk : lost point %d", im+1 );
+ }
+ }
+
+ if( add_remove_pt && count < MAX_COUNT )
+ {
+ points[1][count++] = cvPointTo32f(pt);
+ cvFindCornerSubPix( grey, points[1] + count - 1, 1,
+ cvSize(win_size,win_size), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
+ add_remove_pt = 0;
+ }
+
+ CV_SWAP( prev_grey, grey, swap_temp );
+ CV_SWAP( prev_pyramid, pyramid, swap_temp );
+ CV_SWAP( points[0], points[1], swap_points );
+ need_to_init = 0;
+
+ memcpy( image.data, grey->imageData, image.xsize*image.ysize );
+}
+
+/////////////////////////////////////////////////////////
+// static member function
+//
+/////////////////////////////////////////////////////////
+
+void pix_opencv_lk :: obj_setupCallback(t_class *classPtr)
+{
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::winSizeMessCallback,
+ gensym("winsize"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::nightModeMessCallback,
+ gensym("nightmode"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::qualityMessCallback,
+ gensym("quality"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::initMessCallback,
+ gensym("init"), A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::markMessCallback,
+ gensym("mark"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::deleteMessCallback,
+ gensym("delete"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::clearMessCallback,
+ gensym("clear"), A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::minDistanceMessCallback,
+ gensym("mindistance"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::maxMoveMessCallback,
+ gensym("maxmove"), A_FLOAT, A_NULL);
+}
+
+void pix_opencv_lk :: winSizeMessCallback(void *data, t_floatarg winsize)
+{
+ GetMyClass(data)->winSizeMess((float)winsize);
+}
+
+void pix_opencv_lk :: nightModeMessCallback(void *data, t_floatarg nightmode)
+{
+ GetMyClass(data)->nightModeMess((float)nightmode);
+}
+
+void pix_opencv_lk :: qualityMessCallback(void *data, t_floatarg quality)
+{
+ GetMyClass(data)->qualityMess((float)quality);
+}
+
+void pix_opencv_lk :: initMessCallback(void *data)
+{
+ GetMyClass(data)->initMess();
+}
+
+void pix_opencv_lk :: markMessCallback(void *data, t_floatarg mx, t_floatarg my)
+{
+ GetMyClass(data)->markMess((float)mx, (float)my);
+}
+
+void pix_opencv_lk :: deleteMessCallback(void *data, t_floatarg index)
+{
+ GetMyClass(data)->deleteMess((float)index);
+}
+
+void pix_opencv_lk :: clearMessCallback(void *data)
+{
+ GetMyClass(data)->clearMess();
+}
+
+void pix_opencv_lk :: minDistanceMessCallback(void *data, t_floatarg mindistance)
+{
+ GetMyClass(data)->minDistanceMess((float)mindistance);
+}
+
+void pix_opencv_lk :: maxMoveMessCallback(void *data, t_floatarg maxmove)
+{
+ GetMyClass(data)->maxMoveMess((float)maxmove);
+}
+
+void pix_opencv_lk :: winSizeMess(float winsize)
+{
+ if (winsize>1.0) win_size = (int)winsize;
+}
+
+void pix_opencv_lk :: nightModeMess(float nightmode)
+{
+ if ((nightmode==0.0)||(nightmode==1.0)) night_mode = (int)nightmode;
+}
+
+void pix_opencv_lk :: qualityMess(float quality)
+{
+ if (quality>0.0) quality = quality;
+}
+
+void pix_opencv_lk :: initMess(void)
+{
+ need_to_init = 1;
+}
+
+void pix_opencv_lk :: markMess(float mx, float my)
+{
+ int i;
+ int inserted;
+
+ if ( ( mx < 0.0 ) || ( mx >= comp_xsize ) || ( my < 0.0 ) || ( my >= comp_ysize ) )
+ {
+ return;
+ }
+
+ inserted = 0;
+ for ( i=0; i<MAX_MARKERS; i++)
+ {
+ if ( x_xmark[i] == -1 )
+ {
+ x_xmark[i] = (int)(mx);
+ x_ymark[i] = (int)(my);
+ post( "pix_opencv_lk : inserted point (%d,%d)", x_xmark[i], x_ymark[i] );
+ inserted = 1;
+ break;
+ }
+ }
+ if ( !inserted )
+ {
+ post( "pix_opencv_lk : max markers reached" );
+ }
+}
+
+void pix_opencv_lk :: deleteMess(float index)
+{
+ int i;
+
+ if ( ( index < 1.0 ) || ( index > MAX_MARKERS ) )
+ {
+ return;
+ }
+
+ x_xmark[(int)index-1] = -1;
+ x_ymark[(int)index-1] = -1;
+
+}
+
+void pix_opencv_lk :: clearMess(void)
+{
+ int i;
+
+ for ( i=0; i<MAX_MARKERS; i++)
+ {
+ x_xmark[i] = -1;
+ x_ymark[i] = -1;
+ }
+
+}
+
+void pix_opencv_lk :: minDistanceMess(float mindistance)
+{
+ if (mindistance>1.0) min_distance = (int)mindistance;
+}
+
+void pix_opencv_lk :: maxMoveMess(float maxmove)
+{
+ // has to be more than the size of a point
+ if (maxmove>=3.0) maxmove = (int)maxmove;
+}
+
diff --git a/pix_opencv_lk.h b/pix_opencv_lk.h
new file mode 100755
index 0000000..3f8c8f6
--- /dev/null
+++ b/pix_opencv_lk.h
@@ -0,0 +1,116 @@
+/*-----------------------------------------------------------------
+LOG
+ GEM - Graphics Environment for Multimedia
+
+ Change pix to greyscale
+
+ Copyright (c) 1997-1999 Mark Danks. mark@danks.org
+ Copyright (c) Günther Geiger. geiger@epy.co.at
+ Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM. zmoelnig@iem.kug.ac.at
+ Copyright (c) 2002 James Tittle & Chris Clepper
+ For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
+
+-----------------------------------------------------------------*/
+
+#ifndef INCLUDE_PIX_OPENCV_DISTRANS_H_
+#define INCLUDE_PIX_OPENCV_DISTRANS_H_
+
+#include "Base/GemPixObj.h"
+
+#ifndef _EiC
+#include "cv.h"
+#endif
+
+#define MAX_MARKERS 10
+const int MAX_COUNT = 500;
+
+/*-----------------------------------------------------------------
+-------------------------------------------------------------------
+CLASS
+ pix_opencv_lk
+
+ Change pix to greyscale
+
+KEYWORDS
+ pix
+
+DESCRIPTION
+
+-----------------------------------------------------------------*/
+class GEM_EXTERN pix_opencv_lk : public GemPixObj
+{
+ CPPEXTERN_HEADER(pix_opencv_lk, GemPixObj)
+
+ public:
+
+ //////////
+ // Constructor
+ pix_opencv_lk();
+
+ protected:
+
+ //////////
+ // Destructor
+ virtual ~pix_opencv_lk();
+
+ //////////
+ // Do the processing
+ virtual void processRGBAImage(imageStruct &image);
+ virtual void processRGBImage(imageStruct &image);
+ virtual void processYUVImage(imageStruct &image);
+ virtual void processGrayImage(imageStruct &image);
+
+ void winSizeMess(float winsize);
+ void nightModeMess(float nightmode);
+ void qualityMess(float quality);
+ void initMess(void);
+ void markMess(float mx, float my);
+ void deleteMess(float index);
+ void clearMess(void);
+ void minDistanceMess(float mindistance);
+ void maxMoveMess(float maxmove);
+
+ int comp_xsize;
+ int comp_ysize;
+
+ t_outlet *m_dataout;
+ t_atom x_list[3];
+ int win_size;
+ double quality;
+ int min_distance;
+ int night_mode;
+ int maxmove;
+
+ private:
+
+ //////////
+ // Static member functions
+ static void winSizeMessCallback(void *data, t_floatarg winsize);
+ static void nightModeMessCallback(void *data, t_floatarg nightmode);
+ static void qualityMessCallback(void *data, t_floatarg quality);
+ static void initMessCallback(void *data);
+ static void markMessCallback(void *data, t_floatarg mx, t_floatarg my);
+ static void deleteMessCallback(void *data, t_floatarg index);
+ static void clearMessCallback(void *data);
+ static void minDistanceMessCallback(void *data, t_floatarg mindistance);
+ static void maxMoveMessCallback(void *data, t_floatarg maxmove);
+
+ // Internal Open CV data
+ IplImage *rgba, *rgb, *grey, *prev_grey, *pyramid, *prev_pyramid, *swap_temp;
+ int x_xmark[MAX_MARKERS];
+ int x_ymark[MAX_MARKERS];
+ int x_found[MAX_MARKERS];
+ CvPoint2D32f* points[2], *swap_points;
+ char* status;
+ int count;
+ int need_to_init;
+ int flags;
+ int add_remove_pt;
+ CvPoint pt;
+ CvFont font;
+
+
+};
+
+#endif // for header file