diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 1 | ||||
-rwxr-xr-x | pix_opencv_surf-help.pd | 182 | ||||
-rwxr-xr-x | pix_opencv_surf.cc | 1005 | ||||
-rwxr-xr-x | pix_opencv_surf.h | 120 |
5 files changed, 1308 insertions, 2 deletions
@@ -35,7 +35,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 pix_opencv_lk.cc pix_opencv_hist_compare.cc pix_opencv_knear.cc pix_opencv_threshold.cc pix_opencv_floodfill.cc pix_opencv_athreshold.cc pix_opencv_bgstats.cc pix_opencv_camshift.cc pix_opencv_hu_compare.cc pix_opencv_pgh_compare.cc pix_opencv_hough_circles.cc pix_opencv_hough_lines.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 pix_opencv_hist_compare.cc pix_opencv_knear.cc pix_opencv_threshold.cc pix_opencv_floodfill.cc pix_opencv_athreshold.cc pix_opencv_bgstats.cc pix_opencv_camshift.cc pix_opencv_hu_compare.cc pix_opencv_pgh_compare.cc pix_opencv_hough_circles.cc pix_opencv_hough_lines.cc pix_opencv_hu_moments.cc pix_opencv_surf.cc all: $(SOURCES:.cc=.$(EXTENSION)) @@ -1 +0,0 @@ -See docs/index.htm diff --git a/pix_opencv_surf-help.pd b/pix_opencv_surf-help.pd new file mode 100755 index 0000000..6b35907 --- /dev/null +++ b/pix_opencv_surf-help.pd @@ -0,0 +1,182 @@ +#N canvas 117 89 1211 737 10; +#X obj 218 -57 gemhead; +#X obj 218 457 pix_texture; +#X obj 28 132 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577 +0; +#N canvas 189 149 454 304 gemwin 0; +#X obj 130 218 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 129 165 create \, 1; +#X msg 205 166 destroy; +#N canvas 87 154 363 340 Gem.init 0; +#X obj 112 15 loadbang; +#X msg 62 93 reset; +#X obj 49 135 outlet; +#X msg 107 89 dimen 320 240; +#X msg 202 89 frame 5; +#X obj 107 51 t b b b; +#X connect 0 0 5 0; +#X connect 1 0 2 0; +#X connect 3 0 2 0; +#X connect 4 0 2 0; +#X connect 5 0 3 0; +#X connect 5 1 4 0; +#X connect 5 2 1 0; +#X restore 289 80 pd Gem.init; +#X obj 128 109 t b b b; +#X msg 156 138 dimen 320 240; +#X msg 251 138 frame 15; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 3 0 9 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 9 0 6 0; +#X connect 9 1 10 0; +#X connect 9 2 11 0; +#X connect 10 0 0 0; +#X connect 11 0 0 0; +#X restore 35 178 pd gemwin; +#X msg 35 157 destroy; +#X text 36 136 Create window and render; +#X obj 340 180 cnv 15 600 450 empty empty empty 20 12 0 14 -24198 -66577 +0; +#X obj 333 -86 bng 25 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 346 108 unpack 0 0 0; +#X floatatom 336 131 5 0 0 3 length - -; +#X floatatom 385 131 5 0 0 3 width - -; +#X floatatom 435 131 5 0 0 3 height - -; +#X obj 390 89 bng 15 250 50 0 empty empty end_reached 20 7 0 10 -262144 +-1 -1; +#X floatatom 382 72 5 0 10000 1 frame# - -; +#X obj 333 -57 openpanel; +#X msg 333 -37 open \$1; +#X obj 321 72 pix_film; +#X msg 339 6 auto \$1; +#X obj 339 -12 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#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 obj 952 123 gemmouse; +#X obj 1008 230 f; +#X obj 978 229 f; +#X obj 1022 201 t b b; +#X obj 975 274 pack f f; +#X obj 998 151 route 1; +#X msg 1019 176 bang; +#X floatatom 969 251 5 0 0 0 - - -; +#X floatatom 1022 254 5 0 0 0 - - -; +#X obj 208 534 rectangle 4 3; +#X obj 212 489 pix_resize 320 240; +#X obj 410 -7 loadbang; +#X msg 410 18 colorspace RGBA; +#X msg 514 18 colorspace RGB; +#X msg 473 -8 colorspace Grey; +#X obj 384 524 pix_opencv_surf; +#X obj 467 252 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X msg 382 253 nightmode \$1; +#X text 486 256 set nightmode; +#X msg 429 316 mark \$1 \$2; +#X msg 435 339 delete \$1; +#X text 628 340 delete a marker; +#X msg 446 362 clear; +#X text 494 363 delete all markers; +#X msg 461 392 maxmove \$1; +#X text 575 392 max movement of a marker ( default 5 pisels ); +#X floatatom 537 394 5 0 0 0 - - -; +#X text 502 316 mark %x %y : mark a point to track ( max points : 10 +); +#X text 546 441 make a delaunay with all points; +#X msg 465 439 delaunay on; +#X msg 467 460 delaunay off; +#X text 577 471 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 obj 500 339 hradio 15 1 0 8 empty empty empty 0 -8 0 10 -262144 +-1 -1 0; +#X msg 473 483 pdelaunay 1 50; +#X msg 363 224 hessian \$1; +#X floatatom 438 225 5 0 0 0 - - -; +#X floatatom 546 416 5 0 0 0 - - -; +#X msg 464 415 ftolerance \$1; +#X text 589 416 frame tolerance for point recognition ( default : 5 +); +#X msg 406 272 mark all; +#X text 476 273 mark all points; +#X msg 416 293 mark none; +#X text 486 294 suppress all marks; +#X text 654 27 written by Lluis Gomez i Bigorda ( lluisgomez@hangar.org +) and Yves Degoyon ( ydegoyon@gmail.com ); +#X text 652 4 pix_opencv_surf : SURF ( Speed Up Robust Features ) points +detection and tracking; +#X text 478 224 hessian threshold ( default 1000 ); +#X connect 0 0 16 0; +#X connect 1 0 35 0; +#X connect 3 0 4 0; +#X connect 4 0 3 0; +#X connect 7 0 14 0; +#X connect 8 0 9 0; +#X connect 8 1 10 0; +#X connect 8 2 11 0; +#X connect 12 0 13 0; +#X connect 13 0 16 1; +#X connect 14 0 15 0; +#X connect 15 0 16 0; +#X connect 16 0 40 0; +#X connect 16 1 8 0; +#X connect 16 2 12 0; +#X connect 17 0 16 0; +#X connect 18 0 17 0; +#X connect 19 0 20 0; +#X connect 19 1 21 0; +#X connect 24 0 19 0; +#X connect 25 0 27 1; +#X connect 25 1 26 1; +#X connect 25 2 30 0; +#X connect 26 0 29 1; +#X connect 26 0 33 0; +#X connect 27 0 29 0; +#X connect 27 0 32 0; +#X connect 28 0 27 0; +#X connect 28 1 26 0; +#X connect 29 0 44 0; +#X connect 30 0 31 0; +#X connect 31 0 28 0; +#X connect 35 0 34 0; +#X connect 36 0 37 0; +#X connect 37 0 16 0; +#X connect 38 0 16 0; +#X connect 39 0 16 0; +#X connect 40 0 1 0; +#X connect 40 1 24 0; +#X connect 41 0 42 0; +#X connect 42 0 40 0; +#X connect 44 0 40 0; +#X connect 45 0 40 0; +#X connect 47 0 40 0; +#X connect 49 0 40 0; +#X connect 51 0 49 0; +#X connect 54 0 40 0; +#X connect 55 0 40 0; +#X connect 57 0 45 0; +#X connect 58 0 40 0; +#X connect 59 0 40 0; +#X connect 60 0 59 0; +#X connect 61 0 62 0; +#X connect 62 0 40 0; +#X connect 64 0 40 0; +#X connect 66 0 40 0; diff --git a/pix_opencv_surf.cc b/pix_opencv_surf.cc new file mode 100755 index 0000000..c1cfe9a --- /dev/null +++ b/pix_opencv_surf.cc @@ -0,0 +1,1005 @@ + +// +// 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_surf.h" +#include <stdio.h> + + +CPPEXTERN_NEW(pix_opencv_surf) + +///////////////////////////////////////////////////////// +// +// pix_opencv_surf +// +///////////////////////////////////////////////////////// +// Constructor +// +///////////////////////////////////////////////////////// + +pix_opencv_surf :: pix_opencv_surf() +{ + int i; + + comp_xsize=320; + comp_ysize=240; + + m_dataout = outlet_new(this->x_obj, &s_anything); + + night_mode = 0; + x_maxmove = 8; + x_delaunay = -1; + x_threshold = -1; + + objectKeypoints = NULL; + objectDescriptors = NULL; + x_hessian = 1000; + x_ftolerance = 5; + + x_markall = 0; + 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 ); + orgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + gray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + ogray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + +} + +///////////////////////////////////////////////////////// +// Destructor +// +///////////////////////////////////////////////////////// +pix_opencv_surf :: ~pix_opencv_surf() +{ + // Destroy cv_images + cvReleaseImage( &rgba ); + cvReleaseImage( &orgb ); + cvReleaseImage( &rgb ); + cvReleaseImage( &gray ); + cvReleaseImage( &ogray ); +} + +///////////////////////////////////////////////////////// +// processImage +// +///////////////////////////////////////////////////////// +void pix_opencv_surf :: processRGBAImage(imageStruct &image) +{ + int i, k; + int im; + int marked; + int descsize; + char tindex[4]; + + if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize)) + { + + this->comp_xsize=image.xsize; + this->comp_ysize=image.ysize; + + cvReleaseImage( &rgba ); + cvReleaseImage( &orgb ); + cvReleaseImage( &rgb ); + cvReleaseImage( &gray ); + cvReleaseImage( &ogray ); + + rgba = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 4 ); + orgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + gray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + ogray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + + } + + memcpy( rgba->imageData, image.data, image.xsize*image.ysize*4 ); + cvCvtColor(rgba, orgb, CV_BGRA2BGR); + cvCvtColor(rgba, rgb, CV_BGRA2BGR); + cvCvtColor(rgba, gray, CV_BGRA2GRAY); + + x_storage = cvCreateMemStorage(0); + + if( night_mode ) + cvZero( rgb ); + + for ( im=0; im<MAX_MARKERS; im++ ) + { + x_found[im]--; + } + + if ( x_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_subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*x_subdiv), + sizeof(CvSubdiv2DPoint), + sizeof(CvQuadEdge2D), + x_storage ); + cvInitSubdivDelaunay2D( x_subdiv, x_fullrect ); + } + + cvExtractSURF( gray, 0, &objectKeypoints, &objectDescriptors, x_storage, cvSURFParams(x_hessian, 1) ); + descsize = (int)(objectDescriptors->elem_size/sizeof(float)); + + for( i = 0; i < objectKeypoints->total; i++ ) + { + CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); + const float* rdesc = (const float*)cvGetSeqElem( objectDescriptors, i ); + + if ( x_delaunay == 0 ) // add all the points + { + cvSubdivDelaunay2DInsert( x_subdiv, r1->pt ); + cvCalcSubdivVoronoi2D( x_subdiv ); + } + + // only add points included in (color-threshold)<p<(color+treshold) + if ( ( x_delaunay > 0 ) && ( x_xmark[x_delaunay-1] != -1 ) ) + { + int px = cvPointFrom32f(r1->pt).x; + int py = cvPointFrom32f(r1->pt).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*)(orgb->imageData + orgb->widthStep*ppx))[ppy*3]; + uchar green = ((uchar*)(orgb->imageData + orgb->widthStep*ppx))[ppy*3+1]; + uchar blue = ((uchar*)(orgb->imageData + orgb->widthStep*ppx))[ppy*3+2]; + + uchar pred = ((uchar*)(orgb->imageData + orgb->widthStep*x_xmark[x_delaunay-1]))[x_ymark[x_delaunay-1]*3]; + uchar pgreen = ((uchar*)(orgb->imageData + orgb->widthStep*x_xmark[x_delaunay-1]))[x_ymark[x_delaunay-1]*3+1]; + uchar pblue = ((uchar*)(orgb->imageData + orgb->widthStep*x_xmark[x_delaunay-1]))[x_ymark[x_delaunay-1]*3+2]; + + int diff = abs(red-pred) + abs(green-pgreen) + abs(blue-pblue); + + // post( "pdp_opencv_surf : point (%d,%d,%d) : diff : %d", blue, green, red, diff ); + + if ( diff < x_threshold ) + { + cvSubdivDelaunay2DInsert( x_subdiv, r1->pt ); + cvCalcSubdivVoronoi2D( x_subdiv ); + } + } + } + } + + cvCircle( rgb, cvPointFrom32f(r1->pt), 3, CV_RGB(0,255,0), -1, 8,0); + + // mark the point if it is not already + if ( x_markall ) + { + int marked = 0; + + for ( im=0; im<MAX_MARKERS; im++ ) + { + if ( x_xmark[im] != -1.0 ) + { + if ( ( abs( r1->pt.x - x_xmark[im] ) <= x_maxmove ) && ( abs( r1->pt.y - x_ymark[im] ) <= x_maxmove ) ) + { + marked = 1; + // post( "pdp_opencv_surf : point already marked" ); + break; + } + } + } + if ( !marked ) + { + for ( i=0; i<MAX_MARKERS; i++) + { + if ( x_xmark[i] == -1 ) + { + x_xmark[i] = r1->pt.x; + x_ymark[i] = r1->pt.y; + x_found[i] = x_ftolerance; + memset( (float * )x_rdesc[i], 0x0, DSCSIZE*sizeof(float)); + break; + } + } + } + } + } + + for ( im=0; im<MAX_MARKERS; im++ ) + { + int neighbour = -1; + double d, dist1 = 1000000, dist2 = 1000000; + + for( i = 0; i < objectKeypoints->total; i++ ) + { + CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); + const float* rdesc = (const float*)cvGetSeqElem( objectDescriptors, i ); + int descsize = (int)(objectDescriptors->elem_size/sizeof(float)); + + // manually marked points + // recognized on position + if ( x_xmark[im] != -1.0 ) + { + if ( ( abs( r1->pt.x - x_xmark[im] ) <= x_maxmove ) && ( abs( r1->pt.y - x_ymark[im] ) <= x_maxmove ) ) + { + sprintf( tindex, "%d", im+1 ); + cvPutText( rgb, tindex, cvPointFrom32f(r1->pt), &font, CV_RGB(255,255,255)); + x_xmark[im]=r1->pt.x; + x_ymark[im]=r1->pt.y; + memcpy( (float * )x_rdesc[im], rdesc, descsize*sizeof(float)); + x_found[im]++; + 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 ); + break; + } + } + } + } + + // draw the delaunay + if ( x_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 ); + } + } + + // suppress lost points + 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( "pdp_opencv_surf : lost point %d", im+1 ); + } + } + + cvReleaseMemStorage( &x_storage ); + + cvCvtColor(rgb, rgba, CV_BGR2BGRA); + memcpy( image.data, rgba->imageData, image.xsize*image.ysize*4 ); +} + +void pix_opencv_surf :: processRGBImage(imageStruct &image) +{ + int i, k; + int im; + int marked; + int descsize; + char tindex[4]; + + if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize)) + { + + this->comp_xsize=image.xsize; + this->comp_ysize=image.ysize; + + cvReleaseImage( &rgba ); + cvReleaseImage( &orgb ); + cvReleaseImage( &rgb ); + cvReleaseImage( &gray ); + cvReleaseImage( &ogray ); + + rgba = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 4 ); + orgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + gray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + ogray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + + } + + memcpy( rgb->imageData, image.data, image.xsize*image.ysize*3 ); + memcpy( orgb->imageData, image.data, image.xsize*image.ysize*3 ); + cvCvtColor(rgb, gray, CV_BGRA2GRAY); + + x_storage = cvCreateMemStorage(0); + + if( night_mode ) + cvZero( rgb ); + + for ( im=0; im<MAX_MARKERS; im++ ) + { + x_found[im]--; + } + + if ( x_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_subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*x_subdiv), + sizeof(CvSubdiv2DPoint), + sizeof(CvQuadEdge2D), + x_storage ); + cvInitSubdivDelaunay2D( x_subdiv, x_fullrect ); + } + + cvExtractSURF( gray, 0, &objectKeypoints, &objectDescriptors, x_storage, cvSURFParams(x_hessian, 1) ); + descsize = (int)(objectDescriptors->elem_size/sizeof(float)); + + for( i = 0; i < objectKeypoints->total; i++ ) + { + CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); + const float* rdesc = (const float*)cvGetSeqElem( objectDescriptors, i ); + + if ( x_delaunay == 0 ) // add all the points + { + cvSubdivDelaunay2DInsert( x_subdiv, r1->pt ); + cvCalcSubdivVoronoi2D( x_subdiv ); + } + + // only add points included in (color-threshold)<p<(color+treshold) + if ( ( x_delaunay > 0 ) && ( x_xmark[x_delaunay-1] != -1 ) ) + { + int px = cvPointFrom32f(r1->pt).x; + int py = cvPointFrom32f(r1->pt).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*)(orgb->imageData + orgb->widthStep*ppx))[ppy*3]; + uchar green = ((uchar*)(orgb->imageData + orgb->widthStep*ppx))[ppy*3+1]; + uchar blue = ((uchar*)(orgb->imageData + orgb->widthStep*ppx))[ppy*3+2]; + + uchar pred = ((uchar*)(orgb->imageData + orgb->widthStep*x_xmark[x_delaunay-1]))[x_ymark[x_delaunay-1]*3]; + uchar pgreen = ((uchar*)(orgb->imageData + orgb->widthStep*x_xmark[x_delaunay-1]))[x_ymark[x_delaunay-1]*3+1]; + uchar pblue = ((uchar*)(orgb->imageData + orgb->widthStep*x_xmark[x_delaunay-1]))[x_ymark[x_delaunay-1]*3+2]; + + int diff = abs(red-pred) + abs(green-pgreen) + abs(blue-pblue); + + // post( "pdp_opencv_surf : point (%d,%d,%d) : diff : %d", blue, green, red, diff ); + + if ( diff < x_threshold ) + { + cvSubdivDelaunay2DInsert( x_subdiv, r1->pt ); + cvCalcSubdivVoronoi2D( x_subdiv ); + } + } + } + } + + cvCircle( rgb, cvPointFrom32f(r1->pt), 3, CV_RGB(0,255,0), -1, 8,0); + + // mark the point if it is not already + if ( x_markall ) + { + int marked = 0; + + for ( im=0; im<MAX_MARKERS; im++ ) + { + if ( x_xmark[im] != -1.0 ) + { + if ( ( abs( r1->pt.x - x_xmark[im] ) <= x_maxmove ) && ( abs( r1->pt.y - x_ymark[im] ) <= x_maxmove ) ) + { + marked = 1; + // post( "pdp_opencv_surf : point already marked" ); + break; + } + } + } + if ( !marked ) + { + for ( i=0; i<MAX_MARKERS; i++) + { + if ( x_xmark[i] == -1 ) + { + x_xmark[i] = r1->pt.x; + x_ymark[i] = r1->pt.y; + x_found[i] = x_ftolerance; + memset( (float * )x_rdesc[i], 0x0, DSCSIZE*sizeof(float)); + break; + } + } + } + } + } + + for ( im=0; im<MAX_MARKERS; im++ ) + { + int neighbour = -1; + double d, dist1 = 1000000, dist2 = 1000000; + + for( i = 0; i < objectKeypoints->total; i++ ) + { + CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); + const float* rdesc = (const float*)cvGetSeqElem( objectDescriptors, i ); + int descsize = (int)(objectDescriptors->elem_size/sizeof(float)); + + // manually marked points + // recognized on position + if ( x_xmark[im] != -1.0 ) + { + if ( ( abs( r1->pt.x - x_xmark[im] ) <= x_maxmove ) && ( abs( r1->pt.y - x_ymark[im] ) <= x_maxmove ) ) + { + sprintf( tindex, "%d", im+1 ); + cvPutText( rgb, tindex, cvPointFrom32f(r1->pt), &font, CV_RGB(255,255,255)); + x_xmark[im]=r1->pt.x; + x_ymark[im]=r1->pt.y; + memcpy( (float * )x_rdesc[im], rdesc, descsize*sizeof(float)); + x_found[im]++; + 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 ); + break; + } + } + } + } + + // draw the delaunay + if ( x_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 ); + } + } + + // suppress lost points + 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( "pdp_opencv_surf : lost point %d", im+1 ); + } + } + + cvReleaseMemStorage( &x_storage ); + memcpy( image.data, rgb->imageData, image.xsize*image.ysize*3 ); +} + +void pix_opencv_surf :: processYUVImage(imageStruct &image) +{ + post( "pix_opencv_surf : yuv format not supported" ); +} + +void pix_opencv_surf :: processGrayImage(imageStruct &image) +{ + int i, k; + int im; + int marked; + int descsize; + char tindex[4]; + + if ((this->comp_xsize!=image.xsize)&&(this->comp_ysize!=image.ysize)) + { + + this->comp_xsize=image.xsize; + this->comp_ysize=image.ysize; + + cvReleaseImage( &rgba ); + cvReleaseImage( &orgb ); + cvReleaseImage( &rgb ); + cvReleaseImage( &gray ); + cvReleaseImage( &ogray ); + + rgba = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 4 ); + orgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + rgb = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 3 ); + gray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + ogray = cvCreateImage( cvSize(comp_xsize, comp_ysize), 8, 1 ); + + } + + memcpy( gray->imageData, image.data, image.xsize*image.ysize ); + memcpy( ogray->imageData, image.data, image.xsize*image.ysize ); + x_storage = cvCreateMemStorage(0); + + if( night_mode ) + cvZero( gray ); + + for ( im=0; im<MAX_MARKERS; im++ ) + { + x_found[im]--; + } + + if ( x_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_subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*x_subdiv), + sizeof(CvSubdiv2DPoint), + sizeof(CvQuadEdge2D), + x_storage ); + cvInitSubdivDelaunay2D( x_subdiv, x_fullrect ); + } + + cvExtractSURF( ogray, 0, &objectKeypoints, &objectDescriptors, x_storage, cvSURFParams(x_hessian, 1) ); + descsize = (int)(objectDescriptors->elem_size/sizeof(float)); + + for( i = 0; i < objectKeypoints->total; i++ ) + { + CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); + const float* rdesc = (const float*)cvGetSeqElem( objectDescriptors, i ); + + if ( x_delaunay == 0 ) // add all the points + { + cvSubdivDelaunay2DInsert( x_subdiv, r1->pt ); + cvCalcSubdivVoronoi2D( x_subdiv ); + } + + // only add points included in (color-threshold)<p<(color+treshold) + if ( ( x_delaunay > 0 ) && ( x_xmark[x_delaunay-1] != -1 ) ) + { + int px = cvPointFrom32f(r1->pt).x; + int py = cvPointFrom32f(r1->pt).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*)(ogray->imageData + ogray->widthStep*ppx))[ppy]; + + uchar plum = ((uchar*)(ogray->imageData + ogray->widthStep*x_xmark[x_delaunay-1]))[x_ymark[x_delaunay-1]]; + + int diff = abs(lum-plum); + + if ( diff < x_threshold ) + { + cvSubdivDelaunay2DInsert( x_subdiv, r1->pt ); + cvCalcSubdivVoronoi2D( x_subdiv ); + } + } + } + } + + cvCircle( gray, cvPointFrom32f(r1->pt), 3, CV_RGB(255,255,255), -1, 8,0); + + // mark the point if it is not already + if ( x_markall ) + { + int marked = 0; + + for ( im=0; im<MAX_MARKERS; im++ ) + { + if ( x_xmark[im] != -1.0 ) + { + if ( ( abs( r1->pt.x - x_xmark[im] ) <= x_maxmove ) && ( abs( r1->pt.y - x_ymark[im] ) <= x_maxmove ) ) + { + marked = 1; + // post( "pdp_opencv_surf : point already marked" ); + break; + } + } + } + if ( !marked ) + { + for ( i=0; i<MAX_MARKERS; i++) + { + if ( x_xmark[i] == -1 ) + { + x_xmark[i] = r1->pt.x; + x_ymark[i] = r1->pt.y; + x_found[i] = x_ftolerance; + memset( (float * )x_rdesc[i], 0x0, DSCSIZE*sizeof(float)); + break; + } + } + } + } + } + + for ( im=0; im<MAX_MARKERS; im++ ) + { + int neighbour = -1; + double d, dist1 = 1000000, dist2 = 1000000; + + for( i = 0; i < objectKeypoints->total; i++ ) + { + CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); + const float* rdesc = (const float*)cvGetSeqElem( objectDescriptors, i ); + int descsize = (int)(objectDescriptors->elem_size/sizeof(float)); + + // manually marked points + // recognized on position + if ( x_xmark[im] != -1.0 ) + { + if ( ( abs( r1->pt.x - x_xmark[im] ) <= x_maxmove ) && ( abs( r1->pt.y - x_ymark[im] ) <= x_maxmove ) ) + { + sprintf( tindex, "%d", im+1 ); + cvPutText( gray, tindex, cvPointFrom32f(r1->pt), &font, CV_RGB(255,255,255)); + x_xmark[im]=r1->pt.x; + x_ymark[im]=r1->pt.y; + memcpy( (float * )x_rdesc[im], rdesc, descsize*sizeof(float)); + x_found[im]++; + 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 ); + break; + } + } + } + } + + // draw the delaunay + if ( x_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( gray, iorg, idst, CV_RGB(255,255,255), 1, CV_AA, 0 ); + } + } + + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + } + + // suppress lost points + 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( "pdp_opencv_surf : lost point %d", im+1 ); + } + } + + cvReleaseMemStorage( &x_storage ); + memcpy( image.data, gray->imageData, image.xsize*image.ysize ); +} + +///////////////////////////////////////////////////////// +// static member function +// +///////////////////////////////////////////////////////// + +void pix_opencv_surf :: obj_setupCallback(t_class *classPtr) +{ + class_addmethod(classPtr, (t_method)&pix_opencv_surf::nightModeMessCallback, + gensym("nightmode"), A_FLOAT, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::hessianMessCallback, + gensym("hessian"), A_FLOAT, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::markMessCallback, + gensym("mark"), A_GIMME, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::deleteMessCallback, + gensym("delete"), A_FLOAT, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::clearMessCallback, + gensym("clear"), A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::maxMoveMessCallback, + gensym("maxmove"), A_FLOAT, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::ftoleranceMessCallback, + gensym("ftolerance"), A_FLOAT, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::delaunayMessCallback, + gensym("delaunay"), A_SYMBOL, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_surf::pdelaunayMessCallback, + gensym("pdelaunay"), A_FLOAT, A_FLOAT, A_NULL); +} + +void pix_opencv_surf :: nightModeMessCallback(void *data, t_floatarg nightmode) +{ + GetMyClass(data)->nightModeMess((float)nightmode); +} + +void pix_opencv_surf :: hessianMessCallback(void *data, t_floatarg hessian) +{ + GetMyClass(data)->hessianMess((float)hessian); +} + +void pix_opencv_surf :: markMessCallback(void *data, t_symbol *s, int argc, t_atom *argv) +{ + GetMyClass(data)->markMess(argc, argv); +} + +void pix_opencv_surf :: deleteMessCallback(void *data, t_floatarg index) +{ + GetMyClass(data)->deleteMess((float)index); +} + +void pix_opencv_surf :: clearMessCallback(void *data) +{ + GetMyClass(data)->clearMess(); +} + +void pix_opencv_surf :: maxMoveMessCallback(void *data, t_floatarg maxmove) +{ + GetMyClass(data)->maxMoveMess((float)maxmove); +} + +void pix_opencv_surf :: ftoleranceMessCallback(void *data, t_floatarg ftolerance) +{ + GetMyClass(data)->ftoleranceMess((float)ftolerance); +} + +void pix_opencv_surf :: delaunayMessCallback(void *data, t_symbol *s) +{ + GetMyClass(data)->delaunayMess(s); +} + +void pix_opencv_surf :: pdelaunayMessCallback(void *data, t_floatarg fpoint, t_floatarg fthreshold) +{ + GetMyClass(data)->pdelaunayMess(fpoint, fthreshold); +} + +void pix_opencv_surf :: nightModeMess(float nightmode) +{ + if ((nightmode==0.0)||(nightmode==1.0)) night_mode = (int)nightmode; +} + +void pix_opencv_surf :: hessianMess(float hessian) +{ + if (hessian>0.0) x_hessian = (int)hessian; +} + +void pix_opencv_surf :: markMess(int argc, t_atom *argv) +{ + int i; + int inserted; + + if ( argc == 1 ) // mark all or none + { + if ( argv[0].a_type != A_SYMBOL ) + { + error( "pix_opencv_surf : wrong argument (should be 'all')" ); + return; + } + if ( !strcmp( argv[0].a_w.w_symbol->s_name, "all" ) ) + { + x_markall = 1; + return; + } + if ( !strcmp( argv[0].a_w.w_symbol->s_name, "none" ) ) + { + x_markall = 0; + clearMess(); + return; + } + } + else + { + if ( ( argv[0].a_type != A_FLOAT ) || ( argv[1].a_type != A_FLOAT ) ) + { + error( "pix_opencv_surf : wrong argument (should be mark px py)" ); + return; + } + else + { + float fpx = argv[0].a_w.w_float; + float fpy = argv[1].a_w.w_float; + int px, py; + + if ( ( fpx < 0.0 ) || ( fpx > comp_xsize ) || ( fpy < 0.0 ) || ( fpy > comp_ysize ) ) + { + return; + } + + px = (int)fpx; + py = comp_ysize-(int)fpy; + 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] = x_ftolerance; + inserted = 1; + // post( "pix_opencv_surf : inserted point (%d,%d)", px, py ); + break; + } + } + if ( !inserted ) + { + post( "pix_opencv_surf : max markers reached" ); + } + } + } +} + +void pix_opencv_surf :: 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_surf :: clearMess(void) +{ + int i; + + for ( i=0; i<MAX_MARKERS; i++) + { + x_xmark[i] = -1; + x_ymark[i] = -1; + } + +} + +void pix_opencv_surf :: maxMoveMess(float maxmove) +{ + // has to be more than the size of a point + if (maxmove>=3.0) maxmove = (int)maxmove; +} + +void pix_opencv_surf :: ftoleranceMess(float ftolerance) +{ + if (ftolerance>=0.0) ftolerance = (int)ftolerance; +} + +void pix_opencv_surf :: delaunayMess(t_symbol *s) +{ + if (s == gensym("on")) + x_delaunay = 0; + if (s == gensym("off")) + x_delaunay = -1; +} + +void pix_opencv_surf :: pdelaunayMess(t_floatarg point, t_floatarg threshold) +{ + if (((int)point>0) && ((int)point<MAX_MARKERS)) + { + x_delaunay = (int)point; + x_threshold = (int)threshold; + } +} + diff --git a/pix_opencv_surf.h b/pix_opencv_surf.h new file mode 100755 index 0000000..bbc0277 --- /dev/null +++ b/pix_opencv_surf.h @@ -0,0 +1,120 @@ +/*----------------------------------------------------------------- +LOG + GEM - Graphics Environment for Multimedia + + SURF point detection and tracking + + 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_SURF_H_ +#define INCLUDE_PIX_OPENCV_SURF_H_ + +#include "Base/GemPixObj.h" + +#ifndef _EiC +#include "cv.h" +#endif + +#define MAX_MARKERS 500 +#define DSCSIZE 128 + +/*----------------------------------------------------------------- +------------------------------------------------------------------- +CLASS + pix_opencv_surf + + SURF point detection and tracking + +KEYWORDS + pix + +DESCRIPTION + +-----------------------------------------------------------------*/ +class GEM_EXTERN pix_opencv_surf : public GemPixObj +{ + CPPEXTERN_HEADER(pix_opencv_surf, GemPixObj) + + public: + + ////////// + // Constructor + pix_opencv_surf(); + + protected: + + ////////// + // Destructor + virtual ~pix_opencv_surf(); + + ////////// + // Do the processing + virtual void processRGBAImage(imageStruct &image); + virtual void processRGBImage(imageStruct &image); + virtual void processYUVImage(imageStruct &image); + virtual void processGrayImage(imageStruct &image); + + void nightModeMess(float nightmode); + void hessianMess(float hessian); + void markMess(int, t_atom*); + void deleteMess(float index); + void clearMess(void); + 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; + + t_outlet *m_dataout; + int x_hessian; + int x_criteria; + int night_mode; + int x_maxmove; + int x_markall; + int x_ftolerance; + int x_delaunay; + int x_threshold; + + private: + + ////////// + // Static member functions + static void nightModeMessCallback(void *data, t_floatarg nightmode); + static void hessianMessCallback(void *data, t_floatarg hessian); + 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 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 *orgb, *rgba, *rgb, *gray, *ogray; + t_atom x_list[3]; + + int x_xmark[MAX_MARKERS]; + int x_ymark[MAX_MARKERS]; + float x_rdesc[MAX_MARKERS][DSCSIZE]; + int x_found[MAX_MARKERS]; + + // internal OpenCV structures + CvSeq *objectKeypoints, *objectDescriptors; + CvFont font; + + // structures needed for the delaunay + CvRect x_fullrect; + CvMemStorage* x_storage; + CvSubdiv2D* x_subdiv; +}; + +#endif // for header file |