makerow.cpp

来自「一OCR的相关资料。.希望对研究OCR的朋友有所帮助.」· C++ 代码 · 共 1,691 行 · 第 1/5 页

CPP
1,691
字号
/********************************************************************** * File:        makerow.cpp  (Formerly makerows.c) * Description: Code to arrange blobs into rows of text. * Author:		Ray Smith * Created:		Mon Sep 21 14:34:48 BST 1992 * * (C) Copyright 1992, Hewlett-Packard Ltd. ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** http://www.apache.org/licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. * **********************************************************************/#include "mfcpch.h"#ifdef __UNIX__#include          <assert.h>#endif#include          "stderr.h"#include          "blobbox.h"#include          "lmedsq.h"#include          "statistc.h"#include          "drawtord.h"#include          "blkocc.h"#include          "sortflts.h"#include          "oldbasel.h"#include          "tordmain.h"#include          "underlin.h"#include          "makerow.h"#include          "tprintf.h"#define EXTERNEXTERN BOOL_VAR (textord_heavy_nr, FALSE, "Vigorously remove noise");EXTERN BOOL_VAR (textord_show_initial_rows, FALSE,"Display row accumulation");EXTERN BOOL_VAR (textord_show_parallel_rows, FALSE,"Display page correlated rows");EXTERN BOOL_VAR (textord_show_expanded_rows, FALSE,"Display rows after expanding");EXTERN BOOL_VAR (textord_show_final_rows, FALSE,"Display rows after final fittin");EXTERN BOOL_VAR (textord_show_final_blobs, FALSE,"Display blob bounds after pre-ass");EXTERN BOOL_VAR (textord_test_landscape, FALSE, "Tests refer to land/port");EXTERN BOOL_VAR (textord_parallel_baselines, TRUE,"Force parallel baselines");EXTERN BOOL_VAR (textord_straight_baselines, FALSE,"Force straight baselines");EXTERN BOOL_VAR (textord_quadratic_baselines, FALSE, "Use quadratic splines");EXTERN BOOL_VAR (textord_old_baselines, TRUE, "Use old baseline algorithm");EXTERN BOOL_VAR (textord_old_xheight, TRUE, "Use old xheight algorithm");EXTERN BOOL_VAR (textord_fix_xheight_bug, TRUE, "Use spline baseline");EXTERN BOOL_VAR (textord_fix_makerow_bug, TRUE, "Prevent multiple baselines");EXTERN BOOL_VAR (textord_row_xheights, FALSE, "Use row height policy");EXTERN BOOL_VAR (textord_block_xheights, TRUE, "Use block height policy");EXTERN BOOL_VAR (textord_xheight_tweak, FALSE, "New min condition on height");EXTERN BOOL_VAR (textord_cblob_blockocc, TRUE,"Use new projection for underlines");EXTERN BOOL_VAR (textord_debug_xheights, FALSE, "Test xheight algorithms");EXTERN BOOL_VAR (textord_biased_skewcalc, TRUE,"Bias skew estimates with line length");EXTERN BOOL_VAR (textord_interpolating_skew, TRUE, "Interpolate across gaps");EXTERN INT_VAR (textord_skewsmooth_offset, 2, "For smooth factor");EXTERN INT_VAR (textord_test_x, 0, "coord of test pt");EXTERN INT_VAR (textord_test_y, 0, "coord of test pt");EXTERN INT_VAR (textord_min_blobs_in_row, 4,"Min blobs before gradient counted");EXTERN INT_VAR (textord_spline_minblobs, 8,"Min blobs in each spline segment");EXTERN INT_VAR (textord_spline_medianwin, 6,"Size of window for spline segmentation");EXTERN INT_VAR (textord_min_xheight, 10, "Min credible pixel xheight");EXTERN double_VAR (textord_spline_shift_fraction, 0.02,"Fraction of line spacing for quad");EXTERN double_VAR (textord_spline_outlier_fraction, 0.1,"Fraction of line spacing for outlier");EXTERN double_VAR (textord_skew_ile, 0.5, "Ile of gradients for page skew");EXTERN double_VAR (textord_skew_lag, 0.01,"Lag for skew on row accumulation");EXTERN double_VAR (textord_linespace_iqrlimit, 0.2,"Max iqr/median for linespace");EXTERN double_VAR (textord_width_limit, 8, "Max width of blobs to make rows");EXTERN double_VAR (textord_chop_width, 1.5, "Max width before chopping");EXTERN double_VAR (textord_merge_desc, 0.25,"Fraction of linespace for desc drop");EXTERN double_VAR (textord_merge_x, 0.5,"Fraction of linespace for x height");EXTERN double_VAR (textord_merge_asc, 0.25,"Fraction of linespace for asc height");EXTERN double_VAR (textord_minxh, 0.25,"fraction of linesize for min xheight");EXTERN double_VAR (textord_min_linesize, 1.25,"* blob height for initial linesize");EXTERN double_VAR (textord_excess_blobsize, 1.3,"New row made if blob makes row this big");EXTERN double_VAR (textord_occupancy_threshold, 0.4,"Fraction of neighbourhood");EXTERN double_VAR (textord_underline_width, 2.0,"Multiple of line_size for underline");EXTERN double_VAR (textord_xheight_mode_fraction, 0.4,"Min pile height to make xheight");EXTERN double_VAR (textord_ascheight_mode_fraction, 0.15,"Min pile height to make ascheight");EXTERN double_VAR (textord_ascx_ratio_min, 1.2, "Min cap/xheight");EXTERN double_VAR (textord_ascx_ratio_max, 1.7, "Max cap/xheight");EXTERN double_VAR (textord_descx_ratio_min, 0.15, "Min desc/xheight");EXTERN double_VAR (textord_descx_ratio_max, 0.6, "Max desc/xheight");EXTERN double_VAR (textord_xheight_error_margin, 0.1, "Accepted variation");#define MAX_HEIGHT_MODES  12/********************************************************************** * make_rows * * Arrange the blobs into rows. **********************************************************************/float make_rows(                             //make rows                ICOORD page_tr,              //top right                BLOCK_LIST *blocks,          //block list                TO_BLOCK_LIST *land_blocks,  //rotated for landscape                TO_BLOCK_LIST *port_blocks   //output list               ) {  float port_m;                  //global skew  float port_err;                //global noise  //   float                                     land_m;                                         //global skew  //      float                                   land_err;                                       //global noise  TO_BLOCK_IT block_it;          //iterator  //don't do landscape for now  //      block_it.set_to_list(land_blocks);  //      for (block_it.mark_cycle_pt();!block_it.cycled_list();block_it.forward())  //              make_initial_textrows(page_tr,block_it.data(),FCOORD(0,-1),  //                      (BOOL8)textord_test_landscape);  block_it.set_to_list (port_blocks);  for (block_it.mark_cycle_pt (); !block_it.cycled_list ();    block_it.forward ())  make_initial_textrows (page_tr, block_it.data (), FCOORD (1.0f, 0.0f),      !(BOOL8) textord_test_landscape);                                 //compute globally  compute_page_skew(port_blocks, port_m, port_err);  //      compute_page_skew(land_blocks,land_m,land_err);                 //compute globally  //      tprintf("Portrait skew gradient=%g, error=%g.\n",  //              port_m,port_err);  //      tprintf("Landscape skew gradient=%g, error=%g.\n",  //              land_m,land_err);  block_it.set_to_list (port_blocks);  for (block_it.mark_cycle_pt (); !block_it.cycled_list ();  block_it.forward ()) {    cleanup_rows (page_tr, block_it.data (), port_m, FCOORD (1.0f, 0.0f),      block_it.data ()->block->bounding_box ().left (),      !(BOOL8) textord_test_landscape);  }  block_it.set_to_list (land_blocks);  //      for (block_it.mark_cycle_pt();!block_it.cycled_list();block_it.forward())  //      {  //              cleanup_rows(page_tr,block_it.data(),land_m,FCOORD(0,-1),  //                      -block_it.data()->block->bounding_box().top(),  //                      (BOOL8)textord_test_landscape);  //      }  return port_m;                 //global skew}/********************************************************************** * make_initial_textrows * * Arrange the good blobs into rows of text. **********************************************************************/void make_initial_textrows(                  //find lines                           ICOORD page_tr,                           TO_BLOCK *block,  //block to do                           FCOORD rotation,  //for drawing                           BOOL8 testing_on  //correct orientation                          ) {  TO_ROW_IT row_it = block->get_rows ();#ifndef GRAPHICS_DISABLED  COLOUR colour;                 //of row  if (textord_show_initial_rows && testing_on) {    if (to_win == NO_WINDOW)      create_to_win(page_tr);  }#endif                                 //guess skew  assign_blobs_to_rows (block, NULL, 0, TRUE, TRUE, textord_show_initial_rows && testing_on);  row_it.move_to_first ();  for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())    fit_lms_line (row_it.data ());#ifndef GRAPHICS_DISABLED  if (textord_show_initial_rows && testing_on) {    colour = RED;    for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {      plot_to_row (row_it.data (), colour, rotation);      colour = (COLOUR) (colour + 1);      if (colour > MAGENTA)        colour = RED;    }  }#endif}/********************************************************************** * fit_lms_line * * Fit an LMS line to a row. **********************************************************************/void fit_lms_line(             //sort function                  TO_ROW *row  //row to fit                 ) {  float m, c;                    //fitted line  BOX box;                       //blob box  LMS lms (row->blob_list ()->length ());                                 //blobs  BLOBNBOX_IT blob_it = row->blob_list ();  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {    box = blob_it.data ()->bounding_box ();    lms.add (FCOORD ((box.left () + box.right ()) / 2.0, box.bottom ()));  }  lms.fit (m, c);  row->set_line (m, c, lms.error ());}/********************************************************************** * compute_page_skew * * Compute the skew over a full page by averaging the gradients over * all the lines. Get the error of the same row. **********************************************************************/void compute_page_skew(                        //get average gradient                       TO_BLOCK_LIST *blocks,  //list of blocks                       float &page_m,          //average gradient                       float &page_err         //average error                      ) {  INT32 row_count;               //total rows  INT32 blob_count;              //total_blobs  INT32 row_err;                 //integer error  float *gradients;              //of rows  float *errors;                 //of rows  INT32 row_index;               //of total  TO_ROW *row;                   //current row  TO_BLOCK_IT block_it = blocks; //iterator  TO_ROW_IT row_it;  row_count = 0;  blob_count = 0;  for (block_it.mark_cycle_pt (); !block_it.cycled_list ();  block_it.forward ()) {    row_count += block_it.data ()->get_rows ()->length ();    //count up rows    row_it.set_to_list (block_it.data ()->get_rows ());    for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())      blob_count += row_it.data ()->blob_list ()->length ();  }  if (row_count == 0) {    page_m = 0.0f;    page_err = 0.0f;    return;  }  gradients = (float *) alloc_mem (blob_count * sizeof (float));  //get mem  errors = (float *) alloc_mem (blob_count * sizeof (float));  if (gradients == NULL || errors == NULL)    MEMORY_OUT.error ("compute_page_skew", ABORT, NULL);  row_index = 0;  for (block_it.mark_cycle_pt (); !block_it.cycled_list ();  block_it.forward ()) {    row_it.set_to_list (block_it.data ()->get_rows ());    for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {      row = row_it.data ();      blob_count = row->blob_list ()->length ();      row_err = (INT32) ceil (row->line_error ());      if (row_err <= 0)        row_err = 1;      if (textord_biased_skewcalc) {        blob_count /= row_err;        for (blob_count /= row_err; blob_count > 0; blob_count--) {          gradients[row_index] = row->line_m ();          errors[row_index] = row->line_error ();          row_index++;        }      }      else if (blob_count >= textord_min_blobs_in_row) {                                 //get gradient        gradients[row_index] = row->line_m ();        errors[row_index] = row->line_error ();        row_index++;      }    }  }  if (row_index == 0) {                                 //desperate    for (block_it.mark_cycle_pt (); !block_it.cycled_list ();    block_it.forward ()) {      row_it.set_to_list (block_it.data ()->get_rows ());      for (row_it.mark_cycle_pt (); !row_it.cycled_list ();      row_it.forward ()) {        row = row_it.data ();        gradients[row_index] = row->line_m ();        errors[row_index] = row->line_error ();        row_index++;      }    }  }  row_count = row_index;  row_index = choose_nth_item ((INT32) (row_count * textord_skew_ile),    gradients, row_count);  page_m = gradients[row_index];  row_index = choose_nth_item ((INT32) (row_count * textord_skew_ile),    errors, row_count);  page_err = errors[row_index];  free_mem(gradients);  free_mem(errors);}const double kNoiseSize = 0.5;  // Fraction of xheight.const int kMinSize = 8;  // Min pixels to be xheight.// Return true if the dot looks like it is part of the i.// Doesn't work for any other diacritical.static bool dot_of_i(BLOBNBOX* dot, BLOBNBOX* i, TO_ROW* row) {  const BOX& ibox = i->bounding_box();  const BOX& dotbox = dot->bounding_box();  // Must overlap horizontally by enough and be high enough.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?