diff options
-rw-r--r-- | pdp_opencv_floodfill-help.pd | 102 | ||||
-rw-r--r-- | pdp_opencv_floodfill.c | 393 |
2 files changed, 316 insertions, 179 deletions
diff --git a/pdp_opencv_floodfill-help.pd b/pdp_opencv_floodfill-help.pd index f8dc2db..8aa3a5f 100644 --- a/pdp_opencv_floodfill-help.pd +++ b/pdp_opencv_floodfill-help.pd @@ -1,20 +1,82 @@ -#N canvas 0 0 521 599 10; -#X obj 101 158 pdp_xv; -#X msg 101 -138 open /dev/video0; -#X obj 101 57 pdp_v4l2; -#X msg 207 60 set; -#X floatatom 273 102 5 0 0 0 - - -; -#X text 317 103 number of frames to take as average bg; -#X obj 191 224 pdp_xv; -#X floatatom 363 168 5 0 0 0 - - -; -#X text 407 169 number of frames to take as average bg; -#X obj 191 165 pdp_opencv_floodfill; -#X obj 101 99 pdp_opencv_threshold; -#X connect 1 0 2 0; -#X connect 2 0 10 0; -#X connect 3 0 10 0; -#X connect 4 0 10 2; -#X connect 7 0 9 1; -#X connect 9 0 6 0; -#X connect 10 0 0 0; -#X connect 10 0 9 0; +#N canvas 461 101 826 623 10; +#X msg 91 -56 open /dev/video0; +#X obj 109 41 pdp_v4l2; +#X obj 104 390 pdp_xv; +#X obj 104 279 pdp_opencv_floodfill; +#X obj 109 -6 metro 40; +#X text 102 489 used in tracking algorithms as an object selector; +#X text 102 502 Written by Lluis Gomez i Bigorda ( lluis@artefacte.org +); +#X text 102 516 and Yves Degoyon ( ydegoyon@gmail.com ); +#X floatatom 270 240 5 0 0 0 - - -; +#X floatatom 277 260 5 0 0 0 - - -; +#X msg 110 -37 bang; +#X msg 206 -54 open /dev/video0; +#X obj 216 -4 metro 40; +#X msg 217 -35 bang; +#X obj 216 32 pdp_v4l; +#X msg 213 70 mark \$1 \$2; +#X obj 104 417 route press; +#X msg 260 219 color \$1; +#X obj 322 220 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X text 348 218 activate color mode ( default : on ); +#X msg 154 389 cursor 1; +#X msg 249 144 fillcolor 1 255 0 123; +#X text 387 145 fillcolor of nth component ( 1 < n < 10 ); +#X text 226 389 <-- click in the video window on the shape/component +you want to mark; +#X text 288 56 mark %x %y : mark a component; +#X text 288 68 ( 0 <= %x <= 1 ); +#X text 289 79 ( 0 <= %y <= 1 ); +#X obj 221 307 route 0 1 2 3 4 5 6 7 8 9; +#X floatatom 222 352 5 0 0 0 - - -; +#X floatatom 258 353 5 0 0 0 - - -; +#X floatatom 294 353 5 0 0 0 - - -; +#X floatatom 330 353 5 0 0 0 - - -; +#X obj 222 330 unpack f f f f; +#X text 224 369 X; +#X text 261 369 Y; +#X text 293 370 Width; +#X text 331 370 Height; +#X msg 228 98 delete 1; +#X msg 242 120 clear; +#X text 288 98 delete a component ( 1 <= index <= 10 ); +#X text 291 120 delete all components; +#X text 380 308 detected components; +#X text 311 239 outbound tolerance ( default 20 ); +#X text 317 259 inbound tolerance ( default 20 ); +#X msg 256 170 connectivty 4; +#X msg 258 193 connectivty 8; +#X text 350 181 set connectivity ( default 4 ); +#X text 101 466 pdp_opencv_floodfill : mark image components with a +specific color; +#X connect 0 0 3 0; +#X connect 1 0 3 0; +#X connect 2 0 16 0; +#X connect 3 0 2 0; +#X connect 3 0 20 0; +#X connect 3 1 27 0; +#X connect 4 0 1 0; +#X connect 8 0 3 1; +#X connect 9 0 3 2; +#X connect 10 0 4 0; +#X connect 11 0 14 0; +#X connect 12 0 14 0; +#X connect 13 0 12 0; +#X connect 14 0 3 0; +#X connect 15 0 3 0; +#X connect 16 0 15 0; +#X connect 17 0 3 0; +#X connect 18 0 17 0; +#X connect 20 0 2 0; +#X connect 21 0 3 0; +#X connect 27 0 32 0; +#X connect 32 0 28 0; +#X connect 32 1 29 0; +#X connect 32 2 30 0; +#X connect 32 3 31 0; +#X connect 37 0 3 0; +#X connect 38 0 3 0; +#X connect 44 0 3 0; +#X connect 45 0 3 0; diff --git a/pdp_opencv_floodfill.c b/pdp_opencv_floodfill.c index 864e41c..7e697ca 100644 --- a/pdp_opencv_floodfill.c +++ b/pdp_opencv_floodfill.c @@ -31,7 +31,7 @@ #include "cv.h" #endif - +#define MAX_COMPONENTS 10 typedef struct pdp_opencv_floodfill_struct { @@ -39,6 +39,8 @@ typedef struct pdp_opencv_floodfill_struct t_float x_f; t_outlet *x_outlet0; + t_outlet *x_outlet1; + t_atom x_list[5]; int x_packet0; int x_packet1; int x_dropped; @@ -50,20 +52,22 @@ typedef struct pdp_opencv_floodfill_struct int x_infosok; - int up_diff; - int lo_diff; - int ffill_case; - int connectivity; - int is_color; - int is_mask; - int new_mask_val; + int x_up; + int x_lo; + int x_connectivity; + int x_color; + + // tracked components + int x_xcomp[MAX_COMPONENTS]; + int x_ycomp[MAX_COMPONENTS]; - // The output and temporary images + // fill color + int x_r[MAX_COMPONENTS]; + int x_g[MAX_COMPONENTS]; + int x_b[MAX_COMPONENTS]; - IplImage* color_img0; - IplImage* mask; + // opencv data IplImage* color_img; - IplImage* gray_img0; IplImage* gray_img; } t_pdp_opencv_floodfill; @@ -72,39 +76,31 @@ typedef struct pdp_opencv_floodfill_struct static void pdp_opencv_floodfill_process_rgb(t_pdp_opencv_floodfill *x) { - t_pdp *header = pdp_packet_header(x->x_packet0); - short int *data = (short int *)pdp_packet_data(x->x_packet0); - t_pdp *newheader = pdp_packet_header(x->x_packet1); - short int *newdata = (short int *)pdp_packet_data(x->x_packet1); - int i; - + t_pdp *header = pdp_packet_header(x->x_packet0); + short int *data = (short int *)pdp_packet_data(x->x_packet0); + t_pdp *newheader = pdp_packet_header(x->x_packet1); + short int *newdata = (short int *)pdp_packet_data(x->x_packet1); + int i; + CvConnectedComp comp; + int flags = x->x_connectivity + ( 255 << 8 ) + CV_FLOODFILL_FIXED_RANGE; if ((x->x_width != (t_int)header->info.image.width) || (x->x_height != (t_int)header->info.image.height)) { - post("pdp_opencv_floodfill :: resizing plugins"); - - //cv_freeplugins(x); - - x->x_width = header->info.image.width; - x->x_height = header->info.image.height; - x->x_size = x->x_width*x->x_height; + post("pdp_opencv_floodfill :: resizing plugins"); + + x->x_width = header->info.image.width; + x->x_height = header->info.image.height; + x->x_size = x->x_width*x->x_height; - //Destroy cv_images - cvReleaseImage( &x->color_img ); - cvReleaseImage( &x->color_img0 ); - cvReleaseImage( &x->mask ); - cvReleaseImage( &x->gray_img ); - cvReleaseImage( &x->gray_img0 ); - + //Destroy cv_images + cvReleaseImage( &x->color_img ); + cvReleaseImage( &x->gray_img ); - //Create cv_images - x->color_img0 = cvCreateImage( cvSize(x->x_width,x->x_height), 8, 3 ); - x->color_img = cvCreateImage( cvSize(x->x_width,x->x_height), 8, 3 ); - x->gray_img0 = cvCreateImage( cvSize(x->x_width, x->x_height), 8, 1 ); - x->gray_img = cvCreateImage( cvSize(x->x_width, x->x_height), 8, 1 ); - x->mask = cvCreateImage( cvSize(x->x_width + 2, x->x_height + 2), 8, 1 ); + //Create cv_images + x->color_img = cvCreateImage( cvSize(x->x_width,x->x_height), 8, 3 ); + x->gray_img = cvCreateImage( cvSize(x->x_width, x->x_height), 8, 1 ); } newheader->info.image.encoding = header->info.image.encoding; @@ -112,88 +108,57 @@ static void pdp_opencv_floodfill_process_rgb(t_pdp_opencv_floodfill *x) newheader->info.image.height = x->x_height; memcpy( newdata, data, x->x_size*3 ); - // FEM UNA COPIA DEL PACKET A x->grey->imageData ... http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html aqui veiem la estructura de IplImage memcpy( x->color_img->imageData, data, x->x_size*3 ); - - cvCvtColor(x->color_img, x->gray_img, CV_BGR2GRAY); - - - int px = 0; - int py = 0; - int biggestNum=0,biggestLocX=0,biggestLocY=0; - int haveOne=0; - CvPixelPosition8u sil; - int stride = x->gray_img->widthStep; - unsigned char * pI = (unsigned char *)x->gray_img->imageData; - CV_INIT_PIXEL_POS(sil, pI, x->gray_img->widthStep, cvSize(x->gray_img->width, x->gray_img->height), 0, 0,IPL_ORIGIN_TL); - CvPoint xy; - CvPoint seed = cvPoint(px,py); - int lo = x->ffill_case == 0 ? 0 : x->lo_diff; - int up = x->ffill_case == 0 ? 0 : x->up_diff; - int flags = x->connectivity + (x->new_mask_val << 8) + - (x->ffill_case == 1 ? CV_FLOODFILL_FIXED_RANGE : 0); - CvConnectedComp comp; - int min_area_size = 200; - - for(py=0; py<x->gray_img->height; py++) - { - for(px=0; px<x->gray_img->width; px++) - { - if(*(sil.currline + sil.x) != 0) // check if used yet - { - xy.x = px; - xy.y = py; - cvFloodFill ( x->gray_img, xy, cvRealScalar(100), cvRealScalar(lo), cvRealScalar(up), &comp, flags, NULL ); - // if size is too small remove that region - // Also, keep only the biggest region!!! - if( ((int)(comp.area)<min_area_size) || ((int)(comp.area)<biggestNum) ) - { - // remove it - //cvFloodFill ( x->gray_img, xy, cvRealScalar(0), cvRealScalar(lo), cvRealScalar(up), &comp, flags, NULL ); - } else { // for keeping just the largest - // remove previous max - if(haveOne) - { - xy.x = biggestLocX; - xy.y = biggestLocY; - //cvFloodFill ( x->gray_img, xy, cvRealScalar(0), cvRealScalar(lo), cvRealScalar(up), &comp, flags, NULL ); - } else haveOne=1; - biggestNum=(int)(comp.area); - biggestLocX=px; - biggestLocY=py; - } - } - CV_MOVE_RIGHT_WRAP(sil, 1); - } - CV_MOVE_DOWN(sil, 1); - } - if(haveOne) - { - xy.x = biggestLocX; - xy.y = biggestLocY; - //cvFloodFill ( x->gray_img, xy, cvRealScalar(255), cvRealScalar(lo), cvRealScalar(up), &comp, flags, NULL ); - } - - - - //CvScalar brightness = cvRealScalar(255); - //cvFloodFill( x->color_img, seed, CV_RGB(255,255,255), CV_RGB(lo,lo,lo), - // CV_RGB(up,up,up), &comp, flags, NULL ); - - cvCvtColor(x->gray_img, x->color_img, CV_GRAY2BGR); + if ( !x->x_color ) + { + cvCvtColor(x->color_img, x->gray_img, CV_BGR2GRAY); + } + + // mark recognized components + for ( i=0; i<MAX_COMPONENTS; i++ ) + { + if ( x->x_xcomp[i] != -1 ) + { + if ( x->x_color ) + { + CvPoint seed = cvPoint(x->x_xcomp[i],x->x_ycomp[i]); + CvScalar color = CV_RGB( x->x_r[i], x->x_g[i], x->x_b[i] ); + cvFloodFill( x->color_img, seed, color, CV_RGB( x->x_lo, x->x_lo, x->x_lo ), + CV_RGB( x->x_up, x->x_up, x->x_up ), &comp, flags, NULL ); + SETFLOAT(&x->x_list[0], i); + SETFLOAT(&x->x_list[1], comp.rect.x); + SETFLOAT(&x->x_list[2], comp.rect.y); + SETFLOAT(&x->x_list[3], comp.rect.width); + SETFLOAT(&x->x_list[4], comp.rect.height); + outlet_list( x->x_outlet1, 0, 5, x->x_list ); + } + else + { + CvPoint seed = cvPoint(x->x_xcomp[i],x->x_ycomp[i]); + CvScalar brightness = cvRealScalar((x->x_r[i]*2 + x->x_g[i]*7 + x->x_b[i] + 5)/10); + cvFloodFill( x->gray_img, seed, brightness, cvRealScalar(x->x_lo), + cvRealScalar(x->x_up), &comp, flags, NULL ); + SETFLOAT(&x->x_list[0], i); + SETFLOAT(&x->x_list[1], comp.rect.x); + SETFLOAT(&x->x_list[2], comp.rect.y); + SETFLOAT(&x->x_list[3], comp.rect.width); + SETFLOAT(&x->x_list[4], comp.rect.height); + outlet_list( x->x_outlet1, 0, 5, x->x_list ); + } + } + } + + if ( !x->x_color ) + { + cvCvtColor(x->gray_img, x->color_img, CV_GRAY2RGB); + } memcpy( newdata, x->color_img->imageData, x->x_size*3 ); - //printf("%g pixels were repainted\n", comp.area ); return; } -static void pdp_opencv_floodfill_diff(t_pdp_opencv_floodfill *x, t_floatarg f) -{ - if ((f==1)||(f==3)||(f==5)||(f==7)) x->up_diff = (int)f; -} - static void pdp_opencv_floodfill_sendpacket(t_pdp_opencv_floodfill *x) { /* release the packet */ @@ -206,34 +171,27 @@ static void pdp_opencv_floodfill_sendpacket(t_pdp_opencv_floodfill *x) static void pdp_opencv_floodfill_process(t_pdp_opencv_floodfill *x) { - int encoding; - t_pdp *header = 0; - char *parname; - unsigned pi; - int partype; - float pardefault; - t_atom plist[2]; - t_atom tlist[2]; - t_atom vlist[2]; - - /* check if image data packets are compatible */ - if ( (header = pdp_packet_header(x->x_packet0)) - && (PDP_BITMAP == header->type)){ + int encoding; + t_pdp *header = 0; + + /* check if image data packets are compatible */ + if ( (header = pdp_packet_header(x->x_packet0)) + && (PDP_BITMAP == header->type)){ - /* pdp_opencv_floodfill_process inputs and write into active inlet */ - switch(pdp_packet_header(x->x_packet0)->info.image.encoding){ + /* pdp_opencv_floodfill_process inputs and write into active inlet */ + switch(pdp_packet_header(x->x_packet0)->info.image.encoding){ - case PDP_BITMAP_RGB: + case PDP_BITMAP_RGB: x->x_packet1 = pdp_packet_clone_rw(x->x_packet0); pdp_queue_add(x, pdp_opencv_floodfill_process_rgb, pdp_opencv_floodfill_sendpacket, &x->x_queue_id); - break; + break; - default: - /* don't know the type, so dont pdp_opencv_floodfill_process */ - break; - - } - } + default: + /* don't know the type, so dont pdp_opencv_floodfill_process */ + break; + + } + } } @@ -257,28 +215,137 @@ static void pdp_opencv_floodfill_free(t_pdp_opencv_floodfill *x) pdp_queue_finish(x->x_queue_id); pdp_packet_mark_unused(x->x_packet0); - //cv_freeplugins(x); - //Destroy cv_images - cvReleaseImage( &x->color_img ); - cvReleaseImage( &x->color_img0 ); - cvReleaseImage( &x->mask ); - cvReleaseImage( &x->gray_img ); - cvReleaseImage( &x->gray_img0 ); + //Destroy cv_images + cvReleaseImage( &x->color_img ); + cvReleaseImage( &x->gray_img ); } -t_class *pdp_opencv_floodfill_class; +static void pdp_opencv_floodfill_up_diff(t_pdp_opencv_floodfill *x, t_floatarg fupdiff ) +{ + if ( ( (int)fupdiff >= 0 ) && ( (int)fupdiff <= 255 ) ) + { + x->x_up = (int)fupdiff; + } +} + +static void pdp_opencv_floodfill_lo_diff(t_pdp_opencv_floodfill *x, t_floatarg flodiff ) +{ + if ( ( (int)flodiff >= 0 ) && ( (int)flodiff <= 255 ) ) + { + x->x_lo = (int)flodiff; + } +} + +static void pdp_opencv_floodfill_color(t_pdp_opencv_floodfill *x, t_floatarg fcolor ) +{ + if ( ( (int)fcolor == 0 ) || ( (int)fcolor == 1 ) ) + { + x->x_color = (int)fcolor; + } +} + +static void pdp_opencv_floodfill_fillcolor(t_pdp_opencv_floodfill *x, t_floatarg findex, t_floatarg fr, t_floatarg fg, t_floatarg fb ) +{ + if ( ( (int)findex <= 0 ) || ( (int)findex > MAX_COMPONENTS ) ) + { + post( "pdp_opencv_floodfill : wrong color index : %d", (int)findex ); + return; + } + + if ( ( (int)fr >= 0 ) || ( (int)fr <= 255 ) ) + { + x->x_r[(int)findex-1] = (int)fr; + } + + if ( ( (int)fg >= 0 ) || ( (int)fg <= 255 ) ) + { + x->x_g[(int)findex-1] = (int)fg; + } + if ( ( (int)fb >= 0 ) || ( (int)fb <= 255 ) ) + { + x->x_b[(int)findex-1] = (int)fb; + } + +} + +static void pdp_opencv_floodfill_mark(t_pdp_opencv_floodfill *x, t_floatarg fperx, t_floatarg fpery ) +{ + int i; + int inserted; + + if ( ( fperx < 0.0 ) || ( fperx > 1.0 ) || ( fpery < 0.0 ) || ( fpery > 1.0 ) ) + { + return; + } + + inserted = 0; + for ( i=0; i<MAX_COMPONENTS; i++) + { + if ( x->x_xcomp[i] == -1 ) + { + x->x_xcomp[i] = (int)(fperx*x->x_width); + x->x_ycomp[i] = (int)(fpery*x->x_height); + post( "pdp_opencv_floodfill : inserted point (%d,%d)", x->x_xcomp[i], x->x_ycomp[i] ); + inserted = 1; + break; + } + } + if ( !inserted ) + { + post( "pdp_opencv_floodfill : max components reached" ); + } +} + +static void pdp_opencv_floodfill_delete(t_pdp_opencv_floodfill *x, t_floatarg findex ) +{ + int i; + + if ( ( findex < 1.0 ) || ( findex > 10 ) ) + { + return; + } + + x->x_xcomp[(int)findex-1] = -1; + x->x_ycomp[(int)findex-1] = -1; +} + +static void pdp_opencv_floodfill_connectivity(t_pdp_opencv_floodfill *x, t_floatarg fconnectivity ) +{ + int i; + + if ( ( fconnectivity != 4.0 ) && ( fconnectivity != 8.0 ) ) + { + return; + } + + x->x_connectivity = (int)fconnectivity; +} + +static void pdp_opencv_floodfill_clear(t_pdp_opencv_floodfill *x ) +{ + int i; + + for ( i=0; i<MAX_COMPONENTS; i++) + { + x->x_xcomp[i] = -1; + x->x_ycomp[i] = -1; + } +} + +t_class *pdp_opencv_floodfill_class; void *pdp_opencv_floodfill_new(t_floatarg f) { - int i; + int i; t_pdp_opencv_floodfill *x = (t_pdp_opencv_floodfill *)pd_new(pdp_opencv_floodfill_class); inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("lo_diff")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("up_diff")); x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); + x->x_outlet1 = outlet_new(&x->x_obj, &s_anything); x->x_packet0 = -1; x->x_packet1 = -1; @@ -290,21 +357,23 @@ void *pdp_opencv_floodfill_new(t_floatarg f) x->x_infosok = 0; - x->ffill_case = 1; - x->lo_diff = 20; - x->up_diff = 20; - x->connectivity = 4; - x->is_color = 1; - x->is_mask = 0; - x->new_mask_val = 255; + x->x_lo = 20; + x->x_up = 20; + x->x_connectivity = 4; + x->x_color = 1; + + for ( i=0; i<MAX_COMPONENTS; i++) + { + x->x_xcomp[i] = -1; + x->x_ycomp[i] = -1; + x->x_r[i] = rand() & 255; + x->x_g[i] = rand() & 255; + x->x_b[i] = rand() & 255; + } - x->color_img0 = cvCreateImage( cvSize(x->x_width,x->x_height), 8, 3 ); x->color_img = cvCreateImage( cvSize(x->x_width,x->x_height), 8, 3 ); - x->mask = cvCreateImage( cvSize(x->x_width + 2, x->x_height + 2), 8, 1 ); - x->gray_img0 = cvCreateImage( cvSize(x->x_width, x->x_height), 8, 1 ); x->gray_img = cvCreateImage( cvSize(x->x_width, x->x_height), 8, 1 ); - return (void *)x; } @@ -318,13 +387,19 @@ extern "C" void pdp_opencv_floodfill_setup(void) { - post( " pdp_opencv_floodfill"); + post( " pdp_opencv_floodfill"); pdp_opencv_floodfill_class = class_new(gensym("pdp_opencv_floodfill"), (t_newmethod)pdp_opencv_floodfill_new, - (t_method)pdp_opencv_floodfill_free, sizeof(t_pdp_opencv_floodfill), 0, A_DEFFLOAT, A_NULL); + (t_method)pdp_opencv_floodfill_free, sizeof(t_pdp_opencv_floodfill), 0, A_DEFFLOAT, A_NULL); class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL); - //class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_up_diff, gensym("up_diff"), A_FLOAT, A_NULL ); - //class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_lo_diff, gensym("lo_diff"), A_FLOAT, A_NULL ); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_color, gensym("color"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_fillcolor, gensym("fillcolor"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_mark, gensym("mark"), A_DEFFLOAT, A_DEFFLOAT, A_NULL); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_delete, gensym("delete"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_connectivity, gensym("connectivity"), A_DEFFLOAT, A_NULL); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_clear, gensym("clear"), A_NULL); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_up_diff, gensym("up_diff"), A_FLOAT, A_NULL ); + class_addmethod(pdp_opencv_floodfill_class, (t_method)pdp_opencv_floodfill_lo_diff, gensym("lo_diff"), A_FLOAT, A_NULL ); } |