tesseract  4.00.00dev
makerow.h File Reference
#include "params.h"
#include "ocrblock.h"
#include "blobs.h"
#include "blobbox.h"
#include "statistc.h"

Go to the source code of this file.

Enumerations

enum  OVERLAP_STATE { ASSIGN, REJECT, NEW_ROW }
 
enum  ROW_CATEGORY { ROW_ASCENDERS_FOUND, ROW_DESCENDERS_FOUND, ROW_UNKNOWN, ROW_INVALID }
 

Functions

void get_min_max_xheight (int block_linesize, int *min_height, int *max_height)
 
ROW_CATEGORY get_row_category (const TO_ROW *row)
 
bool within_error_margin (float test, float num, float margin)
 
void fill_heights (TO_ROW *row, float gradient, int min_height, int max_height, STATS *heights, STATS *floating_heights)
 
float make_single_row (ICOORD page_tr, bool allow_sub_blobs, TO_BLOCK *block, TO_BLOCK_LIST *blocks)
 
float make_rows (ICOORD page_tr, TO_BLOCK_LIST *port_blocks)
 
void make_initial_textrows (ICOORD page_tr, TO_BLOCK *block, FCOORD rotation, BOOL8 testing_on)
 
void fit_lms_line (TO_ROW *row)
 
void compute_page_skew (TO_BLOCK_LIST *blocks, float &page_m, float &page_err)
 
void vigorous_noise_removal (TO_BLOCK *block)
 
