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 |