Exemple #1
0
void save_chop_cfragment(                            //chop the outline
                         int16_t head_index,           //head of fragment
                         ICOORD head_pos,            //head of fragment
                         int16_t tail_index,           //tail of fragment
                         ICOORD tail_pos,            //tail of fragment
                         C_OUTLINE *srcline,         //source of edgesteps
                         C_OUTLINE_FRAG_LIST *frags  //fragment list
                        ) {
  int16_t jump;                    //gap across end
  int16_t stepcount;               //total steps
  C_OUTLINE_FRAG *head;          //head of fragment
  C_OUTLINE_FRAG *tail;          //tail of fragment
  int16_t tail_y;                  //ycoord of tail

  ASSERT_HOST (tail_pos.x () == head_pos.x ());
  ASSERT_HOST (tail_index != head_index);
  stepcount = tail_index - head_index;
  if (stepcount < 0)
    stepcount += srcline->pathlength ();
  jump = tail_pos.y () - head_pos.y ();
  if (jump < 0)
    jump = -jump;
  if (jump == stepcount)
    return;                      //its a nop
  tail_y = tail_pos.y ();
  head = new C_OUTLINE_FRAG (head_pos, tail_pos, srcline,
    head_index, tail_index);
  tail = new C_OUTLINE_FRAG (head, tail_y);
  head->other_end = tail;
  add_frag_to_list(head, frags);
  add_frag_to_list(tail, frags);
}
Exemple #2
0
void C_OUTLINE::plot(                //draw it
                     ScrollView* window,       // window to draw in
                     ScrollView::Color colour  // colour to draw in
                    ) const {
  inT16 stepindex;               // index to cstep
  ICOORD pos;                    // current position
  DIR128 stepdir;                // direction of step

  pos = start;                   // current position
  window->Pen(colour);
  if (stepcount == 0) {
    window->Rectangle(box.left(), box.top(), box.right(), box.bottom());
    return;
  }
  window->SetCursor(pos.x(), pos.y());

  stepindex = 0;
  while (stepindex < stepcount) {
    pos += step(stepindex);    // step to next
    stepdir = step_dir(stepindex);
    stepindex++;               // count steps
    // merge straight lines
    while (stepindex < stepcount &&
           stepdir.get_dir() == step_dir(stepindex).get_dir()) {
      pos += step(stepindex);
      stepindex++;
    }
    window->DrawTo(pos.x(), pos.y());
  }
}
Exemple #3
0
void vertical_coutline_projection(                     //project outlines
                                  C_OUTLINE *outline,  //outline to project
                                  STATS *stats         //output
                                 ) {
  ICOORD pos;                    //current point
  ICOORD step;                   //edge step
  inT32 length;                  //of outline
  inT16 stepindex;               //current step
  C_OUTLINE_IT out_it = outline->child ();

  pos = outline->start_pos ();
  length = outline->pathlength ();
  for (stepindex = 0; stepindex < length; stepindex++) {
    step = outline->step (stepindex);
    if (step.x () > 0) {
     stats->add (pos.x (), -pos.y ());
    } else if (step.x () < 0) {
      stats->add (pos.x () - 1, pos.y ());
    }
    pos += step;
  }

  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
    vertical_coutline_projection (out_it.data (), stats);
  }
}
void find_cblob_hlimits(                //get x limits
                        C_BLOB *blob,   //blob to search
                        float bottomy,  //y limits
                        float topy,
                        float &xmin,    //output x limits
                        float &xmax) {
  INT16 stepindex;               //current point
  ICOORD pos;                    //current coords
  ICOORD vec;                    //rotated step
  C_OUTLINE *outline;            //current outline
                                 //outlines
  C_OUTLINE_IT out_it = blob->out_list ();

  xmin = (float) MAX_INT32;
  xmax = (float) -MAX_INT32;
  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
    outline = out_it.data ();
    pos = outline->start_pos (); //get coords
    for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
                                 //inside
      if (pos.y () >= bottomy && pos.y () <= topy) {
        if (pos.x () > xmax)
          xmax = pos.x ();
        if (pos.x () < xmin)
          xmin = pos.x ();
      }
      vec = outline->step (stepindex);
      pos += vec;                //move to next
    }
  }
}
Exemple #5
0
void find_cblob_vlimits(               //get y limits
                        C_BLOB *blob,  //blob to search
                        float leftx,   //x limits
                        float rightx,
                        float &ymin,   //output y limits
                        float &ymax) {
  inT16 stepindex;               //current point
  ICOORD pos;                    //current coords
  ICOORD vec;                    //rotated step
  C_OUTLINE *outline;            //current outline
                                 //outlines
  C_OUTLINE_IT out_it = blob->out_list ();

  ymin = (float) MAX_INT32;
  ymax = (float) -MAX_INT32;
  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
    outline = out_it.data ();
    pos = outline->start_pos (); //get coords
    for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
                                 //inside
      if (pos.x () >= leftx && pos.x () <= rightx) {
        UpdateRange(pos.y(), &ymin, &ymax);
      }
      vec = outline->step (stepindex);
      pos += vec;                //move to next
    }
  }
}
Exemple #6
0
void POLY_BLOCK::compute_bb() {  //constructor
  ICOORD ibl, itr;               //integer bb
  ICOORD botleft;                //bounding box
  ICOORD topright;
  ICOORD pos;                    //current pos;
  ICOORDELT_IT pts = &vertices;  //iterator

  botleft = *pts.data ();
  topright = botleft;
  do {
    pos = *pts.data ();
    if (pos.x () < botleft.x ())
                                 //get bounding box
      botleft = ICOORD (pos.x (), botleft.y ());
    if (pos.y () < botleft.y ())
      botleft = ICOORD (botleft.x (), pos.y ());
    if (pos.x () > topright.x ())
      topright = ICOORD (pos.x (), topright.y ());
    if (pos.y () > topright.y ())
      topright = ICOORD (topright.x (), pos.y ());
    pts.forward ();
  }
  while (!pts.at_first ());
  ibl = ICOORD (botleft.x (), botleft.y ());
  itr = ICOORD (topright.x (), topright.y ());
  box = TBOX (ibl, itr);
}
Exemple #7
0
OL_BUCKETS::OL_BUCKETS(
ICOORD bleft,                    // corners
ICOORD tright):         bl(bleft), tr(tright) {
  bxdim =(tright.x() - bleft.x()) / BUCKETSIZE + 1;
  bydim =(tright.y() - bleft.y()) / BUCKETSIZE + 1;
                                 // make array
  buckets = new C_OUTLINE_LIST[bxdim * bydim];
  index = 0;
}
Exemple #8
0
// (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
// and bleft, tright are the bounding box of everything to go in it.
void GridBase::Init(int gridsize, const ICOORD& bleft, const ICOORD& tright) {
  gridsize_ = gridsize;
  bleft_ = bleft;
  tright_ = tright;
  if (gridsize_ == 0)
    gridsize_ = 1;
  gridwidth_ = (tright.x() - bleft.x() + gridsize_ - 1) / gridsize_;
  gridheight_ = (tright.y() - bleft.y() + gridsize_ - 1) / gridsize_;
  gridbuckets_ = gridwidth_ * gridheight_;
}
Exemple #9
0
// Finds vertical lines in the given list of BLOBNBOXes. bleft and tright
// are the bounds of the image on which the input line_bblobs were found.
// The input line_bblobs list is const really.
// The output vertical_x and vertical_y are the total of all the vectors.
// The output list of TabVector makes no reference to the input BLOBNBOXes.
void LineFinder::FindLineVectors(const ICOORD& bleft, const ICOORD& tright,
                                 BLOBNBOX_LIST* line_bblobs,
                                 int* vertical_x, int* vertical_y,
                                 TabVector_LIST* vectors) {
  BLOBNBOX_IT bbox_it(line_bblobs);
  int b_count = 0;
  // Put all the blobs into the grid to find the lines, and move the blobs
  // to the output lists.
  AlignedBlob blob_grid(kLineFindGridSize, bleft, tright);
  for (bbox_it.mark_cycle_pt(); !bbox_it.cycled_list(); bbox_it.forward()) {
    BLOBNBOX* bblob = bbox_it.data();
    bblob->set_left_tab_type(TT_UNCONFIRMED);
    bblob->set_left_rule(bleft.x());
    bblob->set_right_rule(tright.x());
    bblob->set_left_crossing_rule(bleft.x());
    bblob->set_right_crossing_rule(tright.x());
    blob_grid.InsertBBox(false, true, bblob);
    ++b_count;
  }
  if (textord_debug_tabfind)
    tprintf("Inserted %d line blobs into grid\n", b_count);
  if (b_count == 0)
    return;

  // Search the entire grid, looking for vertical line vectors.
  GridSearch<BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT> lsearch(&blob_grid);
  BLOBNBOX* bbox;
  TabVector_IT vector_it(vectors);
  *vertical_x = 0;
  *vertical_y = 1;
  lsearch.StartFullSearch();
  while ((bbox = lsearch.NextFullSearch()) != NULL) {
    if (bbox->left_tab_type() == TT_UNCONFIRMED) {
      const TBOX& box = bbox->bounding_box();
      if (AlignedBlob::WithinTestRegion(2, box.left(), box.bottom()))
        tprintf("Finding line vector starting at bbox (%d,%d)\n",
                box.left(), box.bottom());
      AlignedBlobParams align_params(*vertical_x, *vertical_y, box.width());
      TabVector* vector = blob_grid.FindVerticalAlignment(align_params, bbox,
                                                          vertical_x,
                                                          vertical_y);
      if (vector != NULL) {
        vector->Freeze();
        vector_it.add_to_end(vector);
      }
    }
  }
  ScrollView* line_win = NULL;
  if (textord_tabfind_show_vlines) {
    line_win = blob_grid.MakeWindow(0, 50, "Vlines");
    blob_grid.DisplayBoxes(line_win);
    line_win = blob_grid.DisplayTabs("Vlines", line_win);
  }
}
Exemple #10
0
/**********************************************************************
 * C_OUTLINE::C_OUTLINE
 *
 * Constructor to build a C_OUTLINE from a C_OUTLINE_FRAG.
 **********************************************************************/
