aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <sevyves@users.sourceforge.net>2009-08-29 21:43:37 +0000
committerN.N. <sevyves@users.sourceforge.net>2009-08-29 21:43:37 +0000
commit5f48da1ffe239dc989c4561668c86a1852f7e0cf (patch)
tree53ba6ddb52ce93dbdf8cfd9a2a932d3330e3f85f
parent9ccaf6ebab9d445e5b8ed04f58956cacb7ac7467 (diff)
updated opencv_lk with delaunay
svn path=/trunk/externals/pix_opencv/; revision=12139
-rw-r--r--INSTALL33
-rwxr-xr-xpix_opencv_lk-help.pd93
-rwxr-xr-xpix_opencv_lk.cc487
-rwxr-xr-xpix_opencv_lk.h18
4 files changed, 551 insertions, 80 deletions
diff --git a/INSTALL b/INSTALL
index e747357..b2a498d 100644
--- a/INSTALL
+++ b/INSTALL
@@ -7,23 +7,25 @@ Download the package here : [[http://hangar.org/wikis/lab/pd/pdp_opencv-0.1a.tar
(actually only tested in GNU/Linux Ubuntu)
-unpack it ::
+first install opencv development packages,
+on ubuntu :
- tar xzvf pix_opencv-0.1a.tar.gz
+apt-get install libcv-dev
+apt-get install libcvaux-dev
+apt-get install libhighgui-dev
-cd into the library folder ::
+get the _SOURCES_ of the pd you are using
+and of the GEM that you are loading
+( it might not work if the version
+is different )
- cd pix_opencv
-
-or
+cd into the package folder ::
- cd pdp_opencv
+ cd pix_opencv
edit the Makefile to fit your system and sources folders:
-for pix_opencv edit the Makefile and change the values for PD_DIR and GEM_DIR variables
-
-for pdp_opencv edit the Makefile.config and change the values for OPENCV_CPPFLAGS, PD_CPPFLAGS, PDP_CFLAGS variables
+edit the Makefile and change the values for PD_DIR and GEM_DIR variables
then, compile it ::
@@ -38,20 +40,23 @@ and copy the .pd_linux to your externals folder ::
===== MAC OSX (intel and powerPC) =====
-(This is only for pix_opencv Actually there is no MACOSX makefile for pdp_opencv.)
-
first install openCV MacOS framework
download openCV private framework from http://www.ient.rwth-aachen.de/cms/software/opencv/
copy the provided OpenCV.framework folder in your /System/Library/Frameworks/ directory ::
cp -Rf /Volumes/OpenCV\ Private\ Framework/OpenCV.framework /System/Library/Frameworks/
-cd into the library folder ::
+get the _SOURCES_ of the pd you are using
+and of the GEM that you are loading
+( it might not work if the version
+is different )
+
+cd into the package folder ::
cd pix_opencv
edit the Makefile to fit your system and sources folders:
-for pix_opencv edit the Makefile and change the values for PD_DIR and GEM_DIR variables
+edit the Makefile and change the values for PD_DIR and GEM_DIR variables
then, compile it ::
diff --git a/pix_opencv_lk-help.pd b/pix_opencv_lk-help.pd
index 4b67d7c..f77ff9b 100755
--- a/pix_opencv_lk-help.pd
+++ b/pix_opencv_lk-help.pd
@@ -1,4 +1,4 @@
-#N canvas 288 90 1192 685 10;
+#N canvas 3 105 1192 685 10;
#X obj 396 -37 gemhead;
#X obj 212 501 pix_texture;
#X obj 212 529 square 2;
@@ -37,7 +37,7 @@
#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
+#X obj 340 180 cnv 15 600 450 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;
@@ -57,8 +57,8 @@
#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 floatatom 488 520 5 0 0 0 - - -;
+#X text 523 519 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;
@@ -72,38 +72,54 @@
#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 msg 494 328 mark \$1 \$2;
+#X msg 508 349 delete \$1;
+#X text 579 349 delete a marker;
+#X msg 516 369 clear;
+#X text 564 370 delete all markers;
+#X msg 522 389 maxmove \$1;
+#X text 636 389 max movement of a marker ( default 5 pisels );
+#X floatatom 598 391 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 485 575 unpack f f;
+#X floatatom 486 600 5 0 0 0 - - -;
+#X floatatom 544 601 5 0 0 0 - - -;
+#X text 487 616 X;
+#X text 542 617 Y;
+#X obj 484 549 route 1 2 3 4 5 6 7 8 9 10;
+#X text 650 498 position of each marked point;
+#X obj 378 538 pix_opencv_lk;
#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 text 573 329 mark x y : mark a point to track ( max points : 10
);
#X obj 998 151 route 1;
#X msg 1019 176 bang;
+#X msg 477 283 mark all;
+#X msg 487 304 mark none;
+#X text 540 284 mark all points;
+#X text 557 305 reset all markers;
+#X text 622 433 make a delaunay with all points;
+#X msg 542 433 delaunay on;
+#X msg 550 453 delaunay off;
+#X text 651 466 make a delaunay with point 1 and a tolerance of 50
+( all points which color is in that range will be included in the delaunay)
+;
+#X msg 552 478 pdelaunay 1 50;
+#X msg 533 409 ftolerance \$1;
+#X floatatom 625 409 5 0 0 0 - - -;
+#X text 665 409 frame tolerance for point identification ( default
+: 5 );
+#X text 44 11 written by Lluis Gomez i Bigorda ( lluisgomez@hangar.org
+) and Yves Degoyon ( ydegoyon@gmail.com );
+#X text 43 -1 Corner points detection based on Shi and Tomasi;
+#X text 43 -13 pix_opencv_lk : Lukas-Kanade corner points tracking
+;
#X connect 0 0 21 0;
#X connect 1 0 2 0;
#X connect 4 0 5 0;
@@ -150,13 +166,20 @@
#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;
+#X connect 60 0 62 1;
+#X connect 60 1 61 1;
+#X connect 60 2 66 0;
+#X connect 61 0 64 1;
+#X connect 62 0 64 0;
+#X connect 63 0 62 0;
+#X connect 63 1 61 0;
+#X connect 64 0 41 0;
+#X connect 66 0 67 0;
+#X connect 67 0 63 0;
+#X connect 68 0 59 0;
+#X connect 69 0 59 0;
+#X connect 73 0 59 0;
+#X connect 74 0 59 0;
+#X connect 76 0 59 0;
+#X connect 77 0 59 0;
+#X connect 78 0 77 0;
diff --git a/pix_opencv_lk.cc b/pix_opencv_lk.cc
index 3217dcb..65daa24 100755
--- a/pix_opencv_lk.cc
+++ b/pix_opencv_lk.cc
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////
+
//
// GEM - Graphics Environment for Multimedia
//
@@ -52,6 +52,10 @@ pix_opencv_lk :: pix_opencv_lk()
quality = 0.1;
min_distance = 10;
maxmove = 8;
+ markall = 0;
+ ftolerance = 5;
+ delaunay = -1;
+ threshold = -1;
for ( i=0; i<MAX_MARKERS; i++ )
{
@@ -97,6 +101,7 @@ void pix_opencv_lk :: processRGBAImage(imageStruct &image)
{
int i, k;
int im;
+ int marked;
if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize))
{
@@ -124,7 +129,23 @@ void pix_opencv_lk :: processRGBAImage(imageStruct &image)
for ( im=0; im<MAX_MARKERS; im++ )
{
- x_found[im] = 0;
+ x_found[im]--;
+ }
+
+ if ( delaunay >= 0 )
+ {
+ // init data structures for the delaunay
+ x_fullrect.x = -comp_xsize/2;
+ x_fullrect.y = -comp_ysize/2;
+ x_fullrect.width = 2*comp_xsize;
+ x_fullrect.height = 2*comp_ysize;
+
+ x_storage = cvCreateMemStorage(0);
+ x_subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*x_subdiv),
+ sizeof(CvSubdiv2DPoint),
+ sizeof(CvQuadEdge2D),
+ x_storage );
+ cvInitSubdivDelaunay2D( x_subdiv, x_fullrect );
}
if( need_to_init )
@@ -168,8 +189,50 @@ void pix_opencv_lk :: processRGBAImage(imageStruct &image)
continue;
points[1][k++] = points[1][i];
+ if ( delaunay == 0 ) // add all the points
+ {
+ cvSubdivDelaunay2DInsert( x_subdiv, points[1][i] );
+ cvCalcSubdivVoronoi2D( x_subdiv );
+ }
+ // only add points included in (color-threshold)<p<(color+treshold)
+ if ( ( delaunay > 0 ) && ( x_xmark[delaunay-1] != -1 ) )
+ {
+ int px = cvPointFrom32f(points[1][i]).x;
+ int py = cvPointFrom32f(points[1][i]).y;
+ int ppx, ppy;
+
+ // eight connected pixels
+ for ( ppx=px-1; ppx<=px+1; ppx++ )
+ {
+ for ( ppy=py-1; ppy<=py+1; ppy++ )
+ {
+ if ( ( ppx < 0 ) || ( ppx >= comp_xsize ) ) continue;
+ if ( ( ppy < 0 ) || ( ppy >= comp_ysize ) ) continue;
+
+ uchar red = ((uchar*)(rgba->imageData + rgba->widthStep*ppx))[ppy*4];
+ uchar green = ((uchar*)(rgba->imageData + rgba->widthStep*ppx))[ppy*4+1];
+ uchar blue = ((uchar*)(rgba->imageData + rgba->widthStep*ppx))[ppy*4+2];
+
+ uchar pred = ((uchar*)(rgba->imageData + rgba->widthStep*x_xmark[delaunay-1]))[x_ymark[delaunay-1]*4];
+ uchar pgreen = ((uchar*)(rgba->imageData + rgba->widthStep*x_xmark[delaunay-1]))[x_ymark[delaunay-1]*4+1];
+ uchar pblue = ((uchar*)(rgba->imageData + rgba->widthStep*x_xmark[delaunay-1]))[x_ymark[delaunay-1]*4+2];
+
+ int diff = abs(red-pred) + abs(green-pgreen) + abs(blue-pblue);
+
+ // post( "pix_opencv_lk : point (%d,%d,%d) : diff : %d", blue, green, red, diff );
+
+ if ( diff < threshold )
+ {
+ cvSubdivDelaunay2DInsert( x_subdiv, points[1][i] );
+ cvCalcSubdivVoronoi2D( x_subdiv );
+ }
+ }
+ }
+ }
+
cvCircle( rgba, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
+ marked=0;
for ( im=0; im<MAX_MARKERS; im++ )
{
// first marking
@@ -182,7 +245,8 @@ void pix_opencv_lk :: processRGBAImage(imageStruct &image)
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;
+ x_found[im]=ftolerance;
+ marked=1;
SETFLOAT(&x_list[0], im+1);
SETFLOAT(&x_list[1], x_xmark[im]);
SETFLOAT(&x_list[2], x_ymark[im]);
@@ -190,6 +254,20 @@ void pix_opencv_lk :: processRGBAImage(imageStruct &image)
}
}
}
+
+ if ( markall && !marked )
+ {
+ for ( im=0; im<MAX_MARKERS; im++)
+ {
+ if ( x_xmark[im] == -1 )
+ {
+ x_xmark[im]=points[1][i].x;
+ x_ymark[im]=points[1][i].y;
+ x_found[im]=ftolerance;
+ break;
+ }
+ }
+ }
}
count = k;
}
@@ -218,6 +296,49 @@ void pix_opencv_lk :: processRGBAImage(imageStruct &image)
add_remove_pt = 0;
}
+ // draw the delaunay
+ if ( delaunay >= 0 )
+ {
+ CvSeqReader reader;
+ int i, total = x_subdiv->edges->total;
+ int elem_size = x_subdiv->edges->elem_size;
+
+ cvStartReadSeq( (CvSeq*)(x_subdiv->edges), &reader, 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
+ CvSubdiv2DPoint* org_pt;
+ CvSubdiv2DPoint* dst_pt;
+ CvPoint2D32f org;
+ CvPoint2D32f dst;
+ CvPoint iorg, idst;
+
+ if( CV_IS_SET_ELEM( edge ))
+ {
+ org_pt = cvSubdiv2DEdgeOrg((CvSubdiv2DEdge)edge);
+ dst_pt = cvSubdiv2DEdgeDst((CvSubdiv2DEdge)edge);
+
+ if( org_pt && dst_pt )
+ {
+ org = org_pt->pt;
+ dst = dst_pt->pt;
+
+ iorg = cvPoint( cvRound( org.x ), cvRound( org.y ));
+ idst = cvPoint( cvRound( dst.x ), cvRound( dst.y ));
+
+ if ( ( org.x > 0 ) && ( org.x < comp_xsize ) &&
+ ( dst.x > 0 ) && ( dst.x < comp_xsize ) &&
+ ( org.y > 0 ) && ( org.y < comp_ysize ) &&
+ ( dst.y > 0 ) && ( dst.y < comp_ysize ) )
+ cvLine( rgba, iorg, idst, CV_RGB(255,0,0), 1, CV_AA, 0 );
+ }
+ }
+
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+ }
+
CV_SWAP( prev_grey, grey, swap_temp );
CV_SWAP( prev_pyramid, pyramid, swap_temp );
CV_SWAP( points[0], points[1], swap_points );
@@ -230,6 +351,7 @@ void pix_opencv_lk :: processRGBImage(imageStruct &image)
{
int i, k;
int im;
+ int marked;
if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize))
{
@@ -257,7 +379,23 @@ void pix_opencv_lk :: processRGBImage(imageStruct &image)
for ( im=0; im<MAX_MARKERS; im++ )
{
- x_found[im] = 0;
+ x_found[im]--;
+ }
+
+ if ( delaunay >= 0 )
+ {
+ // init data structures for the delaunay
+ x_fullrect.x = -comp_xsize/2;
+ x_fullrect.y = -comp_ysize/2;
+ x_fullrect.width = 2*comp_xsize;
+ x_fullrect.height = 2*comp_ysize;
+
+ x_storage = cvCreateMemStorage(0);
+ x_subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*x_subdiv),
+ sizeof(CvSubdiv2DPoint),
+ sizeof(CvQuadEdge2D),
+ x_storage );
+ cvInitSubdivDelaunay2D( x_subdiv, x_fullrect );
}
if( need_to_init )
@@ -301,8 +439,50 @@ void pix_opencv_lk :: processRGBImage(imageStruct &image)
continue;
points[1][k++] = points[1][i];
+ if ( delaunay == 0 ) // add all the points
+ {
+ cvSubdivDelaunay2DInsert( x_subdiv, points[1][i] );
+ cvCalcSubdivVoronoi2D( x_subdiv );
+ }
+ // only add points included in (color-threshold)<p<(color+treshold)
+ if ( ( delaunay > 0 ) && ( x_xmark[delaunay-1] != -1 ) )
+ {
+ int px = cvPointFrom32f(points[1][i]).x;
+ int py = cvPointFrom32f(points[1][i]).y;
+ int ppx, ppy;
+
+ // eight connected pixels
+ for ( ppx=px-1; ppx<=px+1; ppx++ )
+ {
+ for ( ppy=py-1; ppy<=py+1; ppy++ )
+ {
+ if ( ( ppx < 0 ) || ( ppx >= comp_xsize ) ) continue;
+ if ( ( ppy < 0 ) || ( ppy >= comp_ysize ) ) continue;
+
+ uchar red = ((uchar*)(rgb->imageData + rgb->widthStep*ppx))[ppy*3];
+ uchar green = ((uchar*)(rgb->imageData + rgb->widthStep*ppx))[ppy*3+1];
+ uchar blue = ((uchar*)(rgb->imageData + rgb->widthStep*ppx))[ppy*3+2];
+
+ uchar pred = ((uchar*)(rgb->imageData + rgb->widthStep*x_xmark[delaunay-1]))[x_ymark[delaunay-1]*3];
+ uchar pgreen = ((uchar*)(rgb->imageData + rgb->widthStep*x_xmark[delaunay-1]))[x_ymark[delaunay-1]*3+1];
+ uchar pblue = ((uchar*)(rgb->imageData + rgb->widthStep*x_xmark[delaunay-1]))[x_ymark[delaunay-1]*3+2];
+
+ int diff = abs(red-pred) + abs(green-pgreen) + abs(blue-pblue);
+
+ // post( "pix_opencv_lk : point (%d,%d,%d) : diff : %d", blue, green, red, diff );
+
+ if ( diff < threshold )
+ {
+ cvSubdivDelaunay2DInsert( x_subdiv, points[1][i] );
+ cvCalcSubdivVoronoi2D( x_subdiv );
+ }
+ }
+ }
+ }
+
cvCircle( rgb, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
+ marked=0;
for ( im=0; im<MAX_MARKERS; im++ )
{
// first marking
@@ -315,7 +495,8 @@ void pix_opencv_lk :: processRGBImage(imageStruct &image)
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;
+ x_found[im]=ftolerance;
+ marked=1;
SETFLOAT(&x_list[0], im+1);
SETFLOAT(&x_list[1], x_xmark[im]);
SETFLOAT(&x_list[2], x_ymark[im]);
@@ -323,6 +504,20 @@ void pix_opencv_lk :: processRGBImage(imageStruct &image)
}
}
}
+
+ if ( markall && !marked )
+ {
+ for ( im=0; im<MAX_MARKERS; im++)
+ {
+ if ( x_xmark[im] == -1 )
+ {
+ x_xmark[im]=points[1][i].x;
+ x_ymark[im]=points[1][i].y;
+ x_found[im]=ftolerance;
+ break;
+ }
+ }
+ }
}
count = k;
}
@@ -351,6 +546,49 @@ void pix_opencv_lk :: processRGBImage(imageStruct &image)
add_remove_pt = 0;
}
+ // draw the delaunay
+ if ( delaunay >= 0 )
+ {
+ CvSeqReader reader;
+ int i, total = x_subdiv->edges->total;
+ int elem_size = x_subdiv->edges->elem_size;
+
+ cvStartReadSeq( (CvSeq*)(x_subdiv->edges), &reader, 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
+ CvSubdiv2DPoint* org_pt;
+ CvSubdiv2DPoint* dst_pt;
+ CvPoint2D32f org;
+ CvPoint2D32f dst;
+ CvPoint iorg, idst;
+
+ if( CV_IS_SET_ELEM( edge ))
+ {
+ org_pt = cvSubdiv2DEdgeOrg((CvSubdiv2DEdge)edge);
+ dst_pt = cvSubdiv2DEdgeDst((CvSubdiv2DEdge)edge);
+
+ if( org_pt && dst_pt )
+ {
+ org = org_pt->pt;
+ dst = dst_pt->pt;
+
+ iorg = cvPoint( cvRound( org.x ), cvRound( org.y ));
+ idst = cvPoint( cvRound( dst.x ), cvRound( dst.y ));
+
+ if ( ( org.x > 0 ) && ( org.x < comp_xsize ) &&
+ ( dst.x > 0 ) && ( dst.x < comp_xsize ) &&
+ ( org.y > 0 ) && ( org.y < comp_ysize ) &&
+ ( dst.y > 0 ) && ( dst.y < comp_ysize ) )
+ cvLine( rgb, iorg, idst, CV_RGB(255,0,0), 1, CV_AA, 0 );
+ }
+ }
+
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+ }
+
CV_SWAP( prev_grey, grey, swap_temp );
CV_SWAP( prev_pyramid, pyramid, swap_temp );
CV_SWAP( points[0], points[1], swap_points );
@@ -368,6 +606,7 @@ void pix_opencv_lk :: processGrayImage(imageStruct &image)
{
int i, k;
int im;
+ int marked;
if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize))
{
@@ -394,7 +633,23 @@ void pix_opencv_lk :: processGrayImage(imageStruct &image)
for ( im=0; im<MAX_MARKERS; im++ )
{
- x_found[im] = 0;
+ x_found[im]--;
+ }
+
+ if ( delaunay >= 0 )
+ {
+ // init data structures for the delaunay
+ x_fullrect.x = -comp_xsize/2;
+ x_fullrect.y = -comp_ysize/2;
+ x_fullrect.width = 2*comp_xsize;
+ x_fullrect.height = 2*comp_ysize;
+
+ x_storage = cvCreateMemStorage(0);
+ x_subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*x_subdiv),
+ sizeof(CvSubdiv2DPoint),
+ sizeof(CvQuadEdge2D),
+ x_storage );
+ cvInitSubdivDelaunay2D( x_subdiv, x_fullrect );
}
if( need_to_init )
@@ -438,8 +693,45 @@ void pix_opencv_lk :: processGrayImage(imageStruct &image)
continue;
points[1][k++] = points[1][i];
+ if ( delaunay == 0 ) // add all the points
+ {
+ cvSubdivDelaunay2DInsert( x_subdiv, points[1][i] );
+ cvCalcSubdivVoronoi2D( x_subdiv );
+ }
+ // only add points included in (color-threshold)<p<(color+treshold)
+ if ( ( delaunay > 0 ) && ( x_xmark[delaunay-1] != -1 ) )
+ {
+ int px = cvPointFrom32f(points[1][i]).x;
+ int py = cvPointFrom32f(points[1][i]).y;
+ int ppx, ppy;
+
+ // eight connected pixels
+ for ( ppx=px-1; ppx<=px+1; ppx++ )
+ {
+ for ( ppy=py-1; ppy<=py+1; ppy++ )
+ {
+ if ( ( ppx < 0 ) || ( ppx >= comp_xsize ) ) continue;
+ if ( ( ppy < 0 ) || ( ppy >= comp_ysize ) ) continue;
+
+ uchar lum = ((uchar*)(grey->imageData + grey->widthStep*ppx))[ppy];
+ uchar plum = ((uchar*)(grey->imageData + grey->widthStep*x_xmark[delaunay-1]))[x_ymark[delaunay-1]];
+
+ int diff = abs(plum-lum);
+
+ // post( "pix_opencv_lk : point (%d,%d,%d) : diff : %d", blue, green, red, diff );
+
+ if ( diff < threshold )
+ {
+ cvSubdivDelaunay2DInsert( x_subdiv, points[1][i] );
+ cvCalcSubdivVoronoi2D( x_subdiv );
+ }
+ }
+ }
+ }
+
cvCircle( grey, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
+ marked=0;
for ( im=0; im<MAX_MARKERS; im++ )
{
// first marking
@@ -452,7 +744,8 @@ void pix_opencv_lk :: processGrayImage(imageStruct &image)
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;
+ x_found[im]=ftolerance;
+ marked=1;
SETFLOAT(&x_list[0], im+1);
SETFLOAT(&x_list[1], x_xmark[im]);
SETFLOAT(&x_list[2], x_ymark[im]);
@@ -460,6 +753,20 @@ void pix_opencv_lk :: processGrayImage(imageStruct &image)
}
}
}
+
+ if ( markall && !marked )
+ {
+ for ( im=0; im<MAX_MARKERS; im++)
+ {
+ if ( x_xmark[im] == -1 )
+ {
+ x_xmark[im]=points[1][i].x;
+ x_ymark[im]=points[1][i].y;
+ x_found[im]=ftolerance;
+ break;
+ }
+ }
+ }
}
count = k;
}
@@ -488,6 +795,49 @@ void pix_opencv_lk :: processGrayImage(imageStruct &image)
add_remove_pt = 0;
}
+ // draw the delaunay
+ if ( delaunay >= 0 )
+ {
+ CvSeqReader reader;
+ int i, total = x_subdiv->edges->total;
+ int elem_size = x_subdiv->edges->elem_size;
+
+ cvStartReadSeq( (CvSeq*)(x_subdiv->edges), &reader, 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
+ CvSubdiv2DPoint* org_pt;
+ CvSubdiv2DPoint* dst_pt;
+ CvPoint2D32f org;
+ CvPoint2D32f dst;
+ CvPoint iorg, idst;
+
+ if( CV_IS_SET_ELEM( edge ))
+ {
+ org_pt = cvSubdiv2DEdgeOrg((CvSubdiv2DEdge)edge);
+ dst_pt = cvSubdiv2DEdgeDst((CvSubdiv2DEdge)edge);
+
+ if( org_pt && dst_pt )
+ {
+ org = org_pt->pt;
+ dst = dst_pt->pt;
+
+ iorg = cvPoint( cvRound( org.x ), cvRound( org.y ));
+ idst = cvPoint( cvRound( dst.x ), cvRound( dst.y ));
+
+ if ( ( org.x > 0 ) && ( org.x < comp_xsize ) &&
+ ( dst.x > 0 ) && ( dst.x < comp_xsize ) &&
+ ( org.y > 0 ) && ( org.y < comp_ysize ) &&
+ ( dst.y > 0 ) && ( dst.y < comp_ysize ) )
+ cvLine( grey, iorg, idst, CV_RGB(255,0,0), 1, CV_AA, 0 );
+ }
+ }
+
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+ }
+
CV_SWAP( prev_grey, grey, swap_temp );
CV_SWAP( prev_pyramid, pyramid, swap_temp );
CV_SWAP( points[0], points[1], swap_points );
@@ -512,7 +862,7 @@ void pix_opencv_lk :: obj_setupCallback(t_class *classPtr)
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);
+ gensym("mark"), A_GIMME, 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,
@@ -521,6 +871,12 @@ void pix_opencv_lk :: obj_setupCallback(t_class *classPtr)
gensym("mindistance"), A_FLOAT, A_NULL);
class_addmethod(classPtr, (t_method)&pix_opencv_lk::maxMoveMessCallback,
gensym("maxmove"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::ftoleranceMessCallback,
+ gensym("ftolerance"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::delaunayMessCallback,
+ gensym("delaunay"), A_SYMBOL, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_lk::pdelaunayMessCallback,
+ gensym("pdelaunay"), A_FLOAT, A_FLOAT, A_NULL);
}
void pix_opencv_lk :: winSizeMessCallback(void *data, t_floatarg winsize)
@@ -543,9 +899,9 @@ void pix_opencv_lk :: initMessCallback(void *data)
GetMyClass(data)->initMess();
}
-void pix_opencv_lk :: markMessCallback(void *data, t_floatarg mx, t_floatarg my)
+void pix_opencv_lk :: markMessCallback(void *data, t_symbol *s, int argc, t_atom *argv)
{
- GetMyClass(data)->markMess((float)mx, (float)my);
+ GetMyClass(data)->markMess(argc, argv);
}
void pix_opencv_lk :: deleteMessCallback(void *data, t_floatarg index)
@@ -568,6 +924,21 @@ void pix_opencv_lk :: maxMoveMessCallback(void *data, t_floatarg maxmove)
GetMyClass(data)->maxMoveMess((float)maxmove);
}
+void pix_opencv_lk :: ftoleranceMessCallback(void *data, t_floatarg ftolerance)
+{
+ GetMyClass(data)->ftoleranceMess((float)ftolerance);
+}
+
+void pix_opencv_lk :: delaunayMessCallback(void *data, t_symbol *s)
+{
+ GetMyClass(data)->delaunayMess(s);
+}
+
+void pix_opencv_lk :: pdelaunayMessCallback(void *data, t_floatarg fpoint, t_floatarg fthreshold)
+{
+ GetMyClass(data)->pdelaunayMess(fpoint, fthreshold);
+}
+
void pix_opencv_lk :: winSizeMess(float winsize)
{
if (winsize>1.0) win_size = (int)winsize;
@@ -588,32 +959,68 @@ void pix_opencv_lk :: initMess(void)
need_to_init = 1;
}
-void pix_opencv_lk :: markMess(float mx, float my)
+void pix_opencv_lk :: markMess(int argc, t_atom *argv)
{
int i;
int inserted;
- if ( ( mx < 0.0 ) || ( mx >= comp_xsize ) || ( my < 0.0 ) || ( my >= comp_ysize ) )
+ if ( argc == 1 ) // mark all or none
{
- 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 ( argv[0].a_type != A_SYMBOL )
+ {
+ error( "pix_opencv_lk : wrong argument (should be 'all')" );
+ return;
+ }
+ if ( !strcmp( argv[0].a_w.w_symbol->s_name, "all" ) )
+ {
+ markall = 1;
+ return;
+ }
+ if ( !strcmp( argv[0].a_w.w_symbol->s_name, "none" ) )
+ {
+ markall = 0;
+ clearMess();
+ return;
+ }
}
- if ( !inserted )
+ else
{
- post( "pix_opencv_lk : max markers reached" );
- }
+ if ( ( argv[0].a_type != A_FLOAT ) || ( argv[1].a_type != A_FLOAT ) )
+ {
+ error( "pix_opencv_lk : wrong argument (should be mark px py)" );
+ return;
+ }
+ else
+ {
+ float fperx = argv[0].a_w.w_float;
+ float fpery = argv[1].a_w.w_float;
+ int px, py;
+
+ if ( ( fperx < 0.0 ) || ( fperx > 1.0 ) || ( fpery < 0.0 ) || ( fpery > 1.0 ) )
+ {
+ return;
+ }
+
+ px = (int)(fperx*comp_xsize);
+ py = (int)(fpery*comp_ysize);
+ inserted = 0;
+ for ( i=0; i<MAX_MARKERS; i++)
+ {
+ if ( x_xmark[i] == -1 )
+ {
+ x_xmark[i] = px;
+ x_ymark[i] = py;
+ x_found[i] = ftolerance;
+ inserted = 1;
+ break;
+ }
+ }
+ if ( !inserted )
+ {
+ post( "pix_opencv_lk : max markers reached" );
+ }
+ }
+ }
}
void pix_opencv_lk :: deleteMess(float index)
@@ -653,3 +1060,25 @@ void pix_opencv_lk :: maxMoveMess(float maxmove)
if (maxmove>=3.0) maxmove = (int)maxmove;
}
+void pix_opencv_lk :: ftoleranceMess(float ftolerance)
+{
+ if (ftolerance>=0.0) ftolerance = (int)ftolerance;
+}
+
+void pix_opencv_lk :: delaunayMess(t_symbol *s)
+{
+ if (s == gensym("on"))
+ delaunay = 0;
+ if (s == gensym("off"))
+ delaunay = -1;
+}
+
+void pix_opencv_lk :: pdelaunayMess(t_floatarg point, t_floatarg threshold)
+{
+ if (((int)point>0) && ((int)point<MAX_MARKERS))
+ {
+ delaunay = (int)point;
+ threshold = (int)threshold;
+ }
+}
+
diff --git a/pix_opencv_lk.h b/pix_opencv_lk.h
index 97859a8..c8be6a7 100755
--- a/pix_opencv_lk.h
+++ b/pix_opencv_lk.h
@@ -65,11 +65,14 @@ class GEM_EXTERN pix_opencv_lk : public GemPixObj
void nightModeMess(float nightmode);
void qualityMess(float quality);
void initMess(void);
- void markMess(float mx, float my);
+ void markMess(int, t_atom*);
void deleteMess(float index);
void clearMess(void);
void minDistanceMess(float mindistance);
void maxMoveMess(float maxmove);
+ void ftoleranceMess(float ftolerance);
+ void delaunayMess(t_symbol *s);
+ void pdelaunayMess(t_floatarg fpoint, t_floatarg fthreshold);
int comp_xsize;
int comp_ysize;
@@ -81,6 +84,10 @@ class GEM_EXTERN pix_opencv_lk : public GemPixObj
int min_distance;
int night_mode;
int maxmove;
+ int markall;
+ int ftolerance;
+ int delaunay;
+ int threshold;
private:
@@ -90,11 +97,14 @@ class GEM_EXTERN pix_opencv_lk : public GemPixObj
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 markMessCallback(void *data, t_symbol* name, int argc, t_atom* argv);
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);
+ static void ftoleranceMessCallback(void *data, t_floatarg ftolerance);
+ static void delaunayMessCallback(void *data, t_symbol *s);
+ static void pdelaunayMessCallback(void *data, t_floatarg fpoint, t_floatarg fthreshold);
// Internal Open CV data
IplImage *rgba, *rgb, *grey, *prev_grey, *pyramid, *prev_pyramid, *swap_temp;
@@ -110,6 +120,10 @@ class GEM_EXTERN pix_opencv_lk : public GemPixObj
CvPoint pt;
CvFont font;
+ // structures needed for the delaunay
+ CvRect x_fullrect;
+ CvMemStorage* x_storage;
+ CvSubdiv2D* x_subdiv;
};