diff options
-rw-r--r-- | pix_opencv_bgsubstract-help.pd | 17 | ||||
-rw-r--r-- | pix_opencv_contours_boundingrect-help.pd | 140 | ||||
-rw-r--r-- | pix_opencv_contours_boundingrect.cc | 355 | ||||
-rw-r--r-- | pix_opencv_contours_boundingrect.h | 26 |
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; }; |