C_OUTLINE::C_OUTLINE (
//constructor
                                 //steps to copy
ICOORD startpt, DIR128 * new_steps,
inT16 length                     //length of loop
):start (startpt), offsets(NULL) {
  inT8 dirdiff;                  //direction difference
  DIR128 prevdir;                //previous direction
  DIR128 dir;                    //current direction
  DIR128 lastdir;                //dir of last step
  TBOX new_box;                   //easy bounding
  inT16 stepindex;               //index to step
  inT16 srcindex;                //source steps
  ICOORD pos;                    //current position

  pos = startpt;
  stepcount = length;            // No. of steps.
  ASSERT_HOST(length >= 0);
  steps = reinterpret_cast<uinT8*>(alloc_mem(step_mem()));  // Get memory.
  memset(steps, 0, step_mem());

  lastdir = new_steps[length - 1];
  prevdir = lastdir;
  for (stepindex = 0, srcindex = 0; srcindex < length;
  stepindex++, srcindex++) {
    new_box = TBOX (pos, pos);
    box += new_box;
                                 //copy steps
    dir = new_steps[srcindex];
    set_step(stepindex, dir);
    dirdiff = dir - prevdir;
    pos += step (stepindex);
    if ((dirdiff == 64 || dirdiff == -64) && stepindex > 0) {
      stepindex -= 2;            //cancel there-and-back
      prevdir = stepindex >= 0 ? step_dir (stepindex) : lastdir;
    }
    else
      prevdir = dir;
  }
  ASSERT_HOST (pos.x () == startpt.x () && pos.y () == startpt.y ());
  do {
    dirdiff = step_dir (stepindex - 1) - step_dir (0);
    if (dirdiff == 64 || dirdiff == -64) {
      start += step (0);
      stepindex -= 2;            //cancel there-and-back
      for (int i = 0; i < stepindex; ++i)
        set_step(i, step_dir(i + 1));
    }
  }
  while (stepindex > 1 && (dirdiff == 64 || dirdiff == -64));
  stepcount = stepindex;
  ASSERT_HOST (stepcount >= 4);
}
Exemple #11
0
// Renders the outline to the given pix, with left and top being
// the coords of the upper-left corner of the pix.
void C_OUTLINE::render(int left, int top, Pix* pix) const {
  ICOORD pos = start;
  for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
    ICOORD next_step = step(stepindex);
    if (next_step.y() < 0) {
      pixRasterop(pix, 0, top - pos.y(), pos.x() - left, 1,
                  PIX_NOT(PIX_DST), NULL, 0, 0);
    } else if (next_step.y() > 0) {
      pixRasterop(pix, 0, top - pos.y() - 1, pos.x() - left, 1,
                  PIX_NOT(PIX_DST), NULL, 0, 0);
    }
    pos += next_step;
  }
}
Exemple #12
0
// As TraceOutlineOnReducedPix above, but on a BLOCK instead of a C_OUTLINE.
Pix* TraceBlockOnReducedPix(BLOCK* block, int gridsize,
                            ICOORD bleft, int* left, int* bottom) {
  TBOX box = block->bounding_box();
  Pix* pix = GridReducedPix(box, gridsize, bleft, left, bottom);
  int wpl = pixGetWpl(pix);
  l_uint32* data = pixGetData(pix);
  ICOORDELT_IT it(block->poly_block()->points());
  for (it.mark_cycle_pt(); !it.cycled_list();) {
    ICOORD pos = *it.data();
    it.forward();
    ICOORD next_pos = *it.data();
    ICOORD line_vector = next_pos - pos;
    int major, minor;
    ICOORD major_step, minor_step;
    line_vector.setup_render(&major_step, &minor_step, &major, &minor);
    int accumulator = major / 2;
    while (pos != next_pos) {
      int grid_x = (pos.x() - bleft.x()) / gridsize - *left;
      int grid_y = (pos.y() - bleft.y()) / gridsize - *bottom;
      SET_DATA_BIT(data + grid_y * wpl, grid_x);
      pos += major_step;
      accumulator += minor;
      if (accumulator >= major) {
        accumulator -= major;
        pos += minor_step;
      }
    }
  }
  return pix;
}
Exemple #13
0
BOOL8 PDBLK::contains(           //test containment
                      ICOORD pt  //point to test
                     ) {
  BLOCK_RECT_IT it = this;       //rectangle iterator
  ICOORD bleft, tright;          //corners of rectangle

  for (it.start_block (); !it.cycled_rects (); it.forward ()) {
                                 //get rectangle
    it.bounding_box (bleft, tright);
                                 //inside rect
    if (pt.x () >= bleft.x () && pt.x () <= tright.x ()
      && pt.y () >= bleft.y () && pt.y () <= tright.y ())
      return TRUE;               //is inside
  }
  return FALSE;                  //not inside
}
Exemple #14
0
inT16 POLY_BLOCK::winding_number(const ICOORD &point) {
  inT16 count;                   //winding count
  ICOORD pt;                     //current point
  ICOORD vec;                    //point to current point
  ICOORD vvec;                   //current point to next point
  inT32 cross;                   //cross product
  ICOORDELT_IT it = &vertices;   //iterator

  count = 0;
  do {
    pt = *it.data ();
    vec = pt - point;
    vvec = *it.data_relative (1) - pt;
                                 //crossing the line
    if (vec.y () <= 0 && vec.y () + vvec.y () > 0) {
      cross = vec * vvec;        //cross product
      if (cross > 0)
        count++;                 //crossing right half
      else if (cross == 0)
        return INTERSECTING;     //going through point
    }
    else if (vec.y () > 0 && vec.y () + vvec.y () <= 0) {
      cross = vec * vvec;
      if (cross < 0)
        count--;                 //crossing back
      else if (cross == 0)
        return INTERSECTING;     //illegal
    }
    else if (vec.y () == 0 && vec.x () == 0)
      return INTERSECTING;
    it.forward ();
  }
  while (!it.at_first ());
  return count;                  //winding number
}
Exemple #15
0
// Renders just the outline to the given pix (no fill), with left and top
// being the coords of the upper-left corner of the pix.
void C_OUTLINE::render_outline(int left, int top, Pix* pix) const {
  ICOORD pos = start;
  for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
    ICOORD next_step = step(stepindex);
    if (next_step.y() < 0) {
      pixSetPixel(pix, pos.x() - left, top - pos.y(), 1);
    } else if (next_step.y() > 0) {
      pixSetPixel(pix, pos.x() - left - 1, top - pos.y() - 1, 1);
    } else if (next_step.x() < 0) {
      pixSetPixel(pix, pos.x() - left - 1, top - pos.y(), 1);
    } else if (next_step.x() > 0) {
      pixSetPixel(pix, pos.x() - left, top - pos.y() - 1, 1);
    }
    pos += next_step;
  }
}
Exemple #16
0
// Helper function to compute a fictitious end point that is on a line
// of a given gradient through the given start.
ICOORD ComputeEndFromGradient(const ICOORD& start, double m) {
  if (m > 1.0 || m < -1.0) {
    // dy dominates. Force it to have the opposite sign of start.y() and
    // compute dx based on dy being as large as possible
    int dx = static_cast<int>(floor(MAX_INT16 / m));
    if (dx < 0) ++dx;  // Truncate towards 0.
    if (start.y() > 0) dx = - dx;  // Force dy to be opposite to start.y().
    // Constrain dx so the result fits in an inT16.
    while (start.x() + dx > MAX_INT16 || start.x() + dx < -MAX_INT16)
      dx /= 2;
    if (-1 <= dx && dx <= 1) {
      return ICOORD(start.x(), start.y() + 1);  // Too steep for anything else.
    }
    int y = start.y() + static_cast<int>(floor(dx * m + 0.5));
    ASSERT_HOST(-MAX_INT16 <= y && y <= MAX_INT16);
    return ICOORD(start.x() + dx, y);
  } else {
    // dx dominates. Force it to have the opposite sign of start.x() and
    // compute dy based on dx being as large as possible.
    int dy = static_cast<int>(floor(MAX_INT16 * m));
    if (dy < 0) ++dy;  // Truncate towards 0.
    if (start.x() > 0) dy = - dy;  // Force dx to be opposite to start.x().
    // Constrain dy so the result fits in an inT16.
    while (start.y() + dy > MAX_INT16 || start.y() + dy < -MAX_INT16)
      dy /= 2;
    if (-1 <= dy && dy <= 1) {
      return ICOORD(start.x() + 1, start.y());  // Too flat for anything else.
    }
    int x = start.x() + static_cast<int>(floor(dy / m + 0.5));
    ASSERT_HOST(-MAX_INT16 <= x && x <= MAX_INT16);
    return ICOORD(x, start.y() + dy);
  }
}
Exemple #17
0
// Moves by the given vec in place.
void TESSLINE::Move(const ICOORD vec) {
  EDGEPT* pt = loop;
  do {
    pt->pos.x += vec.x();
    pt->pos.y += vec.y();
    pt = pt->next;
  } while (pt != loop);
  SetupFromPos();
}
Exemple #18
0
inT16 loop_bounding_box(                    //get bounding box
                        CRACKEDGE *&start,  //edge loop
                        ICOORD &botleft,    //bounding box
                        ICOORD &topright) {
  inT16 length;                  //length of loop
  inT16 leftmost;                //on top row
  CRACKEDGE *edgept;             //current point
  CRACKEDGE *realstart;          //topleft start

  edgept = start;
  realstart = start;
  botleft = topright = ICOORD (edgept->pos.x (), edgept->pos.y ());
  leftmost = edgept->pos.x ();
  length = 0;                    //coutn length
  do {
    edgept = edgept->next;
    if (edgept->pos.x () < botleft.x ())
                                 //get bounding box
      botleft.set_x (edgept->pos.x ());
    else if (edgept->pos.x () > topright.x ())
      topright.set_x (edgept->pos.x ());
    if (edgept->pos.y () < botleft.y ())
                                 //get bounding box
      botleft.set_y (edgept->pos.y ());
    else if (edgept->pos.y () > topright.y ()) {
      realstart = edgept;
      leftmost = edgept->pos.x ();
      topright.set_y (edgept->pos.y ());
    }
    else if (edgept->pos.y () == topright.y ()
    && edgept->pos.x () < leftmost) {
                                 //leftmost on line
      leftmost = edgept->pos.x ();
      realstart = edgept;
    }
    length++;                    //count elements
  }
  while (edgept != start);
  start = realstart;             //shift it to topleft
  return length;
}
Exemple #19
0
// Adds sub-pixel resolution EdgeOffsets for the outline using only
// a binary image source.
// Runs a sliding window of 5 edge steps over the outline, maintaining a count
// of the number of steps in each of the 4 directions in the window, and a
// sum of the x or y position of each step (as appropriate to its direction.)
// Ignores single-count steps EXCEPT the sharp U-turn and smoothes out the
// perpendicular direction. Eg
// ___              ___       Chain code from the left:
//    |___    ___   ___|      222122212223221232223000
//        |___|  |_|          Corresponding counts of each direction:
//                          0   00000000000000000123
//                          1   11121111001111100000
//                          2   44434443443333343321
//                          3   00000001111111112111
// Count of direction at center 41434143413313143313
// Step gets used?              YNYYYNYYYNYYNYNYYYyY (y= U-turn exception)
// Path redrawn showing only the used points:
// ___              ___
//     ___    ___   ___|
//         ___    _
// Sub-pixel edge position cannot be shown well with ASCII-art, but each
// horizontal step's y position is the mean of the y positions of the steps
// in the same direction in the sliding window, which makes a much smoother
// outline, without losing important detail.
void C_OUTLINE::ComputeBinaryOffsets() {
  delete [] offsets;
  offsets = new EdgeOffset[stepcount];
  // Count of the number of steps in each direction in the sliding window.
  int dir_counts[4];
  // Sum of the positions (y for a horizontal step, x for vertical) in each
  // direction in the sliding window.
  int pos_totals[4];
  memset(dir_counts, 0, sizeof(dir_counts));
  memset(pos_totals, 0, sizeof(pos_totals));
  ICOORD pos = start;
  ICOORD tail_pos = pos;
  // tail_pos is the trailing position, with the next point to be lost from
  // the window.
  tail_pos -= step(stepcount - 1);
  tail_pos -= step(stepcount - 2);
  // head_pos is the leading position, with the next point to be added to the
  // window.
  ICOORD head_pos = tail_pos;
  // Set up the initial window with 4 points in [-2, 2)
  for (int s = -2; s < 2; ++s) {
    increment_step(s, 1, &head_pos, dir_counts, pos_totals);
  }
  for (int s = 0; s < stepcount; pos += step(s++)) {
    // At step s, s in in the middle of [s-2, s+2].
    increment_step(s + 2, 1, &head_pos, dir_counts, pos_totals);
    int dir_index = chain_code(s);
    ICOORD step_vec = step(s);
    int best_diff = 0;
    int offset = 0;
    // Use only steps that have a count of >=2 OR the strong U-turn with a
    // single d and 2 at d-1 and 2 at d+1 (mod 4).
    if (dir_counts[dir_index] >= 2 || (dir_counts[dir_index] == 1 &&
        dir_counts[Modulo(dir_index - 1, 4)] == 2 &&
        dir_counts[Modulo(dir_index + 1, 4)] == 2)) {
      // Valid step direction.
      best_diff = dir_counts[dir_index];
      int edge_pos = step_vec.x() == 0 ? pos.x() : pos.y();
      // The offset proposes that the actual step should be positioned at
      // the mean position of the steps in the window of the same direction.
      // See ASCII art above.
      offset = pos_totals[dir_index] - best_diff * edge_pos;
    }
    offsets[s].offset_numerator =
        static_cast<inT8>(ClipToRange(offset, -MAX_INT8, MAX_INT8));
    offsets[s].pixel_diff = static_cast<uinT8>(ClipToRange(best_diff, 0 ,
                                                           MAX_UINT8));
    // The direction is just the vector from start to end of the window.
    FCOORD direction(head_pos.x() - tail_pos.x(), head_pos.y() - tail_pos.y());
    offsets[s].direction = direction.to_direction();
    increment_step(s - 2, -1, &tail_pos, dir_counts, pos_totals);
  }
}
Exemple #20
0
void QSPLINE::move(            // reposition spline
                   ICOORD vec  // by vector
                  ) {
  inT32 segment;                 //index of segment
  inT16 x_shift = vec.x ();

  for (segment = 0; segment < segments; segment++) {
    xcoords[segment] += x_shift;
    quadratics[segment].move (vec);
  }
  xcoords[segment] += x_shift;
}
TBOX::TBOX(                   //construtor
         const ICOORD pt1,  //one corner
         const ICOORD pt2   //the other corner
        ) {
  if (pt1.x () <= pt2.x ()) {
    if (pt1.y () <= pt2.y ()) {
      bot_left = pt1;
      top_right = pt2;
    }
    else {
      bot_left = ICOORD (pt1.x (), pt2.y ());
      top_right = ICOORD (pt2.x (), pt1.y ());
    }
  }
  else {
    if (pt1.y () <= pt2.y ()) {
      bot_left = ICOORD (pt2.x (), pt1.y ());
      top_right = ICOORD (pt1.x (), pt2.y ());
    }
    else {
      bot_left = pt2;
      top_right = pt1;
    }
  }
}
Exemple #22
0
inT16 BLOCK_LINE_IT::get_line(             //get a line
                              inT16 y,     //line to get
                              inT16 &xext  //output extent
                             ) {
  ICOORD bleft;                  //bounding box
  ICOORD tright;                 //of block & rect

                                 //get block box
  block->bounding_box (bleft, tright);
  if (y < bleft.y () || y >= tright.y ()) {
    //              block->print(stderr,FALSE);
    BADBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
  }

                                 //get rectangle box
  rect_it.bounding_box (bleft, tright);
                                 //inside rectangle
  if (y >= bleft.y () && y < tright.y ()) {
                                 //width of line
    xext = tright.x () - bleft.x ();
    return bleft.x ();           //start of line
  }
  for (rect_it.start_block (); !rect_it.cycled_rects (); rect_it.forward ()) {
                                 //get rectangle box
    rect_it.bounding_box (bleft, tright);
                                 //inside rectangle
    if (y >= bleft.y () && y < tright.y ()) {
                                 //width of line
      xext = tright.x () - bleft.x ();
      return bleft.x ();         //start of line
    }
  }
  LOSTBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
  return 0;                      //dummy to stop warning
}
Exemple #23
0
// Helper function to return a scaled Pix with one pixel per grid cell,
// set (black) where the given outline enters the corresponding grid cell,
// and clear where the outline does not touch the grid cell.
// Also returns the grid coords of the bottom-left of the Pix, in *left
// and *bottom, which corresponds to (0, 0) on the Pix.
// Note that the Pix is used upside-down, with (0, 0) being the bottom-left.
Pix* TraceOutlineOnReducedPix(C_OUTLINE* outline, int gridsize,
                              ICOORD bleft, int* left, int* bottom) {
  TBOX box = outline->bounding_box();
  Pix* pix = GridReducedPix(box, gridsize, bleft, left, bottom);
  int wpl = pixGetWpl(pix);
  l_uint32* data = pixGetData(pix);
  int length = outline->pathlength();
  ICOORD pos = outline->start_pos();
  for (int i = 0; i < length; ++i) {
    int grid_x = (pos.x() - bleft.x()) / gridsize - *left;
    int grid_y = (pos.y() - bleft.y()) / gridsize - *bottom;
    SET_DATA_BIT(data + grid_y * wpl, grid_x);
    pos += outline->step(i);
  }
  return pix;
}
Exemple #24
0
/** Returns the polygon outline of the current block. The returned Pta must
 *  be ptaDestroy-ed after use. */