void cleanup_rows_making (ICOORD page_tr, TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
 
void delete_non_dropout_rows (TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
 
BOOL8 find_best_dropout_row (TO_ROW *row, inT32 distance, float dist_limit, inT32 line_index, TO_ROW_IT *row_it, BOOL8 testing_on)
 
TBOX deskew_block_coords (TO_BLOCK *block, float gradient)
 
void compute_line_occupation (TO_BLOCK *block, float gradient, inT32 min_y, inT32 max_y, inT32 *occupation, inT32 *deltas)
 
void compute_occupation_threshold (inT32 low_window, inT32 high_window, inT32 line_count, inT32 *occupation, inT32 *thresholds)
 
void compute_dropout_distances (inT32 *occupation, inT32 *thresholds, inT32 line_count)
 
void expand_rows (ICOORD page_tr, TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
 
void adjust_row_limits (TO_BLOCK *block)
 
void compute_row_stats (TO_BLOCK *block, BOOL8 testing_on)
 
float median_block_xheight (TO_BLOCK *block, float gradient)
 
int compute_xheight_from_modes (STATS *heights, STATS *floating_heights, bool cap_only, int min_height, int max_height, float *xheight, float *ascrise)
 
inT32 compute_row_descdrop (TO_ROW *row, float gradient, int xheight_blob_count, STATS *heights)
 
inT32 compute_height_modes (STATS *heights, inT32 min_height, inT32 max_height, inT32 *modes, inT32 maxmodes)
 
void correct_row_xheight (TO_ROW *row, float xheight, float ascrise, float descdrop)
 
void separate_underlines (TO_BLOCK *block, float gradient, FCOORD rotation, BOOL8 testing_on)
 
void pre_associate_blobs (ICOORD page_tr, TO_BLOCK *block, FCOORD rotation, BOOL8 testing_on)
 
void fit_parallel_rows (TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
 
void fit_parallel_lms (float gradient, TO_ROW *row)
 
void make_baseline_spline (TO_ROW *row, TO_BLOCK *block)
 
BOOL8 segment_baseline (TO_ROW *row, TO_BLOCK *block, inT32 &segments, inT32 xstarts[])
 
double * linear_spline_baseline (TO_ROW *row, TO_BLOCK *block, inT32 &segments, inT32 xstarts[])
 
void assign_blobs_to_rows (TO_BLOCK *block, float *gradient, int pass, BOOL8 reject_misses, BOOL8 make_new_rows, BOOL8 drawing_skew)
 
OVERLAP_STATE most_overlapping_row (TO_ROW_IT *row_it, TO_ROW *&best_row, float top, float bottom, float rowsize, BOOL8 testing_blob)
 
int blob_x_order (const void *item1, const void *item2)
 
int row_y_order (const void *item1, const void *item2)
 
int row_spacing_order (const void *item1, const void *item2)
 
void mark_repeated_chars (TO_ROW *row)
 

Variables

bool textord_heavy_nr = FALSE
 
bool textord_show_initial_rows = FALSE
 
bool textord_show_parallel_rows = FALSE
 
bool textord_show_expanded_rows = FALSE
 
bool textord_show_final_rows = FALSE
 
bool textord_show_final_blobs = FALSE
 
bool textord_test_landscape = FALSE
 
bool textord_parallel_baselines = TRUE
 
bool textord_straight_baselines = FALSE
 
bool textord_quadratic_baselines = FALSE
 
bool textord_old_baselines = TRUE
 
bool textord_old_xheight = TRUE
 
bool textord_fix_xheight_bug = TRUE
 
bool textord_fix_makerow_bug = TRUE
 
bool textord_cblob_blockocc = TRUE
 
bool textord_debug_xheights = FALSE
 
int textord_test_x = -MAX_INT32
 
int textord_test_y = -MAX_INT32
 
int textord_min_blobs_in_row = 4
 
int textord_spline_minblobs = 8
 
int textord_spline_medianwin = 6
 
int textord_min_xheight = 10
 
double textord_spline_shift_fraction = 0.02
 
double textord_spline_outlier_fraction = 0.1
 
double textord_skew_ile = 0.5
 
double textord_skew_lag = 0.75
 
double textord_linespace_iqrlimit = 0.2
 
double textord_width_limit = 8
 
double textord_chop_width = 1.5
 
double textord_minxh = 0.25
 
double textord_min_linesize = 1.25
 
double textord_excess_blobsize = 1.3
 
double textord_occupancy_threshold = 0.4
 
double textord_underline_width = 2.0
 
double textord_min_blob_height_fraction = 0.75
 
double textord_xheight_mode_fraction = 0.4
 
double textord_ascheight_mode_fraction = 0.15
 
double textord_ascx_ratio_min = 1.2
 
double textord_ascx_ratio_max = 1.7
 
double textord_descx_ratio_min = 0.15
 
double textord_descx_ratio_max = 0.6
 
double textord_xheight_error_margin = 0.1
 
int textord_lms_line_trials = 12
 
bool textord_new_initial_xheight = TRUE
 
bool textord_debug_blob = FALSE
 

Enumeration Type Documentation

◆ OVERLAP_STATE

Enumerator
ASSIGN 
REJECT 
NEW_ROW 

Definition at line 29 of file makerow.h.

30 {
31  ASSIGN, //assign it to row
32  REJECT, //reject it - dual overlap
33  NEW_ROW
34 };
Definition: makerow.h:31
Definition: makerow.h:32

◆ ROW_CATEGORY

Enumerator
ROW_ASCENDERS_FOUND 
ROW_DESCENDERS_FOUND 
ROW_UNKNOWN 
ROW_INVALID 

Definition at line 36 of file makerow.h.

Function Documentation

◆ adjust_row_limits()

void adjust_row_limits ( TO_BLOCK block)

adjust_row_limits

Change the limits of rows to suit the default fractions.

Definition at line 1120 of file makerow.cpp.

1122  {
1123  TO_ROW *row; //current row
1124  float size; //size of row
1125  float ymax; //top of row
1126  float ymin; //bottom of row
1127  TO_ROW_IT row_it = block->get_rows ();
1128 
1130  tprintf("Adjusting row limits for block(%d,%d)\n",
1131  block->block->bounding_box().left(),
1132  block->block->bounding_box().top());
1133  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
1134  row = row_it.data ();
1135  size = row->max_y () - row->min_y ();
1137  tprintf("Row at %f has min %f, max %f, size %f\n",
1138  row->intercept(), row->min_y(), row->max_y(), size);
1142  ymax = size * (tesseract::CCStruct::kXHeightFraction +
1145  row->set_limits (row->intercept () + ymin, row->intercept () + ymax);
1146  row->merged = FALSE;
1147  }
1148 }
static const double kAscenderFraction
Definition: ccstruct.h:35
static const double kDescenderFraction
Definition: ccstruct.h:33
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
voidpf void uLong size
Definition: ioapi.h:39
static const double kXHeightFraction
Definition: ccstruct.h:34
#define tprintf(...)
Definition: tprintf.h:31
float intercept() const
Definition: blobbox.h:584
float min_y() const
Definition: blobbox.h:557
void set_limits(float new_min, float new_max)
Definition: blobbox.h:618
bool textord_show_expanded_rows
Definition: makerow.cpp:47
#define FALSE
Definition: capi.h:46
float max_y() const
Definition: blobbox.h:554
BOOL8 merged
Definition: blobbox.h:641
BLOCK * block
Definition: blobbox.h:773
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700

◆ assign_blobs_to_rows()

void assign_blobs_to_rows ( TO_BLOCK block,
float *  gradient,
int  pass,
BOOL8  reject_misses,
BOOL8  make_new_rows,
BOOL8  drawing_skew 
)

Definition at line 2296 of file makerow.cpp.

2303  {
2304  OVERLAP_STATE overlap_result; //what to do with it
2305  float ycoord; //current y
2306  float top, bottom; //of blob
2307  float g_length = 1.0f; //from gradient
2308  inT16 row_count; //no of rows
2309  inT16 left_x; //left edge
2310  inT16 last_x; //previous edge
2311  float block_skew; //y delta
2312  float smooth_factor; //for new coords
2313  float near_dist; //dist to nearest row
2314  ICOORD testpt; //testing only
2315  BLOBNBOX *blob; //current blob
2316  TO_ROW *row; //current row
2317  TO_ROW *dest_row = NULL; //row to put blob in
2318  //iterators
2319  BLOBNBOX_IT blob_it = &block->blobs;
2320  TO_ROW_IT row_it = block->get_rows ();
2321 
2322  ycoord =
2323  (block->block->bounding_box ().bottom () +
2324  block->block->bounding_box ().top ()) / 2.0f;
2325  if (gradient != NULL)
2326  g_length = sqrt (1 + *gradient * *gradient);
2327 #ifndef GRAPHICS_DISABLED
2328  if (drawing_skew)
2329  to_win->SetCursor(block->block->bounding_box ().left (), ycoord);
2330 #endif
2331  testpt = ICOORD (textord_test_x, textord_test_y);
2332  blob_it.sort (blob_x_order);
2333  smooth_factor = 1.0;
2334  block_skew = 0.0f;
2335  row_count = row_it.length (); //might have rows
2336  if (!blob_it.empty ()) {
2337  left_x = blob_it.data ()->bounding_box ().left ();
2338  }
2339  else {
2340  left_x = block->block->bounding_box ().left ();
2341  }
2342  last_x = left_x;
2343  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {
2344  blob = blob_it.data ();
2345  if (gradient != NULL) {
2346  block_skew = (1 - 1 / g_length) * blob->bounding_box ().bottom ()
2347  + *gradient / g_length * blob->bounding_box ().left ();
2348  }
2349  else if (blob->bounding_box ().left () - last_x > block->line_size / 2
2350  && last_x - left_x > block->line_size * 2
2352  // tprintf("Interpolating skew from %g",block_skew);
2353  block_skew *= (float) (blob->bounding_box ().left () - left_x)
2354  / (last_x - left_x);
2355  // tprintf("to %g\n",block_skew);
2356  }
2357  last_x = blob->bounding_box ().left ();
2358  top = blob->bounding_box ().top () - block_skew;
2359  bottom = blob->bounding_box ().bottom () - block_skew;
2360 #ifndef GRAPHICS_DISABLED
2361  if (drawing_skew)
2362  to_win->DrawTo(blob->bounding_box ().left (), ycoord + block_skew);
2363 #endif
2364  if (!row_it.empty ()) {
2365  for (row_it.move_to_first ();
2366  !row_it.at_last () && row_it.data ()->min_y () > top;
2367  row_it.forward ());
2368  row = row_it.data ();
2369  if (row->min_y () <= top && row->max_y () >= bottom) {
2370  //any overlap
2371  dest_row = row;
2372  overlap_result = most_overlapping_row (&row_it, dest_row,
2373  top, bottom,
2374  block->line_size,
2375  blob->bounding_box ().
2376  contains (testpt));
2377  if (overlap_result == NEW_ROW && !reject_misses)
2378  overlap_result = ASSIGN;
2379  }
2380  else {
2381  overlap_result = NEW_ROW;
2382  if (!make_new_rows) {
2383  near_dist = row_it.data_relative (-1)->min_y () - top;
2384  //below bottom
2385  if (bottom < row->min_y ()) {
2386  if (row->min_y () - bottom <=
2387  (block->line_spacing -
2389  //done it
2390  overlap_result = ASSIGN;
2391  dest_row = row;
2392  }
2393  }
2394  else if (near_dist > 0
2395  && near_dist < bottom - row->max_y ()) {
2396  row_it.backward ();
2397  dest_row = row_it.data ();
2398  if (dest_row->min_y () - bottom <=
2399  (block->line_spacing -
2401  //done it
2402  overlap_result = ASSIGN;
2403  }
2404  }
2405  else {
2406  if (top - row->max_y () <=
2407  (block->line_spacing -
2408  block->line_size) * (textord_overlap_x +
2410  //done it
2411  overlap_result = ASSIGN;
2412  dest_row = row;
2413  }
2414  }
2415  }
2416  }
2417  if (overlap_result == ASSIGN)
2418  dest_row->add_blob (blob_it.extract (), top, bottom,
2419  block->line_size);
2420  if (overlap_result == NEW_ROW) {
2421  if (make_new_rows && top - bottom < block->max_blob_size) {
2422  dest_row =
2423  new TO_ROW (blob_it.extract (), top, bottom,
2424  block->line_size);
2425  row_count++;
2426  if (bottom > row_it.data ()->min_y ())
2427  row_it.add_before_then_move (dest_row);
2428  //insert in right place
2429  else
2430  row_it.add_after_then_move (dest_row);
2431  smooth_factor =
2432  1.0 / (row_count * textord_skew_lag +
2434  }
2435  else
2436  overlap_result = REJECT;
2437  }
2438  }
2439  else if (make_new_rows && top - bottom < block->max_blob_size) {
2440  overlap_result = NEW_ROW;
2441  dest_row =
2442  new TO_ROW(blob_it.extract(), top, bottom, block->line_size);
2443  row_count++;
2444  row_it.add_after_then_move(dest_row);
2445  smooth_factor = 1.0 / (row_count * textord_skew_lag +
2447  }
2448  else
2449  overlap_result = REJECT;
2450  if (blob->bounding_box ().contains(testpt) && textord_debug_blob) {
2451  if (overlap_result != REJECT) {
2452  tprintf("Test blob assigned to row at (%g,%g) on pass %d\n",
2453  dest_row->min_y(), dest_row->max_y(), pass);
2454  }
2455  else {
2456  tprintf("Test blob assigned to no row on pass %d\n", pass);
2457  }
2458  }
2459  if (overlap_result != REJECT) {
2460  while (!row_it.at_first() &&
2461  row_it.data()->min_y() > row_it.data_relative(-1)->min_y()) {
2462  row = row_it.extract();
2463  row_it.backward();
2464  row_it.add_before_then_move(row);
2465  }
2466  while (!row_it.at_last() &&
2467  row_it.data ()->min_y() < row_it.data_relative (1)->min_y()) {
2468  row = row_it.extract();
2469  row_it.forward();
2470  // Keep rows in order.
2471  row_it.add_after_then_move(row);
2472  }
2473  BLOBNBOX_IT added_blob_it(dest_row->blob_list());
2474  added_blob_it.move_to_last();
2475  TBOX prev_box = added_blob_it.data_relative(-1)->bounding_box();
2476  if (dest_row->blob_list()->singleton() ||
2477  !prev_box.major_x_overlap(blob->bounding_box())) {
2478  block_skew = (1 - smooth_factor) * block_skew
2479  + smooth_factor * (blob->bounding_box().bottom() -
2480  dest_row->initial_min_y());
2481  }
2482  }
2483  }
2484  for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {
2485  if (row_it.data()->blob_list()->empty())
2486  delete row_it.extract(); // Discard empty rows.
2487  }
2488 }
Definition: makerow.h:31
int blob_x_order(const void *item1, const void *item2)
Definition: makerow.cpp:2591
Definition: makerow.h:32
static const double kAscenderFraction
Definition: ccstruct.h:35
float initial_min_y() const
Definition: blobbox.h:563
static const double kDescenderFraction
Definition: ccstruct.h:33
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
double textord_skew_lag
Definition: makerow.cpp:75
int textord_skewsmooth_offset
Definition: makerow.cpp:60
#define tprintf(...)
Definition: tprintf.h:31
bool major_x_overlap(const TBOX &box) const
Definition: rect.h:402
float min_y() const
Definition: blobbox.h:557
int16_t inT16
Definition: host.h:36
void SetCursor(int x, int y)
Definition: scrollview.cpp:525
inT16 left() const
Definition: rect.h:68
int textord_test_x
Definition: makerow.cpp:62
float line_size
Definition: blobbox.h:781
OVERLAP_STATE
Definition: makerow.h:29
bool textord_debug_blob
Definition: makerow.cpp:103
BLOBNBOX_LIST blobs
Definition: blobbox.h:768
double textord_overlap_x
Definition: makerow.cpp:81
EXTERN ScrollView * to_win
Definition: drawtord.cpp:38
int textord_skewsmooth_offset2
Definition: makerow.cpp:61
bool contains(const FCOORD pt) const
Definition: rect.h:323
inT16 top() const
Definition: rect.h:54
float max_y() const
Definition: blobbox.h:554
int textord_test_y
Definition: makerow.cpp:63
Definition: rect.h:30
OVERLAP_STATE most_overlapping_row(TO_ROW_IT *row_it, TO_ROW *&best_row, float top, float bottom, float rowsize, BOOL8 testing_blob)
Definition: makerow.cpp:2496
inT16 bottom() const
Definition: rect.h:61
BLOCK * block
Definition: blobbox.h:773
bool textord_interpolating_skew
Definition: makerow.cpp:59
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
void add_blob(BLOBNBOX *blob, float top, float bottom, float row_size)
Definition: blobbox.cpp:728
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
float line_spacing
Definition: blobbox.h:775
const TBOX & bounding_box() const
Definition: blobbox.h:215
void DrawTo(int x, int y)
Definition: scrollview.cpp:531
integer coordinate
Definition: points.h:30

◆ blob_x_order()

int blob_x_order ( const void *  item1,
const void *  item2 
)

Definition at line 2591 of file makerow.cpp.

2593  {
2594  //converted ptr
2595  BLOBNBOX *blob1 = *(BLOBNBOX **) item1;
2596  //converted ptr
2597  BLOBNBOX *blob2 = *(BLOBNBOX **) item2;
2598 
2599  if (blob1->bounding_box ().left () < blob2->bounding_box ().left ())
2600  return -1;
2601  else if (blob1->bounding_box ().left () > blob2->bounding_box ().left ())
2602  return 1;
2603  else
2604  return 0;
2605 }
inT16 left() const
Definition: rect.h:68
const TBOX & bounding_box() const
Definition: blobbox.h:215

◆ cleanup_rows_making()

void cleanup_rows_making ( ICOORD  page_tr,
TO_BLOCK block,
float  gradient,
FCOORD  rotation,
inT32  block_edge,
BOOL8  testing_on 
)

cleanup_rows_making

Remove overlapping rows and fit all the blobs to what's left.

Definition at line 524 of file makerow.cpp.

531  {
532  //iterators
533  BLOBNBOX_IT blob_it = &block->blobs;
534  TO_ROW_IT row_it = block->get_rows ();
535 
536 #ifndef GRAPHICS_DISABLED
537  if (textord_show_parallel_rows && testing_on) {
538  if (to_win == NULL)
539  create_to_win(page_tr);
540  }
541 #endif
542  //get row coords
543  fit_parallel_rows(block,
544  gradient,
545  rotation,
546  block_edge,
547  textord_show_parallel_rows &&testing_on);
549  gradient,
550  rotation,
551  block_edge,
552  textord_show_parallel_rows &&testing_on);
553  expand_rows(page_tr, block, gradient, rotation, block_edge, testing_on);
554  blob_it.set_to_list (&block->blobs);
555  row_it.set_to_list (block->get_rows ());
556  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())
557  blob_it.add_list_after (row_it.data ()->blob_list ());
558  //give blobs back
559  assign_blobs_to_rows (block, &gradient, 1, FALSE, FALSE, FALSE);
560  //now new rows must be genuine
561  blob_it.set_to_list (&block->blobs);
562  blob_it.add_list_after (&block->large_blobs);
563  assign_blobs_to_rows (block, &gradient, 2, TRUE, TRUE, FALSE);
564  //safe to use big ones now
565  blob_it.set_to_list (&block->blobs);
566  //throw all blobs in
567  blob_it.add_list_after (&block->noise_blobs);
568  blob_it.add_list_after (&block->small_blobs);
569  assign_blobs_to_rows (block, &gradient, 3, FALSE, FALSE, FALSE);
570 }
bool textord_show_parallel_rows
Definition: makerow.cpp:46
#define TRUE
Definition: capi.h:45
BLOBNBOX_LIST large_blobs
Definition: blobbox.h:772
void expand_rows(ICOORD page_tr, TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
Definition: makerow.cpp:962
void delete_non_dropout_rows(TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
Definition: makerow.cpp:577
BLOBNBOX_LIST small_blobs
Definition: blobbox.h:771
void assign_blobs_to_rows(TO_BLOCK *block, float *gradient, int pass, BOOL8 reject_misses, BOOL8 make_new_rows, BOOL8 drawing_skew)
Definition: makerow.cpp:2296
#define FALSE
Definition: capi.h:46
BLOBNBOX_LIST blobs
Definition: blobbox.h:768
EXTERN ScrollView * to_win
Definition: drawtord.cpp:38
ScrollView * create_to_win(ICOORD page_tr)
Definition: drawtord.cpp:47
void fit_parallel_rows(TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
Definition: makerow.cpp:1948
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
BLOBNBOX_LIST noise_blobs
Definition: blobbox.h:770

◆ compute_dropout_distances()

void compute_dropout_distances ( inT32 occupation,
inT32 thresholds,
inT32  line_count 
)

Definition at line 915 of file makerow.cpp.

919  {
920  inT32 line_index; //of thresholds line
921  inT32 distance; //from prev dropout
922  inT32 next_dist; //to next dropout
923  inT32 back_index; //for back filling
924  inT32 prev_threshold; //before overwrite
925 
926  distance = -line_count;
927  line_index = 0;
928  do {
929  do {
930  distance--;
931  prev_threshold = thresholds[line_index];
932  //distance from prev
933  thresholds[line_index] = distance;
934  line_index++;
935  }
936  while (line_index < line_count
937  && (occupation[line_index] < thresholds[line_index]
938  || occupation[line_index - 1] >= prev_threshold));
939  if (line_index < line_count) {
940  back_index = line_index - 1;
941  next_dist = 1;
942  while (next_dist < -distance && back_index >= 0) {
943  thresholds[back_index] = next_dist;
944  back_index--;
945  next_dist++;
946  distance++;
947  }
948  distance = 1;
949  }
950  }
951  while (line_index < line_count);
952 }
int32_t inT32
Definition: host.h:38

◆ compute_height_modes()

inT32 compute_height_modes ( STATS heights,
inT32  min_height,
inT32  max_height,
inT32 modes,
inT32  maxmodes 
)

Definition at line 1640 of file makerow.cpp.

1644  { // size of modes
1645  inT32 pile_count; // no in source pile
1646  inT32 src_count; // no of source entries
1647  inT32 src_index; // current entry
1648  inT32 least_count; // height of smalllest
1649  inT32 least_index; // index of least
1650  inT32 dest_count; // index in modes
1651 
1652  src_count = max_height + 1 - min_height;
1653  dest_count = 0;
1654  least_count = MAX_INT32;
1655  least_index = -1;
1656  for (src_index = 0; src_index < src_count; src_index++) {
1657  pile_count = heights->pile_count(min_height + src_index);
1658  if (pile_count > 0) {
1659  if (dest_count < maxmodes) {
1660  if (pile_count < least_count) {
1661  // find smallest in array
1662  least_count = pile_count;
1663  least_index = dest_count;
1664  }
1665  modes[dest_count++] = min_height + src_index;
1666  } else if (pile_count >= least_count) {
1667  while (least_index < maxmodes - 1) {
1668  modes[least_index] = modes[least_index + 1];
1669  // shuffle up
1670  least_index++;
1671  }
1672  // new one on end
1673  modes[maxmodes - 1] = min_height + src_index;
1674  if (pile_count == least_count) {
1675  // new smallest
1676  least_index = maxmodes - 1;
1677  } else {
1678  least_count = heights->pile_count(modes[0]);
1679  least_index = 0;
1680  for (dest_count = 1; dest_count < maxmodes; dest_count++) {
1681  pile_count = heights->pile_count(modes[dest_count]);
1682  if (pile_count < least_count) {
1683  // find smallest
1684  least_count = pile_count;
1685  least_index = dest_count;
1686  }
1687  }
1688  }
1689  }
1690  }
1691  }
1692  return dest_count;
1693 }
int32_t inT32
Definition: host.h:38
#define MAX_INT32
Definition: host.h:62
inT32 pile_count(inT32 value) const
Definition: statistc.h:78

◆ compute_line_occupation()

void compute_line_occupation ( TO_BLOCK block,
float  gradient,
inT32  min_y,
inT32  max_y,
inT32 occupation,
inT32 deltas 
)

Definition at line 781 of file makerow.cpp.

788  {
789  inT32 line_count; //maxy-miny+1
790  inT32 line_index; //of scan line
791  int index; //array index for daft compilers
792  TO_ROW *row; //current row
793  TO_ROW_IT row_it = block->get_rows ();
794  BLOBNBOX *blob; //current blob
795  BLOBNBOX_IT blob_it; //iterator
796  float length; //of skew vector
797  TBOX blob_box; //bounding box
798  FCOORD rotation; //inverse of skew
799 
800  line_count = max_y - min_y + 1;
801  length = sqrt (gradient * gradient + 1);
802  rotation = FCOORD (1 / length, -gradient / length);
803  for (line_index = 0; line_index < line_count; line_index++)
804  deltas[line_index] = 0;
805  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
806  row = row_it.data ();
807  blob_it.set_to_list (row->blob_list ());
808  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list ();
809  blob_it.forward ()) {
810  blob = blob_it.data ();
811  blob_box = blob->bounding_box ();
812  blob_box.rotate (rotation);//de-skew it
813  int32_t width = blob_box.right() - blob_box.left();
814  index = blob_box.bottom() - min_y;
815  ASSERT_HOST(index >= 0 && index < line_count);
816  //count transitions
817  deltas[index] += width;
818  index = blob_box.top() - min_y;
819  ASSERT_HOST(index >= 0 && index < line_count);
820  deltas[index] -= width;
821  }
822  }
823  occupation[0] = deltas[0];
824  for (line_index = 1; line_index < line_count; line_index++)
825  occupation[line_index] = occupation[line_index - 1] + deltas[line_index];
826 }
Definition: points.h:189
int32_t inT32
Definition: host.h:38
#define ASSERT_HOST(x)
Definition: errcode.h:84
inT16 left() const
Definition: rect.h:68
inT16 top() const
Definition: rect.h:54
Definition: rect.h:30
inT16 right() const
Definition: rect.h:75
inT16 bottom() const
Definition: rect.h:61
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
const TBOX & bounding_box() const
Definition: blobbox.h:215
void rotate(const FCOORD &vec)
Definition: rect.h:189

◆ compute_occupation_threshold()

void compute_occupation_threshold ( inT32  low_window,
inT32  high_window,
inT32  line_count,
inT32 occupation,
inT32 thresholds 
)

compute_occupation_threshold

Compute thresholds for textline or not for the occupation array.

Definition at line 834 of file makerow.cpp.

840  {
841  inT32 line_index; //of thresholds line
842  inT32 low_index; //in occupation
843  inT32 high_index; //in occupation
844  inT32 sum; //current average
845  inT32 divisor; //to get thresholds
846  inT32 min_index; //of min occ
847  inT32 min_occ; //min in locality
848  inT32 test_index; //for finding min
849 
850  divisor =
851  (inT32) ceil ((low_window + high_window) / textord_occupancy_threshold);
852  if (low_window + high_window < line_count) {
853  for (sum = 0, high_index = 0; high_index < low_window; high_index++)
854  sum += occupation[high_index];
855  for (low_index = 0; low_index < high_window; low_index++, high_index++)
856  sum += occupation[high_index];
857  min_occ = occupation[0];
858  min_index = 0;
859  for (test_index = 1; test_index < high_index; test_index++) {
860  if (occupation[test_index] <= min_occ) {
861  min_occ = occupation[test_index];
862  min_index = test_index; //find min in region
863  }
864  }
865  for (line_index = 0; line_index < low_window; line_index++)
866  thresholds[line_index] = (sum - min_occ) / divisor + min_occ;
867  //same out to end
868  for (low_index = 0; high_index < line_count; low_index++, high_index++) {
869  sum -= occupation[low_index];
870  sum += occupation[high_index];
871  if (occupation[high_index] <= min_occ) {
872  //find min in region
873  min_occ = occupation[high_index];
874  min_index = high_index;
875  }
876  //lost min from region
877  if (min_index <= low_index) {
878  min_occ = occupation[low_index + 1];
879  min_index = low_index + 1;
880  for (test_index = low_index + 2; test_index <= high_index;
881  test_index++) {
882  if (occupation[test_index] <= min_occ) {
883  min_occ = occupation[test_index];
884  //find min in region
885  min_index = test_index;
886  }
887  }
888  }
889  thresholds[line_index++] = (sum - min_occ) / divisor + min_occ;
890  }
891  }
892  else {
893  min_occ = occupation[0];
894  min_index = 0;
895  for (sum = 0, low_index = 0; low_index < line_count; low_index++) {
896  if (occupation[low_index] < min_occ) {
897  min_occ = occupation[low_index];
898  min_index = low_index;
899  }
900  sum += occupation[low_index];
901  }
902  line_index = 0;
903  }
904  for (; line_index < line_count; line_index++)
905  thresholds[line_index] = (sum - min_occ) / divisor + min_occ;
906  //same out to end
907 }
int32_t inT32
Definition: host.h:38
double textord_occupancy_threshold
Definition: makerow.cpp:86

◆ compute_page_skew()

void compute_page_skew ( TO_BLOCK_LIST *  blocks,
float &  page_m,
float &  page_err 
)

Definition at line 287 of file makerow.cpp.

291  {
292  inT32 row_count; //total rows
293  inT32 blob_count; //total_blobs
294  inT32 row_err; //integer error
295  float *gradients; //of rows
296  float *errors; //of rows
297  inT32 row_index; //of total
298  TO_ROW *row; //current row
299  TO_BLOCK_IT block_it = blocks; //iterator
300  TO_ROW_IT row_it;
301 
302  row_count = 0;
303  blob_count = 0;
304  for (block_it.mark_cycle_pt (); !block_it.cycled_list ();
305  block_it.forward ()) {
306  POLY_BLOCK* pb = block_it.data()->block->poly_block();
307  if (pb != NULL && !pb->IsText())
308  continue; // Pretend non-text blocks don't exist.
309  row_count += block_it.data ()->get_rows ()->length ();
310  //count up rows
311  row_it.set_to_list (block_it.data ()->get_rows ());
312  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())
313  blob_count += row_it.data ()->blob_list ()->length ();
314  }
315  if (row_count == 0) {
316  page_m = 0.0f;
317  page_err = 0.0f;
318  return;
319  }
320  gradients = (float *) alloc_mem (blob_count * sizeof (float));
321  //get mem
322  errors = (float *) alloc_mem (blob_count * sizeof (float));
323  if (gradients == NULL || errors == NULL)
324  MEMORY_OUT.error ("compute_page_skew", ABORT, NULL);
325 
326  row_index = 0;
327  for (block_it.mark_cycle_pt (); !block_it.cycled_list ();
328  block_it.forward ()) {
329  POLY_BLOCK* pb = block_it.data()->block->poly_block();
330  if (pb != NULL && !pb->IsText())
331  continue; // Pretend non-text blocks don't exist.
332  row_it.set_to_list (block_it.data ()->get_rows ());
333  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
334  row = row_it.data ();
335  blob_count = row->blob_list ()->length ();
336  row_err = (inT32) ceil (row->line_error ());
337  if (row_err <= 0)
338  row_err = 1;
340  blob_count /= row_err;
341  for (blob_count /= row_err; blob_count > 0; blob_count--) {
342  gradients[row_index] = row->line_m ();
343  errors[row_index] = row->line_error ();
344  row_index++;
345  }
346  }
347  else if (blob_count >= textord_min_blobs_in_row) {
348  //get gradient
349  gradients[row_index] = row->line_m ();
350  errors[row_index] = row->line_error ();
351  row_index++;
352  }
353  }
354  }
355  if (row_index == 0) {
356  //desperate
357  for (block_it.mark_cycle_pt (); !block_it.cycled_list ();
358  block_it.forward ()) {
359  POLY_BLOCK* pb = block_it.data()->block->poly_block();
360  if (pb != NULL && !pb->IsText())
361  continue; // Pretend non-text blocks don't exist.
362  row_it.set_to_list (block_it.data ()->get_rows ());
363  for (row_it.mark_cycle_pt (); !row_it.cycled_list ();
364  row_it.forward ()) {
365  row = row_it.data ();
366  gradients[row_index] = row->line_m ();
367  errors[row_index] = row->line_error ();
368  row_index++;
369  }
370  }
371  }
372  row_count = row_index;
373  row_index = choose_nth_item ((inT32) (row_count * textord_skew_ile),
374  gradients, row_count);
375  page_m = gradients[row_index];
376  row_index = choose_nth_item ((inT32) (row_count * textord_skew_ile),
377  errors, row_count);
378  page_err = errors[row_index];
379  free_mem(gradients);
380  free_mem(errors);
381 }
void free_mem(void *oldchunk)
Definition: memry.cpp:47
int32_t inT32
Definition: host.h:38
double textord_skew_ile
Definition: makerow.cpp:74
float line_m() const
Definition: blobbox.h:566
bool IsText() const
Definition: polyblk.h:52
inT32 choose_nth_item(inT32 index, float *array, inT32 count)
Definition: statistc.cpp:638
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
void * alloc_mem(inT32 count)
Definition: memry.cpp:39
const ERRCODE MEMORY_OUT
Definition: stderr.h:25
int textord_min_blobs_in_row
Definition: makerow.cpp:64
Definition: errcode.h:30
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
bool textord_biased_skewcalc
Definition: makerow.cpp:58
float line_error() const
Definition: blobbox.h:572

◆ compute_row_descdrop()

inT32 compute_row_descdrop ( TO_ROW row,
float  gradient,
int  xheight_blob_count,
STATS heights 
)

Definition at line 1580 of file makerow.cpp.

1581  {
1582  // Count how many potential ascenders are in this row.
1583  int i_min = asc_heights->min_bucket();
1584  if ((i_min / row->xheight) < textord_ascx_ratio_min) {
1585  i_min = static_cast<int>(
1586  floor(row->xheight * textord_ascx_ratio_min + 0.5));
1587  }
1588  int i_max = asc_heights->max_bucket();
1589  if ((i_max / row->xheight) > textord_ascx_ratio_max) {
1590  i_max = static_cast<int>(floor(row->xheight * textord_ascx_ratio_max));
1591  }
1592  int num_potential_asc = 0;
1593  for (int i = i_min; i <= i_max; ++i) {
1594  num_potential_asc += asc_heights->pile_count(i);
1595  }
1596  inT32 min_height =
1597  static_cast<inT32>(floor(row->xheight * textord_descx_ratio_min + 0.5));
1598  inT32 max_height =
1599  static_cast<inT32>(floor(row->xheight * textord_descx_ratio_max));
1600  float xcentre; // centre of blob
1601  float height; // height of blob
1602  BLOBNBOX_IT blob_it = row->blob_list();
1603  BLOBNBOX *blob; // current blob
1604  STATS heights (min_height, max_height + 1);
1605  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
1606  blob = blob_it.data();
1607  if (!blob->joined_to_prev()) {
1608  xcentre = (blob->bounding_box().left() +
1609  blob->bounding_box().right()) / 2.0f;
1610  height = (gradient * xcentre + row->parallel_c() -
1611  blob->bounding_box().bottom());
1612  if (height >= min_height && height <= max_height)
1613  heights.add(static_cast<int>(floor(height + 0.5)), 1);
1614  }
1615  }
1616  int blob_index = heights.mode(); // find mode
1617  int blob_count = heights.pile_count(blob_index); // get count of mode
1618  float total_fraction =
1620  if (static_cast<float>(blob_count + num_potential_asc) <
1621  xheight_blob_count * total_fraction) {
1622  blob_count = 0;
1623  }
1624  int descdrop = blob_count > 0 ? -blob_index : 0;
1625  if (textord_debug_xheights) {
1626  tprintf("Descdrop: %d (potential ascenders %d, descenders %d)\n",
1627  descdrop, num_potential_asc, blob_count);
1628  heights.print();
1629  }
1630  return descdrop;
1631 }
bool textord_debug_xheights
Definition: makerow.cpp:57
double textord_descheight_mode_fraction
Definition: makerow.cpp:95
int32_t inT32
Definition: host.h:38
float xheight
Definition: blobbox.h:653
double textord_descx_ratio_max
Definition: makerow.cpp:99
#define tprintf(...)
Definition: tprintf.h:31
bool joined_to_prev() const
Definition: blobbox.h:241
inT32 pile_count(inT32 value) const
Definition: statistc.h:78
double textord_ascx_ratio_min
Definition: makerow.cpp:96
double textord_ascx_ratio_max
Definition: makerow.cpp:97
inT16 left() const
Definition: rect.h:68
double textord_ascheight_mode_fraction
Definition: makerow.cpp:93
void add(inT32 value, inT32 count)
Definition: statistc.cpp:101
inT32 mode() const
Definition: statistc.cpp:115
inT16 right() const
Definition: rect.h:75
Definition: statistc.h:33
inT16 bottom() const
Definition: rect.h:61
void print() const
Definition: statistc.cpp:534
double textord_descx_ratio_min
Definition: makerow.cpp:98
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
const TBOX & bounding_box() const
Definition: blobbox.h:215
float parallel_c() const
Definition: blobbox.h:575

◆ compute_row_stats()

void compute_row_stats ( TO_BLOCK block,
BOOL8  testing_on 
)

Definition at line 1156 of file makerow.cpp.

1159  {
1160  inT32 row_index; //of median
1161  TO_ROW *row; //current row
1162  TO_ROW *prev_row; //previous row
1163  float iqr; //inter quartile range
1164  TO_ROW_IT row_it = block->get_rows ();
1165  //number of rows
1166  inT16 rowcount = row_it.length ();
1167  TO_ROW **rows; //for choose nth
1168 
1169  rows = (TO_ROW **) alloc_mem (rowcount * sizeof (TO_ROW *));
1170  if (rows == NULL)
1171  MEMORY_OUT.error ("compute_row_stats", ABORT, NULL);
1172  rowcount = 0;
1173  prev_row = NULL;
1174  row_it.move_to_last (); //start at bottom
1175  do {
1176  row = row_it.data ();
1177  if (prev_row != NULL) {
1178  rows[rowcount++] = prev_row;
1179  prev_row->spacing = row->intercept () - prev_row->intercept ();
1180  if (testing_on)
1181  tprintf ("Row at %g yields spacing of %g\n",
1182  row->intercept (), prev_row->spacing);
1183  }
1184  prev_row = row;
1185  row_it.backward ();
1186  }
1187  while (!row_it.at_last ());
1188  block->key_row = prev_row;
1189  block->baseline_offset =
1190  fmod (prev_row->parallel_c (), block->line_spacing);
1191  if (testing_on)
1192  tprintf ("Blob based spacing=(%g,%g), offset=%g",
1193  block->line_size, block->line_spacing, block->baseline_offset);
1194  if (rowcount > 0) {
1195  row_index = choose_nth_item (rowcount * 3 / 4, rows, rowcount,
1196  sizeof (TO_ROW *), row_spacing_order);
1197  iqr = rows[row_index]->spacing;
1198  row_index = choose_nth_item (rowcount / 4, rows, rowcount,
1199  sizeof (TO_ROW *), row_spacing_order);
1200  iqr -= rows[row_index]->spacing;
1201  row_index = choose_nth_item (rowcount / 2, rows, rowcount,
1202  sizeof (TO_ROW *), row_spacing_order);
1203  block->key_row = rows[row_index];
1204  if (testing_on)
1205  tprintf (" row based=%g(%g)", rows[row_index]->spacing, iqr);
1206  if (rowcount > 2
1207  && iqr < rows[row_index]->spacing * textord_linespace_iqrlimit) {
1209  if (rows[row_index]->spacing < block->line_spacing
1210  && rows[row_index]->spacing > block->line_size)
1211  //within range
1212  block->line_size = rows[row_index]->spacing;
1213  //spacing=size
1214  else if (rows[row_index]->spacing > block->line_spacing)
1215  block->line_size = block->line_spacing;
1216  //too big so use max
1217  }
1218  else {
1219  if (rows[row_index]->spacing < block->line_spacing)
1220  block->line_size = rows[row_index]->spacing;
1221  else
1222  block->line_size = block->line_spacing;
1223  //too big so use max
1224  }
1225  if (block->line_size < textord_min_xheight)
1226  block->line_size = (float) textord_min_xheight;
1227  block->line_spacing = rows[row_index]->spacing;
1228  block->max_blob_size =
1230  }
1231  block->baseline_offset = fmod (rows[row_index]->intercept (),
1232  block->line_spacing);
1233  }
1234  if (testing_on)
1235  tprintf ("\nEstimate line size=%g, spacing=%g, offset=%g\n",
1236  block->line_size, block->line_spacing, block->baseline_offset);
1237  free_mem(rows);
1238 }
bool textord_new_initial_xheight
Definition: makerow.cpp:102
void free_mem(void *oldchunk)
Definition: memry.cpp:47
int32_t inT32
Definition: host.h:38
double textord_linespace_iqrlimit
Definition: makerow.cpp:76
double textord_excess_blobsize
Definition: makerow.cpp:85
#define tprintf(...)
Definition: tprintf.h:31
float intercept() const
Definition: blobbox.h:584
int16_t inT16
Definition: host.h:36
float baseline_offset
Definition: blobbox.h:783
float line_size
Definition: blobbox.h:781
inT32 choose_nth_item(inT32 index, float *array, inT32 count)
Definition: statistc.cpp:638
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
int textord_min_xheight
Definition: makerow.cpp:69
void * alloc_mem(inT32 count)
Definition: memry.cpp:39
TO_ROW * key_row
Definition: blobbox.h:794
float max_blob_size
Definition: blobbox.h:782
const ERRCODE MEMORY_OUT
Definition: stderr.h:25
Definition: errcode.h:30
float spacing
Definition: blobbox.h:652
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
float line_spacing
Definition: blobbox.h:775
int row_spacing_order(const void *item1, const void *item2)
Definition: makerow.cpp:2635

◆ compute_xheight_from_modes()

int compute_xheight_from_modes ( STATS heights,
STATS floating_heights,
bool  cap_only,
int  min_height,
int  max_height,
float *  xheight,
float *  ascrise 
)

Definition at line 1484 of file makerow.cpp.

1486  {
1487  int blob_index = heights->mode(); // find mode
1488  int blob_count = heights->pile_count(blob_index); // get count of mode
1489  if (textord_debug_xheights) {
1490  tprintf("min_height=%d, max_height=%d, mode=%d, count=%d, total=%d\n",
1491  min_height, max_height, blob_index, blob_count,
1492  heights->get_total());
1493  heights->print();
1494  floating_heights->print();
1495  }
1496  if (blob_count == 0) return 0;
1497  int modes[MAX_HEIGHT_MODES]; // biggest piles
1498  bool in_best_pile = FALSE;
1499  int prev_size = -MAX_INT32;
1500  int best_count = 0;
1501  int mode_count = compute_height_modes(heights, min_height, max_height,
1502  modes, MAX_HEIGHT_MODES);
1503  if (cap_only && mode_count > 1)
1504  mode_count = 1;
1505  int x;
1506  if (textord_debug_xheights) {
1507  tprintf("found %d modes: ", mode_count);
1508  for (x = 0; x < mode_count; x++) tprintf("%d ", modes[x]);
1509  tprintf("\n");
1510  }
1511 
1512  for (x = 0; x < mode_count - 1; x++) {
1513  if (modes[x] != prev_size + 1)
1514  in_best_pile = FALSE; // had empty height
1515  int modes_x_count = heights->pile_count(modes[x]) -
1516  floating_heights->pile_count(modes[x]);
1517  if ((modes_x_count >= blob_count * textord_xheight_mode_fraction) &&
1518  (in_best_pile || modes_x_count > best_count)) {
1519  for (int asc = x + 1; asc < mode_count; asc++) {
1520  float ratio =
1521  static_cast<float>(modes[asc]) / static_cast<float>(modes[x]);
1522  if (textord_ascx_ratio_min < ratio &&
1523  ratio < textord_ascx_ratio_max &&
1524  (heights->pile_count(modes[asc]) >=
1525  blob_count * textord_ascheight_mode_fraction)) {
1526  if (modes_x_count > best_count) {
1527  in_best_pile = true;
1528  best_count = modes_x_count;
1529  }
1530  if (textord_debug_xheights) {
1531  tprintf("X=%d, asc=%d, count=%d, ratio=%g\n",
1532  modes[x], modes[asc]-modes[x], modes_x_count, ratio);
1533  }
1534  prev_size = modes[x];
1535  *xheight = static_cast<float>(modes[x]);
1536  *ascrise = static_cast<float>(modes[asc] - modes[x]);
1537  }
1538  }
1539  }
1540  }
1541  if (*xheight == 0) { // single mode
1542  // Remove counts of the "floating" blobs (the one whose height is too
1543  // small in relation to it's top end of the bounding box) from heights
1544  // before computing the single-mode xheight.
1545  // Restore the counts in heights after the mode is found, since
1546  // floating blobs might be useful for determining potential ascenders
1547  // in compute_row_descdrop().
1548  if (floating_heights->get_total() > 0) {
1549  for (x = min_height; x < max_height; ++x) {
1550  heights->add(x, -(floating_heights->pile_count(x)));
1551  }
1552  blob_index = heights->mode(); // find the modified mode
1553  for (x = min_height; x < max_height; ++x) {
1554  heights->add(x, floating_heights->pile_count(x));
1555  }
1556  }
1557  *xheight = static_cast<float>(blob_index);
1558  *ascrise = 0.0f;
1559  best_count = heights->pile_count(blob_index);
1561  tprintf("Single mode xheight set to %g\n", *xheight);
1562  } else if (textord_debug_xheights) {
1563  tprintf("Multi-mode xheight set to %g, asc=%g\n", *xheight, *ascrise);
1564  }
1565  return best_count;
1566 }
bool textord_debug_xheights
Definition: makerow.cpp:57
inT32 get_total() const
Definition: statistc.h:86
#define MAX_INT32
Definition: host.h:62
#define tprintf(...)
Definition: tprintf.h:31
inT32 pile_count(inT32 value) const
Definition: statistc.h:78
double textord_ascx_ratio_min
Definition: makerow.cpp:96
double textord_ascx_ratio_max
Definition: makerow.cpp:97
double textord_xheight_mode_fraction
Definition: makerow.cpp:91
inT32 compute_height_modes(STATS *heights, inT32 min_height, inT32 max_height, inT32 *modes, inT32 maxmodes)
Definition: makerow.cpp:1640
#define FALSE
Definition: capi.h:46
double textord_ascheight_mode_fraction
Definition: makerow.cpp:93
#define MAX_HEIGHT_MODES
Definition: makerow.cpp:105
void add(inT32 value, inT32 count)
Definition: statistc.cpp:101
inT32 mode() const
Definition: statistc.cpp:115
void print() const
Definition: statistc.cpp:534

◆ correct_row_xheight()

void correct_row_xheight ( TO_ROW row,
float  xheight,
float  ascrise,
float  descdrop 
)

Definition at line 1702 of file makerow.cpp.

1703  {
1704  ROW_CATEGORY row_category = get_row_category(row);
1705  if (textord_debug_xheights) {
1706  tprintf("correcting row xheight: row->xheight %.4f"
1707  ", row->acrise %.4f row->descdrop %.4f\n",
1708  row->xheight, row->ascrise, row->descdrop);
1709  }
1710  bool normal_xheight =
1712  bool cap_xheight =
1713  within_error_margin(row->xheight, xheight + ascrise,
1715  // Use the average xheight/ascrise for the following cases:
1716  // -- the xheight of the row could not be determined at all
1717  // -- the row has descenders (e.g. "many groups", "ISBN 12345 p.3")
1718  // and its xheight is close to either cap height or average xheight
1719  // -- the row does not have ascenders or descenders, but its xheight
1720  // is close to the average block xheight (e.g. row with "www.mmm.com")
1721  if (row_category == ROW_ASCENDERS_FOUND) {
1722  if (row->descdrop >= 0.0) {
1723  row->descdrop = row->xheight * (descdrop / xheight);
1724  }
1725  } else if (row_category == ROW_INVALID ||
1726  (row_category == ROW_DESCENDERS_FOUND &&
1727  (normal_xheight || cap_xheight)) ||
1728  (row_category == ROW_UNKNOWN && normal_xheight)) {
1729  if (textord_debug_xheights) tprintf("using average xheight\n");
1730  row->xheight = xheight;
1731  row->ascrise = ascrise;
1732  row->descdrop = descdrop;
1733  } else if (row_category == ROW_DESCENDERS_FOUND) {
1734  // Assume this is a row with mostly lowercase letters and it's xheight
1735  // is computed correctly (unfortunately there is no way to distinguish
1736  // this from the case when descenders are found, but the most common
1737  // height is capheight).
1738  if (textord_debug_xheights) tprintf("lowercase, corrected ascrise\n");
1739  row->ascrise = row->xheight * (ascrise / xheight);
1740  } else if (row_category == ROW_UNKNOWN) {
1741  // Otherwise assume this row is an all-caps or small-caps row
1742  // and adjust xheight and ascrise of the row.
1743 
1744  row->all_caps = true;
1745  if (cap_xheight) { // regular all caps
1746  if (textord_debug_xheights) tprintf("all caps\n");
1747  row->xheight = xheight;
1748  row->ascrise = ascrise;
1749  row->descdrop = descdrop;
1750  } else { // small caps or caps with an odd xheight
1751  if (textord_debug_xheights) {
1752  if (row->xheight < xheight + ascrise && row->xheight > xheight) {
1753  tprintf("small caps\n");
1754  } else {
1755  tprintf("all caps with irregular xheight\n");
1756  }
1757  }
1758  row->ascrise = row->xheight * (ascrise / (xheight + ascrise));
1759  row->xheight -= row->ascrise;
1760  row->descdrop = row->xheight * (descdrop / xheight);
1761  }
1762  }
1763  if (textord_debug_xheights) {
1764  tprintf("corrected row->xheight = %.4f, row->acrise = %.4f, row->descdrop"
1765  " = %.4f\n", row->xheight, row->ascrise, row->descdrop);
1766  }
1767 }
bool textord_debug_xheights
Definition: makerow.cpp:57
ROW_CATEGORY get_row_category(const TO_ROW *row)
Definition: makerow.h:123
float xheight
Definition: blobbox.h:653
float descdrop
Definition: blobbox.h:656
#define tprintf(...)
Definition: tprintf.h:31
ROW_CATEGORY
Definition: makerow.h:36
double textord_xheight_error_margin
Definition: makerow.cpp:100
float ascrise
Definition: blobbox.h:655
BOOL8 all_caps
Definition: blobbox.h:642
bool within_error_margin(float test, float num, float margin)
Definition: makerow.h:129

◆ delete_non_dropout_rows()

void delete_non_dropout_rows ( TO_BLOCK block,
float  gradient,
FCOORD  rotation,
inT32  block_edge,
BOOL8  testing_on 
)

delete_non_dropout_rows

Compute the linespacing and offset.

Definition at line 577 of file makerow.cpp.

583  {
584  TBOX block_box; //deskewed block
585  inT32 *deltas; //change in occupation
586  inT32 *occupation; //of pixel coords
587  inT32 max_y; //in block
588  inT32 min_y;
589  inT32 line_index; //of scan line
590  inT32 line_count; //no of scan lines
591  inT32 distance; //to drop-out
592  inT32 xleft; //of block
593  inT32 ybottom; //of block
594  TO_ROW *row; //current row
595  TO_ROW_IT row_it = block->get_rows ();
596  BLOBNBOX_IT blob_it = &block->blobs;
597 
598  if (row_it.length () == 0)
599  return; //empty block
600  block_box = deskew_block_coords (block, gradient);
601  xleft = block->block->bounding_box ().left ();
602  ybottom = block->block->bounding_box ().bottom ();
603  min_y = block_box.bottom () - 1;
604  max_y = block_box.top () + 1;
605  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
606  line_index = (inT32) floor (row_it.data ()->intercept ());
607  if (line_index <= min_y)
608  min_y = line_index - 1;
609  if (line_index >= max_y)
610  max_y = line_index + 1;
611  }
612  line_count = max_y - min_y + 1;
613  if (line_count <= 0)
614  return; //empty block
615  deltas = (inT32 *) alloc_mem (line_count * sizeof (inT32));
616  occupation = (inT32 *) alloc_mem (line_count * sizeof (inT32));
617  if (deltas == NULL || occupation == NULL)
618  MEMORY_OUT.error ("compute_line_spacing", ABORT, NULL);
619 
620  compute_line_occupation(block, gradient, min_y, max_y, occupation, deltas);
622  ceil (block->line_spacing *
625  (inT32) ceil (block->line_spacing *
628  max_y - min_y + 1, occupation, deltas);
629 #ifndef GRAPHICS_DISABLED
630  if (testing_on) {
631  draw_occupation(xleft, ybottom, min_y, max_y, occupation, deltas);
632  }
633 #endif
634  compute_dropout_distances(occupation, deltas, line_count);
635  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
636  row = row_it.data ();
637  line_index = (inT32) floor (row->intercept ());
638  distance = deltas[line_index - min_y];
639  if (find_best_dropout_row (row, distance, block->line_spacing / 2,
640  line_index, &row_it, testing_on)) {
641 #ifndef GRAPHICS_DISABLED
642  if (testing_on)
643  plot_parallel_row(row, gradient, block_edge,
644  ScrollView::WHITE, rotation);
645 #endif
646  blob_it.add_list_after (row_it.data ()->blob_list ());
647  delete row_it.extract (); //too far away
648  }
649  }
650  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
651  blob_it.add_list_after (row_it.data ()->blob_list ());
652  }
653 
654  free_mem(deltas);
655  free_mem(occupation);
656 }
void free_mem(void *oldchunk)
Definition: memry.cpp:47
int32_t inT32
Definition: host.h:38
static const double kAscenderFraction
Definition: ccstruct.h:35
static const double kDescenderFraction
Definition: ccstruct.h:33
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
void compute_line_occupation(TO_BLOCK *block, float gradient, inT32 min_y, inT32 max_y, inT32 *occupation, inT32 *deltas)
Definition: makerow.cpp:781
TBOX deskew_block_coords(TO_BLOCK *block, float gradient)
Definition: makerow.cpp:745
static const double kXHeightFraction
Definition: ccstruct.h:34
float intercept() const
Definition: blobbox.h:584
void plot_parallel_row(TO_ROW *row, float gradient, inT32 left, ScrollView::Color colour, FCOORD rotation)
Definition: drawtord.cpp:125
void compute_occupation_threshold(inT32 low_window, inT32 high_window, inT32 line_count, inT32 *occupation, inT32 *thresholds)
Definition: makerow.cpp:834
void compute_dropout_distances(inT32 *occupation, inT32 *thresholds, inT32 line_count)
Definition: makerow.cpp:915
void draw_occupation(inT32 xleft, inT32 ybottom, inT32 min_y, inT32 max_y, inT32 occupation[], inT32 thresholds[])
Definition: drawtord.cpp:166
BLOBNBOX_LIST blobs
Definition: blobbox.h:768
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
BOOL8 find_best_dropout_row(TO_ROW *row, inT32 distance, float dist_limit, inT32 line_index, TO_ROW_IT *row_it, BOOL8 testing_on)
Definition: makerow.cpp:665
inT16 top() const
Definition: rect.h:54
void * alloc_mem(inT32 count)
Definition: memry.cpp:39
Definition: rect.h:30
const ERRCODE MEMORY_OUT
Definition: stderr.h:25
inT16 bottom() const
Definition: rect.h:61
BLOCK * block
Definition: blobbox.h:773
Definition: errcode.h:30
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
float line_spacing
Definition: blobbox.h:775

◆ deskew_block_coords()

TBOX deskew_block_coords ( TO_BLOCK block,
float  gradient 
)

Definition at line 745 of file makerow.cpp.

748  {
749  TBOX result; //block bounds
750  TBOX blob_box; //of block
751  FCOORD rotation; //deskew vector
752  float length; //of gradient vector
753  TO_ROW_IT row_it = block->get_rows ();
754  TO_ROW *row; //current row
755  BLOBNBOX *blob; //current blob
756  BLOBNBOX_IT blob_it; //iterator
757 
758  length = sqrt (gradient * gradient + 1);
759  rotation = FCOORD (1 / length, -gradient / length);
760  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
761  row = row_it.data ();
762  blob_it.set_to_list (row->blob_list ());
763  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list ();
764  blob_it.forward ()) {
765  blob = blob_it.data ();
766  blob_box = blob->bounding_box ();
767  blob_box.rotate (rotation);//de-skew it
768  result += blob_box;
769  }
770  }
771  return result;
772 }
Definition: points.h:189
Definition: rect.h:30
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
const TBOX & bounding_box() const
Definition: blobbox.h:215
void rotate(const FCOORD &vec)
Definition: rect.h:189

