src/textord/edgblob.cpp
int32_t OL_BUCKETS::outline_complexity(C_OUTLINE *outline, // parent outline
                                       int32_t max_count,  // max output
                                       int16_t depth       // recurion depth
) {
  TDimension xmin, xmax;    // coord limits
  TDimension ymin, ymax;
  C_OUTLINE *child;         // current child
  int32_t child_count;      // no of children
  int32_t grandchild_count; // no of grandchildren
  C_OUTLINE_IT child_it;    // search iterator

  TBOX olbox = outline->bounding_box();
  xmin = (olbox.left() - bl.x()) / BUCKETSIZE;
  xmax = (olbox.right() - bl.x()) / BUCKETSIZE;
  ymin = (olbox.bottom() - bl.y()) / BUCKETSIZE;
  ymax = (olbox.top() - bl.y()) / BUCKETSIZE;
  child_count = 0;
  grandchild_count = 0;
  if (++depth > edges_max_children_layers) { // nested loops are too deep
    return max_count + depth;
  }

  for (auto yindex = ymin; yindex <= ymax; yindex++) {
    for (auto xindex = xmin; xindex <= xmax; xindex++) {
      child_it.set_to_list(&buckets[yindex * bxdim + xindex]);
      if (child_it.empty()) {
        continue;
      }
      for (child_it.mark_cycle_pt(); !child_it.cycled_list();
           child_it.forward()) {
        child = child_it.data();
        if (child == outline || !(*child < *outline)) {
          continue;
        }
        child_count++;

        if (child_count > edges_max_children_per_outline) { // too fragmented
          if (edges_debug) {
            tprintf(
                "Discard outline on child_count=%d > "
                "max_children_per_outline=%d\n",
                child_count,
                static_cast<int32_t>(edges_max_children_per_outline));
          }
          return max_count + child_count;
        }

        // Compute the "complexity" of each child recursively
        int32_t remaining_count = max_count - child_count - grandchild_count;
        if (remaining_count > 0) {
          grandchild_count += edges_children_per_grandchild *
                              outline_complexity(child, remaining_count, depth);
        }
        if (child_count + grandchild_count > max_count) { // too complex
          if (edges_debug) {
            tprintf(
                "Disgard outline on child_count=%d + grandchild_count=%d "
                "> max_count=%d\n",
                child_count, grandchild_count, max_count);
          }
          return child_count + grandchild_count;
        }
      }
    }
  }
  return child_count + grandchild_count;
}
/**
 * @name OL_BUCKETS::outline_complexity
 *
 * This is the new version of count_child.
 *
 * The goal of this function is to determine if an outline and its
 * interiors could be part of a character blob.  This is done by
 * computing a "complexity" index for the outline, which is the return
 * value of this function, and checking it against a threshold.
 * The max_count is used for short-circuiting the recursion and forcing
 * a rejection that guarantees to fail the threshold test.
 * The complexity F for outline X with N children X[i] is
 *   F(X) = N + sum_i F(X[i]) * edges_children_per_grandchild
 * so each layer of nesting increases complexity exponentially.
 * An outline can be rejected as a text blob candidate if its complexity
 * is too high, has too many children(likely a container), or has too
 * many layers of nested inner loops.  This has the side-effect of
 * flattening out boxed or reversed video text regions.
 */


