baseapi.cpp

来自「一个google的OCR源码」· C++ 代码 · 共 1,123 行 · 第 1/3 页

CPP
1,123
字号
/********************************************************************** * File:        baseapi.cpp * Description: Simple API for calling tesseract. * Author:      Ray Smith * Created:     Fri Oct 06 15:35:01 PDT 2006 * * (C) Copyright 2006, Google Inc. ** 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 "baseapi.h"// Include automatically generated configuration file if running autoconf.#ifdef HAVE_CONFIG_H#include "config_auto.h"#endif#ifdef HAVE_LIBLEPT// Include leptonica library only if autoconf (or makefile etc) tell us to.#include "allheaders.h"#endif#include "tessedit.h"#include "ocrclass.h"#include "pageres.h"#include "tessvars.h"#include "control.h"#include "applybox.h"#include "pgedit.h"#include "varabled.h"#include "variables.h"#include "output.h"#include "globals.h"#include "adaptmatch.h"#include "edgblob.h"#include "tessbox.h"#include "tordvars.h"#include "imgs.h"#include "makerow.h"#include "tstruct.h"#include "tessout.h"#include "tface.h"#include "permute.h"BOOL_VAR(tessedit_resegment_from_boxes, FALSE,         "Take segmentation and labeling from box file");BOOL_VAR(tessedit_train_from_boxes, FALSE,         "Generate training data from boxed chars");// Minimum sensible image size to be worth running tesseract.const int kMinRectSize = 10;static STRING input_file = "noname.tif";// Set the value of an internal "variable" (of either old or new types).// Supply the name of the variable and the value as a string, just as// you would in a config file.// Returns false if the name lookup failed.bool TessBaseAPI::SetVariable(const char* variable, const char* value) {  if (set_new_style_variable(variable, value))    return true;  return set_old_style_variable(variable, value);}void TessBaseAPI::SimpleInit(const char* datapath,                             const char* language,                             bool numeric_mode) {  InitWithLanguage(datapath, NULL, language, NULL, numeric_mode, 0, NULL);}// Start tesseract.// The datapath must be the name of the data directory or some other file// in which the data directory resides (for instance argv[0].)// The configfile is the name of a file in the tessconfigs directory// (eg batch) or NULL to run on defaults.// Outputbase may also be NULL, and is the basename of various output files.// If the output of any of these files is enabled, then a name nmust be given.// If numeric_mode is true, only possible digits and roman numbers are// returned. Returns 0 if successful. Crashes if not.// The argc and argv may be 0 and NULL respectively. They are used for// providing config files for debug/display purposes.// TODO(rays) get the facts straight. Is it OK to call// it more than once? Make it properly check for errors and return them.int TessBaseAPI::Init(const char* datapath, const char* outputbase,                              const char* configfile, bool numeric_mode,                              int argc, char* argv[]) {  return InitWithLanguage(datapath, outputbase, NULL, configfile,                          numeric_mode, argc, argv);}// Start tesseract.// Similar to Init() except that it is possible to specify the language.// Language is the code of the language for which the data will be loaded.// (Codes follow ISO 639-3.) If it is NULL, english (eng) will be loaded.int TessBaseAPI::InitWithLanguage(const char* datapath, const char* outputbase,                              const char* language, const char* configfile,                              bool numeric_mode, int argc, char* argv[]) {  int result = init_tesseract(datapath, outputbase, language,      configfile, argc, argv);  bln_numericmode.set_value(numeric_mode);  return result;}// Init the lang model component of Tesseractint TessBaseAPI::InitLangMod(const char* datapath, const char* outputbase,                                const char* language, const char* configfile,                                bool numeric_mode, int argc, char* argv[]) {  return init_tesseract_lm(datapath, outputbase, language,      configfile, argc, argv);}// Set the name of the input file. Needed only for training and// loading a UNLV zone file.void TessBaseAPI::SetInputName(const char* name) {  input_file = name;}// Recognize a rectangle from an image and return the result as a string.// May be called many times for a single Init.// Currently has no error checking.// Greyscale of 8 and color of 24 or 32 bits per pixel may be given.// Palette color images will not work properly and must be converted to// 24 bit.// Binary images of 1 bit per pixel may also be given but they must be// byte packed with the MSB of the first byte being the first pixel, and a// one pixel is WHITE. For binary images set bytes_per_pixel=0.// The recognized text is returned as a char* which (in future will be coded// as UTF8 and) must be freed with the delete [] operator.char* TessBaseAPI::TesseractRect(const unsigned char* imagedata,                                 int bytes_per_pixel,                                 int bytes_per_line,                                 int left, int top,                                 int width, int height) {  if (width < kMinRectSize || height < kMinRectSize)    return NULL;  // Nothing worth doing.  // Copy/Threshold the image to the tesseract global page_image.  CopyImageToTesseract(imagedata, bytes_per_pixel, bytes_per_line,                       left, top, width, height);  return RecognizeToString();}// As TesseractRect but produces a box file as output.char* TessBaseAPI::TesseractRectBoxes(const unsigned char* imagedata,                                      int bytes_per_pixel,                                      int bytes_per_line,                                      int left, int top,                                      int width, int height,                                      int imageheight) {  if (width < kMinRectSize || height < kMinRectSize)  return NULL;  // Nothing worth doing.  // Copy/Threshold the image to the tesseract global page_image.  CopyImageToTesseract(imagedata, bytes_per_pixel, bytes_per_line,                       left, top, width, height);  BLOCK_LIST    block_list;  FindLines(&block_list);  // Now run the main recognition.  PAGE_RES* page_res = Recognize(&block_list, NULL);  return TesseractToBoxText(page_res, left, imageheight - (top + height));}char* TessBaseAPI::TesseractRectUNLV(const unsigned char* imagedata,                                     int bytes_per_pixel,                                     int bytes_per_line,                                     int left, int top,                                     int width, int height) {  if (width < kMinRectSize || height < kMinRectSize)    return NULL;  // Nothing worth doing.  // Copy/Threshold the image to the tesseract global page_image.  CopyImageToTesseract(imagedata, bytes_per_pixel, bytes_per_line,                       left, top, width, height);  BLOCK_LIST    block_list;  FindLines(&block_list);  // Now run the main recognition.  PAGE_RES* page_res = Recognize(&block_list, NULL);  return TesseractToUNLV(page_res);}// Call between pages or documents etc to free up memory and forget// adaptive data.void TessBaseAPI::ClearAdaptiveClassifier() {  ResetAdaptiveClassifier();}// Close down tesseract and free up memory.void TessBaseAPI::End() {  ResetAdaptiveClassifier();  end_tesseract();}// Dump the internal binary image to a PGM file.void TessBaseAPI::DumpPGM(const char* filename) {  IMAGELINE line;  line.init(page_image.get_xsize());  FILE *fp = fopen(filename, "w");  fprintf(fp, "P5 " INT32FORMAT " " INT32FORMAT " 255\n", page_image.get_xsize(),          page_image.get_ysize());  for (int j = page_image.get_ysize()-1; j >= 0 ; --j) {    page_image.get_line(0, j, page_image.get_xsize(), &line, 0);    for (int i = 0; i < page_image.get_xsize(); ++i) {      uinT8 b = line.pixels[i] ? 255 : 0;      fwrite(&b, 1, 1, fp);    }  }  fclose(fp);}#ifdef HAVE_LIBLEPT// ONLY available if you have Leptonica installed.// Get a copy of the thresholded global image from Tesseract.Pix* TessBaseAPI::GetTesseractImage() {  return page_image.ToPix();}#endif  // HAVE_LIBLEPT// Copy the given image rectangle to Tesseract, with adaptive thresholding// if the image is not already binary.void TessBaseAPI::CopyImageToTesseract(const unsigned char* imagedata,                                       int bytes_per_pixel,                                       int bytes_per_line,                                       int left, int top,                                       int width, int height) {  if (bytes_per_pixel > 0) {    // Threshold grey or color.    int* thresholds = new int[bytes_per_pixel];    int* hi_values = new int[bytes_per_pixel];    // Compute the thresholds.    OtsuThreshold(imagedata, bytes_per_pixel, bytes_per_line,                  left, top, left + width, top + height,                  thresholds, hi_values);    // Threshold the image to the tesseract global page_image.    ThresholdRect(imagedata, bytes_per_pixel, bytes_per_line,                  left, top, width, height,                  thresholds, hi_values);    delete [] thresholds;    delete [] hi_values;  } else {    CopyBinaryRect(imagedata, bytes_per_line, left, top, width, height);  }}// Compute the Otsu threshold(s) for the given image rectangle, making one// for each channel. Each channel is always one byte per pixel.// Returns an array of threshold values and an array of hi_values, such// that a pixel value >threshold[channel] is considered foreground if// hi_values[channel] is 0 or background if 1. A hi_value of -1 indicates// that there is no apparent foreground. At least one hi_value will not be -1.// thresholds and hi_values are assumed to be of bytes_per_pixel size.void TessBaseAPI::OtsuThreshold(const unsigned char* imagedata,                                int bytes_per_pixel,                                int bytes_per_line,                                int left, int top, int right, int bottom,                                int* thresholds,                                int* hi_values) {  // Of all channels with no good hi_value, keep the best so we can always  // produce at least one answer.  int best_hi_value = 0;  int best_hi_index = 0;  bool any_good_hivalue = false;  double best_hi_dist = 0.0;  for (int ch = 0; ch < bytes_per_pixel; ++ch) {    thresholds[ch] = 0;    hi_values[ch] = -1;    // Compute the histogram of the image rectangle.    int histogram[256];    HistogramRect(imagedata + ch, bytes_per_pixel, bytes_per_line,                  left, top, right, bottom, histogram);    int H;    int best_omega_0;    int best_t = OtsuStats(histogram, &H, &best_omega_0);    if (best_omega_0 == 0 || best_omega_0 == H) {       // This channel is empty.       continue;     }    // To be a convincing foreground we must have a small fraction of H    // or to be a convincing background we must have a large fraction of H.    // In between we assume this channel contains no thresholding information.    int hi_value = best_omega_0 < H * 0.5;    thresholds[ch] = best_t;    if (best_omega_0 > H * 0.75) {      any_good_hivalue = true;      hi_values[ch] = 0;    }    else if (best_omega_0 < H * 0.25) {      any_good_hivalue = true;      hi_values[ch] = 1;    }    else {      // In case all channels are like this, keep the best of the bad lot.      double hi_dist = hi_value ? (H - best_omega_0) : best_omega_0;      if (hi_dist > best_hi_dist) {        best_hi_dist = hi_dist;        best_hi_value = hi_value;        best_hi_index = ch;      }    }  }  if (!any_good_hivalue) {    // Use the best of the ones that were not good enough.    hi_values[best_hi_index] = best_hi_value;  }}// Compute the histogram for the given image rectangle, and the given// channel. (Channel pointed to by imagedata.) Each channel is always// one byte per pixel.// Bytes per pixel is used to skip channels not being// counted with this call in a multi-channel (pixel-major) image.// Histogram is always a 256 element array to count occurrences of// each pixel value.void TessBaseAPI::HistogramRect(const unsigned char* imagedata,                                int bytes_per_pixel,                                int bytes_per_line,                                int left, int top, int right, int bottom,                                int* histogram) {  int width = right - left;  memset(histogram, 0, sizeof(*histogram) * 256);  const unsigned char* pixels = imagedata +                                top*bytes_per_line +                                left*bytes_per_pixel;  for (int y = top; y < bottom; ++y) {    for (int x = 0; x < width; ++x) {      ++histogram[pixels[x * bytes_per_pixel]];    }    pixels += bytes_per_line;  }}// Compute the Otsu threshold(s) for the given histogram.// Also returns H = total count in histogram, and// omega0 = count of histogram below threshold.int TessBaseAPI::OtsuStats(const int* histogram,                           int* H_out,                           int* omega0_out) {  int H = 0;  double mu_T = 0.0;  for (int i = 0; i < 256; ++i) {    H += histogram[i];    mu_T += i * histogram[i];  }  // Now maximize sig_sq_B over t.  // http://www.ctie.monash.edu.au/hargreave/Cornall_Terry_328.pdf  int best_t = -1;  int omega_0, omega_1;  int best_omega_0 = 0;  double best_sig_sq_B = 0.0;  double mu_0, mu_1, mu_t;  omega_0 = 0;  mu_t = 0.0;

⌨️ 快捷键说明

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