aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <sevyves@users.sourceforge.net>2009-07-01 19:29:18 +0000
committerN.N. <sevyves@users.sourceforge.net>2009-07-01 19:29:18 +0000
commit11ec35baaa2ee0d44f88c5ecab2a3ea71d3c4105 (patch)
treee6db15bb0a1022a3420fe949717d9bd33d2eaa53
parentbb51cb7b85a80bae5c867fdc92d15028d718b257 (diff)
added parameters and identification
svn path=/trunk/externals/pix_opencv/; revision=11840
-rw-r--r--pix_opencv_bgsubstract-help.pd17
-rw-r--r--pix_opencv_contours_boundingrect-help.pd140
-rw-r--r--pix_opencv_contours_boundingrect.cc355
-rw-r--r--pix_opencv_contours_boundingrect.h26
4 files changed, 465 insertions, 73 deletions
diff --git a/pix_opencv_bgsubstract-help.pd b/pix_opencv_bgsubstract-help.pd
index 2ad204f..cd3aa34 100644
--- a/pix_opencv_bgsubstract-help.pd
+++ b/pix_opencv_bgsubstract-help.pd
@@ -1,5 +1,5 @@
-#N canvas 510 70 691 547 10;
-#X obj 286 -33 gemhead;
+#N canvas 515 94 691 547 10;
+#X obj 618 -33 gemhead;
#X obj 364 374 pix_texture;
#X obj 364 402 square 2;
#X obj 20 159 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577
@@ -61,6 +61,19 @@
#X msg 472 288 set;
#X text 508 288 set the background;
#X text 572 320 threshold (default 13);
+#X text 26 -2 This object takes an image as a background reference
+and the compare each incomming frame with that. On the output you get
+a bw image \, black pixels are considered as background and white poixels
+as foreground.;
+#X text 27 -94 pix_opencv_bgsubstract :: A simple background substract
+and binarization object.;
+#X text 26 -49 It is useful if you want to detect objects that are
+in front of an static background and you want to isolate the foreground
+silhouete of the foreground objects.;
+#X text 26 59 pix_opencv_bgsubstract works comparing color values of
+each pixel \, so it can fail if the foreground object has the same
+color that the background \, and also if the light conditions or the
+shadows changes since you SET the background image.;
#X connect 0 0 21 0;
#X connect 1 0 2 0;
#X connect 4 0 5 0;
diff --git a/pix_opencv_contours_boundingrect-help.pd b/pix_opencv_contours_boundingrect-help.pd
index 0071513..10376d5 100644
--- a/pix_opencv_contours_boundingrect-help.pd
+++ b/pix_opencv_contours_boundingrect-help.pd
@@ -1,10 +1,10 @@
-#N canvas 510 70 691 547 10;
-#X obj 286 -33 gemhead;
-#X obj 364 374 pix_texture;
-#X obj 364 402 square 2;
-#X obj 20 159 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577
+#N canvas 68 50 1040 775 10;
+#X obj 441 -19 gemhead;
+#X obj 365 456 pix_texture;
+#X obj 365 484 square 2;
+#X obj 21 444 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577
0;
-#N canvas 0 22 454 304 gemwin 0;
+#N canvas 5 49 454 304 gemwin 0;
#X obj 132 136 gemwin;
#X obj 67 89 outlet;
#X obj 67 10 inlet;
@@ -13,7 +13,7 @@
#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;
+#N canvas 92 178 247 179 Gem.init 0;
#X obj 118 46 loadbang;
#X msg 118 81 reset;
#X obj 118 113 outlet;
@@ -30,50 +30,83 @@
#X connect 6 0 0 0;
#X connect 7 0 0 0;
#X connect 8 0 0 0;
-#X restore 25 203 pd gemwin;
-#X msg 25 179 destroy;
-#X text 21 159 Create window and render;
+#X restore 26 488 pd gemwin;
+#X msg 26 464 destroy;
+#X text 22 444 Create window and render;
#X obj 200 368 pix_texture;
#X obj 200 396 square 2;
#X obj 266 167 translateXYZ -2 0 0;
-#X obj 367 224 separator;
-#X obj 346 281 cnv 15 255 67 empty empty empty 20 12 0 14 -24198 -66577
+#X obj 281 199 separator;
+#X obj 344 254 cnv 15 550 180 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
+#X obj 527 164 unpack 0 0 0;
+#X floatatom 517 187 5 0 0 3 length - -;
+#X floatatom 566 187 5 0 0 3 width - -;
+#X floatatom 616 187 5 0 0 3 height - -;
+#X obj 571 145 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 floatatom 553 110 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 1 1
+#X obj 502 128 pix_film;
+#X msg 479 23 auto \$1;
+#X obj 479 5 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
-#X obj 364 259 translateXYZ 4 0 0;
-#X floatatom 473 288 5 0 0 0 - - -;
-#X obj 364 324 pix_opencv_contours_boundingrect;
+#X obj 281 227 translateXYZ 4 0 0;
+#X floatatom 482 374 5 0 0 0 - - -;
+#X obj 365 406 pix_opencv_contours_boundingrect;
#X obj 378 110 pix_invert;
#X obj 319 135 pix_threshold;
-#X floatatom 425 142 5 0 0 0 - - -;
-#X msg 441 191 0.33;
-#X obj 479 192 loadbang;
-#X msg 528 50 colorspace RGBA;
-#X text 516 287 min area in pixels (default 1);
-#X floatatom 580 304 5 0 0 0 - - -;
-#X text 623 303 max area in pixels (default 76800);
-#X floatatom 587 443 5 0 0 0 - - -;
-#X floatatom 622 443 5 0 0 0 - - -;
-#X floatatom 659 443 5 0 0 0 - - -;
-#X floatatom 693 443 5 0 0 0 - - -;
-#X obj 584 414 unpack 0 0 0 0 0;
-#X obj 584 363 route 0 1 2 3 4;
-#X text 737 443 Xorigin Yorigin Width Height;
-#X text 644 381 For each contour detected;
+#X floatatom 322 103 5 0 0 0 - - -;
+#X msg 289 101 0.33;
+#X obj 234 101 loadbang;
+#X text 517 370 min area in pixels (default 1);
+#X floatatom 568 388 5 0 0 0 - - -;
+#X text 606 387 max area in pixels (default 76800);
+#X floatatom 498 542 5 0 0 0 - - -;
+#X floatatom 533 542 5 0 0 0 - - -;
+#X floatatom 570 542 5 0 0 0 - - -;
+#X floatatom 604 542 5 0 0 0 - - -;
+#X obj 495 513 unpack 0 0 0 0 0;
+#X obj 495 462 route 0 1 2 3 4;
+#X text 648 542 Xorigin Yorigin Width Height;
+#X text 555 480 For each contour detected;
+#X text 655 -107 It is useful as a motion tracker if you have well
+isolated silouets of the objects you want to track.;
+#X msg 385 260 mode \$1;
+#X obj 446 261 hradio 15 1 0 4 empty empty empty 0 -8 0 10 -262144
+-1 -1 0;
+#X text 515 262 retrieval mode ( see cvFindContours );
+#X obj 481 286 hradio 15 1 0 5 empty empty empty 0 -8 0 10 -262144
+-1 -1 0;
+#X text 563 286 retrieval method ( see cvFindContours );
+#X msg 414 285 method \$1;
+#X msg 437 308 maxmove \$1;
+#X floatatom 511 309 5 0 0 0 - - -;
+#X floatatom 535 333 5 0 0 0 - - -;
+#X msg 447 330 ftolerance \$1;
+#X text 554 308 maximum move of a countour ( default 10 );
+#X text 571 331 frame tolerance for identification ( default 5 );
+#X text 656 -141 pix_opencv_contours_boundingrect :: Calculates up-right
+bounding rectangle of all contours of a binary image.;
+#X text 655 -68 This object considers a contour to be analyzed any
+group of white pixels in a black background \, for this reason you
+will find useful to use pdp_bgsubstract or pdp_threshold to obtain
+a correct input for pix_opencv_contours_boundingrect.;
+#X text 655 -14 pix_opencv_contours_boundingrect works detecting any
+white areas in the input image \, it's important to set max/min values
+of the areas you want to detect to filter non interesting noise or
+areas \, also sometimes you will need to use pix_opencv_morphology
+to transform the contours of the shapes to be analyzed..;
+#X msg 490 350 clear;
+#X floatatom 598 445 5 0 0 0 - - -;
+#X text 636 446 number of contours;
+#X msg 531 87 colorspace RGBA;
+#X msg 521 66 colorspace RGB;
+#X msg 513 46 colorspace Gray;
+#X obj 562 21 loadbang;
#X connect 0 0 21 0;
#X connect 1 0 2 0;
#X connect 4 0 5 0;
@@ -98,16 +131,29 @@
#X connect 24 0 26 0;
#X connect 25 0 26 1;
#X connect 26 0 1 0;
-#X connect 26 1 41 0;
+#X connect 26 1 40 0;
+#X connect 26 2 60 0;
#X connect 27 0 28 0;
#X connect 28 0 9 0;
#X connect 29 0 28 1;
#X connect 30 0 29 0;
#X connect 31 0 30 0;
-#X connect 32 0 21 0;
-#X connect 34 0 26 2;
-#X connect 40 0 36 0;
-#X connect 40 1 37 0;
-#X connect 40 2 38 0;
-#X connect 40 3 39 0;
-#X connect 41 0 40 0;
+#X connect 33 0 26 2;
+#X connect 39 0 35 0;
+#X connect 39 1 36 0;
+#X connect 39 2 37 0;
+#X connect 39 3 38 0;
+#X connect 40 0 39 0;
+#X connect 44 0 26 0;
+#X connect 45 0 44 0;
+#X connect 47 0 49 0;
+#X connect 49 0 26 0;
+#X connect 50 0 26 0;
+#X connect 51 0 50 0;
+#X connect 52 0 53 0;
+#X connect 53 0 26 0;
+#X connect 59 0 26 0;
+#X connect 62 0 21 0;
+#X connect 63 0 21 0;
+#X connect 64 0 21 0;
+#X connect 65 0 62 0;
diff --git a/pix_opencv_contours_boundingrect.cc b/pix_opencv_contours_boundingrect.cc
index c6ebd94..201d701 100644
--- a/pix_opencv_contours_boundingrect.cc
+++ b/pix_opencv_contours_boundingrect.cc
@@ -16,6 +16,7 @@
/////////////////////////////////////////////////////////
#include "pix_opencv_contours_boundingrect.h"
+#include <stdio.h>
CPPEXTERN_NEW(pix_opencv_contours_boundingrect)
@@ -32,6 +33,7 @@ pix_opencv_contours_boundingrect :: pix_opencv_contours_boundingrect()
inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("minarea"));
inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("maxarea"));
m_dataout = outlet_new(this->x_obj, 0);
+ m_countout = outlet_new(this->x_obj, 0);
minarea = 1;
maxarea = 320*240;
comp_xsize = 0;
@@ -40,6 +42,13 @@ pix_opencv_contours_boundingrect :: pix_opencv_contours_boundingrect()
gray = NULL;
cnt_img = NULL;
rgb = NULL;
+ x_ftolerance = 5;
+ x_mmove = 10;
+ x_cmode = CV_RETR_TREE;
+ x_cmethod = CV_CHAIN_APPROX_SIMPLE;
+
+ // initialize font
+ cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 1.0, 1.0, 1.0, 1, 8 );
}
@@ -57,12 +66,42 @@ pix_opencv_contours_boundingrect :: ~pix_opencv_contours_boundingrect()
}
/////////////////////////////////////////////////////////
+// Mark a contour
+//
+/////////////////////////////////////////////////////////
+int pix_opencv_contours_boundingrect :: mark(float fx, float fy )
+{
+ int i;
+
+ if ( ( fx < 0.0 ) || ( fx > this->comp_xsize ) || ( fy < 0 ) || ( fy > this->comp_ysize ) )
+ {
+ return -1;
+ }
+
+ for ( i=0; i<MAX_MARKERS; i++)
+ {
+ if ( x_xmark[i] == -1 )
+ {
+ x_xmark[i] = (int)fx;
+ x_ymark[i] = (int)fy;
+ x_found[i] = x_ftolerance;
+ return i;
+ }
+ }
+
+ // post( "pix_opencv_contours_boundingrect : max markers reached" );
+ return -1;
+}
+
+/////////////////////////////////////////////////////////
// processImage
//
/////////////////////////////////////////////////////////
void pix_opencv_contours_boundingrect :: processRGBAImage(imageStruct &image)
{
unsigned char *pixels = image.data;
+ char tindex[4];
+ int im = 0; // Indicator of markers.
if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!orig)) {
@@ -80,9 +119,9 @@ void pix_opencv_contours_boundingrect :: processRGBAImage(imageStruct &image)
// Create the output images with new sizes
rgb = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 3);
- cnt_img = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 3);
gray = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 1);
+ cnt_img = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 1);
}
// Here we make a copy of the pixel data from image to orig->imageData
@@ -97,22 +136,54 @@ void pix_opencv_contours_boundingrect :: processRGBAImage(imageStruct &image)
CvMemStorage* stor02;
stor02 = cvCreateMemStorage(0);
- cvFindContours( gray, stor02, &contours, sizeof(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
+ cvFindContours( gray, stor02, &contours, sizeof(CvContour), x_cmode, x_cmethod, cvPoint(0,0) );
if (contours) contours = cvApproxPoly( contours, sizeof(CvContour), stor02, CV_POLY_APPROX_DP, 3, 1 );
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( x_xmark[im] != -1.0 )
+ {
+ x_found[im]--;
+ }
+ }
int i = 0; // Indicator of cycles.
for( ; contours != 0; contours = contours->h_next )
- {
+ {
int count = contours->total; // This is number point in contour
CvRect rect;
+ int oi, found;
rect = cvContourBoundingRect( contours, 1);
if ( ( (rect.width*rect.height) > minarea ) && ( (rect.width*rect.height) < maxarea ) ) {
+
+ found = 0;
+ oi = -1;
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // check if the object is already known
+ if ( ( abs( rect.x - x_xmark[im] ) < x_mmove ) && ( abs( rect.y - x_ymark[im] ) < x_mmove ) )
+ {
+ oi=im;
+ found=1;
+ x_found[im] = x_ftolerance;
+ x_xmark[im] = rect.x;
+ x_ymark[im] = rect.y;
+ break;
+ }
+ }
+ // new object detected
+ if ( !found )
+ {
+ oi = this->mark(rect.x, rect.y );
+ }
+
cvRectangle( orig, cvPoint(rect.x,rect.y), cvPoint(rect.x+rect.width,rect.y+rect.height), CV_RGB(255,0,0), 2, 8 , 0 );
+ sprintf( tindex, "%d", oi );
+ cvPutText( orig, tindex, cvPoint(rect.x,rect.y), &font, CV_RGB(255,255,255));
t_atom rlist[4];
- SETFLOAT(&rlist[0], i);
+ SETFLOAT(&rlist[0], oi);
SETFLOAT(&rlist[1], rect.x);
SETFLOAT(&rlist[2], rect.y);
SETFLOAT(&rlist[3], rect.width);
@@ -121,11 +192,22 @@ void pix_opencv_contours_boundingrect :: processRGBAImage(imageStruct &image)
outlet_list( m_dataout, 0, 5, rlist );
i++;
}
+ outlet_float( m_countout, i );
- }
+ }
- cvReleaseMemStorage( &stor02 );
+ // delete lost objects
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( x_found[im] < 0 )
+ {
+ x_xmark[im] = -1.0;
+ x_ymark[im] = -1,0;
+ x_found[im] = x_ftolerance;
+ }
+ }
+ cvReleaseMemStorage( &stor02 );
//copy back the processed frame to image
memcpy( image.data, orig->imageData, image.xsize*image.ysize*4 );
@@ -134,6 +216,8 @@ void pix_opencv_contours_boundingrect :: processRGBAImage(imageStruct &image)
void pix_opencv_contours_boundingrect :: processRGBImage(imageStruct &image)
{
unsigned char *pixels = image.data;
+ char tindex[4];
+ int im = 0; // Indicator of markers.
if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!rgb)) {
@@ -149,10 +233,8 @@ void pix_opencv_contours_boundingrect :: processRGBImage(imageStruct &image)
//create the orig image with new size
rgb = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 3);
- // Create the output images with new sizes
- cnt_img = cvCreateImage(cvSize(rgb->width,rgb->height), IPL_DEPTH_8U, 3);
-
gray = cvCreateImage(cvSize(rgb->width,rgb->height), IPL_DEPTH_8U, 1);
+ cnt_img = cvCreateImage(cvSize(rgb->width,rgb->height), IPL_DEPTH_8U, 1);
}
// FEM UNA COPIA DEL PACKET A image->imageData ... http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html aqui veiem la estructura de IplImage
@@ -165,22 +247,54 @@ void pix_opencv_contours_boundingrect :: processRGBImage(imageStruct &image)
CvMemStorage* stor02;
stor02 = cvCreateMemStorage(0);
- cvFindContours( gray, stor02, &contours, sizeof(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
+ cvFindContours( gray, stor02, &contours, sizeof(CvContour), x_cmode, x_cmethod, cvPoint(0,0) );
if (contours) contours = cvApproxPoly( contours, sizeof(CvContour), stor02, CV_POLY_APPROX_DP, 3, 1 );
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( x_xmark[im] != -1.0 )
+ {
+ x_found[im]--;
+ }
+ }
int i = 0; // Indicator of cycles.
for( ; contours != 0; contours = contours->h_next )
- {
+ {
int count = contours->total; // This is number point in contour
CvRect rect;
+ int oi, found;
rect = cvContourBoundingRect( contours, 1);
if ( ( (rect.width*rect.height) > minarea ) && ( (rect.width*rect.height) < maxarea ) ) {
+
+ found = 0;
+ oi = -1;
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // check if the object is already known
+ if ( ( abs( rect.x - x_xmark[im] ) < x_mmove ) && ( abs( rect.y - x_ymark[im] ) < x_mmove ) )
+ {
+ oi=im;
+ found=1;
+ x_found[im] = x_ftolerance;
+ x_xmark[im] = rect.x;
+ x_ymark[im] = rect.y;
+ break;
+ }
+ }
+ // new object detected
+ if ( !found )
+ {
+ oi = this->mark(rect.x, rect.y );
+ }
+
cvRectangle( rgb, cvPoint(rect.x,rect.y), cvPoint(rect.x+rect.width,rect.y+rect.height), CV_RGB(255,0,0), 2, 8 , 0 );
+ sprintf( tindex, "%d", oi );
+ cvPutText( rgb, tindex, cvPoint(rect.x,rect.y), &font, CV_RGB(255,255,255));
t_atom rlist[4];
- SETFLOAT(&rlist[0], i);
+ SETFLOAT(&rlist[0], oi);
SETFLOAT(&rlist[1], rect.x);
SETFLOAT(&rlist[2], rect.y);
SETFLOAT(&rlist[3], rect.width);
@@ -189,13 +303,23 @@ void pix_opencv_contours_boundingrect :: processRGBImage(imageStruct &image)
outlet_list( m_dataout, 0, 5, rlist );
i++;
}
+ outlet_float( m_countout, i );
- }
+ }
- cvReleaseMemStorage( &stor02 );
+ // delete lost objects
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( x_found[im] < 0 )
+ {
+ x_xmark[im] = -1.0;
+ x_ymark[im] = -1,0;
+ x_found[im] = x_ftolerance;
+ }
+ }
+ cvReleaseMemStorage( &stor02 );
- //cvShowImage(wndname, cedge);
memcpy( image.data, rgb->imageData, image.xsize*image.ysize*3 );
}
@@ -205,6 +329,8 @@ void pix_opencv_contours_boundingrect :: processYUVImage(imageStruct &image)
void pix_opencv_contours_boundingrect :: processGrayImage(imageStruct &image)
{
+ char tindex[4];
+ int im = 0; // Indicator of markers.
if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!orig)) {
@@ -222,37 +348,69 @@ void pix_opencv_contours_boundingrect :: processGrayImage(imageStruct &image)
// Create the output images with new sizes
rgb = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 3);
- cnt_img = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 3);
gray = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 1);
+ cnt_img = cvCreateImage(cvSize(orig->width,orig->height), IPL_DEPTH_8U, 1);
}
// Here we make a copy of the pixel data from image to orig->imageData
// orig is a IplImage struct, the default image type in openCV, take a look on the IplImage data structure here
// http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html
memcpy( gray->imageData, image.data, image.xsize*image.ysize );
-
+ memcpy( cnt_img->imageData, image.data, image.xsize*image.ysize );
CvSeq* contours;
CvMemStorage* stor02;
stor02 = cvCreateMemStorage(0);
- cvFindContours( gray, stor02, &contours, sizeof(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
+ cvFindContours( gray, stor02, &contours, sizeof(CvContour), x_cmode, x_cmethod, cvPoint(0,0) );
if (contours) contours = cvApproxPoly( contours, sizeof(CvContour), stor02, CV_POLY_APPROX_DP, 3, 1 );
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( x_xmark[im] != -1.0 )
+ {
+ x_found[im]--;
+ }
+ }
int i = 0; // Indicator of cycles.
for( ; contours != 0; contours = contours->h_next )
- {
+ {
int count = contours->total; // This is number point in contour
CvRect rect;
+ int oi, found;
rect = cvContourBoundingRect( contours, 1);
if ( ( (rect.width*rect.height) > minarea ) && ( (rect.width*rect.height) < maxarea ) ) {
- cvRectangle( gray, cvPoint(rect.x,rect.y), cvPoint(rect.x+rect.width,rect.y+rect.height), CV_RGB(255,0,0), 2, 8 , 0 );
+
+ found = 0;
+ oi = -1;
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // check if the object is already known
+ if ( ( abs( rect.x - x_xmark[im] ) < x_mmove ) && ( abs( rect.y - x_ymark[im] ) < x_mmove ) )
+ {
+ oi=im;
+ found=1;
+ x_found[im] = x_ftolerance;
+ x_xmark[im] = rect.x;
+ x_ymark[im] = rect.y;
+ break;
+ }
+ }
+ // new object detected
+ if ( !found )
+ {
+ oi = this->mark(rect.x, rect.y );
+ }
+
+ cvRectangle( cnt_img, cvPoint(rect.x,rect.y), cvPoint(rect.x+rect.width,rect.y+rect.height), cvScalarAll(255), 2, 8 , 0 );
+ sprintf( tindex, "%d", oi );
+ cvPutText( cnt_img, tindex, cvPoint(rect.x,rect.y), &font, cvScalarAll(255));
t_atom rlist[4];
- SETFLOAT(&rlist[0], i);
+ SETFLOAT(&rlist[0], oi);
SETFLOAT(&rlist[1], rect.x);
SETFLOAT(&rlist[2], rect.y);
SETFLOAT(&rlist[3], rect.width);
@@ -261,14 +419,25 @@ void pix_opencv_contours_boundingrect :: processGrayImage(imageStruct &image)
outlet_list( m_dataout, 0, 5, rlist );
i++;
}
+ outlet_float( m_countout, i );
- }
+ }
- cvReleaseMemStorage( &stor02 );
+ // delete lost objects
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( x_found[im] < 0 )
+ {
+ x_xmark[im] = -1.0;
+ x_ymark[im] = -1,0;
+ x_found[im] = x_ftolerance;
+ }
+ }
+ cvReleaseMemStorage( &stor02 );
//copy back the processed frame to image
- memcpy( image.data, gray->imageData, image.xsize*image.ysize );
+ memcpy( image.data, cnt_img->imageData, image.xsize*image.ysize );
}
/////////////////////////////////////////////////////////
@@ -279,11 +448,112 @@ void pix_opencv_contours_boundingrect :: floatMinAreaMess (float minarea)
{
if (minarea>0) this->minarea = (int)minarea;
}
+
void pix_opencv_contours_boundingrect :: floatMaxAreaMess (float maxarea)
{
if (maxarea>0) this->maxarea = (int)maxarea;
}
+void pix_opencv_contours_boundingrect :: floatFToleranceMess (float ftolerance)
+{
+ if ((int)ftolerance>=1) x_ftolerance = (int)ftolerance;
+}
+
+void pix_opencv_contours_boundingrect :: floatMMoveMess (float mmove)
+{
+ if ((int)mmove>=1) x_mmove = (int)mmove;
+}
+
+void pix_opencv_contours_boundingrect :: floatCModeMess (float cmode)
+{
+ // CV_RETR_EXTERNAL || CV_RETR_LIST || CV_RETR_CCOMP || CV_RETR_TREE
+ int mode = (int)cmode;
+
+ if ( mode == CV_RETR_EXTERNAL )
+ {
+ x_cmode = CV_RETR_EXTERNAL;
+ post( "pix_opencv_contours_boundingrect : mode set to CV_RETR_EXTERNAL" );
+ }
+ if ( mode == CV_RETR_LIST )
+ {
+ x_cmode = CV_RETR_LIST;
+ post( "pix_opencv_contours_boundingrect : mode set to CV_RETR_LIST" );
+ }
+ if ( mode == CV_RETR_CCOMP )
+ {
+ x_cmode = CV_RETR_CCOMP;
+ post( "pix_opencv_contours_boundingrect : mode set to CV_RETR_CCOMP" );
+ }
+ if ( mode == CV_RETR_TREE )
+ {
+ x_cmode = CV_RETR_TREE;
+ post( "pix_opencv_contours_boundingrect : mode set to CV_RETR_TREE" );
+ }
+}
+
+void pix_opencv_contours_boundingrect :: floatCMethodMess (float cmethod)
+{
+ int method = (int)cmethod;
+
+ // CV_CHAIN_CODE || CV_CHAIN_APPROX_NONE || CV_CHAIN_APPROX_SIMPLE || CV_CHAIN_APPROX_TC89_L1 || CV_CHAIN_APPROX_TC89_KCOS || CV_LINK_RUNS
+ if ( method == CV_CHAIN_CODE )
+ {
+ post( "pix_opencv_contours_boundingrect : not supported method : CV_CHAIN_CODE" );
+ }
+ if ( method == CV_CHAIN_APPROX_NONE )
+ {
+ x_cmethod = CV_CHAIN_APPROX_NONE;
+ post( "pix_opencv_contours_boundingrect : method set to CV_CHAIN_APPROX_NONE" );
+ }
+ if ( method == CV_CHAIN_APPROX_SIMPLE )
+ {
+ x_cmethod = CV_CHAIN_APPROX_SIMPLE;
+ post( "pix_opencv_contours_boundingrect : method set to CV_CHAIN_APPROX_SIMPLE" );
+ }
+ if ( method == CV_CHAIN_APPROX_TC89_L1 )
+ {
+ x_cmethod = CV_CHAIN_APPROX_TC89_L1;
+ post( "pix_opencv_contours_boundingrect : method set to CV_CHAIN_APPROX_TC89_L1" );
+ }
+ if ( method == CV_CHAIN_APPROX_TC89_KCOS )
+ {
+ x_cmethod = CV_CHAIN_APPROX_TC89_KCOS;
+ post( "pix_opencv_contours_boundingrect : method set to CV_CHAIN_APPROX_TC89_KCOS" );
+ }
+ if ( ( method == CV_LINK_RUNS ) && ( x_cmode == CV_RETR_LIST ) )
+ {
+ x_cmethod = CV_LINK_RUNS;
+ post( "pix_opencv_contours_boundingrect : method set to CV_LINK_RUNS" );
+ }
+
+}
+
+void pix_opencv_contours_boundingrect :: deleteMark(t_floatarg findex )
+{
+ int i;
+
+ if ( ( findex < 1.0 ) || ( findex > MAX_MARKERS ) )
+ {
+ return;
+ }
+
+ x_xmark[(int)findex-1] = -1;
+ x_ymark[(int)findex-1] = -1;
+}
+
+
+void pix_opencv_contours_boundingrect :: floatClearMess (void)
+{
+ int i;
+
+ for ( i=0; i<MAX_MARKERS; i++)
+ {
+ x_xmark[i] = -1;
+ x_ymark[i] = -1;
+ x_found[i] = x_ftolerance;
+ }
+}
+
/////////////////////////////////////////////////////////
// static member function
//
@@ -294,12 +564,49 @@ void pix_opencv_contours_boundingrect :: obj_setupCallback(t_class *classPtr)
gensym("minarea"), A_FLOAT, A_NULL);
class_addmethod(classPtr, (t_method)&pix_opencv_contours_boundingrect::floatMaxAreaMessCallback,
gensym("maxarea"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_contours_boundingrect::floatFToleranceMessCallback,
+ gensym("ftolerance"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_contours_boundingrect::floatMMoveMessCallback,
+ gensym("mmove"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_contours_boundingrect::floatCModeMessCallback,
+ gensym("cmode"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_contours_boundingrect::floatCMethodMessCallback,
+ gensym("cmethod"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_contours_boundingrect::floatClearMessCallback,
+ gensym("clear"), A_FLOAT, A_NULL);
}
+
void pix_opencv_contours_boundingrect :: floatMaxAreaMessCallback(void *data, t_floatarg maxarea)
{
GetMyClass(data)->floatMaxAreaMess((float)maxarea);
}
+
void pix_opencv_contours_boundingrect :: floatMinAreaMessCallback(void *data, t_floatarg minarea)
{
GetMyClass(data)->floatMinAreaMess((float)minarea);
}
+
+void pix_opencv_contours_boundingrect :: floatFToleranceMessCallback(void *data, t_floatarg ftolerance)
+{
+ GetMyClass(data)->floatFToleranceMess((float)ftolerance);
+}
+
+void pix_opencv_contours_boundingrect :: floatMMoveMessCallback(void *data, t_floatarg mmove)
+{
+ GetMyClass(data)->floatMMoveMess((float)mmove);
+}
+
+void pix_opencv_contours_boundingrect :: floatCModeMessCallback(void *data, t_floatarg cmode)
+{
+ GetMyClass(data)->floatCModeMess((float)cmode);
+}
+
+void pix_opencv_contours_boundingrect :: floatCMethodMessCallback(void *data, t_floatarg cmethod)
+{
+ GetMyClass(data)->floatCMethodMess((float)cmethod);
+}
+
+void pix_opencv_contours_boundingrect :: floatClearMessCallback(void *data)
+{
+ GetMyClass(data)->floatClearMess();
+}
diff --git a/pix_opencv_contours_boundingrect.h b/pix_opencv_contours_boundingrect.h
index 8ae88d1..cdec706 100644
--- a/pix_opencv_contours_boundingrect.h
+++ b/pix_opencv_contours_boundingrect.h
@@ -22,6 +22,8 @@ LOG
#include "cv.h"
#endif
+#define MAX_MARKERS 100
+
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
@@ -62,24 +64,48 @@ class GEM_EXTERN pix_opencv_contours_boundingrect : public GemPixObj
// Set the new edge threshold
void floatMinAreaMess(float minarea);
void floatMaxAreaMess(float maxarea);
+ void floatFToleranceMess(float maxarea);
+ void floatMMoveMess(float maxarea);
+ void floatCModeMess(float maxarea);
+ void floatCMethodMess(float maxarea);
+ void floatClearMess(void);
+ int mark(float fx, float fy );
+ void deleteMark(float findex);
// The new minimal/maximal area
int minarea;
int maxarea;
// to detect changes in the image size
int comp_xsize;
int comp_ysize;
+ int x_xmark[MAX_MARKERS];
+ int x_ymark[MAX_MARKERS];
+ int x_found[MAX_MARKERS];
+ int x_ftolerance;
+ int x_mmove;
+
+ // contours retrieval mode
+ int x_cmode;
+ // contours retrieval method
+ int x_cmethod;
private:
t_outlet *m_dataout;
+ t_outlet *m_countout;
//////////
// Static member functions
static void floatMinAreaMessCallback(void *data, t_floatarg minarea);
static void floatMaxAreaMessCallback(void *data, t_floatarg maxarea);
+ static void floatFToleranceMessCallback(void *data, t_floatarg ftolerance);
+ static void floatMMoveMessCallback(void *data, t_floatarg mmove);
+ static void floatCModeMessCallback(void *data, t_floatarg cmode);
+ static void floatCMethodMessCallback(void *data, t_floatarg cmethod);
+ static void floatClearMessCallback(void *data);
/////////
// IplImage needed
IplImage *rgb, *orig, *cnt_img, *gray;
+ CvFont font;
};