◆ expand_rows()

void expand_rows ( ICOORD  page_tr,
TO_BLOCK block,
float  gradient,
FCOORD  rotation,
inT32  block_edge,
BOOL8  testing_on 
)

Definition at line 962 of file makerow.cpp.

969  {
970  BOOL8 swallowed_row; //eaten a neighbour
971  float y_max, y_min; //new row limits
972  float y_bottom, y_top; //allowed limits
973  TO_ROW *test_row; //next row
974  TO_ROW *row; //current row
975  //iterators
976  BLOBNBOX_IT blob_it = &block->blobs;
977  TO_ROW_IT row_it = block->get_rows ();
978 
979 #ifndef GRAPHICS_DISABLED
980  if (textord_show_expanded_rows && testing_on) {
981  if (to_win == NULL)
982  create_to_win(page_tr);
983  }
984 #endif
985 
986  adjust_row_limits(block); //shift min,max.
988  if (block->get_rows ()->length () == 0)
989  return;
990  compute_row_stats(block, textord_show_expanded_rows &&testing_on);
991  }
992  assign_blobs_to_rows (block, &gradient, 4, TRUE, FALSE, FALSE);
993  //get real membership
994  if (block->get_rows ()->length () == 0)
995  return;
996  fit_parallel_rows(block,
997  gradient,
998  rotation,
999  block_edge,
1000  textord_show_expanded_rows &&testing_on);
1002  compute_row_stats(block, textord_show_expanded_rows &&testing_on);
1003  row_it.move_to_last ();
1004  do {
1005  row = row_it.data ();
1006  y_max = row->max_y (); //get current limits
1007  y_min = row->min_y ();
1008  y_bottom = row->intercept () - block->line_size * textord_expansion_factor *
1010  y_top = row->intercept () + block->line_size * textord_expansion_factor *
1013  if (y_min > y_bottom) { //expansion allowed
1014  if (textord_show_expanded_rows && testing_on)
1015  tprintf("Expanding bottom of row at %f from %f to %f\n",
1016  row->intercept(), y_min, y_bottom);
1017  //expandable
1018  swallowed_row = TRUE;
1019  while (swallowed_row && !row_it.at_last ()) {
1020  swallowed_row = FALSE;
1021  //get next one
1022  test_row = row_it.data_relative (1);
1023  //overlaps space
1024  if (test_row->max_y () > y_bottom) {
1025  if (test_row->min_y () > y_bottom) {
1026  if (textord_show_expanded_rows && testing_on)
1027  tprintf("Eating row below at %f\n", test_row->intercept());
1028  row_it.forward ();
1029 #ifndef GRAPHICS_DISABLED
1030  if (textord_show_expanded_rows && testing_on)
1031  plot_parallel_row(test_row,
1032  gradient,
1033  block_edge,
1035  rotation);
1036 #endif
1037  blob_it.set_to_list (row->blob_list ());
1038  blob_it.add_list_after (test_row->blob_list ());
1039  //swallow complete row
1040  delete row_it.extract ();
1041  row_it.backward ();
1042  swallowed_row = TRUE;
1043  }
1044  else if (test_row->max_y () < y_min) {
1045  //shorter limit
1046  y_bottom = test_row->max_y ();
1047  if (textord_show_expanded_rows && testing_on)
1048  tprintf("Truncating limit to %f due to touching row at %f\n",
1049  y_bottom, test_row->intercept());
1050  }
1051  else {
1052  y_bottom = y_min; //can't expand it
1053  if (textord_show_expanded_rows && testing_on)
1054  tprintf("Not expanding limit beyond %f due to touching row at %f\n",
1055  y_bottom, test_row->intercept());
1056  }
1057  }
1058  }
1059  y_min = y_bottom; //expand it
1060  }
1061  if (y_max < y_top) { //expansion allowed
1062  if (textord_show_expanded_rows && testing_on)
1063  tprintf("Expanding top of row at %f from %f to %f\n",
1064  row->intercept(), y_max, y_top);
1065  swallowed_row = TRUE;
1066  while (swallowed_row && !row_it.at_first ()) {
1067  swallowed_row = FALSE;
1068  //get one above
1069  test_row = row_it.data_relative (-1);
1070  if (test_row->min_y () < y_top) {
1071  if (test_row->max_y () < y_top) {
1072  if (textord_show_expanded_rows && testing_on)
1073  tprintf("Eating row above at %f\n", test_row->intercept());
1074  row_it.backward ();
1075  blob_it.set_to_list (row->blob_list ());
1076 #ifndef GRAPHICS_DISABLED
1077  if (textord_show_expanded_rows && testing_on)
1078  plot_parallel_row(test_row,
1079  gradient,
1080  block_edge,
1082  rotation);
1083 #endif
1084  blob_it.add_list_after (test_row->blob_list ());
1085  //swallow complete row
1086  delete row_it.extract ();
1087  row_it.forward ();
1088  swallowed_row = TRUE;
1089  }
1090  else if (test_row->min_y () < y_max) {
1091  //shorter limit
1092  y_top = test_row->min_y ();
1093  if (textord_show_expanded_rows && testing_on)
1094  tprintf("Truncating limit to %f due to touching row at %f\n",
1095  y_top, test_row->intercept());
1096  }
1097  else {
1098  y_top = y_max; //can't expand it
1099  if (textord_show_expanded_rows && testing_on)
1100  tprintf("Not expanding limit beyond %f due to touching row at %f\n",
1101  y_top, test_row->intercept());
1102  }
1103  }
1104  }
1105  y_max = y_top;
1106  }
1107  //new limits
1108  row->set_limits (y_min, y_max);
1109  row_it.backward ();
1110  }
1111  while (!row_it.at_last ());
1112 }
bool textord_new_initial_xheight
Definition: makerow.cpp:102
#define TRUE
Definition: capi.h:45
static const double kAscenderFraction
Definition: ccstruct.h:35
static const double kDescenderFraction
Definition: ccstruct.h:33
static const double kXHeightFraction
Definition: ccstruct.h:34
#define tprintf(...)
Definition: tprintf.h:31
float intercept() const
Definition: blobbox.h:584
void plot_parallel_row(TO_ROW *row, float gradient, inT32 left, ScrollView::Color colour, FCOORD rotation)
Definition: drawtord.cpp:125
float min_y() const
Definition: blobbox.h:557
void set_limits(float new_min, float new_max)
Definition: blobbox.h:618
bool textord_show_expanded_rows
Definition: makerow.cpp:47
float line_size
Definition: blobbox.h:781
void assign_blobs_to_rows(TO_BLOCK *block, float *gradient, int pass, BOOL8 reject_misses, BOOL8 make_new_rows, BOOL8 drawing_skew)
Definition: makerow.cpp:2296
unsigned char BOOL8
Definition: host.h:44
#define FALSE
Definition: capi.h:46
BLOBNBOX_LIST blobs
Definition: blobbox.h:768
EXTERN ScrollView * to_win
Definition: drawtord.cpp:38
ScrollView * create_to_win(ICOORD page_tr)
Definition: drawtord.cpp:47
float max_y() const
Definition: blobbox.h:554
void fit_parallel_rows(TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
Definition: makerow.cpp:1948
double textord_expansion_factor
Definition: makerow.cpp:80
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
void adjust_row_limits(TO_BLOCK *block)
Definition: makerow.cpp:1120
void compute_row_stats(TO_BLOCK *block, BOOL8 testing_on)
Definition: makerow.cpp:1156

◆ fill_heights()

void fill_heights ( TO_ROW row,
float  gradient,
int  min_height,
int  max_height,
STATS heights,
STATS floating_heights 
)

Definition at line 1423 of file makerow.cpp.

1424  {
1425  float xcentre; // centre of blob
1426  float top; // top y coord of blob
1427  float height; // height of blob
1428  BLOBNBOX *blob; // current blob
1429  int repeated_set;
1430  BLOBNBOX_IT blob_it = row->blob_list();
1431  if (blob_it.empty()) return; // no blobs in this row
1432  bool has_rep_chars =
1433  row->rep_chars_marked() && row->num_repeated_sets() > 0;
1434  do {
1435  blob = blob_it.data();
1436  if (!blob->joined_to_prev()) {
1437  xcentre = (blob->bounding_box().left() +
1438  blob->bounding_box().right()) / 2.0f;
1439  top = blob->bounding_box().top();
1440  height = blob->bounding_box().height();
1442  top -= row->baseline.y(xcentre);
1443  else
1444  top -= gradient * xcentre + row->parallel_c();
1445  if (top >= min_height && top <= max_height) {
1446  heights->add(static_cast<inT32>(floor(top + 0.5)), 1);
1447  if (height / top < textord_min_blob_height_fraction) {
1448  floating_heights->add(static_cast<inT32>(floor(top + 0.5)), 1);
1449  }
1450  }
1451  }
1452  // Skip repeated chars, since they are likely to skew the height stats.
1453  if (has_rep_chars && blob->repeated_set() != 0) {
1454  repeated_set = blob->repeated_set();
1455  blob_it.forward();
1456  while (!blob_it.at_first() &&
1457  blob_it.data()->repeated_set() == repeated_set) {
1458  blob_it.forward();
1460  tprintf("Skipping repeated char when computing xheight\n");
1461  }
1462  } else {
1463  blob_it.forward();
1464  }
1465  } while (!blob_it.at_first());
1466 }
bool textord_debug_xheights
Definition: makerow.cpp:57
int num_repeated_sets() const
Definition: blobbox.h:633
#define tprintf(...)
Definition: tprintf.h:31
bool joined_to_prev() const
Definition: blobbox.h:241
inT16 left() const
Definition: rect.h:68
int repeated_set() const
Definition: blobbox.h:247
QSPLINE baseline
Definition: blobbox.h:666
bool textord_fix_xheight_bug
Definition: makerow.cpp:55
double y(double x) const
Definition: quspline.cpp:217
double textord_min_blob_height_fraction
Definition: makerow.cpp:89
void add(inT32 value, inT32 count)
Definition: statistc.cpp:101
inT16 top() const
Definition: rect.h:54
bool rep_chars_marked() const
Definition: blobbox.h:627
inT16 height() const
Definition: rect.h:104
inT16 right() const
Definition: rect.h:75
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
const TBOX & bounding_box() const
Definition: blobbox.h:215
float parallel_c() const
Definition: blobbox.h:575

◆ find_best_dropout_row()

BOOL8 find_best_dropout_row ( TO_ROW row,
inT32  distance,
float  dist_limit,
inT32  line_index,
TO_ROW_IT *  row_it,
BOOL8  testing_on 
)

Definition at line 665 of file makerow.cpp.

672  {
673  inT32 next_index; // of neighbouring row
674  inT32 row_offset; //from current row
675  inT32 abs_dist; //absolute distance
676  inT8 row_inc; //increment to row_index
677  TO_ROW *next_row; //nextious row
678 
679  if (testing_on)
680  tprintf ("Row at %g(%g), dropout dist=%d,",
681  row->intercept (), row->parallel_c (), distance);
682  if (distance < 0) {
683  row_inc = 1;
684  abs_dist = -distance;
685  }
686  else {
687  row_inc = -1;
688  abs_dist = distance;
689  }
690  if (abs_dist > dist_limit) {
691  if (testing_on) {
692  tprintf (" too far - deleting\n");
693  }
694  return TRUE;
695  }
696  if ((distance < 0 && !row_it->at_last ())
697  || (distance >= 0 && !row_it->at_first ())) {
698  row_offset = row_inc;
699  do {
700  next_row = row_it->data_relative (row_offset);
701  next_index = (inT32) floor (next_row->intercept ());
702  if ((distance < 0
703  && next_index < line_index
704  && next_index > line_index + distance + distance)
705  || (distance >= 0
706  && next_index > line_index
707  && next_index < line_index + distance + distance)) {
708  if (testing_on) {
709  tprintf (" nearer neighbour (%d) at %g\n",
710  line_index + distance - next_index,
711  next_row->intercept ());
712  }
713  return TRUE; //other is nearer
714  }
715  else if (next_index == line_index
716  || next_index == line_index + distance + distance) {
717  if (row->believability () <= next_row->believability ()) {
718  if (testing_on) {
719  tprintf (" equal but more believable at %g (%g/%g)\n",
720  next_row->intercept (),
721  row->believability (),
722  next_row->believability ());
723  }
724  return TRUE; //other is more believable
725  }
726  }
727  row_offset += row_inc;
728  }
729  while ((next_index == line_index
730  || next_index == line_index + distance + distance)
731  && row_offset < row_it->length ());
732  if (testing_on)
733  tprintf (" keeping\n");
734  }
735  return FALSE;
736 }
#define TRUE
Definition: capi.h:45
int32_t inT32
Definition: host.h:38
#define tprintf(...)
Definition: tprintf.h:31
float intercept() const
Definition: blobbox.h:584
#define FALSE
Definition: capi.h:46
float believability() const
Definition: blobbox.h:581
int8_t inT8
Definition: host.h:34
float parallel_c() const
Definition: blobbox.h:575

◆ fit_lms_line()

void fit_lms_line ( TO_ROW row)

Definition at line 267 of file makerow.cpp.

267  {
268  float m, c; // fitted line
270  BLOBNBOX_IT blob_it = row->blob_list();
271 
272  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
273  const TBOX& box = blob_it.data()->bounding_box();
274  lms.Add(ICOORD((box.left() + box.right()) / 2, box.bottom()));
275  }
276  double error = lms.Fit(&m, &c);
277  row->set_line(m, c, error);
278 }
inT16 left() const
Definition: rect.h:68
void set_line(float new_m, float new_c, float new_error)
Definition: blobbox.h:599
Definition: rect.h:30
void Add(const ICOORD &pt)
Definition: detlinefit.cpp:52
inT16 right() const
Definition: rect.h:75
inT16 bottom() const
Definition: rect.h:61
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
integer coordinate
Definition: points.h:30
double Fit(ICOORD *pt1, ICOORD *pt2)
Definition: detlinefit.h:75