The goal of this function is to determine if an outline and its
interiors could be part of a character blob.  This is done by
computing a "complexity" index for the outline, which is the return
value of this function, and checking it against a threshold.
The max_count is used for short-circuiting the recursion and forcing
a rejection that guarantees to fail the threshold test.
The complexity F for outline X with N children X[i] is
F(X) = N + sum_i F(X[i]) * edges_children_per_grandchild
so each layer of nesting increases complexity exponentially.
An outline can be rejected as a text blob candidate if its complexity
is too high, has too many children(likely a container), or has too
many layers of nested inner loops.  This has the side-effect of
flattening out boxed or reversed video text regions.
The goal of this function is to determine if an outline and its interiors could be part of a character blob . This is done by computing a " complexity " index for the outline which is the return value of this function and checking it against a threshold . The max_count is used for short - circuiting the recursion and forcing a rejection that guarantees to fail the threshold test . The complexity F for outline X with N children X [ i ] is F ( X ) = N + sum_i F ( X [ i ] ) * edges_children_per_grandchild so each layer of nesting increases complexity exponentially . An outline can be rejected as a text blob candidate if its complexity is too high has too many children ( likely a container ) or has too many layers of nested inner loops . This has the side - effect of flattening out boxed or reversed video text regions .
int32_t OL_BUCKETS::outline_complexity(C_OUTLINE *outline, 
                                       int32_t max_count,  
                                       int16_t depth       
) {
  TDimension xmin, xmax;    
  TDimension ymin, ymax;
  C_OUTLINE *child;         
  int32_t child_count;      
  int32_t grandchild_count; 
  C_OUTLINE_IT child_it;    
  TBOX olbox = outline->bounding_box();
  xmin = (olbox.left() - bl.x()) / BUCKETSIZE;
  xmax = (olbox.right() - bl.x()) / BUCKETSIZE;
  ymin = (olbox.bottom() - bl.y()) / BUCKETSIZE;
  ymax = (olbox.top() - bl.y()) / BUCKETSIZE;
  child_count = 0;
  grandchild_count = 0;
  if (++depth > edges_max_children_layers) { 
    return max_count + depth;
  }
  for (auto yindex = ymin; yindex <= ymax; yindex++) {
    for (auto xindex = xmin; xindex <= xmax; xindex++) {
      child_it.set_to_list(&buckets[yindex * bxdim + xindex]);
      if (child_it.empty()) {
        continue;
      }
      for (child_it.mark_cycle_pt(); !child_it.cycled_list();
           child_it.forward()) {
        child = child_it.data();
        if (child == outline || !(*child < *outline)) {
          continue;
        }
        child_count++;
        if (child_count > edges_max_children_per_outline) { 
          if (edges_debug) {
            tprintf(
                "Discard outline on child_count=%d > "
                "max_children_per_outline=%d\n",
                child_count,
                static_cast<int32_t>(edges_max_children_per_outline));
          }
          return max_count + child_count;
        }
        int32_t remaining_count = max_count - child_count - grandchild_count;
        if (remaining_count > 0) {
          grandchild_count += edges_children_per_grandchild *
                              outline_complexity(child, remaining_count, depth);
        }
        if (child_count + grandchild_count > max_count) { 
          if (edges_debug) {
            tprintf(
                "Disgard outline on child_count=%d + grandchild_count=%d "
                "> max_count=%d\n",
                child_count, grandchild_count, max_count);
          }
          return child_count + grandchild_count;
        }
      }
    }
  }
  return child_count + grandchild_count;
}
int32_t OL_BUCKETS :: outline_complexity ( C_OUTLINE * outline , int32_t max_count , int16_t depth ) { TDimension xmin , xmax ; TDimension ymin , ymax ; C_OUTLINE * child ; int32_t child_count ; int32_t grandchild_count ; C_OUTLINE_IT child_it ; TBOX olbox = outline -> bounding_box ( ) ; xmin = ( olbox . left ( ) - bl . x ( ) ) / BUCKETSIZE ; xmax = ( olbox . right ( ) - bl . x ( ) ) / BUCKETSIZE ; ymin = ( olbox . bottom ( ) - bl . y ( ) ) / BUCKETSIZE ; ymax = ( olbox . top ( ) - bl . y ( ) ) / BUCKETSIZE ; child_count = 0 ; grandchild_count = 0 ; if ( ++ depth > edges_max_children_layers ) { return max_count + depth ; } for ( auto yindex = ymin ; yindex <= ymax ; yindex ++ ) { for ( auto xindex = xmin ; xindex <= xmax ; xindex ++ ) { child_it . set_to_list ( & buckets [ yindex * bxdim + xindex ] ) ; if ( child_it . empty ( ) ) { continue ; } for ( child_it . mark_cycle_pt ( ) ; ! child_it . cycled_list ( ) ; child_it . forward ( ) ) { child = child_it . data ( ) ; if ( child == outline || ! ( * child < * outline ) ) { continue ; } child_count ++ ; if ( child_count > edges_max_children_per_outline ) { if ( edges_debug ) { tprintf ( " " " \n " , child_count , static_cast < int32_t > ( edges_max_children_per_outline ) ) ; } return max_count + child_count ; } int32_t remaining_count = max_count - child_count - grandchild_count ; if ( remaining_count > 0 ) { grandchild_count += edges_children_per_grandchild * outline_complexity ( child , remaining_count , depth ) ; } if ( child_count + grandchild_count > max_count ) { if ( edges_debug ) { tprintf ( " " " \n " , child_count , grandchild_count , max_count ) ; } return child_count + grandchild_count ; } } } } return child_count + grandchild_count ; }
@name OL_BUCKETS::outline_complexity
 This is the new version of count_child.
@name OL_BUCKETS :: outline_complexity This is the new version of count_child .
// parent outline // max output // recurion depth // coord limits // current child // no of children // no of grandchildren // search iterator // nested loops are too deep // too fragmented // Compute the "complexity" of each child recursively // too complex