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 + -
显示快捷键?