◆ fit_parallel_lms()

void fit_parallel_lms ( float  gradient,
TO_ROW row 
)

Definition at line 1990 of file makerow.cpp.

1990  {
1991  float c; // fitted line
1992  int blobcount; // no of blobs
1994  BLOBNBOX_IT blob_it = row->blob_list();
1995 
1996  blobcount = 0;
1997  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
1998  if (!blob_it.data()->joined_to_prev()) {
1999  const TBOX& box = blob_it.data()->bounding_box();
2000  lms.Add(ICOORD((box.left() + box.right()) / 2, box.bottom()));
2001  blobcount++;
2002  }
2003  }
2004  double error = lms.ConstrainedFit(gradient, &c);
2005  row->set_parallel_line(gradient, c, error);
2007  error = lms.Fit(&gradient, &c);
2008  }
2009  //set the other too
2010  row->set_line(gradient, c, error);
2011 }
bool textord_straight_baselines
Definition: makerow.cpp:52
inT16 left() const
Definition: rect.h:68
void set_parallel_line(float gradient, float new_c, float new_error)
Definition: blobbox.h:607
int textord_lms_line_trials
Definition: makerow.cpp:101
void set_line(float new_m, float new_c, float new_error)
Definition: blobbox.h:599
Definition: rect.h:30
void Add(const ICOORD &pt)
Definition: detlinefit.cpp:52
inT16 right() const
Definition: rect.h:75
inT16 bottom() const
Definition: rect.h:61
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
double ConstrainedFit(const FCOORD &direction, double min_dist, double max_dist, bool debug, ICOORD *line_pt)
Definition: detlinefit.cpp:131
integer coordinate
Definition: points.h:30
double Fit(ICOORD *pt1, ICOORD *pt2)
Definition: detlinefit.h:75

