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

phblob.c

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 <ImageGfx.h>
00033 #include <ImageUtil.h>
00034 
00035 #include <phQuicksort.h>
00036 #include <phblob.h>
00037 
00038 #include <phError.h>
00039 #include <phMemory.h>
00040 #include <phPrint.h>
00041 
00042 /* ---------------------------------------------------------------------- */
00043 #ifdef __cplusplus
00044 extern "C" {
00045 #endif
00046 
00047 /* ---------------------------------------------------------------------- */
00048 __inline__ phblob_line_segment *phblob_get_segment( const int32_t index,
00049                                                     phblob_line_segment *const line_array);
00050 
00051 __inline__ phblob_line_segment *phblob_get_next_segment(const phblob_line_segment *const seg,
00052                                                               phblob_line_segment *const line_array);
00053 
00054 __inline__ phblob *phblob_get_next_blob(const phblob *const blob,
00055                                               phblob *const blobs);
00056 
00057 __inline__ int32_t phblob_compare   ( const void *_one, const void *_two );
00058 
00059 /* ---------------------------------------------------------------------- */
00060 __inline__ phblob_line_segment *phblob_get_segment( const int32_t index,
00061                                                     phblob_line_segment *const line_array)
00062 {
00063     /* Get the line segment by indexing into the pool */
00064     if (index >= 0) 
00065         return &(line_array[index]);
00066     else 
00067         return NULL;
00068 }
00069 /* ---------------------------------------------------------------------- */
00070 __inline__ phblob_line_segment *phblob_get_next_segment(const phblob_line_segment *const seg,
00071                                                               phblob_line_segment *const line_array )
00072 {
00073     int32_t next_index = seg->next_index;
00074     /* Get the line segment by indexing into the pool */
00075     if (next_index >= 0) 
00076         return &(line_array[next_index]);
00077     else 
00078         return NULL;
00079 }
00080  
00081 /* ---------------------------------------------------------------------- */
00082 __inline__ phblob *phblob_get_next_blob( const phblob *const blob,
00083                                                phblob *const blobs )
00084 {
00085     int32_t next_index = blob->next_index;
00086     /* Get the line segment by indexing into the pool */
00087     if (next_index >= 0) 
00088         return &(blobs[next_index]);
00089     else 
00090         return NULL;
00091 }
00092 
00093 /* ---------------------------------------------------------------------- */
00094 int phblob_data_new ( phblob_data **data )
00095 {
00096     phFUNCTION("phblob_data_new")
00097 
00098     if (data == NULL) return phFAIL;
00099 
00100     (*data) = (phblob_data *)phCalloc(1,sizeof(phblob_data));
00101     phCHECK_PTR(*data,"phCalloc", "phCalloc failed.");
00102     
00103     return phSUCCESS;
00104 error:
00105     return phFAIL;
00106 }
00107 
00108 /* ---------------------------------------------------------------------- */
00109 int phblob_data_init( phblob_data *data  )
00110 {
00111     phFUNCTION("phblob_data_init")
00112 
00113     if (data == NULL) return phFAIL;
00114 
00115     phMemset(data,0,sizeof(phblob_data));
00116     
00117     return phSUCCESS;
00118 }
00119 
00120 /* ---------------------------------------------------------------------- */
00121 int phblob_data_reset( phblob_data *data )
00122 {
00123     if (data == NULL) return phFAIL;
00124 
00125     phFree(data->lines);
00126     phFree(data->rows);
00127     phFree(data->rowindex);
00128     phFree(data->blobs);
00129     phMemset(data,0,sizeof(phblob_data));
00130     
00131     return phSUCCESS;
00132 }
00133 
00134 /* ---------------------------------------------------------------------- */
00135 int phblob_data_free( phblob_data **data )
00136 {
00137     phFUNCTION("phblob_data_free")
00138 
00139     if (data == NULL) return phFAIL;
00140 
00141     rc = phblob_data_reset( *data );
00142     phCHECK_RC(rc,NULL,"phblob_data_reset");
00143     
00144     phFree(*data);
00145     
00146     return phSUCCESS;
00147 error:
00148     return phFAIL;
00149 }
00150 
00151 /* ---------------------------------------------------------------------- */
00152 int phblob_data_copy( phblob_data *in,
00153                       phblob_data *out)
00154 {
00155     phFUNCTION("phblob_data_copy")
00156 
00157     #if 0
00158     int32_t i = 0;
00159     int32_t index = 0;
00160     
00161     int32_t             total_lines     = 0;
00162     phblob_line_segment *line_array     = NULL;
00163     int32_t             total_rows      = 0;
00164     phblob_line_segment **row_ptr_array = NULL;
00165     int32_t             *row_index_array= NULL;
00166     int32_t             total_blobs     = 0;
00167     phblob              *blob_array     = NULL;
00168     #endif
00169         
00170     #if 0
00171     /*----------------------------------------------------------------------*/
00172     /* Copy the line information and relink the pointers too */
00173     /*----------------------------------------------------------------------*/
00174     if (in->nlines > 0)
00175     {
00176         phDALLOC_RESIZE(out->lines,
00177                         out->lines_size,
00178                         in->nlines,
00179                         phblob_line_segment );
00180     }
00181     
00182     out->nlines = in->nlines;
00183     
00184     if ((in->lines != NULL) && (in->nlines > 0))
00185     {
00186         phMemcpy(out->lines, in->lines, out->lines_size);
00187         
00188         /* relink the line segment ptrs to the addresses for the 
00189          * new array */
00190         rc = phblob_data_relink_line_ptrs( out );
00191         phPRINT_RC(rc,NULL,"relink_line_ptrs");
00192     }
00193     
00194     /*----------------------------------------------------------------------*/
00195     /* Copy the row data */
00196     /*----------------------------------------------------------------------*/
00197     if (in->nrows > 0)
00198     {
00199         phDALLOC_RESIZE(out->rows,     out->rows_size,
00200                         in->nrows,     phblob_line_segment *);
00201         phDALLOC_RESIZE(out->rowindex, out->rowindex_size,
00202                         in->nrows,     int32_t);
00203     }
00204     
00205     out->nrows = in->nrows;
00206     
00207     if ((in->rowindex != NULL) && (out->nrows > 0))
00208     {
00209         phMemcpy(out->rowindex, in->rowindex, out->rowindex_size);
00210         
00211         /* Set the pointers to the appropriate ptr into the
00212          * line array */
00213         for (i = 0; i < in->nrows; i++)
00214         {
00215             index = out->rowindex[i];
00216             
00217             /* -1 == invalid */
00218             if (index >= 0) out->rows[i] = &(out->lines[index]);
00219         }
00220     }
00221     #endif
00222     /*----------------------------------------------------------------------*/
00223     /* Copy the blob data */
00224     /*----------------------------------------------------------------------*/
00225     if (in->nblobs > 0)
00226     {
00227         phDALLOC_RESIZE(out->blobs,
00228                         out->blobs_size,
00229                         in->nblobs,
00230                         phblob );
00231     }
00232 
00233     out->nblobs = in->nblobs;
00234 
00235     if ((in->blobs != NULL) && (out->nblobs > 0))
00236     {
00237         phMemcpy(out->blobs, in->blobs, out->blobs_size );
00238         
00239         #if 0
00240         /* relink the ptrs to the line segments */
00241         for (i = 0; i < in->nblobs; i++ )
00242         {
00243             index = out->blobs[i].last_segment_index;
00244             if (index >= 0)
00245                 out->blobs[i].last_segment =
00246                     &(out->lines[index]);
00247             
00248             index = out->blobs[i].first_segment_index;
00249             if (index >= 0)
00250                 out->blobs[i].first_segment =
00251                     &(out->lines[index]);
00252             
00253             index = out->blobs[i].next_index;
00254             if (index >= 0)
00255                 out->blobs[i].next = &(out->blobs[index]);
00256             
00257             index = out->blobs[i].previous_index;
00258             if (index >= 0)
00259                 out->blobs[i].previous = &(out->blobs[index]);
00260         }
00261         #endif
00262     }
00263 
00264     return phSUCCESS;
00265 error:
00266     return phFAIL;
00267 }
00268 
00269 /* ---------------------------------------------------------------------- */
00270 int phblob_data_relink_line_ptrs( phblob_data *data )
00271 {
00272     uint32_t            i       = 0;
00273     uint32_t            nlines  = 0;
00274     uint32_t            j       = 0;
00275     int32_t             index   = 0;
00276     phblob_line_segment *lines  = NULL;
00277 
00278     if (data == NULL) return phFAIL;
00279 
00280     lines   = data->lines;
00281     nlines  = data->nlines;
00282     
00283     for (i = 0; i < nlines; i++ )
00284     {
00285         index = lines[i].next_index;
00286         if (index >= 0)
00287             lines[i].next = &(lines[index]);
00288         
00289         index = lines[i].previous_index;
00290         if (index >= 0)
00291             lines[i].previous = &(lines[index]);
00292         
00293         index = lines[i].first_up_index;
00294         if (index >= 0)
00295             lines[i].first_up = &(lines[index]);
00296         
00297         index = lines[i].first_down_index;
00298         if (index >= 0)
00299             lines[i].first_down = &(lines[index]);
00300         
00301         index = lines[i].last_up_index;
00302         if (index >= 0)
00303             lines[i].last_up = &(lines[index]);
00304         
00305         index = lines[i].last_down_index;
00306         if (index >= 0)
00307             lines[i].last_down = &(lines[index]);
00308         
00309         index = lines[i].left_index;
00310         if (index >= 0)
00311             lines[i].left = &(lines[index]);
00312         
00313         index = lines[i].right_index;
00314         if (index >= 0)
00315             lines[i].right = &(lines[index]);
00316 
00317         for (j = 0; j < phSEGMENT_CONNECTION_COUNT; j++)
00318         {
00319             index = lines[i].connection_index[j];
00320             if (index >= 0)
00321                 lines[i].connection[j] = &(lines[index]);
00322         }
00323     }
00324 
00325     return phSUCCESS;
00326 }
00327 
00328 /* ---------------------------------------------------------------------- */
00329 int phblob_find_line_segments_color(phblob_args *args,
00330                                     phblob_data *data )
00331 {
00332     phFUNCTION("phblob_find_line_segments_color")
00333 
00334     uint32_t i = 0;
00335     uint32_t j = 0;
00336     
00337     /* make local copies of these */
00338     uint8_t             *imgptr     = *(args->imgptr);
00339     uint32_t            width       = args->width;
00340     uint32_t            height      = args->height;
00341     uint8_t             depth       = args->depth;
00342     /* uint32_t            format      = args->format; */
00343     phColor             *incolors   = *args->incolor;
00344     phColor             *thresholds = *args->threshold;
00345     volatile uint32_t   nColors     = *args->nColors;
00346     phColor             incolor;
00347     phColor             threshold;
00348 
00349     phblob_line_segment *line_array          = (data->lines);
00350     uint32_t            line_array_size      = (data->lines_size);
00351     phblob_line_segment **row_ptr_array      = (data->rows);
00352     uint32_t            row_ptr_array_size   = (data->rows_size);
00353     int32_t             *row_index_array     = (data->rowindex);
00354     uint32_t            row_index_array_size = (data->rowindex_size);
00355  
00356 
00357     /* Used for comparison in the search for a color and
00358      * whether it's within the giving threshold. */
00359     int32_t     diff[phCOLOR_MAXBYTES]  = {0}; 
00360     int32_t     diff_temp_1             = 0;
00361     int32_t     diff_temp_2             = 0;
00362     uint32_t    color_matches           = 0;
00363     uint32_t    matched                 = 0;
00364     uint32_t    k                       = 0;
00365     uint32_t    l                       = 0;
00366     /* max elements for a color */
00367     uint32_t    max_compare = 1;
00368    
00369     /* Used in line segment discovery */
00370     int32_t             larray_index        = 0;
00371     phblob_line_segment *current_segment    = NULL;
00372     phblob_line_segment *last_segment       = NULL;
00373 
00374     uint32_t half_npixels = ((width * height) + ((width * height) % 2)) / 2;
00375 
00376     /* 0.) Make sure we have enough memory and all variables are
00377      * initialized */
00378   
00379     /* A.) allocate the max number of segments possible for the image:
00380      * 
00381      * i.) the maximum number of lines is when every other pixel in a row
00382      * matches and is ((width * height) / 2) line segments,
00383      *  
00384      * ii.) the minimum number of lines when all the pixels match is height,
00385      */
00386     phDALLOC(line_array,
00387                   line_array_size,
00388                   half_npixels,
00389                   phblob_line_segment);
00390 
00391     /* b.) row_ptr_array is used to store line segments within a row of the image */
00392     phDALLOC(row_ptr_array,
00393              row_ptr_array_size,
00394              height,
00395              phblob_line_segment *);
00396 
00397     /* c.) row_index_array stores the index into the row_ptr_array array for 
00398      * the user can since a phMemcpy of the row_ptr_array/line_array 
00399      * invalidates the pointer values */
00400     phDALLOC(row_index_array,
00401              row_index_array_size,
00402              height,
00403              int32_t);
00404 
00405     if (incolors != NULL)
00406         max_compare = phColorDepth[incolors[0].type];
00407     
00408     for (i = 0; (i < height) && (max_compare > 0); i++)
00409     {
00410         /* -1 is the value used to denote no index */
00411         row_index_array[i] = -1;
00412         
00413         /* reset and initialize all the line variables */
00414         current_segment = NULL;
00415         last_segment = NULL;
00416         
00417         for (j = 0; j < width; j++)
00418         {
00419             /* just in case there are no colors being checked */
00420             for ( l = 0; (l < nColors) && (matched == 0); l++ )
00421             {
00422                 incolor = incolors[l];
00423                 threshold = thresholds[l];
00424                 
00425                 color_matches = 1;
00426                 for ( k = 0; 
00427                       (k < max_compare) && (color_matches > 0); 
00428                       k++ )
00429                 {
00430                     diff_temp_1 = incolor.array.v[k];
00431                     diff_temp_2 = imgptr[k];
00432                     /* Quicker than calling abs     ( ??? ) */
00433                     diff[k] = ((diff_temp_1 >= diff_temp_2) ?
00434                                (diff_temp_1 - diff_temp_2) : 
00435                                (diff_temp_2 - diff_temp_1));
00436                     if (diff[k] > threshold.array.v[k]) color_matches = 0;
00437                 }
00438                 matched = (color_matches) ? 1 : 0;
00439             }
00440             /* if the pixel color matches, ... */
00441             if (matched > 0)
00442             {
00443                 /* reset matched here, chances are, this happens less */
00444                 matched = 0;
00445                 /* create a new phblob_line_segment only if we don't have one */
00446                 if (current_segment == NULL)
00447                 {
00448                     /* there's always enough */
00449                     current_segment = &(line_array[larray_index]);
00450                     current_segment->index = larray_index++;
00451                     /* initialize all the memory to have all bits set */
00452                     current_segment->next_index = -1; /* no next */
00453                     current_segment->blob_index = -1; /* no blob */
00454                     current_segment->previous_index = -1; /* no previous */
00455                     current_segment->previous_visit_index = -1; /* no previous */
00456                     phMemset(current_segment->connection_index,
00457                            255,
00458                            phSEGMENT_CONNECTION_COUNT * sizeof(uint32_t));
00459                     
00460                     /* set the start point */
00461                     current_segment->a.y = current_segment->b.y = i;
00462                     current_segment->a.x = j;
00463                     
00464                     /* first segment for the row */
00465                     if (last_segment == NULL)
00466                     {
00467                         row_ptr_array[i] = current_segment;
00468                         row_index_array[i] = current_segment->index;
00469                     }
00470                     /* link segment to last segment */
00471                     else
00472                     {
00473                         current_segment->previous = last_segment;
00474                         current_segment->previous_index = last_segment->index;
00475                         
00476                         last_segment->next = current_segment;
00477                         last_segment->next_index = current_segment->index;
00478                     }
00479                 }
00480             }
00481             /* if the pixel doesn't match ... */
00482             /* ... and we've created a segment,
00483              * set the end point,
00484              * set the last segment to this segment,
00485              * reset the current segment to NULL,
00486              * 
00487              * this prepares for a search of another line segment */
00488             else if (current_segment != NULL)
00489             {
00490                 /* set the end point to the last valid pixel match*/
00491                 current_segment->b.x = j-1;
00492                 /* set the length - all lines in this routine
00493                  * will be horizontal, which makes the length calculation
00494                  * very easy:
00495                  *  b.x - a.x ; if a.x & b.x == 0, then length == 1; 
00496                  * this means we need to add 1 to every length */
00497                 current_segment->length = (current_segment->b.x - 
00498                                            current_segment->a.x) + 1;
00499 
00500                 if (current_segment->length > 0)
00501                     last_segment = current_segment;
00502                 else
00503                     larray_index--;
00504                 current_segment = NULL;
00505             }
00506 
00507             imgptr += depth;
00508         }
00509         /* make sure if the segment goes to the edge of 
00510          * the image that it's added */
00511         if (current_segment != NULL)
00512         {
00513             /* set the end point */
00514             /* we only get here when j == width,
00515              * the real endpoint is j - 1 */
00516             current_segment->b.x = j - 1;
00517             /* set the length - all lines in this routine
00518              * will be horizontal, which makes the length calculation
00519              * very easy. 
00520              * Again, if a.x == b.x, the length is 1 so we need to add +1
00521              * to every line segment */
00522             current_segment->length = (current_segment->b.x - 
00523                                        current_segment->a.x) + 1;
00524             
00525             last_segment = current_segment;
00526             current_segment = NULL;
00527         }
00528     }
00529     
00530     data->nlines        = larray_index;
00531     data->lines         = line_array;
00532     data->lines_size    = line_array_size;
00533     data->nrows         = height;
00534     data->rows          = row_ptr_array;
00535     data->rows_size     = row_ptr_array_size;
00536     data->rowindex      = row_index_array;
00537     data->rowindex_size = row_index_array_size;
00538     data->blob_method   = phBLOB_COLOR;
00539     data->nblobs        = 0;
00540 
00541     return phSUCCESS;
00542 error:
00543     return phFAIL;
00544 }
00545 
00546 /* ---------------------------------------------------------------------- */
00547 int phblob_find_line_segments_neighbor(phblob_args *args,
00548                                        phblob_data *data )
00549 {
00550     phFUNCTION("phblob_find_line_segments_neighbor")
00551 
00552     uint32_t    i   = 0;
00553     uint32_t    j   = 0;
00554     int         done= 0;
00555     
00556     /* make local copies of these */
00557     uint8_t  *imgptr    = *(args->imgptr);
00558     uint32_t  width     = args->width;
00559     uint32_t  height    = args->height;
00560     uint8_t   depth     = args->depth;
00561     //uint32_t  format    = args->format;
00562 
00563     phblob_line_segment *line_array          = (data->lines);
00564     uint32_t            line_array_size     = (data->lines_size);
00565     phblob_line_segment **row_ptr_array       = (data->rows);
00566     uint32_t            row_ptr_array_size  = (data->rows_size);
00567     int32_t            *row_index_array     = (data->rowindex);
00568     uint32_t            row_index_array_size= (data->rowindex_size);
00569  
00570 
00571     /* Used for comparison in the search for a color and
00572      * whether it's within the giving threshold. */
00573     uint32_t    matched                 = 0;
00574     uint32_t    k                       = 0;
00575     //uint32_t    l                       = 0;
00576 
00577     uint32_t    have_value              = 0;
00578     int32_t     value_high              = 0;
00579     int32_t     value_low               = 0;
00580     int32_t     value                   = 0;
00581     int32_t     *lower_threshold        = (int32_t *)args->lower_threshold;
00582     int32_t     *upper_threshold        = (int32_t *)args->upper_threshold;
00583     int32_t     *loop_threshold         = (int32_t *)args->loop_threshold;
00584     int32_t     current_value[phCOLOR_MAXELEMS];
00585     int32_t     current_value_high[phCOLOR_MAXELEMS];
00586     int32_t     current_value_low[phCOLOR_MAXELEMS];
00587    
00588     /* Used in line segment discovery */
00589     int32_t             larray_index        = 0;
00590     phblob_line_segment *current_segment    = NULL;
00591     int32_t             last_segment_index  = -1;
00592 
00593     //uint32_t npixels = ((width * height) + ((width * height) % 2));
00594 
00595     /* 0.) Make sure we have enough memory and all variables are
00596      * initialized */
00597   
00598     /* A.) allocate the max number of segments possible for the image:
00599      * 
00600      * i.) The maximum number of pixels when we're considering every pixel
00601      * is npixels;
00602      * 
00603      *  
00604      * ii.) the minimum number of lines when all the pixels match is height,
00605      */
00606 #if 0
00607     phDALLOC(line_array,
00608              line_array_size,
00609              npixels,
00610              phblob_line_segment);
00611 #endif
00612        
00613     /* b.) row_ptr_array is used to store line segments within a row of the image */
00614     phDALLOC(row_ptr_array,
00615              row_ptr_array_size,
00616              height,
00617              phblob_line_segment *);
00618 
00619     /* c.) row_index_array stores the index into the row_ptr_array array for 
00620      * the user can since a phMemcpy of the row_ptr_array/line_array 
00621      * invalidates the pointer values */
00622     phDALLOC(row_index_array,
00623              row_index_array_size,
00624              height,
00625              int32_t);
00626 #if 0
00627     phPRINT("lower: %3d %3d %3d %3d\n", lower_threshold[0], lower_threshold[1],
00628                                         lower_threshold[2], lower_threshold[3]);
00629     phPRINT("upper: %3d %3d %3d %3d\n", upper_threshold[0], upper_threshold[1],
00630                                         upper_threshold[2], upper_threshold[3]);
00631     phPRINT("loop : %3d %3d %3d %3d\n", loop_threshold[0], loop_threshold[1],
00632                                         loop_threshold[2], loop_threshold[3]);
00633 #endif
00634 
00635     phMemset(current_value,     0,phCOLOR_MAXELEMS*sizeof(int32_t));
00636     phMemset(current_value_low, 0,phCOLOR_MAXELEMS*sizeof(int32_t));
00637     phMemset(current_value_high,0,phCOLOR_MAXELEMS*sizeof(int32_t));
00638 
00639     for (i = 0; i < height; i++)
00640     {
00641         /* -1 is the value used to denote no index */
00642         row_index_array[i] = -1;
00643         row_ptr_array[i] = NULL;
00644         
00645         /* reset and initialize all the line variables */
00646         current_segment     = NULL;
00647         last_segment_index  = -1;
00648         have_value          = 0;
00649         
00650         j = 0;
00651         while (j < width)
00652         {
00653             if (have_value == 0)
00654             {
00655                 for (k = 0; k < depth; k++ )
00656                 {
00657                     current_value[k] = 
00658                         current_value_high[k] = 
00659                         current_value_low[k] = imgptr[k];
00660                 }
00661                 have_value = 1;
00662                 matched = 1;
00663             }
00664             else 
00665             {
00666                 for (k = 0; k < depth; k++ )
00667                 {
00668                     value       = imgptr[k];
00669                     value_high  = current_value[k] + upper_threshold[k];
00670                     value_low   = current_value[k] - lower_threshold[k];
00671 
00672                     if (loop_threshold[k])
00673                     {
00674                         value_high = value_high % 256;
00675                         if (value_low < 0) value_low = 255 + value_low + 1;
00676                     }
00677                     else
00678                     {
00679                         if (value_high > 255) value_high = 255;
00680                         if (value_low  <   0) value_low  =   0;
00681                     }
00682 
00683                     /* Check to see if the value threshold markers have looped
00684                      * around the highest value mark */
00685                     if (value_low <= value_high) 
00686                     {
00687                         if ((value >= value_low) && (value <= value_high))
00688                         {
00689                             matched++;
00690                         }
00691                     }
00692                     else 
00693                     {
00694                         if (loop_threshold[k] && 
00695                             ((value >= value_low) || (value <= value_high)))
00696                         {
00697                             matched++;
00698                         }
00699                     }
00700                 }
00701                 if (matched != depth) matched = 0;
00702             }
00703             
00704             /* if the pixel color matches, ... */
00705             if (matched > 0)
00706             {
00707                 /* reset matched here, chances are, this happens less */
00708                 matched = 0;
00709                 /* create a new line_segment only if we don't have one */
00710                 if (current_segment == NULL)
00711                 {
00712                     larray_index++;
00713                     phDALLOC_GROW(line_array,
00714                                   line_array_size,
00715                                   larray_index,
00716                                   phblob_line_segment);
00717                     /* there's always enough */
00718                     current_segment         = &(line_array[larray_index-1]);
00719                     phMemset(current_segment,0,sizeof(phblob_line_segment));
00720                     current_segment->index  = larray_index-1;
00721                     /* initialize all the memory to have all bits set */
00722                     current_segment->next_index             = -1; /* no next */
00723                     current_segment->blob_index             = -1; /* no blob */
00724                     current_segment->previous_index         = -1; /* no previous */
00725                     current_segment->previous_visit_index   = -1; /* no previous */
00726                     phMemset(current_segment->connection_index,
00727                              255,
00728                              phSEGMENT_CONNECTION_COUNT * sizeof(uint32_t));
00729 
00730                     /* Set the color information */
00731                     phMemcpy(current_segment->value,
00732                              current_value,
00733                              depth*sizeof(int32_t));
00734                     phMemcpy(current_segment->value_low,
00735                              current_value_low,
00736                              depth*sizeof(int32_t));
00737                     phMemcpy(current_segment->value_high,
00738                              current_value_high,
00739                              depth*sizeof(int32_t));
00740 #if 0
00741                     phPRINT("current: %3d %3d %3d %3d\n",
00742                             current_value[0],
00743                             current_value[1],
00744                             current_value[2],
00745                             current_value[3] );
00746                     phPRINT("low    : %3d %3d %3d %3d\n",
00747                             current_value_low[0],
00748                             current_value_low[1],
00749                             current_value_low[2],
00750                             current_value_low[3] );
00751                     phPRINT("high   : %3d %3d %3d %3d\n",
00752                             current_value_high[0],
00753                             current_value_high[1],
00754                             current_value_high[2],
00755                             current_value_high[3] );
00756 #endif
00757                     
00758                     /* set the start point */
00759                     current_segment->a.y = current_segment->b.y = i;
00760                     current_segment->a.x = j;
00761                     
00762                     /* first segment for the row */
00763                     if (last_segment_index < 0)
00764                     {
00765                         row_index_array[i] = current_segment->index;
00766                     }
00767                     /* link segment to last segment */
00768                     else
00769                     {
00770                         current_segment->previous_index = last_segment_index;
00771                         line_array[last_segment_index].next_index = 
00772                                                       current_segment->index;
00773                     }
00774                 }
00775                 else
00776                 {
00777                     for (k = 0; k < depth; k++ )
00778                     {
00779                         if (current_value_low[k] > imgptr[k])
00780                             current_value_low[k] = imgptr[k];
00781                         if (current_value_high[k] < imgptr[k])
00782                             current_value_high[k] = imgptr[k];
00783                         /* moving value */
00784 #if 1
00785                         current_value[k] = (current_value_high[k] + 
00786                                             current_value_low[k]) / 2;
00787 #endif
00788                     }
00789                 }
00790 
00791                 /* only increment when we've matched */
00792                 imgptr += depth;
00793 
00794                 /* because we're looking at every pixel as a different 
00795                  * potential start for a line segment, and not just whether
00796                  * it matches, we have to begin a new line segment the next
00797                  * time we loop; So, only increment j if we're matching; The
00798                  * next part of this if block ("else if (current_segment != NULL)"),
00799                  * Will reset the line segment information and the next 
00800                  * iteration of this loop will create a new 'matched' segment; 
00801                  * That leads us back here to incrementing 'j' and eventually
00802                  * getting to the end of the current line in the image */
00803                 j++;
00804             }
00805             /* if the pixel doesn't match ... */
00806             /* ... and we've created a segment,
00807              * set the end point,
00808              * set the last segment to this segment,
00809              * reset the current segment to NULL,
00810              * 
00811              * this prepares for a search of another line segment */
00812             else if (current_segment != NULL)
00813             {
00814                 /* set the end point */
00815                 /* The j here is the pixel that didn't match, so 
00816                  * we have to subtract 1 from j */
00817                 current_segment->b.x = j-1;
00818                 
00819                 /* set the length - all lines in this routine
00820                  * will be horizontal, which makes the length calculation
00821                  * very easy. */
00822                 current_segment->length = (current_segment->b.x - 
00823                                            current_segment->a.x)+1;
00824                 
00825                 if (current_segment->length > 0)
00826                     last_segment_index = current_segment->index;
00827                 else
00828                     larray_index--;
00829                 
00830                 phMemcpy(current_segment->value,
00831                          current_value,
00832                          depth*sizeof(int32_t));
00833                 phMemcpy(current_segment->value_low,
00834                          current_value_low,
00835                          depth*sizeof(int32_t));
00836                 phMemcpy(current_segment->value_high,
00837                          current_value_high,
00838                          depth*sizeof(int32_t));
00839                 
00840                 current_segment = NULL;
00841                 have_value      = 0;
00842             }
00843         }
00844         /* make sure if the segment goes to the edge of 
00845          * the image that it's added */
00846         if (current_segment != NULL)
00847         {
00848             /* set the end point */
00849             /* ... because we only get here when j == width,
00850              * the real end point is j - 1 */
00851             current_segment->b.x = j-1;
00852             /* set the length - all lines in this routine
00853              * will be horizontal, which makes the length calculation
00854              * very easy. */
00855             current_segment->length = (current_segment->b.x - 
00856                                        current_segment->a.x) + 1;
00857             
00858             last_segment_index = current_segment->index;
00859             current_segment = NULL;
00860         }
00861     }
00862 
00863     /* Because we're using phDALLOC_GROW, we need to set the pointers
00864      * after we've created all the line segments */
00865     for (i = 0; i < height; i++ )
00866     {
00867         if (row_index_array[i] >= 0)
00868         {
00869             current_segment = &(line_array[row_index_array[i]]);
00870             if (current_segment->index != row_index_array[i])
00871             {
00872                 phPROGRESS("!!! WARNING !!! %d != %d\n",
00873                             current_segment->index,
00874                             row_index_array[i]);
00875             }
00876             row_ptr_array[i] = current_segment;
00877             done = 0;
00878             
00879             do 
00880             {
00881                 /* Set the previous pointer */
00882                 if (current_segment->previous_index >= 0)
00883                 {
00884                     current_segment->previous = 
00885                         &(line_array[current_segment->previous_index]);
00886                 }
00887                 else
00888                 {
00889                     current_segment->previous = NULL;
00890                 }
00891                 /* set the next pointer */
00892                 if (current_segment->next_index >= 0)
00893                 {
00894                     current_segment = (current_segment->next = 
00895                         &(line_array[current_segment->next_index]));
00896                 }
00897                 else
00898                 {
00899                     current_segment->next = NULL;
00900                     done = 1;
00901                 }
00902             }
00903             while (!done);
00904         }
00905     }
00906      
00907     data->nlines        = larray_index;
00908     data->lines         = line_array;
00909     data->lines_size    = line_array_size;
00910     data->nrows         = height;
00911     data->rows          = row_ptr_array;
00912     data->rows_size     = row_ptr_array_size;
00913     data->rowindex      = row_index_array;
00914     data->rowindex_size = row_index_array_size;
00915     data->blob_method   = phBLOB_NEIGHBOR;
00916     data->nblobs        = 0;
00917 
00918     return phSUCCESS;
00919 error:
00920     return phFAIL;
00921 }
00922 
00923 /* ---------------------------------------------------------------------- */
00924 int phblob_link_line_segments( phblob_args *args,
00925                                phblob_data *data )
00926 {
00927     phFUNCTION("phblob_link_line_segments")
00928 
00929     /* Used in line segment linking; ie forming the pointer links to
00930      * facilitate blob group identification */
00931     phblob_line_segment *seg_row0 = NULL;
00932     phblob_line_segment *seg_row1 = NULL;
00933     uint32_t ax0    = 0;
00934     uint32_t bx0    = 0;
00935     uint32_t ax1    = 0;
00936     uint32_t bx1    = 0;
00937     uint32_t new0   = 0;
00938     uint32_t new1   = 0;
00939     uint32_t connect= 0;
00940 
00941     int32_t value           = 0;
00942     int32_t value_low       = 0;
00943     int32_t value_high      = 0;
00944     uint32_t color_matches   = 1;
00945 
00946     uint32_t i = 0;
00947     uint32_t j = 0;
00948     uint32_t k = 0;
00949     
00950     int      blob_neighbor;
00951     uint32_t height;
00952     uint32_t depth; 
00953     int32_t  lower_threshold[phCOLOR_MAXELEMS];
00954     int32_t  upper_threshold[phCOLOR_MAXELEMS];
00955     int32_t  loop_threshold [phCOLOR_MAXELEMS];
00956     phblob_line_segment **row_ptr_array = NULL;
00957         
00958     if ((args == NULL) || (data == NULL) || (data->rows == NULL))
00959     {
00960         return phFAIL;
00961     }
00962 
00963     height  = args->height;
00964     depth   = args->depth;
00965 
00966     phMemcpy(lower_threshold,args->lower_threshold,
00967              phCOLOR_MAXELEMS*sizeof(int32_t));
00968     phMemcpy(upper_threshold,args->upper_threshold,
00969              phCOLOR_MAXELEMS*sizeof(int32_t));
00970     phMemcpy(loop_threshold,args->loop_threshold,
00971              phCOLOR_MAXELEMS*sizeof(int32_t));
00972 
00973     row_ptr_array   = data->rows;
00974     blob_neighbor   = data->blob_method == phBLOB_NEIGHBOR ? 1 : 0;
00975             
00976     for (i = 1; i < height; i++)
00977     {
00978         seg_row0 = row_ptr_array[i - 1];
00979         seg_row1 = row_ptr_array[i];
00980         
00981         if (seg_row0 != NULL)
00982         {
00983             ax0 = seg_row0->a.x;
00984             bx0 = seg_row0->b.x;
00985         }
00986         if (seg_row1 != NULL)
00987         {
00988             ax1 = seg_row1->a.x;
00989             bx1 = seg_row1->b.x;
00990         }
00991         
00992         while ((seg_row0 != NULL) && (seg_row1 != NULL))
00993         {
00994             if (blob_neighbor)
00995             {
00996                 color_matches = 0;
00997                 for (j = 0; (j < 2) && (color_matches < depth); j++)
00998                 {
00999                     /* only loop as high as depth, otherwise there will be
01000                      * indecies where all the values are 0 and the... */
01001                     for (k = 0; k < depth; k++ )
01002                     {
01003                         /* first compare seg_row1->value to seg_row0 */
01004                         if (j == 0)
01005                         {
01006                             value_low   = seg_row0->value_low[k];
01007                             value_high  = seg_row0->value_high[k];
01008                             value       = seg_row1->value[k];
01009                         }
01010                         /* then compare seg_row0->value to seg_row1 */
01011                         else
01012                         {
01013                             value_low   = seg_row1->value_low[k];
01014                             value_high  = seg_row1->value_high[k];
01015                             value       = seg_row0->value[k];
01016                         }
01017                         value_low = value_low - lower_threshold[k];
01018                         value_high= value_high + upper_threshold[k];
01019 
01020                         /* Make sure the value_low/high variables are within the range */
01021                         if (loop_threshold[k])
01022                         {
01023                             value_high = value_high % 256;
01024                             if (value_low < 0) value_low = 255 + value_low + 1;
01025                         }
01026                         else
01027                         {
01028                             if (value_high > 255) value_high = 255;
01029                             if (value_low  <   0) value_low  =   0;
01030                         }
01031                         /* if value_low is less than high, then check if the value is
01032                          * in between both values */
01033                         if (value_low <= value_high)
01034                         {
01035                             if ((value >= value_low) && (value <= value_high))
01036                             {
01037                                 color_matches++;
01038                             }
01039                         }
01040                         /* if we're looping the threshold around, then check to see
01041                          * if the value is greater than low or less than high */
01042                         else 
01043                         {
01044                             if (loop_threshold[k] && 
01045                                     ((value >= value_low) || (value <= value_high)))
01046                             {
01047                                 color_matches++;
01048                             }
01049                         }
01050                     }
01051                     if ((color_matches) && (color_matches < depth))
01052                     {
01053                         color_matches = 0;
01054                     }
01055                 }
01056             }
01057 
01058             /* beginning of 0 occurs before/at end of 1 */
01059             /* 
01060              * 0: a----------b
01061              * 1:    a--------b 
01062              *
01063              * 0:       a----------b
01064              * 1:    a--------b 
01065              *
01066              * 0:             a----------b
01067              * 1:    a--------b 
01068              */
01069             if (ax0 <= bx1)
01070             {
01071                 /* beginning of 0 occurs after/at beginning of 1 */
01072                 /* 
01073                  * 0: a----------b
01074                  * 1: a--------b 
01075                  *
01076                  * 0:      a----------b
01077                  * 1: a--------b 
01078                  */
01079                 if (ax0 >= ax1)
01080                 {
01081                     /* Case 3 : 0 partly within 1 */
01082                     /* connect */
01083                     if (color_matches) connect = 1;
01084                     else new0 = 1;
01085                 }
01086                 /* end of 0 occurs before beginning of 1 */
01087                 /* 0: a------b
01088                  * 1:         a--------b 
01089                  */
01090                 else if (bx0 < ax1)
01091                 {
01092                     /* Case 1 : 0 not partly within 1
01093                      * *          0 is wholey before 1 */
01094                     /* get next element in row 0 */
01095                     new0 = 1;
01096                 }
01097                 /* 0 overlaps with 1 */
01098                 /* 
01099                  * 0: a---------b
01100                  * 1:         a--------b 
01101                  */
01102                 else if (bx0 >= ax1)
01103                 {
01104                     /* Case 2: 0 partly overlaps with 1 on the
01105                      * *          ending section of 0 */
01106                     /* connect them */
01107                     if (color_matches) connect = 1;
01108                     else new1 = 1;
01109                 }
01110             }
01111             /* beginning of 0 occurs after 1 */
01112             /* 
01113              * 0:       a-------b
01114              * 1:  a---b
01115              */
01116             else
01117             {
01118                 /* Case 3: 0 not partly within 1
01119                  * *         0 occurs wholey after 1 */
01120                 /* get next element in row 1 */
01121                 new1 = 1;
01122             }
01123             
01124             if (connect)
01125             {
01126                 /* a.) First element found below */
01127                 if (seg_row0->first_down == NULL)
01128                 {
01129                     /* just set the first_down and last_down pointers */
01130                     seg_row0->first_down = 
01131                         (seg_row0->last_down = seg_row1);
01132                     seg_row0->first_down_index = 
01133                         (seg_row0->last_down_index = seg_row1->index);
01134                     
01135                     FIRST_DOWN_PTR(seg_row0) = 
01136                         (LAST_DOWN_PTR(seg_row0) = seg_row1);
01137                     FIRST_DOWN_INDEX(seg_row0) = 
01138                         (LAST_DOWN_INDEX(seg_row0) = seg_row1->index);
01139                 }
01140                 /* b.) other elements connected below */
01141                 else
01142                 {
01143                     /* i.) connect the two segments that both
01144                      * * overlap row0 from row1 together */
01145                     /* ii.)set the new last_down pointer */
01146                     /* iii.) Copy the index locations */
01147                     seg_row1->left = seg_row0->last_down;
01148                     seg_row1->left_index = seg_row0->last_down->index;
01149                     
01150                     seg_row0->last_down_index =
01151                         (seg_row0->last_down->right_index = seg_row1->index);
01152                     seg_row0->last_down =
01153                         (seg_row0->last_down->right = seg_row1);
01154                     
01155                     LEFT_PTR(seg_row1) = DOWN_PTR(seg_row0);
01156                     LEFT_INDEX(seg_row1) = DOWN_PTR(seg_row0)->index;
01157                     
01158                     DOWN_INDEX(seg_row0) = 
01159                         (RIGHT_INDEX(DOWN_PTR(seg_row0)) = seg_row1->index);
01160                     
01161                     RIGHT_PTR(DOWN_PTR(seg_row0)) = seg_row1;
01162                     DOWN_PTR(seg_row0) = seg_row1;
01163                 }
01164                 
01165                 /* c.) First element found above */
01166                 if (seg_row1->first_up == NULL)
01167                 {
01168                     /* just set the first_up and last_up pointers */
01169                     seg_row1->first_up = 
01170                         (seg_row1->last_up = seg_row0);
01171                     seg_row1->first_up_index = 
01172                         (seg_row1->last_up_index = seg_row0->index);
01173                     
01174                     FIRST_UP_PTR(seg_row1) = 
01175                         (LAST_UP_PTR(seg_row1) = seg_row0);
01176                     FIRST_UP_INDEX(seg_row1) = 
01177                         (LAST_UP_INDEX(seg_row1) = seg_row0->index);
01178                 }
01179                 /* d.) other elements connected above */
01180                 else
01181                 {
01182                     /* i.) connect the two segments that both overlap
01183                      * * in the row1 form row0 together */
01184                     /* ii.) Set the new last_up pointer, 
01185                      * * can only have one: the right most segment */
01186                     /* iii.) Adjust the indexes before adjusting
01187                      * * the pointers */
01188                     seg_row0->left = seg_row1->last_up;
01189                     seg_row0->left_index = seg_row1->last_up->index;
01190                     
01191                     seg_row1->last_up_index = 
01192                         (seg_row1->last_up->right_index = seg_row0->index);
01193                     
01194                     seg_row1->last_up = 
01195                         (seg_row1->last_up->right = seg_row0);
01196                     
01197                     /* if we're here, UP_PTR should not be NULL */
01198                     LEFT_PTR(seg_row0) = UP_PTR(seg_row1);
01199                     LEFT_INDEX(seg_row0) = UP_PTR(seg_row1)->index;
01200                     
01201                     UP_INDEX(seg_row1) = 
01202                         (RIGHT_INDEX(UP_PTR(seg_row1)) = seg_row0->index);
01203                     RIGHT_PTR(UP_PTR(seg_row1)) = seg_row0;
01204                     UP_PTR(seg_row1) = seg_row0;
01205                 }
01206                 
01207                 /* decide which "next" segment to get */
01208                 /* Case 2/3a: end of 0 occurs after end of 1 
01209                  * *      get a new segment from 1 */
01210                 if (bx0 > bx1)      new1 = 1;
01211                 /* Case 2/3b: end of 0 occurs before end of 1 
01212                  * *      get a new segment from 0*/
01213                 else if (bx0 < bx1) new0 = 1;
01214                 /* Case 2/3c: 0 and 1 end in the same place 
01215                  * *      get new segments from 0 and 1 */
01216                 else                new0 = new1 = 1;
01217 
01218 #if 0
01219                 for (k = 0; k < phCOLOR_MAXELEMS; k++)
01220                 {
01221                     if (seg_row0->value_low[k] < seg_row1->value_low[k])
01222                         seg_row1->value_low[k] = seg_row0->value_low[k];
01223                     else
01224                         seg_row0->value_low[k] = seg_row1->value_low[k];
01225                     
01226                     if (seg_row0->value_high[k] > seg_row1->value_high[k])
01227                         seg_row1->value_high[k] = seg_row0->value_high[k];
01228                     else
01229                         seg_row0->value_high[k] = seg_row1->value_high[k];
01230                     
01231 #if 1
01232                     seg_row0->value[k] = (seg_row0->value_high[k] + seg_row0->value_low[k]) / 2;
01233                     seg_row1->value[k] = (seg_row1->value_high[k] + seg_row1->value_low[k]) / 2;
01234 #endif
01235                 }
01236 #endif           
01237                 connect = 0;
01238             }
01239             if (new0)
01240             {
01241                 seg_row0 = seg_row0->next;
01242                 if (seg_row0 != NULL)
01243                 {
01244                     ax0 = seg_row0->a.x;
01245                     bx0 = seg_row0->b.x;
01246                 }
01247                 new0 = 0;
01248             }
01249             if (new1)
01250             {
01251 #if 0
01252                 if (i == (height - 1))
01253                 {
01254                     phPRINT("before:%p\n",seg_row1);
01255                 }
01256 #endif
01257                 seg_row1 = seg_row1->next;
01258                 if (seg_row1 != NULL)
01259                 {
01260                     ax1 = seg_row1->a.x;
01261                     bx1 = seg_row1->b.x;
01262                 }
01263 #if 0
01264                 if (i == (height - 1))
01265                 {
01266                     phPRINT("after:%p\n",seg_row1);
01267                 }
01268 #endif
01269                 new1 = 0;
01270             }
01271         }
01272     }
01273 
01274     return phSUCCESS;
01275 }
01276 /* ---------------------------------------------------------------------- */
01277 int phblob_draw_blob_rects( uint8_t         *imgptr,
01278                             uint32_t        width,
01279                             uint32_t        height,
01280                             uint32_t        format,
01281                             const phColor   *color,
01282                             phblob_data     *data,
01283                             uint32_t        index,
01284                             uint32_t        min_size,
01285                             uint32_t        flag )
01286 {
01287     phFUNCTION("phblob_draw_blob_rects")
01288     
01289     phImageSurface  surface;
01290     phblob         *current_blob = NULL;
01291     phColor         outcolor;
01292     phblob         *blobs       = data->blobs;
01293     uint32_t        nblobs      = data->nblobs;
01294 
01295     if (color == NULL) flag |= phBLOB_COLOR_BLACK;
01296     
01297     if ((flag & phBLOB_COLOR_BLACK) == phBLOB_COLOR_BLACK)
01298     {
01299         if ((format == (uint32_t)phImageYUV9) ||
01300             (format == (uint32_t)phImageNOFORMAT))
01301         {
01302             phCHECK_RC(-1,NULL,"Unsupported Image Format");
01303         }
01304         outcolor = phColor_new(phImageFormatToColorType(format));
01305     }
01306     else
01307     {
01308         outcolor = *color;
01309     }
01310 
01311     surface.p = imgptr;
01312     surface.w = width;
01313     surface.h = height;
01314     surface.f = format;
01315     surface.d = phImageFormatToDepth(format);
01316    
01317     if (((flag & phBLOB_DRAW_ALL) == phBLOB_DRAW_ALL) &&
01318         (nblobs > 0))
01319     {
01320         /* Highlight the first blob */
01321         current_blob = (&(blobs[0]));
01322         
01323         while (current_blob != NULL)
01324         {
01325             if (current_blob->mass > min_size)
01326             {
01327                 ph_draw_hollow_rect(&surface,
01328                                     outcolor,
01329                                     0,
01330                                     current_blob->x1,
01331                                     current_blob->y1,
01332                                     current_blob->x2,
01333                                     current_blob->y2 );
01334             }
01335             
01336             current_blob = phblob_get_next_blob( current_blob, blobs );
01337         }
01338     }
01339     if ((flag & phBLOB_DRAW_INDEX) == phBLOB_DRAW_INDEX)
01340     {
01341         if (index < nblobs)
01342         {
01343             current_blob = (&(blobs[index]));
01344             
01345             ph_draw_hollow_rect(&surface,
01346                              outcolor,
01347                              0,
01348                              current_blob->x1,
01349                              current_blob->y1,
01350                              current_blob->x2,
01351                              current_blob->y2 );
01352         }
01353     }
01354     
01355     return phSUCCESS;
01356 error:
01357     return phFAIL;
01358 }
01359 
01360 /* ---------------------------------------------------------------------- */
01361 int phblob_color_lines(uint8_t         *imgptr,
01362                        uint32_t         width,
01363                        uint32_t         height,
01364                        uint32_t         format,
01365                        const phColor   *color,
01366                        phblob_data     *data,
01367                        uint32_t         blob_min_size,
01368                        uint32_t         index, /* TODO */
01369                        uint32_t         flag )
01370 {
01371     phFUNCTION("phblob_color_lines")
01372     
01373     uint32_t        i               = 0;
01374     uint32_t        j               = 0;
01375     uint32_t        k               = 0;
01376     uint32_t        blob_count      = 0;
01377     int32_t         blob_index      = 0;
01378     uint32_t        irow            = 0;
01379     uint8_t         depth           = 1;
01380     phblob_line_segment   *current_segment = NULL;
01381     phColor         outcolor;
01382 
01383     uint32_t                nblobs  = data->nblobs;
01384     phblob                 *blobs   = data->blobs;
01385     uint32_t                nrows   = data->nrows;
01386     //phblob_line_segment   **rows    = data->rows;
01387     int32_t                *rowindex= data->rowindex;
01388     //uint32_t                nlines  = data->nlines;
01389     phblob_line_segment    *lines   = data->lines;
01390     uint8_t                *ptr     = NULL;
01391 
01392     //uint32_t color_line = 0;
01393 
01394     if (color == NULL) flag |= phBLOB_COLOR_BLACK;
01395     
01396     /* set black if it's requested */
01397     if ((flag & phBLOB_COLOR_BLACK) == phBLOB_COLOR_BLACK)
01398     {
01399         if ((format == (uint32_t)phImageYUV9) ||
01400             (format == (uint32_t)phImageNOFORMAT))
01401         {
01402             phCHECK_RC(-1,NULL,"Unsupported Image Format");
01403         }
01404         outcolor = phColor_new(phImageFormatToColorType(format));
01405     }
01406     else
01407     {
01408         outcolor = *color;
01409     }
01410 
01411         
01412     if ((format == (uint32_t)phImageYUV9) ||
01413         (format == (uint32_t)phImageNOFORMAT))
01414     {
01415         phCHECK_RC(-1,NULL,"Unsupported Image Format");
01416     }
01417     /* Set the depth */
01418     else
01419     {
01420         depth = phImageFormatToDepth(format);
01421     }
01422 
01423     if ((flag & phBLOB_CLEAR_IMG) == phBLOB_CLEAR_IMG)
01424     {
01425         phMemset(imgptr,0,width*height*depth);
01426     }
01427 
01428     if (blob_min_size > 0)
01429     {
01430         for (k = 0; (k < nblobs) && (blobs); k++ )
01431         {
01432             if (blobs[k].mass > blob_min_size) blob_count++;
01433         }
01434     }
01435     else
01436     {
01437         blob_count = nblobs;
01438     }
01439 
01440     /* don't color anything if no blobs were big enough */
01441     if (blob_count > 0)
01442     {
01443         for (i = 0; i < nrows; i++ )
01444         {
01445             irow = i * width;
01446             
01447             /* Get the index to the first line segment in the row */
01448             current_segment = phblob_get_segment( rowindex[i], lines );
01449             
01450             while (current_segment != NULL)
01451             {
01452 #if 0
01453                 phPRINT("segment[%3d]:%3d ( %3d, %3d; %3d, %3d ) [ %3d | %3d | %3d ]\n",
01454                     current_segment->index, current_segment->length,
01455                     current_segment->a.x,   current_segment->a.y,
01456                     current_segment->b.x,   current_segment->b.y,
01457                     current_segment->value[0],  current_segment->value[1],
01458                     current_segment->value[2]
01459                     );
01460 #endif       
01461                 blob_index = current_segment->blob_index;
01462 /* TODO: make coloring all the lines an option */
01463                 if ((blob_index >= 0) && 
01464                     (((uint32_t)blob_index) < nblobs) &&
01465                     ((blob_min_size            == 0) ||                      
01466                      (blobs[blob_index].mass   >= blob_min_size)))
01467                 {
01468                     if (data->blob_method == phBLOB_NEIGHBOR)
01469                     {
01470                         for (j = 0; j < depth; j++)
01471                             outcolor.array.v[j] = blobs[blob_index].value[j];
01472                     }
01473 #if 0
01474                     else
01475                     {
01476                         /* WHITE in HSV */
01477                         /* BLUE in RGB */
01478                         outcolor.array.v[0] = 0;
01479                         outcolor.array.v[1] = 0;
01480                         outcolor.array.v[2] = 127;
01481                         //outcolor.array.v[2] = 0;
01482                     }
01483 #endif
01484                     for (j = 0, 
01485                          ptr = &(imgptr[(irow + current_segment->a.x) * depth]); 
01486                              
01487                          j < current_segment->length; 
01488                          
01489                          j++, ptr += depth)
01490                     {
01491                         phMemcpy(ptr,outcolor.array.v, depth);
01492                     }
01493                 }
01494                 
01495                 current_segment = phblob_get_next_segment(current_segment,
01496                                                           lines);
01497             }
01498         }
01499     }
01500 
01501     return phSUCCESS;
01502 error:
01503     return phFAIL;
01504 }
01505 
01506                                      
01507 /* ---------------------------------------------------------------------- */
01508 #define phTOTAL_DIRS 4
01509 const uint32_t opposite_dir_bit[phTOTAL_DIRS] = 
01510                                 {(1<<1),(1<<0),(1<<3),(1<<2)};
01511 
01512 /* ---------------------------------------------------------------------- */
01513 int phblob_create_blobs(uint32_t        width,
01514                         uint32_t        height,
01515                         phblob_data    *data   )
01516 {
01517     phFUNCTION("phblob_create_blobs")
01518     
01519     uint32_t i = 0;
01520 
01521     /* Used in blob identification */
01522     phblob_line_segment    *current_segment     = NULL;
01523     int32_t                 blob_index          = 0;
01524     phblob                 *current_blob        = NULL;
01525     phblob                 *previous_blob       = NULL;
01526     uint32_t                visit_done          = 0;
01527     uint32_t                made_visit          = 0;
01528     uint32_t                dir                 = 0;
01529     phblob_line_segment    *visit_segment       = NULL;
01530     phblob_line_segment    *prospect_segment    = NULL;
01531 
01532     /* make local copies */
01533     uint32_t            blobs_size  = data->blobs_size;
01534     phblob             *blobs       = data->blobs;
01535     //int32_t             nrows       = data->nrows;
01536     //phblob_line_segment **rows      = data->rows;
01537     int32_t             *rowindex   = data->rowindex;
01538     phblob_line_segment *lines      = data->lines;
01539  
01540     //uint32_t half_npixels = ((width * height) + ((width * height) % 2)) / 2;
01541     uint32_t npixels = ((width * height) + ((width * height) % 2));
01542     
01543     /* 0.) m_blob_array, this is an array that can hold the maximum number of
01544      *      blobs possible, ie half the number of pixels in the image.
01545      *      Each phblob has a mass, upper left and lower right value
01546      *      associated with it */
01547     //phDALLOC(blobs, blobs_size, half_npixels, phblob );
01548     phDALLOC(blobs, blobs_size, npixels, phblob );
01549 
01550     /* begin traverse algorithm */
01551     for (i = 0; i < height; i++ )
01552     {
01553         current_segment = phblob_get_segment( rowindex[i], lines );
01554 
01555         while (current_segment != NULL)
01556         {
01557             /* if the current segment doesn't belong to a 
01558              * blob group yet, start up a new blob 
01559              * member search */
01560             if (current_segment->blob_index < 0)
01561             {
01562                 visit_done = 0;
01563                 visit_segment = current_segment;
01564 
01565                 /* Setup a new blob */
01566                 previous_blob = current_blob;
01567                 current_blob = &(blobs[blob_index]);
01568                 /* init the blob */
01569                 current_segment->blob_index = 
01570                     current_blob->index = blob_index++;
01571                 current_blob->next_index = -1;
01572                 current_blob->previous_index = -1;
01573                 current_blob->first_segment = current_segment;
01574                 current_blob->first_segment_index = 
01575                                 current_segment->index;
01576                 current_blob->last_segment = visit_segment;
01577                 current_blob->last_segment_index = 
01578                                 visit_segment->index;
01579                 current_blob->mass = visit_segment->length;
01580                 current_blob->x1 = visit_segment->a.x;
01581                 current_blob->y1 = visit_segment->a.y;
01582                 current_blob->x2 = visit_segment->b.x;
01583                 current_blob->y2 = visit_segment->b.y;
01584                 current_blob->cx = 
01585                     (current_blob->x1 + current_blob->x2) / 2;
01586                 current_blob->cy = 
01587                     (current_blob->y1 + current_blob->y2) / 2;
01588                 current_blob->w = 
01589                     (current_blob->x2 - current_blob->x1)+1;
01590                 current_blob->h = 
01591                     (current_blob->y2 - current_blob->y1)+1;
01592 
01593                 phMemcpy(current_blob->value,
01594                          current_segment->value,
01595                          sizeof(int32_t)*phCOLOR_MAXELEMS);
01596                 phMemcpy(current_blob->value_low,
01597                          current_segment->value_low,
01598                          sizeof(int32_t)*phCOLOR_MAXELEMS);
01599                 phMemcpy(current_blob->value_high,
01600                          current_segment->value_high,
01601                          sizeof(int32_t)*phCOLOR_MAXELEMS);
01602                
01603                 if (previous_blob != NULL)
01604                 {
01605                     previous_blob->next = current_blob;
01606                     previous_blob->next_index = current_blob->index;
01607 
01608                     current_blob->previous = previous_blob;
01609                     current_blob->previous_index = previous_blob->index;
01610                 }
01611                 
01612                 while ((!visit_done) && (visit_segment != NULL))
01613                 {
01614                     /* used in backing up the traversal when no visits 
01615                      * are made */
01616                     made_visit = 0;
01617                     
01618                     for (dir = 0; 
01619                          (dir < phTOTAL_DIRS) && (made_visit == 0);
01620                          dir++ )
01621                     {
01622                         /* If dir hasn't been visited yet... */
01623                         if (!(visit_segment->visited & (1<<dir)))
01624                         {
01625                             made_visit = 1;
01626                             
01627                             visit_segment->visited |= (1<<dir);
01628                             prospect_segment = visit_segment->connection[dir];
01629                             
01630                             /* If direction isn't NULL... */
01631                             if (prospect_segment != NULL)
01632                             {
01633                                 /* If segment in current direction doen't 
01634                                  * already belong to the group...*/
01635                                 if (prospect_segment->blob_index < 0)
01636                                 {
01637                                     /* Setup reverse paths */
01638                                     prospect_segment->previous_visit_index = 
01639                                         visit_segment->index;
01640                                     prospect_segment->previous_visit =
01641                                         visit_segment;
01642                                     
01643                                     /* go in direction associated with value 'dir' */
01644                                     visit_segment = prospect_segment;
01645                                     visit_segment->blob_index = current_blob->index;
01646                                     
01647                                     /* Set the last segment visited */
01648                                     current_blob->last_segment = visit_segment;
01649                                     current_blob->last_segment_index = 
01650                                                         visit_segment->index;
01651                                     /* Add to the blob mass */
01652                                     current_blob->mass += visit_segment->length;
01653                                     /* Adjust the encompassing rect coords */
01654                                     phSET_MIN(current_blob->x1,visit_segment->a.x);
01655                                     phSET_MIN(current_blob->y1,visit_segment->a.y);
01656                                     phSET_MAX(current_blob->x2,visit_segment->b.x);
01657                                     phSET_MAX(current_blob->y2,visit_segment->b.y);
01658                                     
01659                                     /* prevents traversing in the direction 
01660                                      * of origin. this is a must */
01661                                     visit_segment->visited |= OPPOSITE_DIR_BIT(dir);
01662                                 }
01663                             }
01664                         }
01665                     }
01666                     /* Go back */
01667                     if (made_visit == 0)
01668                     {
01669                         if (visit_segment == current_segment)
01670                         {
01671                             visit_done = 1;
01672                         }
01673                         /* iterative pseudo pop from stack, go back,
01674                          * play that funky beat */
01675                         else
01676                         {
01677                             /* reset the visited variable, the blob_index
01678                              * value will prevent a revisit; this removes
01679                              * the need to retraverse the array to reset
01680                              * the visited variable; allows the line
01681                              * segments to be retraversed */
01682                             visit_segment->visited = 0;
01683                             visit_segment = visit_segment->previous_visit;
01684                         }
01685                     }
01686                 }
01687                 /* The blob is finished being created */
01688                 if (current_blob != NULL)
01689                 {
01690                     current_blob->cx = 
01691                         (current_blob->x1 + current_blob->x2) / 2;
01692                     current_blob->cy = 
01693                         (current_blob->y1 + current_blob->y2) / 2;
01694                     current_blob->w = 
01695                         (current_blob->x2 - current_blob->x1)+1;
01696                     current_blob->h = 
01697                         (current_blob->y2 - current_blob->y1)+1;
01698                 }
01699             }
01700             
01701             current_segment = phblob_get_next_segment(current_segment,
01702                                                       lines);
01703         }
01704     }
01705     data->nblobs    = blob_index;
01706     data->blobs_size= blobs_size;
01707     data->blobs     = blobs;
01708 
01709     return phSUCCESS;
01710 error:
01711     return phFAIL;
01712 }
01713 
01714 /* ---------------------------------------------------------------------- */
01715 __inline__ int32_t phblob_compare( const void *_one, const void *_two )
01716 {
01717     phblob *b_one = (phblob *)_one;
01718     phblob *b_two = (phblob *)_two;
01719     const uint32_t m_one = b_one->mass;
01720     const uint32_t m_two = b_two->mass;
01721 
01722     //phPROGRESS("mass (%p ? %p )\n",b_one,b_two);
01723     /* Greater than : 1 */
01724     if (m_one > m_two)
01725         return 1;
01726     /* Less than : -1 */
01727     else if (m_one < m_two)
01728         return -1;
01729     
01730     //phPROGRESS("cx\n");
01731     /* Compare cx: center of blob mass x-coord */
01732     if (b_one->cx > b_two->cx)
01733         return 1;
01734     else if (b_one->cx < b_two->cx)
01735         return -1;
01736 
01737     //phPROGRESS("cy\n");
01738     /* Compare cy: center of blob mass y-coord */
01739     if (b_one->cy > b_two->cy)
01740         return 1;
01741     else if (b_one->cy < b_two->cy)
01742         return -1;
01743 
01744     //phPROGRESS("x1\n");
01745     /* Compare x1: top-left x-coord */
01746     if (b_one->x1 > b_two->x1)
01747         return 1;
01748     else if (b_one->x1 < b_two->x1)
01749         return -1;
01750 
01751     //phPROGRESS("x2\n");
01752     /* Compare x2: bottom-right x-coord */
01753     if (b_one->x2 > b_two->x2)
01754         return 1;
01755     else if (b_one->x2 < b_two->x2)
01756         return -1;
01757 
01758     //phPROGRESS("y1\n");
01759     /* Compare y1: top-left y-coord */
01760     if (b_one->y1 > b_two->y1)
01761         return 1;
01762     else if (b_one->y1 < b_two->y1)
01763         return -1;
01764 
01765     //phPROGRESS("y2\n");
01766     /* Compare y2: bottom-right y-coord */
01767     if (b_one->y2 > b_two->y2)
01768         return 1;
01769     else if (b_one->y2 < b_two->y2)
01770         return -1;
01771         
01772     //phPROGRESS("height\n");
01773     /* Compare h: height of blob */
01774     if (b_one->h > b_two->h)
01775         return 1;
01776     else if (b_one->h < b_two->h)
01777         return -1;
01778             
01779     //phPROGRESS("width\n");
01780     /* Compare w: width of blob */
01781     if (b_one->w > b_two->w)
01782         return 1;
01783     else if (b_one->w < b_two->w)
01784         return -1;
01785 
01786     //phPROGRESS("%p == %p\n", b_one, b_two);
01787     /* Equal : 0 */
01788     return 0;
01789 }
01790 
01791 /* ---------------------------------------------------------------------- */
01792 int phblob_sort_blobs( phblob_data *data  /* returned */,
01793                        uint32_t    method /* 0: recursive; 1:iterative */ )
01794 {
01795     phFUNCTION("phblob_sort_blobs")
01796     int32_t     i           = 0;
01797     int32_t     j           = 0;
01798     int32_t     k           = 0;
01799     int32_t     prev_index  = 0;
01800     int32_t     next_index  = 0;
01801     phblob     *next        = NULL;
01802     phblob     *prev        = NULL;
01803     phblob      tempblob;
01804     uint8_t    *tempbuf     = NULL;
01805     uint32_t    nblobs      = data->nblobs;
01806     phblob     *blobs       = data->blobs;
01807     
01808     if (nblobs == 0) return phSUCCESS;
01809     
01810     tempbuf = (uint8_t *)phMalloc(sizeof(phblob));
01811     phCHECK_PTR(tempbuf,"phMalloc","phMalloc failed to allocate temp buf");
01812     
01813     if (method)
01814     {
01815         ph_quicksort_iterative( blobs, 
01816                                 0, 
01817                                 nblobs - 1,
01818                                 sizeof(phblob),
01819                                 tempbuf,
01820                                 phblob_compare );
01821     }
01822     else
01823     {
01824         ph_quicksort_recursive( blobs, 
01825                                 0, 
01826                                 nblobs - 1,
01827                                 sizeof(phblob),
01828                                 tempbuf,
01829                                 phblob_compare );
01830     }
01831     /* Reverse the list */
01832     j = nblobs - 1;
01833     for (i = 0; (i < j); i++ )
01834     {
01835         tempblob = blobs[i];
01836         blobs[i] = blobs[j];
01837         blobs[j] = tempblob;
01838         j--;
01839     }
01840    
01841     /* Redo all the indecies and pointers for next/previous */
01842     for (k = 0; k < nblobs; k++ )
01843     {
01844         prev_index = ((k - 1) < 0) ? -1 : k - 1;
01845         next_index = ((k + 1) == nblobs) ? -1 : k + 1;
01846         next = (next_index < 0) ? NULL :
01847                     &(blobs[next_index]);
01848         prev = (prev_index < 0) ? NULL :
01849                     &(blobs[prev_index]);
01850         
01851         blobs[k].index         = k;
01852         blobs[k].next          = next;
01853         blobs[k].next_index    = next_index;
01854         blobs[k].previous      = prev;
01855         blobs[k].previous_index= prev_index;
01856     }
01857 
01858     phFree(tempbuf);
01859     return phSUCCESS;
01860 error:
01861     phFree(tempbuf);
01862     return phFAIL;
01863 }
01864 
01865 /* ---------------------------------------------------------------------- */
01866 #ifdef __cplusplus
01867 } /* extern "C" */
01868 #endif
01869 




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:11 2007 for phission by  doxygen 1.4.4