Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

graphSegmentation_Filter.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission :
00003         Realtime Vision Processing System
00004 
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008 
00009     This file is part of Phission.
00010 
00011     Phission is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU Lesser General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     Phission is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public License
00022     along with Phission; if not, write to the Free Software
00023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025  ---------------------------------------------------------------------------*/
00026 #ifdef HAVE_CONFIG_H
00027     #include <phissionconfig.h>
00028 #endif
00029 
00030 #include <phStandard.h>
00031 
00032 #include <graphSegmentation_Filter.h>
00033 
00034 #include <algorithm>
00035 #include <cmath>
00036 
00037 #include <phError.h>
00038 #include <phMemory.h>
00039 #include <phPrint.h>
00040 
00041 #define phGRAPH_USE_RANDOM_COLORS() 0
00042 
00043 /* ---------------------------------------------------------------------------
00044  * Code in this file from "Efficient Graph Based Segmentation" source code
00045  *
00046  *  graphSegmentation_Filter::SegmentImage
00047  *  graphSegmentation_Filter::SegmentGraph
00048  *  graphSegmentation_Filter::ProcessGraph
00049  *  
00050  *  dist_rgb
00051  *
00052  *  class phUniverse
00053  *
00054  *  bool operator<(const ph_edge &a, const ph_edge &b) 
00055  *
00056  * 05/27/2007
00057  *  Code was edited by Philip Thoren (pthoren@cs.uml.edu)
00058  *  
00059  *  Formatted to my own crazy standards and optimized it for uint8_t images.
00060  *
00061  * ---------------------------------------------------------------------------
00062  * 
00063  * Copyright (C) 2006 Pedro Felzenszwalb
00064  * 
00065  * This program is free software; you can redistribute it and/or modify
00066  * it under the terms of the GNU General Public License as published by
00067  * the Free Software Foundation; either version 2 of the License, or
00068  * (at your option) any later version.
00069  * 
00070  * This program is distributed in the hope that it will be useful,
00071  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00072  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00073  * GNU General Public License for more details.
00074  * 
00075  * You should have received a copy of the GNU General Public License
00076  * along with this program; if not, write to the Free Software
00077  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00078  */
00079 /* ------------------------------------------------------------------------ */
00080 phUniverse::phUniverse( uint32_t elements ) 
00081 {
00082     phFUNCTION("phUniverse::phUniverse")
00083     uint32_t i = 0;
00084     
00085     this->m_elts        = NULL;
00086     this->m_elts_size   = 0;
00087 
00088     if (elements > 0)
00089     {
00090         phDALLOC(this->m_elts,
00091                  this->m_elts_size,
00092                  elements,
00093                  ph_uni_elt);
00094         for (i = 0; i < elements; i++) 
00095         {
00096             this->m_elts[i].rank = 0;
00097             this->m_elts[i].size = 1;
00098             this->m_elts[i].p = i;
00099         }
00100     }
00101 
00102     this->m_elt_count   = elements;
00103     this->m_num         = elements;
00104 
00105 error:
00106     return;
00107 }
00108 
00109 /* ------------------------------------------------------------------------ */
00110 phUniverse::~phUniverse() 
00111 {
00112     phFree(this->m_elts);
00113     this->m_elts_size   = 0;
00114     this->m_elt_count   = 0;
00115     this->m_num         = 0;
00116 }
00117 
00118 /* ------------------------------------------------------------------------ */
00119 void phUniverse::resize( uint32_t elements )
00120 {
00121     phFUNCTION("phUniverse::resize")
00122     if (elements > 0)
00123     {
00124         uint32_t i = 0;
00125 
00126         phDALLOC(this->m_elts,
00127                 this->m_elts_size,
00128                 elements,
00129                 ph_uni_elt);
00130         for (i = 0; i < elements; i++) 
00131         {
00132             this->m_elts[i].rank = 0;
00133             this->m_elts[i].size = 1;
00134             this->m_elts[i].p = i;
00135         }
00136 
00137         this->m_elt_count   = elements;
00138         this->m_num         = elements;
00139     }
00140     
00141     return;
00142 error:
00143     this->m_num         = 0;
00144     this->m_elt_count   = 0;
00145     this->m_elts_size   = 0;
00146 }
00147 
00148 /* ------------------------------------------------------------------------ */
00149 int phUniverse::find(int x) 
00150 {
00151     int y = x;
00152     
00153     while (y != this->m_elts[y].p)
00154     {
00155         y = this->m_elts[y].p;
00156     }
00157     
00158     this->m_elts[x].p = y;
00159     
00160     return y;
00161 }
00162 
00163 /* ------------------------------------------------------------------------ */
00164 int phUniverse::size(int x) const 
00165 { 
00166     return this->m_elts[x].size; 
00167 }
00168 
00169 /* ------------------------------------------------------------------------ */
00170 uint32_t phUniverse::num_sets() const 
00171 { 
00172     return this->m_num; 
00173 }
00174 
00175 /* ------------------------------------------------------------------------ */
00176 void phUniverse::join(int x, int y)
00177 {
00178     ph_uni_elt *elts = this->m_elts;
00179     
00180     /* compare the rank of x and y... */
00181     /* if the rank of x is greater than y, we'll merge y into x */
00182     if (elts[x].rank > elts[y].rank) 
00183     {
00184         /* Set the new parent of y */
00185         elts[y].p = x;
00186         /* Add the size of component y to new parent x */
00187         elts[x].size += elts[y].size;
00188     }
00189     else 
00190     {
00191         /* Set the new parent of x to y */
00192         elts[x].p = y;
00193         /* Add the size of component x to new parent y */
00194         elts[y].size += elts[x].size;
00195         /* increase parent y's rank */
00196         if (elts[x].rank == elts[y].rank)
00197             elts[y].rank++;
00198     }
00199     
00200     if (this->m_num > 0)    this->m_num--;
00201 }
00202 
00203 /* ---------------------------------------------------------------------- */
00204 typedef float (*phDistFunctionType)( const uint8_t *ptr1,
00205                                      const uint8_t *ptr2 );
00206 
00207 /* ---------------------------------------------------------------------- */
00208 float dist_grey8(const uint8_t *ptr1,
00209                  const uint8_t *ptr2 )
00210 {
00211     return ((float)ptr1[0]-(float)ptr2[0]);
00212 }
00213 
00214 /* ---------------------------------------------------------------------- */
00215 float dist_hsv24(const uint8_t *ptr1,
00216                  const uint8_t *ptr2 )
00217 {
00218     float hd = ((float)ptr1[0]-(float)ptr2[0]);
00219     float sd = ((float)ptr1[1]-(float)ptr2[1]);
00220     float vd = ((float)ptr1[2]-(float)ptr2[2]);
00221     return sqrt((hd*hd)+(sd*sd)+(vd*vd));
00222 }
00223 
00224 /* ---------------------------------------------------------------------- */
00225 float dist_rgb24(const uint8_t *ptr1,
00226                  const uint8_t *ptr2 )
00227 {
00228     float rd = ((float)ptr1[0]-(float)ptr2[0]);
00229     float gd = ((float)ptr1[1]-(float)ptr2[1]);
00230     float bd = ((float)ptr1[2]-(float)ptr2[2]);
00231     return sqrt((rd*rd)+(gd*gd)+(bd*bd));
00232 }
00233 
00234 /* ---------------------------------------------------------------------- */
00235 graphSegmentation_Filter::graphSegmentation_Filter( uint32_t    min_size,
00236                                                     uint32_t    threshold,
00237                                                     int         color_blobs ):
00238     phFilter("graphSegmentation_Filter")
00239 
00240 {
00241     //phImageValidFormatMask;
00242     this->m_format = phImageRGB24 | phImageHSV24 | phImageGREY8;
00243 
00244     this->m_num_edges   = 0;
00245     
00246     this->m_edges       = NULL;
00247     this->m_edges_size  = 0;
00248     
00249     this->m_output      = NULL;
00250     this->m_output_size = 0;
00251 
00252     this->m_thresholds      = NULL;
00253     this->m_thresholds_size = 0;
00254 
00255     this->m_universe    = new phUniverse(0);
00256 
00257     this->m_min_size    = min_size;
00258     this->m_thresh      = threshold;
00259     this->m_color_blobs = color_blobs;
00260 
00261     this->m_last_thresh = threshold == 0 ? 1 : 0;
00262     this->m_last_thresholds_size = 0;
00263 }
00264 
00265 /* ---------------------------------------------------------------------- */
00266 graphSegmentation_Filter::~graphSegmentation_Filter()
00267 {
00268     phFree(this->m_edges);
00269     this->m_edges_size = 0;
00270     phFree(this->m_output);
00271     this->m_output_size = 0;
00272     phFree(this->m_thresholds);
00273     this->m_thresholds_size = 0;
00274     phDelete(this->m_universe);
00275 }
00276 
00277 /* ------------------------------------------------------------------------ */
00278 phFilter *graphSegmentation_Filter::cloneFilter()
00279 {
00280     phFUNCTION("graphSegmentation_Filter::cloneFilter")
00281     int locked = 0;
00282     graphSegmentation_Filter *graphSegmentation = new graphSegmentation_Filter();
00283     
00284     phTHIS_LOOSE_LOCK(locked);
00285     
00286     /* graphSegmentation->set(this->m_value); */
00287 
00288     phTHIS_LOOSE_UNLOCK(locked);
00289 
00290     return (phFilter *)graphSegmentation;
00291 }
00292 
00293 /* ---------------------------------------------------------------------- */
00294 int graphSegmentation_Filter::set( uint32_t   min_size,
00295                                    uint32_t   threshold,
00296                                    int        color_blobs )
00297 {
00298     phFUNCTION("graphSegmentation_Filter::set")
00299     int locked = 0;
00300     phTHIS_LOOSE_LOCK(locked);
00301     
00302     this->m_min_size    = min_size;
00303     this->m_thresh      = threshold;
00304     this->m_color_blobs = color_blobs;
00305 
00306     phTHIS_LOOSE_UNLOCK(locked);
00307     
00308     return phSUCCESS;
00309 }
00310 
00311 /* ---------------------------------------------------------------------- */
00312 int graphSegmentation_Filter::setMinSize( uint32_t min_size )
00313 {
00314     phFUNCTION("graphSegmentation_Filter::set")
00315     int locked = 0;
00316     phTHIS_LOOSE_LOCK(locked);
00317     
00318     this->m_min_size = min_size;
00319 
00320     phTHIS_LOOSE_UNLOCK(locked);
00321     
00322     return phSUCCESS;
00323 }
00324 
00325 /* ---------------------------------------------------------------------- */
00326 int graphSegmentation_Filter::setThreshold( uint32_t threshold )
00327 {
00328     phFUNCTION("graphSegmentation_Filter::set")
00329     int locked = 0;
00330     phTHIS_LOOSE_LOCK(locked);
00331     
00332     this->m_thresh = threshold;
00333 
00334     phTHIS_LOOSE_UNLOCK(locked);
00335     
00336     return phSUCCESS;
00337 }
00338 
00339 /* ---------------------------------------------------------------------- */
00340 int graphSegmentation_Filter::setColorBlobs( int color_blobs )
00341 {
00342     phFUNCTION("graphSegmentation_Filter::set")
00343     int locked = 0;
00344     phTHIS_LOOSE_LOCK(locked);
00345     
00346     this->m_color_blobs = color_blobs;
00347 
00348     phTHIS_LOOSE_UNLOCK(locked);
00349     
00350     return phSUCCESS;
00351 }
00352 /* ---------------------------------------------------------------------- */
00353 uint32_t graphSegmentation_Filter::getMinSize()
00354 {
00355     phFUNCTION("graphSegmentation_Filter::set")
00356     int locked = 0;
00357     uint32_t min_size = 0;
00358 
00359     phTHIS_LOOSE_LOCK(locked);
00360     
00361     min_size = this->m_min_size;
00362 
00363     phTHIS_LOOSE_UNLOCK(locked);
00364     
00365     return min_size;
00366 
00367 }
00368 
00369 /* ---------------------------------------------------------------------- */
00370 uint32_t graphSegmentation_Filter::getThreshold()
00371 {
00372     phFUNCTION("graphSegmentation_Filter::set")
00373     int locked = 0;
00374     uint32_t threshold = 0;
00375 
00376     phTHIS_LOOSE_LOCK(locked);
00377 
00378     threshold = this->m_thresh;
00379 
00380     phTHIS_LOOSE_UNLOCK(locked);
00381     
00382     return threshold;
00383 
00384 }
00385  
00386 /* ---------------------------------------------------------------------- */
00387 int graphSegmentation_Filter::getColorBlobs()
00388 {
00389     phFUNCTION("graphSegmentation_Filter::set")
00390     int locked = 0;
00391     int color_blobs = 0;
00392 
00393     phTHIS_LOOSE_LOCK(locked);
00394 
00395     color_blobs = this->m_color_blobs;
00396 
00397     phTHIS_LOOSE_UNLOCK(locked);
00398     
00399     return color_blobs;
00400 }
00401  
00402 /* ---------------------------------------------------------------------- */
00403 /* This algorithm was adapted from the "Efficient Graph Based Segmentation"
00404  * source code at:
00405  *                   http://people.cs.uchicago.edu/~pff/segment/
00406  *
00407  * It has been changed to work with a uint8_t buffer and use pointer arithmetic
00408  * to try and speed up the algorithm.
00409  *
00410  */
00411 void graphSegmentation_Filter::SegmentImage( )
00412 {
00413     ph_edge    *cur_edge = NULL;
00414     uint32_t num_edges= 0;
00415 
00416     phDistFunctionType distpixels = NULL;
00417     
00418           uint8_t *ptr= this->Image;
00419     const uint32_t w  = this->width;
00420     const uint32_t h  = this->height;
00421     const uint32_t d  = this->depth;
00422 
00423     register uint32_t x  = 0;
00424     register uint32_t y  = 0;
00425     register int a  = 0;
00426     //register int b  = 0;
00427     
00428     uint8_t *ptr_cur        = (uint8_t *)ptr;
00429     uint8_t *ptr_right      = NULL;
00430     uint8_t *ptr_down       = NULL;
00431     uint8_t *ptr_down_right = NULL;
00432     uint8_t *ptr_up_right   = NULL;
00433 
00434     switch (format)
00435     {
00436         case phImageRGB24:
00437             distpixels = dist_rgb24;
00438         break;
00439         case phImageHSV24:
00440             distpixels = dist_hsv24;
00441         break;
00442         case phImageGREY8:
00443             distpixels = dist_grey8;
00444         break;
00445     }
00446     
00447     this->m_num_edges   = 0;
00448     cur_edge            = this->m_edges;
00449 
00450     for (y = 0; y < h; y++)
00451     {
00452         ptr_right = &(ptr_cur[d]);
00453         if (y < (h-1))
00454         {
00455             ptr_down        = &(ptr_cur[w*d]);
00456             ptr_down_right  = &(ptr_cur[(w+1)*d]);
00457         }
00458         if (y > 0)
00459         {
00460             ptr_up_right = &(ptr[((((y-1) * w)+1) * d)]);
00461         }
00462         a = y * w;
00463         for (x = 0; x < w; x++, ptr_cur += d, a++)
00464         {
00465             /* right */
00466             if (x < w-1)
00467             {
00468                 cur_edge->a = a;
00469                 cur_edge->b = y * w + (x+1);
00470                 cur_edge->w = (distpixels)(ptr_cur, ptr_right);
00471                 
00472                 cur_edge++;
00473                 num_edges++;
00474                 ptr_right += d;
00475             }
00476 
00477             /* down */
00478             if (y < h-1)
00479             {
00480                 cur_edge->a = a;
00481                 cur_edge->b = (y+1) * w + x;
00482                 cur_edge->w = (distpixels)(ptr_cur, ptr_down);
00483                 
00484                 cur_edge++;
00485                 num_edges++;
00486                 ptr_down += d;
00487             }
00488 
00489             if ((x < w-1) && (y < h-1))
00490             {
00491                 cur_edge->a = a;
00492                 cur_edge->b = (y+1) * w + (x+1);
00493                 cur_edge->w = (distpixels)(ptr_cur, ptr_down_right);
00494 
00495                 cur_edge++;
00496                 num_edges++;
00497                 ptr_down_right += d;
00498             }
00499 
00500             if ((x < w-1) && (y > 0))
00501             {
00502                 cur_edge->a = a;
00503                 cur_edge->b = (y-1) * w + (x+1);
00504                 cur_edge->w = (distpixels)(ptr_cur, ptr_up_right);
00505 
00506                 cur_edge++;
00507                 num_edges++;
00508                 ptr_up_right += d;
00509             }
00510         }
00511     }
00512 
00513     this->m_num_edges   = num_edges;
00514 }
00515 
00516 /* ---------------------------------------------------------------------- */
00517 bool operator<(const ph_edge &a, const ph_edge &b) 
00518 {
00519     return a.w < b.w;
00520 }
00521 
00522 #define ph_GRAPHTHRESHOLD(size, c) (c/size)
00523 
00524 /* ---------------------------------------------------------------------- */
00525 int graphSegmentation_Filter::SegmentGraph()
00526 { 
00527     phFUNCTION("graphSegmentation_Filter::SegmentGraph")
00528 
00529     const uint32_t      num_vertices= (this->width * this->height);
00530     register uint32_t   i = 0;
00531     register int        a = 0;
00532     register int        b = 0;
00533     
00534     /* sort edges by weight */
00535     std::sort(this->m_edges, this->m_edges + this->m_num_edges);
00536     
00537     /* make a disjoint-set forest */
00538     this->m_universe->resize(num_vertices);
00539 
00540     /* init / alloc thresholds */
00541     phDALLOC(this->m_thresholds,
00542              this->m_thresholds_size,
00543              num_vertices,
00544              float);
00545     
00546     if ((this->m_thresh             != this->m_last_thresh          ) ||
00547         (this->m_thresholds_size    != this->m_last_thresholds_size ))
00548     {
00549         for (i = 0; i < num_vertices; i++)
00550         {
00551             this->m_thresholds[i] = ph_GRAPHTHRESHOLD(1,this->m_thresh);
00552         }
00553         this->m_last_thresh             = this->m_thresh;
00554         this->m_last_thresholds_size    = this->m_thresholds_size;
00555     }
00556 
00557     /* for each ph_edge, in non-decreasing weight order... */
00558     for (i = 0; i < this->m_num_edges; i++) 
00559     {
00560         ph_edge *pedge = &(this->m_edges[i]);
00561 
00562         /* components connected by this ph_edge */
00563         a = this->m_universe->find(pedge->a);
00564         b = this->m_universe->find(pedge->b);
00565         if (a != b) 
00566         {
00567             if ((pedge->w <= this->m_thresholds[a]) && 
00568                 (pedge->w <= this->m_thresholds[b])) 
00569             {
00570                 this->m_universe->join(a, b);
00571                 
00572                 a = this->m_universe->find(a);
00573                 
00574                 this->m_thresholds[a] = pedge->w + 
00575                     ph_GRAPHTHRESHOLD(this->m_universe->size(a),
00576                                       this->m_thresh);
00577             }
00578         }
00579     }
00580 
00581     return phSUCCESS;
00582 error:
00583     return phFAIL;
00584 }
00585 
00586 /* ---------------------------------------------------------------------- */
00587 /* 
00588  * This is the code that actually segments the graph from the output 
00589  * generated in the graphSegmentation_Filter::SegmentImage method.
00590  *
00591  * This is also take from the original segment_image function from the
00592  * "Efficient Graph Based Segmentation" source code.
00593  *
00594  */
00595 void graphSegmentation_Filter::ProcessGraph( )
00596 {
00597     register uint32_t       i           = 0;
00598     register uint32_t       y;
00599     uint8_t                *outptr      = this->m_output;
00600     uint32_t                d           = this->depth;
00601     register int            a           = 0;
00602     register int            b           = 0;
00603     const uint32_t          lim         = this->width * this->height;
00604 
00605     phUniverse             *u           = this->m_universe;
00606 
00607     // post process small components
00608     for (i = 0; i < this->m_num_edges; i++)
00609     {
00610         a = u->find(m_edges[i].a);
00611         b = u->find(m_edges[i].b);
00612         if ((a != b) && 
00613             ((u->size(a) < this->m_min_size) || 
00614              (u->size(b) < this->m_min_size)))
00615         {
00616             u->join(a, b);
00617         }
00618     }
00619     
00620     #if phGRAPH_USE_RANDOM_COLORS()
00621     uint8_t *colors = new uint8_t[w*h*d];
00622     uint8_t *col_ptr= colors;
00623     for (y = 0; y < lim; y++ )
00624     {
00625         for (x = 0; x < d; x++ )
00626         {
00627             colors[x+y] = (uint8_t)random();
00628         }
00629     }
00630     #endif
00631 
00632     /* Edited from the original code that colors the blobs in that this 
00633      * colors the image for an RGB image represented by a uint8_t buffer */
00634     if (this->m_color_blobs)
00635     {
00636         for (y = 0; y < lim; y++, outptr += d )
00637         {
00638             phMemcpy(outptr,&(this->Image[u->find(y) * d]),d);
00639 
00640             #if phGRAPH_USE_RANDOM_COLORS()
00641             comp = u->find(y);
00642             phMemcpy(outptr,&(colors[comp*d]),d);
00643             #endif
00644         }
00645     }
00646 
00647     #if phGRAPH_USE_RANDOM_COLORS()
00648     delete [] colors;
00649     #endif
00650 }
00651 
00652 /* ---------------------------------------------------------------------- */
00653 int graphSegmentation_Filter::filter()
00654 {
00655     phFUNCTION("graphSegmentation_Filter::filter")
00656    
00657     /* defined before being called:
00658      *  width, height, depth, format, Image
00659      */
00660     
00661     /* Begin Filter */
00662     phDALLOC(this->m_output,this->m_output_size,
00663              this->width*this->height*this->depth,
00664              uint8_t);
00665 
00666     phDALLOC(this->m_edges,this->m_edges_size,
00667              this->width*this->height*4,
00668              ph_edge)
00669 
00670     /* segment the image : populates this->m_edges */
00671     this->SegmentImage( );
00672     /* segment : Populates this->m_universe */
00673     this->SegmentGraph();
00674     /* process the graph : colors the image */
00675     this->ProcessGraph( );
00676 
00677     this->m_workspaceImage->setImage( this->width,
00678                                       this->height,
00679                                       this->format,
00680                                       0,
00681                                       this->m_output );
00682     
00683     /* End Filter */
00684     
00685     /* make sure to free up any space here, not including Image */
00686     
00687     return phSUCCESS;
00688     
00689 error:
00690     /* make sure to free up any space here, not including Image */
00691     
00692     return phFAIL;
00693     
00694 }
00695 
00696 




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:09 2007 for phission by  doxygen 1.4.4