◆ fit_parallel_rows()

void fit_parallel_rows ( TO_BLOCK block,
float  gradient,
FCOORD  rotation,
inT32  block_edge,
BOOL8  testing_on 
)

Definition at line 1948 of file makerow.cpp.

1954  {
1955 #ifndef GRAPHICS_DISABLED
1956  ScrollView::Color colour; //of row
1957 #endif
1958  TO_ROW_IT row_it = block->get_rows ();
1959 
1960  row_it.move_to_first ();
1961  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
1962  if (row_it.data ()->blob_list ()->empty ())
1963  delete row_it.extract (); //nothing in it
1964  else
1965  fit_parallel_lms (gradient, row_it.data ());
1966  }
1967 #ifndef GRAPHICS_DISABLED
1968  if (testing_on) {
1969  colour = ScrollView::RED;
1970  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
1971  plot_parallel_row (row_it.data (), gradient,
1972  block_edge, colour, rotation);
1973  colour = (ScrollView::Color) (colour + 1);
1974  if (colour > ScrollView::MAGENTA)
1975  colour = ScrollView::RED;
1976  }
1977  }
1978 #endif
1979  row_it.sort (row_y_order); //may have gone out of order
1980 }
void plot_parallel_row(TO_ROW *row, float gradient, inT32 left, ScrollView::Color colour, FCOORD rotation)
Definition: drawtord.cpp:125
void fit_parallel_lms(float gradient, TO_ROW *row)
Definition: makerow.cpp:1990
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
int row_y_order(const void *item1, const void *item2)
Definition: makerow.cpp:2613

