static void make_adjacent( Segmenter *s, Region* r1, Region* r2 ) { if( !is_adjacent( r1, r2 ) ){ if( r1->flags & SATURATED_REGION_FLAG ){ r2->flags |= FRAGMENTED_REGION_FLAG; }else if( r2->flags & SATURATED_REGION_FLAG ){ r1->flags |= FRAGMENTED_REGION_FLAG; }else{ if( r1->adjacent_region_count == s->max_adjacent_regions ){ make_saturated(r1); r2->flags |= FRAGMENTED_REGION_FLAG; if( r2->adjacent_region_count == s->max_adjacent_regions ){ make_saturated(r2); r1->flags |= FRAGMENTED_REGION_FLAG; } }else if( r2->adjacent_region_count == s->max_adjacent_regions ){ make_saturated(r2); r1->flags |= FRAGMENTED_REGION_FLAG; }else{ assert( !(r1->flags & SATURATED_REGION_FLAG) ); assert( !(r2->flags & SATURATED_REGION_FLAG) ); assert( r1->adjacent_region_count < s->max_adjacent_regions ); assert( r2->adjacent_region_count < s->max_adjacent_regions ); r1->adjacent_regions[ r1->adjacent_region_count++ ] = r2; r2->adjacent_regions[ r2->adjacent_region_count++ ] = r1; } } } // postcondition, adjacency link is bi-directional or isn't created assert( (r1_adjacent_contains_r2( r1, r2 ) && r1_adjacent_contains_r2( r2, r1 )) || (!r1_adjacent_contains_r2( r1, r2 ) && !r1_adjacent_contains_r2( r2, r1 )) ); }
// merge r2 into r1 by first removing all common adjacencies from r2 // then transferring the remainder of adjacencies to r1 after discarding // any excess adjacencies. static void merge_regions( Segmenter *s, Region* r1, Region* r2 ) { int i; assert( r1 != r2 ); assert( !r1_adjacent_contains_r2( r1, r2 ) && !r1_adjacent_contains_r2( r2, r1 ) ); if( r1->flags & SATURATED_REGION_FLAG ){ make_saturated( r2 ); if( r2->flags & SATURATED_REGION_FLAG ) make_saturated( r1 ); }else if( r2->flags & SATURATED_REGION_FLAG ){ make_saturated( r1 ); }else{ // remove adjacencies of r2 which are already in r1 for( i = 0; i<r2->adjacent_region_count; ++i ){ Region *a = r2->adjacent_regions[i]; if( is_adjacent( a, r1 ) ){ remove_adjacent_from( a, r2 ); r2->adjacent_regions[i] = r2->adjacent_regions[ --r2->adjacent_region_count ]; } } if( r1->adjacent_region_count + r2->adjacent_region_count > s->max_adjacent_regions ){ make_saturated( r1 ); make_saturated( r2 ); }else{ // remove adjacencies from r2 and add them to r1 for( i=0; i < r2->adjacent_region_count; ++i ){ Region *a = r2->adjacent_regions[ i ]; replace_adjacent( a, r2, r1 ); // replace r2 with r1 in the adjacency list of a r1->adjacent_regions[r1->adjacent_region_count++] = a; assert( a->adjacent_region_count <= s->max_adjacent_regions ); assert( r1->adjacent_region_count <= s->max_adjacent_regions ); } r2->adjacent_region_count = 0; } } r1->flags |= r2->flags; if( r2->left < r1->left ) r1->left = r2->left; if( r2->top < r1->top ) r1->top = r2->top; if( r2->right > r1->right ) r1->right = r2->right; if( r2->bottom > r1->bottom ) r1->bottom = r2->bottom; // postcondition: all adjacencies to r1 are bidirectional #ifndef NDEBUG for( i = 0; i < r1->adjacent_region_count; ++i ){ Region *a = r1->adjacent_regions[i]; assert( r1_adjacent_contains_r2( r1, a ) ); } #endif }
// recursively propagate descendent count and max depth upwards // r->visit_counter is incremented each time we have an opportunity // to traverse to a parent. we only actually visit it once the visit // counter reaches adjacent_region_count - 1 i.e. that we have already // visited all of its other children // as we travel upwards we collect nodes with the constraints defined by // min_target_root_descendent_count, max_target_root_descendent_count, // min_depth and max_depth // we never traverse above a node which exceeds these constraints. we also // never traverse nodes which are saturated or fragmented because it is // ambiguous whether such a node has a parent, or if all it's children are // attched, and we can't determine this in a single pass (we could save a list // of these nodes for a later pass but we don't bother.) // during the calls to this function we store the maximum leaf-to-node depth // in r->depth, later this field has a different meaning static void propagate_descendent_count_and_max_depth_upwards( Segmenter *s, Region *r, FidtrackerX *ft) { int i; Region *parent = 0; assert( r->level == NOT_TRAVERSED ); assert( r->children_visited_count == (r->adjacent_region_count - 1) // has an untraversed parent || r->children_visited_count == r->adjacent_region_count ); // is adjacent to root region r->descendent_count = 0; r->depth = 0; r->level = TRAVERSING; for( i=0; i < r->adjacent_region_count; ++i ){ Region *adjacent = r->adjacent_regions[i]; assert( r1_adjacent_contains_r2( adjacent, r ) ); if( adjacent->level == TRAVERSED ){ r->descendent_count += (short)(adjacent->descendent_count + 1); r->depth = (short)MAX( r->depth, (adjacent->depth + 1) ); }else{ assert( parent == 0 ); parent = adjacent; } } r->level = TRAVERSED; if( r->descendent_count == ft->max_target_root_descendent_count && r->depth >= ft->min_depth && r->depth <= ft->max_depth ){ // found fiducial candidate link_region( &ft->root_regions_head, r ); }else{ if( r->descendent_count >= ft->min_target_root_descendent_count && r->descendent_count < ft->max_target_root_descendent_count && r->depth >= ft->min_depth && r->depth <= ft->max_depth ) { link_region( &ft->root_regions_head, r ); } else if( r->descendent_count >= ft->min_target_root_descendent_count-3 && r->descendent_count < ft->max_target_root_descendent_count+3 && r->depth >= ft->min_depth-1 && r->depth <= ft->max_depth+1 ) { r->flags |= LOST_SYMBOL_FLAG; link_region( &ft->root_regions_head, r ); } if( parent && !(r->flags & ( SATURATED_REGION_FLAG | ADJACENT_TO_ROOT_REGION_FLAG | FREE_REGION_FLAG ) ) ){ ++parent->children_visited_count; if( r->descendent_count < ft->max_target_root_descendent_count && r->depth < ft->max_depth ){ // continue propagating depth and descendent count upwards // so long as parent isn't a saturated node in which case it is // ambiguous whether parent has a parent or not so we skip it if( !(parent->flags & SATURATED_REGION_FLAG) && ( ( (!(parent->flags & (ADJACENT_TO_ROOT_REGION_FLAG | FRAGMENTED_REGION_FLAG) ) && parent->children_visited_count == (parent->adjacent_region_count - 1)) || ((parent->flags & (ADJACENT_TO_ROOT_REGION_FLAG | FRAGMENTED_REGION_FLAG) ) && parent->children_visited_count == parent->adjacent_region_count) ) ) ){ assert( r1_adjacent_contains_r2( r, parent ) ); assert( r1_adjacent_contains_r2( parent, r ) ); propagate_descendent_count_and_max_depth_upwards( s, parent, ft); } } } } }