Pta* PageIterator::BlockPolygon() const {
  if (it_->block() == NULL || it_->block()->block == NULL)
    return NULL;  // Already at the end!
  if (it_->block()->block->poly_block() == NULL)
    return NULL;  // No layout analysis used - no polygon.
  ICOORDELT_IT it(it_->block()->block->poly_block()->points());
  Pta* pta = ptaCreate(it.length());
  int num_pts = 0;
  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward(), ++num_pts) {
    ICOORD* pt = it.data();
    // Convert to top-down coords within the input image.
    float x = static_cast<float>(pt->x()) / scale_ + rect_left_;
    float y = rect_top_ + rect_height_ - static_cast<float>(pt->y()) / scale_;
    ptaAddPt(pta, x, y);
  }
  return pta;
}
Exemple #25
0
void PDBLK::plot(                //draw outline
                 ScrollView* window,  //window to draw in
                 inT32 serial,   //serial number
                 ScrollView::Color colour   //colour to draw in
                ) {
  ICOORD startpt;                //start of outline
  ICOORD endpt;                  //end of outline
  ICOORD prevpt;                 //previous point
  ICOORDELT_IT it = &leftside;   //iterator

                                 //set the colour
  window->Pen(colour);
  window->TextAttributes("Times", BLOCK_LABEL_HEIGHT, false, false, false);

  if (hand_poly != NULL) {
    hand_poly->plot(window, serial);
  } else if (!leftside.empty ()) {
    startpt = *(it.data ());     //bottom left corner
    //              tprintf("Block %d bottom left is (%d,%d)\n",
    //                      serial,startpt.x(),startpt.y());
    char temp_buff[34];
    #ifdef __UNIX__
    sprintf(temp_buff, INT32FORMAT, serial);
    #else
    ultoa (serial, temp_buff, 10);
    #endif
    window->Text(startpt.x (), startpt.y (), temp_buff);

    window->SetCursor(startpt.x (), startpt.y ());
    do {
      prevpt = *(it.data ());    //previous point
      it.forward ();             //move to next point
                                 //draw round corner
    window->DrawTo(prevpt.x (), it.data ()->y ());
    window->DrawTo(it.data ()->x (), it.data ()->y ());
    }
    while (!it.at_last ());      //until end of list
    endpt = *(it.data ());       //end point

                                 //other side of boundary
    window->SetCursor(startpt.x (), startpt.y ());
    it.set_to_list (&rightside);
    prevpt = startpt;
    for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
                                 //draw round corner
    window->DrawTo(prevpt.x (), it.data ()->y ());
    window->DrawTo(it.data ()->x (), it.data ()->y ());
      prevpt = *(it.data ());    //previous point
    }
                                 //close boundary
    window->DrawTo(endpt.x(), endpt.y());
  }
}
Exemple #26
0
// Backwards compatible constrained fit with a supplied gradient.
double DetLineFit::ConstrainedFit(double m, float* c) {
  ICOORDELT_IT it(&pt_list_);
  // Do something sensible with no points.
  if (pt_list_.empty()) {
    *c = 0.0f;
    return 0.0;
  }
  // Count the points and find the first and last kNumEndPoints.
  // Put the ends in a single array to make their use easier later.
  ICOORD* pts[kNumEndPoints * 2];
  int pt_count = 0;
  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
    if (pt_count < kNumEndPoints) {
      pts[pt_count] = it.data();
      pts[kNumEndPoints + pt_count] = pts[pt_count];
    } else {
      for (int i = 1; i < kNumEndPoints; ++i)
        pts[kNumEndPoints + i - 1] = pts[kNumEndPoints + i];
      pts[kNumEndPoints * 2 - 1] = it.data();
    }
    ++pt_count;
  }
  while (pt_count < kNumEndPoints) {
    pts[pt_count] = NULL;
    pts[kNumEndPoints + pt_count++] = NULL;
  }
  int* distances = new int[pt_count];
  double best_uq = -1.0;
  // Iterate each pair of points and find the best fitting line.
  for (int i = 0; i < kNumEndPoints * 2; ++i) {
    ICOORD* start = pts[i];
    if (start == NULL) continue;
    ICOORD end = ComputeEndFromGradient(*start, m);
    // Compute the upper quartile error from the line.
    double dist = ComputeErrors(*start, end, distances);
    if (dist < best_uq || best_uq < 0.0) {
      best_uq = dist;
      *c = start->y() - start->x() * m;
    }
  }
  delete [] distances;
  // Finally compute the square root to return the true distance.
  return best_uq > 0.0 ? sqrt(best_uq) : best_uq;
}
Exemple #27
0
void block_edges(Pix *t_pix,           // thresholded image
                 PDBLK *block,         // block in image
                 C_OUTLINE_IT* outline_it) {
  ICOORD bleft;                  // bounding box
  ICOORD tright;
  BLOCK_LINE_IT line_it = block; // line iterator

  int width = pixGetWidth(t_pix);
  int height = pixGetHeight(t_pix);
  int wpl = pixGetWpl(t_pix);
                                 // lines in progress
  CRACKEDGE **ptrline = new CRACKEDGE*[width + 1];
  CRACKEDGE *free_cracks = NULL;

  block->bounding_box(bleft, tright);  // block box
  int block_width = tright.x() - bleft.x();
  for (int x = block_width; x >= 0; x--)
    ptrline[x] = NULL;           //  no lines in progress

  uinT8* bwline = new uinT8[width];

  uinT8 margin = WHITE_PIX;

  for (int y = tright.y() - 1; y >= bleft.y() - 1; y--) {
    if (y >= bleft.y() && y < tright.y()) {
      // Get the binary pixels from the image.
      l_uint32* line = pixGetData(t_pix) + wpl * (height - 1 - y);
      for (int x = 0; x < block_width; ++x) {
        bwline[x] = GET_DATA_BIT(line, x + bleft.x()) ^ 1;
      }
      make_margins(block, &line_it, bwline, margin, bleft.x(), tright.x(), y);
    } else {
      memset(bwline, margin, block_width * sizeof(bwline[0]));
    }
    line_edges(bleft.x(), y, block_width,
               margin, bwline, ptrline, &free_cracks, outline_it);
  }

  free_crackedges(free_cracks);  // really free them
  delete[] ptrline;
  delete[] bwline;
}
Exemple #28
0
bool fixed_chop_coutline(                                  //chop the outline
        C_OUTLINE* srcline,               //source outline
        int16_t chop_coord,                 //place to chop
        float pitch_error,                //allowed deviation
        C_OUTLINE_FRAG_LIST* left_frags,  //left half of chop
        C_OUTLINE_FRAG_LIST* right_frags  //right half of chop
) {
  bool first_frag;              //fragment
  int16_t left_edge;               //of outline
  int16_t startindex;              //in first fragment
  int32_t length;                  //of outline
  int16_t stepindex;               //into outline
  int16_t head_index;              //start of fragment
  ICOORD head_pos;               //start of fragment
  int16_t tail_index;              //end of fragment
  ICOORD tail_pos;               //end of fragment
  ICOORD pos;                    //current point
  int16_t first_index = 0;         //first tail
  ICOORD first_pos;              //first tail

  length = srcline->pathlength ();
  pos = srcline->start_pos ();
  left_edge = pos.x ();
  tail_index = 0;
  tail_pos = pos;
  for (stepindex = 0; stepindex < length; stepindex++) {
    if (pos.x () < left_edge) {
      left_edge = pos.x ();
      tail_index = stepindex;
      tail_pos = pos;
    }
    pos += srcline->step (stepindex);
  }
  if (left_edge >= chop_coord - pitch_error)
    return false;                //not worth it

  startindex = tail_index;
  first_frag = true;
  head_index = tail_index;
  head_pos = tail_pos;
  do {
    do {
      tail_pos += srcline->step (tail_index);
      tail_index++;
      if (tail_index == length)
        tail_index = 0;
    }
    while (tail_pos.x () != chop_coord && tail_index != startindex);
    if (tail_index == startindex) {
      if (first_frag)
        return false;            //doesn't cross line
      else
        break;
    }
    //#ifdef __UNIX__
    ASSERT_HOST (head_index != tail_index);
    //#endif
    if (!first_frag) {
      save_chop_cfragment(head_index,
                          head_pos,
                          tail_index,
                          tail_pos,
                          srcline,
                          left_frags);
    }
    else {
      first_index = tail_index;
      first_pos = tail_pos;
      first_frag = false;
    }
    while (srcline->step (tail_index).x () == 0) {
      tail_pos += srcline->step (tail_index);
      tail_index++;
      if (tail_index == length)
        tail_index = 0;
    }
    head_index = tail_index;
    head_pos = tail_pos;
    while (srcline->step (tail_index).x () > 0) {
      do {
        tail_pos += srcline->step (tail_index);
        tail_index++;
        if (tail_index == length)
          tail_index = 0;
      }
      while (tail_pos.x () != chop_coord);
      //#ifdef __UNIX__
      ASSERT_HOST (head_index != tail_index);
      //#endif
      save_chop_cfragment(head_index,
                          head_pos,
                          tail_index,
                          tail_pos,
                          srcline,
                          right_frags);
      while (srcline->step (tail_index).x () == 0) {
        tail_pos += srcline->step (tail_index);
        tail_index++;
        if (tail_index == length)
          tail_index = 0;
      }
      head_index = tail_index;
      head_pos = tail_pos;
    }
  }
  while (tail_index != startindex);
  save_chop_cfragment(head_index,
                      head_pos,
                      first_index,
                      first_pos,
                      srcline,
                      left_frags);
  return true;                   //did some chopping
}
Exemple #29
0
// (Re)Fit a line to the stored points. Returns false if the line
// is degenerate. Althougth the TabVector code mostly doesn't care about the
// direction of lines, XAtY would give silly results for a horizontal line.
// The class is mostly aimed at use for vertical lines representing
// horizontal tab stops.
bool TabVector::Fit(ICOORD vertical, bool force_parallel) {
  needs_refit_ = false;
  if (boxes_.empty()) {
    // Don't refit something with no boxes, as that only happens
    // in Evaluate, and we don't want to end up with a zero vector.
    if (!force_parallel)
      return false;
    // If we are forcing parallel, then we just need to set the sort_key_.
    ICOORD midpt = startpt_;
    midpt += endpt_;
    midpt /= 2;
    sort_key_ = SortKey(vertical, midpt.x(), midpt.y());
    return startpt_.y() != endpt_.y();
  }
  if (!force_parallel && !IsRagged()) {
    // Use a fitted line as the vertical.
    DetLineFit linepoints;
    BLOBNBOX_C_IT it(&boxes_);
    // Fit a line to all the boxes in the list.
    for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
      BLOBNBOX* bbox = it.data();
      TBOX box = bbox->bounding_box();
      int x1 = IsRightTab() ? box.right() : box.left();
      ICOORD boxpt(x1, box.bottom());
      linepoints.Add(boxpt);
      if (it.at_last()) {
        ICOORD top_pt(x1, box.top());
        linepoints.Add(top_pt);
      }
    }
    linepoints.Fit(&startpt_, &endpt_);
    if (startpt_.y() != endpt_.y()) {
      vertical = endpt_;
      vertical -= startpt_;
    }
  }
  int start_y = startpt_.y();
  int end_y = endpt_.y();
  sort_key_ = IsLeftTab() ? MAX_INT32 : -MAX_INT32;
  BLOBNBOX_C_IT it(&boxes_);
  // Choose a line parallel to the vertical such that all boxes are on the
  // correct side of it.
  mean_width_ = 0;
  int width_count = 0;
  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
    BLOBNBOX* bbox = it.data();
    TBOX box = bbox->bounding_box();
    mean_width_ += box.width();
    ++width_count;
    int x1 = IsRightTab() ? box.right() : box.left();
    // Test both the bottom and the top, as one will be more extreme, depending
    // on the direction of skew.
    int bottom_y = box.bottom();
    int top_y = box.top();
    int key = SortKey(vertical, x1, bottom_y);
    if (IsLeftTab() == (key < sort_key_)) {
      sort_key_ = key;
      startpt_ = ICOORD(x1, bottom_y);
    }
    key = SortKey(vertical, x1, top_y);
    if (IsLeftTab() == (key < sort_key_)) {
      sort_key_ = key;
      startpt_ = ICOORD(x1, top_y);
    }
    if (it.at_first())
      start_y = bottom_y;
    if (it.at_last())
      end_y = top_y;
  }
  if (width_count > 0) {
    mean_width_ = (mean_width_ + width_count - 1) / width_count;
  }
  endpt_ = startpt_ + vertical;
  needs_evaluation_ = true;
  if (start_y != end_y) {
    // Set the ends of the vector to fully include the first and last blobs.
    startpt_.set_x(XAtY(vertical, sort_key_, start_y));
    startpt_.set_y(start_y);
    endpt_.set_x(XAtY(vertical, sort_key_, end_y));
    endpt_.set_y(end_y);
    return true;
  }
  return false;
}
Exemple #30
0
void block_edges(IMAGE *t_image,       // thresholded image
                 PDBLK *block,         // block in image
                 C_OUTLINE_IT* outline_it) {
  uinT8 margin;                  // margin colour
  inT16 x;                       // line coords
  inT16 y;                       // current line
  ICOORD bleft;                  // bounding box
  ICOORD tright;
  ICOORD block_bleft;            // bounding box
  ICOORD block_tright;
  int xindex;                    // index to pixel
  BLOCK_LINE_IT line_it = block; // line iterator
  IMAGELINE bwline;              // thresholded line
                                 // lines in progress
  CRACKEDGE **ptrline = new CRACKEDGE*[t_image->get_xsize()+1];
  CRACKEDGE *free_cracks = NULL;

  block->bounding_box(bleft, tright);  // block box
  block_bleft = bleft;
  block_tright = tright;
  for (x = tright.x() - bleft.x(); x >= 0; x--)
    ptrline[x] = NULL;           //no lines in progress

  bwline.init(t_image->get_xsize());

  margin = WHITE_PIX;

  for (y = tright.y() - 1; y >= bleft.y() - 1; y--) {
    if (y >= block_bleft.y() && y < block_tright.y()) {
      t_image->get_line(bleft.x(), y, tright.x() - bleft.x(), &bwline, 0);
      make_margins(block, &line_it, bwline.pixels, margin, bleft.x(),
                   tright.x(), y);
    } else {
      x = tright.x() - bleft.x();
      for (xindex = 0; xindex < x; xindex++)
        bwline.pixels[xindex] = margin;
    }
    line_edges(bleft.x(), y, tright.x() - bleft.x(),
               margin, bwline.pixels, ptrline, &free_cracks, outline_it);
  }

  free_crackedges(free_cracks);  // really free them
  delete[] ptrline;
}