◆ get_min_max_xheight()

void get_min_max_xheight ( int  block_linesize,
int min_height,
int max_height 
)
inline

Definition at line 116 of file makerow.h.

117  {
118  *min_height = static_cast<inT32>(floor(block_linesize * textord_minxh));
119  if (*min_height < textord_min_xheight) *min_height = textord_min_xheight;
120  *max_height = static_cast<inT32>(ceil(block_linesize * 3.0));
121 }
int32_t inT32
Definition: host.h:38
double textord_minxh
Definition: makerow.cpp:82
int textord_min_xheight
Definition: makerow.cpp:69

◆ get_row_category()

ROW_CATEGORY get_row_category ( const TO_ROW row)
inline

Definition at line 123 of file makerow.h.

123  {
124  if (row->xheight <= 0) return ROW_INVALID;
125  return (row->ascrise > 0) ? ROW_ASCENDERS_FOUND :
126  (row->descdrop != 0) ? ROW_DESCENDERS_FOUND : ROW_UNKNOWN;
127 }
float xheight
Definition: blobbox.h:653
float descdrop
Definition: blobbox.h:656
float ascrise
Definition: blobbox.h:655

◆ linear_spline_baseline()

double* linear_spline_baseline ( TO_ROW row,
TO_BLOCK block,
inT32 segments,
inT32  xstarts[] 
)

Definition at line 2205 of file makerow.cpp.

2210  {
2211  int blobcount; //no of blobs
2212  int blobindex; //current blob
2213  int index1, index2; //blob numbers
2214  int blobs_per_segment; //blobs in each
2215  TBOX box; //blob box
2216  TBOX new_box; //new_it box
2217  //blobs
2218  BLOBNBOX_IT blob_it = row->blob_list ();
2219  BLOBNBOX_IT new_it = blob_it; //front end
2220  float b, c; //fitted curve
2222  double *coeffs; //quadratic coeffs
2223  inT32 segment; //current segment
2224 
2225  box = box_next_pre_chopped (&blob_it);
2226  xstarts[0] = box.left ();
2227  blobcount = 1;
2228  while (!blob_it.at_first ()) {
2229  blobcount++;
2230  box = box_next_pre_chopped (&blob_it);
2231  }
2232  segments = blobcount / textord_spline_medianwin;
2233  if (segments < 1)
2234  segments = 1;
2235  blobs_per_segment = blobcount / segments;
2236  coeffs = (double *) alloc_mem (segments * 3 * sizeof (double));
2237  if (textord_oldbl_debug)
2238  tprintf
2239  ("Linear splining baseline of %d blobs at (%d,%d), into %d segments of %d blobs\n",
2240  blobcount, box.left (), box.bottom (), segments, blobs_per_segment);
2241  segment = 1;
2242  for (index2 = 0; index2 < blobs_per_segment / 2; index2++)
2243  box_next_pre_chopped(&new_it);
2244  index1 = 0;
2245  blobindex = index2;
2246  do {
2247  blobindex += blobs_per_segment;
2248  lms.Clear();
2249  while (index1 < blobindex || (segment == segments && index1 < blobcount)) {
2250  box = box_next_pre_chopped (&blob_it);
2251  int middle = (box.left() + box.right()) / 2;
2252  lms.Add(ICOORD(middle, box.bottom()));
2253  index1++;
2254  if (index1 == blobindex - blobs_per_segment / 2
2255  || index1 == blobcount - 1) {
2256  xstarts[segment] = box.left ();
2257  }
2258  }
2259  lms.Fit(&b, &c);
2260  coeffs[segment * 3 - 3] = 0;
2261  coeffs[segment * 3 - 2] = b;
2262  coeffs[segment * 3 - 1] = c;
2263  segment++;
2264  if (segment > segments)
2265  break;
2266 
2267  blobindex += blobs_per_segment;
2268  lms.Clear();
2269  while (index2 < blobindex || (segment == segments && index2 < blobcount)) {
2270  new_box = box_next_pre_chopped (&new_it);
2271  int middle = (new_box.left() + new_box.right()) / 2;
2272  lms.Add(ICOORD (middle, new_box.bottom()));
2273  index2++;
2274  if (index2 == blobindex - blobs_per_segment / 2
2275  || index2 == blobcount - 1) {
2276  xstarts[segment] = new_box.left ();
2277  }
2278  }
2279  lms.Fit(&b, &c);
2280  coeffs[segment * 3 - 3] = 0;
2281  coeffs[segment * 3 - 2] = b;
2282  coeffs[segment * 3 - 1] = c;
2283  segment++;
2284  }
2285  while (segment <= segments);
2286  return coeffs;
2287 }
TBOX box_next_pre_chopped(BLOBNBOX_IT *it)
Definition: blobbox.cpp:660
int32_t inT32
Definition: host.h:38
EXTERN bool textord_oldbl_debug
Definition: oldbasel.cpp:39
#define tprintf(...)
Definition: tprintf.h:31
inT16 left() const
Definition: rect.h:68
void * alloc_mem(inT32 count)
Definition: memry.cpp:39
Definition: rect.h:30
void Add(const ICOORD &pt)
Definition: detlinefit.cpp:52
inT16 right() const
Definition: rect.h:75
inT16 bottom() const
Definition: rect.h:61
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
integer coordinate
Definition: points.h:30
double Fit(ICOORD *pt1, ICOORD *pt2)
Definition: detlinefit.h:75
int textord_spline_medianwin
Definition: makerow.cpp:66

◆ make_baseline_spline()

void make_baseline_spline ( TO_ROW row,
TO_BLOCK block 
)

Definition at line 2073 of file makerow.cpp.

2074  {
2075  inT32 *xstarts; // spline boundaries
2076  double *coeffs; // quadratic coeffs
2077  inT32 segments; // no of segments
2078 
2079  xstarts =
2080  (inT32 *) alloc_mem((row->blob_list()->length() + 1) * sizeof(inT32));
2081  if (segment_baseline(row, block, segments, xstarts)
2083  coeffs = linear_spline_baseline(row, block, segments, xstarts);
2084  } else {
2085  xstarts[1] = xstarts[segments];
2086  segments = 1;
2087  coeffs = (double *) alloc_mem (3 * sizeof (double));
2088  coeffs[0] = 0;
2089  coeffs[1] = row->line_m ();
2090  coeffs[2] = row->line_c ();
2091  }
2092  row->baseline = QSPLINE (segments, xstarts, coeffs);
2093  free_mem(coeffs);
2094  free_mem(xstarts);
2095 }
void free_mem(void *oldchunk)
Definition: memry.cpp:47
int32_t inT32
Definition: host.h:38
bool textord_straight_baselines
Definition: makerow.cpp:52
float line_m() const
Definition: blobbox.h:566
float line_c() const
Definition: blobbox.h:569
QSPLINE baseline
Definition: blobbox.h:666
BOOL8 segment_baseline(TO_ROW *row, TO_BLOCK *block, inT32 &segments, inT32 xstarts[])
Definition: makerow.cpp:2106
void * alloc_mem(inT32 count)
Definition: memry.cpp:39
bool textord_parallel_baselines
Definition: makerow.cpp:51
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
double * linear_spline_baseline(TO_ROW *row, TO_BLOCK *block, inT32 &segments, inT32 xstarts[])
Definition: makerow.cpp:2205

◆ make_initial_textrows()

void make_initial_textrows ( ICOORD  page_tr,
TO_BLOCK block,
FCOORD  rotation,
BOOL8  testing_on 
)

Definition at line 227 of file makerow.cpp.

232  {
233  TO_ROW_IT row_it = block->get_rows ();
234 
235 #ifndef GRAPHICS_DISABLED
236  ScrollView::Color colour; //of row
237 
238  if (textord_show_initial_rows && testing_on) {
239  if (to_win == NULL)
240  create_to_win(page_tr);
241  }
242 #endif
243  //guess skew
244  assign_blobs_to_rows (block, NULL, 0, TRUE, TRUE, textord_show_initial_rows && testing_on);
245  row_it.move_to_first ();
246  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())
247  fit_lms_line (row_it.data ());
248 #ifndef GRAPHICS_DISABLED
249  if (textord_show_initial_rows && testing_on) {
250  colour = ScrollView::RED;
251  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
252  plot_to_row (row_it.data (), colour, rotation);
253  colour = (ScrollView::Color) (colour + 1);
254  if (colour > ScrollView::MAGENTA)
255  colour = ScrollView::RED;
256  }
257  }
258 #endif
259 }
#define TRUE
Definition: capi.h:45
void assign_blobs_to_rows(TO_BLOCK *block, float *gradient, int pass, BOOL8 reject_misses, BOOL8 make_new_rows, BOOL8 drawing_skew)
Definition: makerow.cpp:2296
EXTERN ScrollView * to_win
Definition: drawtord.cpp:38
ScrollView * create_to_win(ICOORD page_tr)
Definition: drawtord.cpp:47
bool textord_show_initial_rows
Definition: makerow.cpp:45
void fit_lms_line(TO_ROW *row)
Definition: makerow.cpp:267
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
void plot_to_row(TO_ROW *row, ScrollView::Color colour, FCOORD rotation)
Definition: drawtord.cpp:91

◆ make_rows()

float make_rows ( ICOORD  page_tr,
TO_BLOCK_LIST *  port_blocks 
)

Definition at line 201 of file makerow.cpp.

201  {
202  float port_m; // global skew
203  float port_err; // global noise
204  TO_BLOCK_IT block_it; // iterator
205 
206  block_it.set_to_list(port_blocks);
207  for (block_it.mark_cycle_pt(); !block_it.cycled_list();
208  block_it.forward())
209  make_initial_textrows(page_tr, block_it.data(), FCOORD(1.0f, 0.0f),
211  // compute globally
212  compute_page_skew(port_blocks, port_m, port_err);
213  block_it.set_to_list(port_blocks);
214  for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {
215  cleanup_rows_making(page_tr, block_it.data(), port_m, FCOORD(1.0f, 0.0f),
216  block_it.data()->block->bounding_box().left(),
218  }
219  return port_m; // global skew
220 }
void make_initial_textrows(ICOORD page_tr, TO_BLOCK *block, FCOORD rotation, BOOL8 testing_on)
Definition: makerow.cpp:227
Definition: points.h:189
unsigned char BOOL8
Definition: host.h:44
void cleanup_rows_making(ICOORD page_tr, TO_BLOCK *block, float gradient, FCOORD rotation, inT32 block_edge, BOOL8 testing_on)
Definition: makerow.cpp:524
void compute_page_skew(TO_BLOCK_LIST *blocks, float &page_m, float &page_err)
Definition: makerow.cpp:287
bool textord_test_landscape
Definition: makerow.cpp:50

◆ make_single_row()

float make_single_row ( ICOORD  page_tr,
bool  allow_sub_blobs,
TO_BLOCK block,
TO_BLOCK_LIST *  blocks 
)

Definition at line 164 of file makerow.cpp.

165  {
166  BLOBNBOX_IT blob_it = &block->blobs;
167  TO_ROW_IT row_it = block->get_rows();
168 
169  // Include all the small blobs and large blobs.
170  blob_it.add_list_after(&block->small_blobs);
171  blob_it.add_list_after(&block->noise_blobs);
172  blob_it.add_list_after(&block->large_blobs);
173  if (block->blobs.singleton() && allow_sub_blobs) {
174  blob_it.move_to_first();
175  float size = MakeRowFromSubBlobs(block, blob_it.data()->cblob(), &row_it);
176  if (size > block->line_size)
177  block->line_size = size;
178  } else if (block->blobs.empty()) {
179  // Make a fake blob.
180  C_BLOB* blob = C_BLOB::FakeBlob(block->block->bounding_box());
181  // The blobnbox owns the blob.
182  BLOBNBOX* bblob = new BLOBNBOX(blob);
183  blob_it.add_after_then_move(bblob);
184  }
185  MakeRowFromBlobs(block->line_size, &blob_it, &row_it);
186  // Fit an LMS line to the rows.
187  for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward())
188  fit_lms_line(row_it.data());
189  float gradient;
190  float fit_error;
191  // Compute the skew based on the fitted line.
192  compute_page_skew(blocks, gradient, fit_error);
193  return gradient;
194 }
static C_BLOB * FakeBlob(const TBOX &box)
Definition: stepblob.cpp:238
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
BLOBNBOX_LIST large_blobs
Definition: blobbox.h:772
voidpf void uLong size
Definition: ioapi.h:39
float line_size
Definition: blobbox.h:781
BLOBNBOX_LIST small_blobs
Definition: blobbox.h:771
BLOBNBOX_LIST blobs
Definition: blobbox.h:768
void compute_page_skew(TO_BLOCK_LIST *blocks, float &page_m, float &page_err)
Definition: makerow.cpp:287
float MakeRowFromSubBlobs(TO_BLOCK *block, C_BLOB *blob, TO_ROW_IT *row_it)
Definition: makerow.cpp:137
BLOCK * block
Definition: blobbox.h:773
void fit_lms_line(TO_ROW *row)
Definition: makerow.cpp:267
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
BLOBNBOX_LIST noise_blobs
Definition: blobbox.h:770

◆ mark_repeated_chars()

void mark_repeated_chars ( TO_ROW row)

Definition at line 2657 of file makerow.cpp.

2657  {
2658  BLOBNBOX_IT box_it(row->blob_list()); // Iterator.
2659  int num_repeated_sets = 0;
2660  if (!box_it.empty()) {
2661  do {
2662  BLOBNBOX* bblob = box_it.data();
2663  int repeat_length = 1;
2664  if (bblob->flow() == BTFT_LEADER &&
2665  !bblob->joined_to_prev() && bblob->cblob() != NULL) {
2666  BLOBNBOX_IT test_it(box_it);
2667  for (test_it.forward(); !test_it.at_first();) {
2668  bblob = test_it.data();
2669  if (bblob->flow() != BTFT_LEADER)
2670  break;
2671  test_it.forward();
2672  bblob = test_it.data();
2673  if (bblob->joined_to_prev() || bblob->cblob() == NULL) {
2674  repeat_length = 0;
2675  break;
2676  }
2677  ++repeat_length;
2678  }
2679  }
2680  if (repeat_length >= kMinLeaderCount) {
2681  num_repeated_sets++;
2682  for (; repeat_length > 0; box_it.forward(), --repeat_length) {
2683  bblob = box_it.data();
2684  bblob->set_repeated_set(num_repeated_sets);
2685  }
2686  } else {
2687  bblob->set_repeated_set(0);
2688  box_it.forward();
2689  }
2690  } while (!box_it.at_first()); // until all done
2691  }
2692  row->set_num_repeated_sets(num_repeated_sets);
2693 }
bool joined_to_prev() const
Definition: blobbox.h:241
C_BLOB * cblob() const
Definition: blobbox.h:253
void set_repeated_set(int set_id)
Definition: blobbox.h:250
void set_num_repeated_sets(int num_sets)
Definition: blobbox.h:636
const int kMinLeaderCount
Definition: makerow.cpp:107
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
BlobTextFlowType flow() const
Definition: blobbox.h:280

◆ median_block_xheight()

float median_block_xheight ( TO_BLOCK block,
float  gradient 
)

◆ most_overlapping_row()

OVERLAP_STATE most_overlapping_row ( TO_ROW_IT *  row_it,
TO_ROW *&  best_row,
float  top,
float  bottom,
float  rowsize,
BOOL8  testing_blob 
)

Definition at line 2496 of file makerow.cpp.

2503  {
2504  OVERLAP_STATE result; //result of tests
2505  float overlap; //of blob & row
2506  float bestover; //nearest row
2507  float merge_top, merge_bottom; //size of merged row
2508  ICOORD testpt; //testing only
2509  TO_ROW *row; //current row
2510  TO_ROW *test_row; //for multiple overlaps
2511  BLOBNBOX_IT blob_it; //for merging rows
2512 
2513  result = ASSIGN;
2514  row = row_it->data ();
2515  bestover = top - bottom;
2516  if (top > row->max_y ())
2517  bestover -= top - row->max_y ();
2518  if (bottom < row->min_y ())
2519  //compute overlap
2520  bestover -= row->min_y () - bottom;
2521  if (testing_blob && textord_debug_blob) {
2522  tprintf("Test blob y=(%g,%g), row=(%f,%f), size=%g, overlap=%f\n",
2523  bottom, top, row->min_y(), row->max_y(), rowsize, bestover);
2524  }
2525  test_row = row;
2526  do {
2527  if (!row_it->at_last ()) {
2528  row_it->forward ();
2529  test_row = row_it->data ();
2530  if (test_row->min_y () <= top && test_row->max_y () >= bottom) {
2531  merge_top =
2532  test_row->max_y () >
2533  row->max_y ()? test_row->max_y () : row->max_y ();
2534  merge_bottom =
2535  test_row->min_y () <
2536  row->min_y ()? test_row->min_y () : row->min_y ();
2537  if (merge_top - merge_bottom <= rowsize) {
2538  if (testing_blob) {
2539  tprintf ("Merging rows at (%g,%g), (%g,%g)\n",
2540  row->min_y (), row->max_y (),
2541  test_row->min_y (), test_row->max_y ());
2542  }
2543  test_row->set_limits (merge_bottom, merge_top);
2544  blob_it.set_to_list (test_row->blob_list ());
2545  blob_it.add_list_after (row->blob_list ());
2546  blob_it.sort (blob_x_order);
2547  row_it->backward ();
2548  delete row_it->extract ();
2549  row_it->forward ();
2550  bestover = -1.0f; //force replacement
2551  }
2552  overlap = top - bottom;
2553  if (top > test_row->max_y ())
2554  overlap -= top - test_row->max_y ();
2555  if (bottom < test_row->min_y ())
2556  overlap -= test_row->min_y () - bottom;
2557  if (bestover >= rowsize - 1 && overlap >= rowsize - 1) {
2558  result = REJECT;
2559  }
2560  if (overlap > bestover) {
2561  bestover = overlap; //find biggest overlap
2562  row = test_row;
2563  }
2564  if (testing_blob && textord_debug_blob) {
2565  tprintf("Test blob y=(%g,%g), row=(%f,%f), size=%g, overlap=%f->%f\n",
2566  bottom, top, test_row->min_y(), test_row->max_y(),
2567  rowsize, overlap, bestover);
2568  }
2569  }
2570  }
2571  }
2572  while (!row_it->at_last ()
2573  && test_row->min_y () <= top && test_row->max_y () >= bottom);
2574  while (row_it->data () != row)
2575  row_it->backward (); //make it point to row
2576  //doesn't overlap much
2577  if (top - bottom - bestover > rowsize * textord_overlap_x &&
2578  (!textord_fix_makerow_bug || bestover < rowsize * textord_overlap_x)
2579  && result == ASSIGN)
2580  result = NEW_ROW; //doesn't overlap enough
2581  best_row = row;
2582  return result;
2583 }
Definition: makerow.h:31
int blob_x_order(const void *item1, const void *item2)
Definition: makerow.cpp:2591
Definition: makerow.h:32
#define tprintf(...)
Definition: tprintf.h:31
float min_y() const
Definition: blobbox.h:557
OVERLAP_STATE
Definition: makerow.h:29
bool textord_debug_blob
Definition: makerow.cpp:103
double textord_overlap_x
Definition: makerow.cpp:81
bool textord_fix_makerow_bug
Definition: makerow.cpp:56
float max_y() const
Definition: blobbox.h:554
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
integer coordinate
Definition: points.h:30

◆ pre_associate_blobs()

void pre_associate_blobs ( ICOORD  page_tr,
TO_BLOCK block,
FCOORD  rotation,
BOOL8  testing_on 
)

Definition at line 1862 of file makerow.cpp.

1867  {
1868 #ifndef GRAPHICS_DISABLED
1869  ScrollView::Color colour; //of boxes
1870 #endif
1871  BLOBNBOX *blob; //current blob
1872  BLOBNBOX *nextblob; //next in list
1873  TBOX blob_box;
1874  FCOORD blob_rotation; //inverse of rotation
1875  BLOBNBOX_IT blob_it; //iterator
1876  BLOBNBOX_IT start_it; //iterator
1877  TO_ROW_IT row_it = block->get_rows ();
1878 
1879 #ifndef GRAPHICS_DISABLED
1880  colour = ScrollView::RED;
1881 #endif
1882 
1883  blob_rotation = FCOORD (rotation.x (), -rotation.y ());
1884  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
1885  //get blobs
1886  blob_it.set_to_list (row_it.data ()->blob_list ());
1887  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list ();
1888  blob_it.forward ()) {
1889  blob = blob_it.data ();
1890  blob_box = blob->bounding_box ();
1891  start_it = blob_it; //save start point
1892  // if (testing_on && textord_show_final_blobs)
1893  // {
1894  // tprintf("Blob at (%d,%d)->(%d,%d), addr=%x, count=%d\n",
1895  // blob_box.left(),blob_box.bottom(),
1896  // blob_box.right(),blob_box.top(),
1897  // (void*)blob,blob_it.length());
1898  // }
1899  bool overlap;
1900  do {
1901  overlap = false;
1902  if (!blob_it.at_last ()) {
1903  nextblob = blob_it.data_relative(1);
1904  overlap = blob_box.major_x_overlap(nextblob->bounding_box());
1905  if (overlap) {
1906  blob->merge(nextblob); // merge new blob
1907  blob_box = blob->bounding_box(); // get bigger box
1908  blob_it.forward();
1909  }
1910  }
1911  }
1912  while (overlap);
1913  blob->chop (&start_it, &blob_it,
1914  blob_rotation,
1917  //attempt chop
1918  }
1919 #ifndef GRAPHICS_DISABLED
1920  if (testing_on && textord_show_final_blobs) {
1921  if (to_win == NULL)
1922  create_to_win(page_tr);
1923  to_win->Pen(colour);
1924  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list ();
1925  blob_it.forward ()) {
1926  blob = blob_it.data ();
1927  blob_box = blob->bounding_box ();
1928  blob_box.rotate (rotation);
1929  if (!blob->joined_to_prev ()) {
1930  to_win->Rectangle (blob_box.left (), blob_box.bottom (),
1931  blob_box.right (), blob_box.top ());
1932  }
1933  }
1934  colour = (ScrollView::Color) (colour + 1);
1935  if (colour > ScrollView::MAGENTA)
1936  colour = ScrollView::RED;
1937  }
1938 #endif
1939  }
1940 }
Definition: points.h:189
bool textord_show_final_blobs
Definition: makerow.cpp:49
static const double kXHeightFraction
Definition: ccstruct.h:34
bool joined_to_prev() const
Definition: blobbox.h:241
bool major_x_overlap(const TBOX &box) const
Definition: rect.h:402
inT16 left() const
Definition: rect.h:68
float line_size
Definition: blobbox.h:781
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:606
EXTERN ScrollView * to_win
Definition: drawtord.cpp:38
ScrollView * create_to_win(ICOORD page_tr)
Definition: drawtord.cpp:47
void merge(BLOBNBOX *nextblob)
Definition: blobbox.cpp:87
inT16 top() const
Definition: rect.h:54
Definition: rect.h:30
void chop(BLOBNBOX_IT *start_it, BLOBNBOX_IT *blob_it, FCOORD rotation, float xheight)
Definition: blobbox.cpp:115
float y() const
Definition: points.h:212
inT16 right() const
Definition: rect.h:75
inT16 bottom() const
Definition: rect.h:61
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
float x() const
Definition: points.h:209
const TBOX & bounding_box() const
Definition: blobbox.h:215
void rotate(const FCOORD &vec)
Definition: rect.h:189
double textord_chop_width
Definition: makerow.cpp:78
void Pen(Color color)
Definition: scrollview.cpp:726

◆ row_spacing_order()

int row_spacing_order ( const void *  item1,
const void *  item2 
)

Definition at line 2635 of file makerow.cpp.

2637  {
2638  //converted ptr
2639  TO_ROW *row1 = *(TO_ROW **) item1;
2640  //converted ptr
2641  TO_ROW *row2 = *(TO_ROW **) item2;
2642 
2643  if (row1->spacing < row2->spacing)
2644  return -1;
2645  else if (row1->spacing > row2->spacing)
2646  return 1;
2647  else
2648  return 0;
2649 }
float spacing
Definition: blobbox.h:652

◆ row_y_order()

int row_y_order ( const void *  item1,
const void *  item2 
)

Definition at line 2613 of file makerow.cpp.

2615  {
2616  //converted ptr
2617  TO_ROW *row1 = *(TO_ROW **) item1;
2618  //converted ptr
2619  TO_ROW *row2 = *(TO_ROW **) item2;
2620 
2621  if (row1->parallel_c () > row2->parallel_c ())
2622  return -1;
2623  else if (row1->parallel_c () < row2->parallel_c ())
2624  return 1;
2625  else
2626  return 0;
2627 }
float parallel_c() const
Definition: blobbox.h:575

◆ segment_baseline()

BOOL8 segment_baseline ( TO_ROW row,
TO_BLOCK block,
inT32 segments,
inT32  xstarts[] 
)

Definition at line 2106 of file makerow.cpp.

2111  {
2112  BOOL8 needs_curve; //needs curved line
2113  int blobcount; //no of blobs
2114  int blobindex; //current blob
2115  int last_state; //above, on , below
2116  int state; //of current blob
2117  float yshift; //from baseline
2118  TBOX box; //blob box
2119  TBOX new_box; //new_it box
2120  float middle; //xcentre of blob
2121  //blobs
2122  BLOBNBOX_IT blob_it = row->blob_list ();
2123  BLOBNBOX_IT new_it = blob_it; //front end
2124  SORTED_FLOATS yshifts; //shifts from baseline
2125 
2126  needs_curve = FALSE;
2127  box = box_next_pre_chopped (&blob_it);
2128  xstarts[0] = box.left ();
2129  segments = 1;
2130  blobcount = row->blob_list ()->length ();
2131  if (textord_oldbl_debug)
2132  tprintf ("Segmenting baseline of %d blobs at (%d,%d)\n",
2133  blobcount, box.left (), box.bottom ());
2134  if (blobcount <= textord_spline_medianwin
2135  || blobcount < textord_spline_minblobs) {
2136  blob_it.move_to_last ();
2137  box = blob_it.data ()->bounding_box ();
2138  xstarts[1] = box.right ();
2139  return FALSE;
2140  }
2141  last_state = 0;
2142  new_it.mark_cycle_pt ();
2143  for (blobindex = 0; blobindex < textord_spline_medianwin; blobindex++) {
2144  new_box = box_next_pre_chopped (&new_it);
2145  middle = (new_box.left () + new_box.right ()) / 2.0;
2146  yshift = new_box.bottom () - row->line_m () * middle - row->line_c ();
2147  //record shift
2148  yshifts.add (yshift, blobindex);
2149  if (new_it.cycled_list ()) {
2150  xstarts[1] = new_box.right ();
2151  return FALSE;
2152  }
2153  }
2154  for (blobcount = 0; blobcount < textord_spline_medianwin / 2; blobcount++)
2155  box = box_next_pre_chopped (&blob_it);
2156  do {
2157  new_box = box_next_pre_chopped (&new_it);
2158  //get middle one
2159  yshift = yshifts[textord_spline_medianwin / 2];
2160  if (yshift > textord_spline_shift_fraction * block->line_size)
2161  state = 1;
2162  else if (-yshift > textord_spline_shift_fraction * block->line_size)
2163  state = -1;
2164  else
2165  state = 0;
2166  if (state != 0)
2167  needs_curve = TRUE;
2168  // tprintf("State=%d, prev=%d, shift=%g\n",
2169  // state,last_state,yshift);
2170  if (state != last_state && blobcount > textord_spline_minblobs) {
2171  xstarts[segments++] = box.left ();
2172  blobcount = 0;
2173  }
2174  last_state = state;
2175  yshifts.remove (blobindex - textord_spline_medianwin);
2176  box = box_next_pre_chopped (&blob_it);
2177  middle = (new_box.left () + new_box.right ()) / 2.0;
2178  yshift = new_box.bottom () - row->line_m () * middle - row->line_c ();
2179  yshifts.add (yshift, blobindex);
2180  blobindex++;
2181  blobcount++;
2182  }
2183  while (!new_it.cycled_list ());
2184  if (blobcount > textord_spline_minblobs || segments == 1) {
2185  xstarts[segments] = new_box.right ();
2186  }
2187  else {
2188  xstarts[--segments] = new_box.right ();
2189  }
2190  if (textord_oldbl_debug)
2191  tprintf ("Made %d segments on row at (%d,%d)\n",
2192  segments, box.right (), box.bottom ());
2193  return needs_curve;
2194 }
TBOX box_next_pre_chopped(BLOBNBOX_IT *it)
Definition: blobbox.cpp:660
#define TRUE
Definition: capi.h:45
EXTERN bool textord_oldbl_debug
Definition: oldbasel.cpp:39
#define tprintf(...)
Definition: tprintf.h:31
float line_m() const
Definition: blobbox.h:566
float line_c() const
Definition: blobbox.h:569
inT16 left() const
Definition: rect.h:68
void add(float value, inT32 key)
Definition: sortflts.cpp:28
float line_size
Definition: blobbox.h:781
void remove(inT32 key)
Definition: sortflts.cpp:53
unsigned char BOOL8
Definition: host.h:44
#define FALSE
Definition: capi.h:46
Definition: rect.h:30
double textord_spline_shift_fraction
Definition: makerow.cpp:71
inT16 right() const
Definition: rect.h:75
inT16 bottom() const
Definition: rect.h:61
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
int textord_spline_minblobs
Definition: makerow.cpp:65
int textord_spline_medianwin
Definition: makerow.cpp:66

◆ separate_underlines()

void separate_underlines ( TO_BLOCK block,
float  gradient,
FCOORD  rotation,
BOOL8  testing_on 
)

Definition at line 1789 of file makerow.cpp.

1792  { // correct orientation
1793  BLOBNBOX *blob; // current blob
1794  C_BLOB *rotated_blob; // rotated blob
1795  TO_ROW *row; // current row
1796  float length; // of g_vec
1797  TBOX blob_box;
1798  FCOORD blob_rotation; // inverse of rotation
1799  FCOORD g_vec; // skew rotation
1800  BLOBNBOX_IT blob_it; // iterator
1801  // iterator
1802  BLOBNBOX_IT under_it = &block->underlines;
1803  BLOBNBOX_IT large_it = &block->large_blobs;
1804  TO_ROW_IT row_it = block->get_rows();
1805  int min_blob_height = static_cast<int>(textord_min_blob_height_fraction *
1806  block->line_size + 0.5);
1807 
1808  // length of vector
1809  length = sqrt(1 + gradient * gradient);
1810  g_vec = FCOORD(1 / length, -gradient / length);
1811  blob_rotation = FCOORD(rotation.x(), -rotation.y());
1812  blob_rotation.rotate(g_vec); // undoing everything
1813  for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {
1814  row = row_it.data();
1815  // get blobs
1816  blob_it.set_to_list(row->blob_list());
1817  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();
1818  blob_it.forward()) {
1819  blob = blob_it.data();
1820  blob_box = blob->bounding_box();
1821  if (blob_box.width() > block->line_size * textord_underline_width) {
1822  ASSERT_HOST(blob->cblob() != NULL);
1823  rotated_blob = crotate_cblob (blob->cblob(),
1824  blob_rotation);
1825  if (test_underline(
1826  testing_on && textord_show_final_rows,
1827  rotated_blob, static_cast<inT16>(row->intercept()),
1828  static_cast<inT16>(
1829  block->line_size *
1832  under_it.add_after_then_move(blob_it.extract());
1833  if (testing_on && textord_show_final_rows) {
1834  tprintf("Underlined blob at:");
1835  rotated_blob->bounding_box().print();
1836  tprintf("Was:");
1837  blob_box.print();
1838  }
1839  } else if (CountOverlaps(blob->bounding_box(), min_blob_height,
1840  row->blob_list()) >
1842  large_it.add_after_then_move(blob_it.extract());
1843  if (testing_on && textord_show_final_rows) {
1844  tprintf("Large blob overlaps %d blobs at:",
1845  CountOverlaps(blob_box, min_blob_height,
1846  row->blob_list()));
1847  blob_box.print();
1848  }
1849  }
1850  delete rotated_blob;
1851  }
1852  }
1853  }
1854 }
BLOBNBOX_LIST underlines
Definition: blobbox.h:769
Definition: points.h:189
static const double kAscenderFraction
Definition: ccstruct.h:35
void rotate(const FCOORD vec)
Definition: ipoints.h:471
BLOBNBOX_LIST large_blobs
Definition: blobbox.h:772
static const double kXHeightFraction
Definition: ccstruct.h:34
#define tprintf(...)
Definition: tprintf.h:31
float intercept() const
Definition: blobbox.h:584
double textord_underline_width
Definition: makerow.cpp:87
C_BLOB * cblob() const
Definition: blobbox.h:253
#define ASSERT_HOST(x)
Definition: errcode.h:84
float line_size
Definition: blobbox.h:781
bool textord_show_final_rows
Definition: makerow.cpp:48
double textord_min_blob_height_fraction
Definition: makerow.cpp:89
int textord_max_blob_overlaps
Definition: makerow.cpp:68
Definition: rect.h:30
float y() const
Definition: points.h:212
inT16 width() const
Definition: rect.h:111
C_BLOB * crotate_cblob(C_BLOB *blob, FCOORD rotation)
Definition: blobbox.cpp:606
void print() const
Definition: rect.h:270
BOOL8 test_underline(BOOL8 testing_on, C_BLOB *blob, inT16 baseline, inT16 xheight)
Definition: blkocc.cpp:53
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
float x() const
Definition: points.h:209
const TBOX & bounding_box() const
Definition: blobbox.h:215

◆ vigorous_noise_removal()

void vigorous_noise_removal ( TO_BLOCK block)

Definition at line 473 of file makerow.cpp.

473  {
474  TO_ROW_IT row_it = block->get_rows ();
475  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
476  TO_ROW* row = row_it.data();
477  BLOBNBOX_IT b_it = row->blob_list();
478  // Estimate the xheight on the row.
479  int max_height = 0;
480  for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
481  BLOBNBOX* blob = b_it.data();
482  if (blob->bounding_box().height() > max_height)
483  max_height = blob->bounding_box().height();
484  }
485  STATS hstats(0, max_height + 1);
486  for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
487  BLOBNBOX* blob = b_it.data();
488  int height = blob->bounding_box().height();
489  if (height >= kMinSize)
490  hstats.add(blob->bounding_box().height(), 1);
491  }
492  float xheight = hstats.median();
493  // Delete small objects.
494  BLOBNBOX* prev = NULL;
495  for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
496  BLOBNBOX* blob = b_it.data();
497  const TBOX& box = blob->bounding_box();
498  if (box.height() < kNoiseSize * xheight) {
499  // Small so delete unless it looks like an i dot.
500  if (prev != NULL) {
501  if (dot_of_i(blob, prev, row))
502  continue; // Looks OK.
503  }
504  if (!b_it.at_last()) {
505  BLOBNBOX* next = b_it.data_relative(1);
506  if (dot_of_i(blob, next, row))
507  continue; // Looks OK.
508  }
509  // It might be noise so get rid of it.
510  delete blob->cblob();
511  delete b_it.extract();
512  } else {
513  prev = blob;
514  }
515  }
516  }
517 }
const int kMinSize
Definition: makerow.cpp:384
C_BLOB * cblob() const
Definition: blobbox.h:253
Definition: rect.h:30
inT16 height() const
Definition: rect.h:104
Definition: statistc.h:33
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:595
TO_ROW_LIST * get_rows()
Definition: blobbox.h:700
const TBOX & bounding_box() const
Definition: blobbox.h:215
const double kNoiseSize
Definition: makerow.cpp:383

◆ within_error_margin()

bool within_error_margin ( float  test,
float  num,
float  margin 
)
inline

Definition at line 129 of file makerow.h.

129  {
130  return (test >= num * (1 - margin) && test <= num * (1 + margin));
131 }

Variable Documentation

◆ textord_ascheight_mode_fraction

double textord_ascheight_mode_fraction = 0.15

"Min pile height to make ascheight"

Definition at line 93 of file makerow.cpp.

◆ textord_ascx_ratio_max

double textord_ascx_ratio_max = 1.7

"Max cap/xheight"

Definition at line 97 of file makerow.cpp.

◆ textord_ascx_ratio_min

double textord_ascx_ratio_min = 1.2

"Min cap/xheight"

Definition at line 96 of file makerow.cpp.

◆ textord_cblob_blockocc

bool textord_cblob_blockocc = TRUE

"Use new projection for underlines"

◆ textord_chop_width

double textord_chop_width = 1.5

"Max width before chopping"

Definition at line 78 of file makerow.cpp.

◆ textord_debug_blob

bool textord_debug_blob = FALSE

"Print test blob information"

Definition at line 103 of file makerow.cpp.

◆ textord_debug_xheights

bool textord_debug_xheights = FALSE

"Test xheight algorithms"

Definition at line 57 of file makerow.cpp.

◆ textord_descx_ratio_max

double textord_descx_ratio_max = 0.6

"Max desc/xheight"

Definition at line 99 of file makerow.cpp.

◆ textord_descx_ratio_min

double textord_descx_ratio_min = 0.15

"Min desc/xheight"

Definition at line 98 of file makerow.cpp.

◆ textord_excess_blobsize

double textord_excess_blobsize = 1.3

"New row made if blob makes row this big"

Definition at line 85 of file makerow.cpp.

◆ textord_fix_makerow_bug

bool textord_fix_makerow_bug = TRUE

"Prevent multiple baselines"

Definition at line 56 of file makerow.cpp.

◆ textord_fix_xheight_bug

bool textord_fix_xheight_bug = TRUE

"Use spline baseline"

Definition at line 55 of file makerow.cpp.

◆ textord_heavy_nr

bool textord_heavy_nr = FALSE

"Vigorously remove noise"

Definition at line 44 of file makerow.cpp.

◆ textord_linespace_iqrlimit

double textord_linespace_iqrlimit = 0.2

"Max iqr/median for linespace"

Definition at line 76 of file makerow.cpp.

◆ textord_lms_line_trials

int textord_lms_line_trials = 12

"Number of linew fits to do"

Definition at line 101 of file makerow.cpp.

◆ textord_min_blob_height_fraction

double textord_min_blob_height_fraction = 0.75

"Min blob height/top to include blob top into xheight stats"

Definition at line 89 of file makerow.cpp.

◆ textord_min_blobs_in_row

int textord_min_blobs_in_row = 4

"Min blobs before gradient counted"

Definition at line 64 of file makerow.cpp.

◆ textord_min_linesize

double textord_min_linesize = 1.25

"* blob height for initial linesize"

Definition at line 83 of file makerow.cpp.

◆ textord_min_xheight

int textord_min_xheight = 10

"Min credible pixel xheight"

Definition at line 69 of file makerow.cpp.

◆ textord_minxh

double textord_minxh = 0.25

"fraction of linesize for min xheight"

Definition at line 82 of file makerow.cpp.

◆ textord_new_initial_xheight

bool textord_new_initial_xheight = TRUE

"Use test xheight mechanism"

Definition at line 102 of file makerow.cpp.

◆ textord_occupancy_threshold

double textord_occupancy_threshold = 0.4

"Fraction of neighbourhood"

Definition at line 86 of file makerow.cpp.

◆ textord_old_baselines

bool textord_old_baselines = TRUE

"Use old baseline algorithm"

Definition at line 53 of file makerow.cpp.

◆ textord_old_xheight

bool textord_old_xheight = TRUE

"Use old xheight algorithm"

Definition at line 54 of file makerow.cpp.

◆ textord_parallel_baselines

bool textord_parallel_baselines = TRUE

"Force parallel baselines"

Definition at line 51 of file makerow.cpp.

◆ textord_quadratic_baselines

bool textord_quadratic_baselines = FALSE

"Use quadratic splines"

◆ textord_show_expanded_rows

bool textord_show_expanded_rows = FALSE

"Display rows after expanding"

Definition at line 47 of file makerow.cpp.

◆ textord_show_final_blobs

bool textord_show_final_blobs = FALSE

"Display blob bounds after pre-ass"

Definition at line 49 of file makerow.cpp.

◆ textord_show_final_rows

bool textord_show_final_rows = FALSE

"Display rows after final fitting"

Definition at line 48 of file makerow.cpp.

◆ textord_show_initial_rows

bool textord_show_initial_rows = FALSE

"Display row accumulation"

Definition at line 45 of file makerow.cpp.

◆ textord_show_parallel_rows

bool textord_show_parallel_rows = FALSE

"Display page correlated rows"

Definition at line 46 of file makerow.cpp.

◆ textord_skew_ile

double textord_skew_ile = 0.5

"Ile of gradients for page skew"

Definition at line 74 of file makerow.cpp.

◆ textord_skew_lag

double textord_skew_lag = 0.75

"Lag for skew on row accumulation"

Definition at line 75 of file makerow.cpp.

◆ textord_spline_medianwin

int textord_spline_medianwin = 6

"Size of window for spline segmentation"

Definition at line 66 of file makerow.cpp.

◆ textord_spline_minblobs

int textord_spline_minblobs = 8

"Min blobs in each spline segment"

Definition at line 65 of file makerow.cpp.

◆ textord_spline_outlier_fraction

double textord_spline_outlier_fraction = 0.1

"Fraction of line spacing for outlier"

Definition at line 73 of file makerow.cpp.

◆ textord_spline_shift_fraction

double textord_spline_shift_fraction = 0.02

"Fraction of line spacing for quad"

Definition at line 71 of file makerow.cpp.

◆ textord_straight_baselines

bool textord_straight_baselines = FALSE

"Force straight baselines"

Definition at line 52 of file makerow.cpp.

◆ textord_test_landscape

bool textord_test_landscape = FALSE

"Tests refer to land/port"

Definition at line 50 of file makerow.cpp.

◆ textord_test_x

int textord_test_x = -MAX_INT32

"coord of test pt"

Definition at line 62 of file makerow.cpp.

◆ textord_test_y

int textord_test_y = -MAX_INT32

"coord of test pt"

Definition at line 63 of file makerow.cpp.

◆ textord_underline_width

double textord_underline_width = 2.0

"Multiple of line_size for underline"

Definition at line 87 of file makerow.cpp.

◆ textord_width_limit

double textord_width_limit = 8

"Max width of blobs to make rows"

Definition at line 77 of file makerow.cpp.

◆ textord_xheight_error_margin

double textord_xheight_error_margin = 0.1

"Accepted variation"

Definition at line 100 of file makerow.cpp.

◆ textord_xheight_mode_fraction

double textord_xheight_mode_fraction = 0.4

"Min pile height to make xheight"

Definition at line 91 of file makerow.cpp.