mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2025-01-18 06:30:14 +08:00
Merge remote-tracking branch 'origin/master' into hocrcharboxes
This commit is contained in:
commit
c43e4501e3
5
.clang-format
Normal file
5
.clang-format
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
# Enforce always the same pointer alignment.
|
||||
DerivePointerAlignment: false
|
||||
IndentPPDirectives: AfterHash
|
23
.github/ISSUE_TEMPLATE.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
Before you submit an issue, please review [the guidelines for this repository](https://github.com/tesseract-ocr/tesseract/blob/master/CONTRIBUTING.md).
|
||||
|
||||
Please report an issue only for a BUG, not for asking questions.
|
||||
|
||||
Note that it will be much easier for us to fix the issue if a test case that
|
||||
reproduces the problem is provided. Ideally this test case should not have any
|
||||
external dependencies. Provide a copy of the image or link to files for the test case.
|
||||
|
||||
Please delete this text and fill in the template below.
|
||||
|
||||
------------------------
|
||||
|
||||
### Environment
|
||||
|
||||
* **Tesseract Version**: <!-- compulsory. you must provide your version -->
|
||||
* **Commit Number**: <!-- optional. if known - specify commit used, if built from source -->
|
||||
* **Platform**: <!-- either `uname -a` output, or if Windows, version and 32-bit or 64-bit -->
|
||||
|
||||
### Current Behavior:
|
||||
|
||||
### Expected Behavior:
|
||||
|
||||
### Suggested Fix:
|
89
.gitignore
vendored
89
.gitignore
vendored
@ -13,14 +13,6 @@
|
||||
*.res
|
||||
*.ipch
|
||||
*.manifest
|
||||
vs2010/DLL_Debug/*
|
||||
vs2010/DLL_Release/*
|
||||
vs2010/LIB_Debug/*
|
||||
vs2010/LIB_Release/*
|
||||
vs2010/LIB_OpenCL_Release/*
|
||||
vs2010/LIB_OpenCL_Debug/*
|
||||
|
||||
|
||||
|
||||
# Linux
|
||||
# ignore local configuration
|
||||
@ -36,24 +28,44 @@ libtool
|
||||
stamp-h1
|
||||
tesseract.pc
|
||||
config_auto.h
|
||||
doc/html/*
|
||||
api/tesseract
|
||||
training/ambiguous_words
|
||||
training/classifier_tester
|
||||
training/cntraining
|
||||
training/combine_tessdata
|
||||
training/dawg2wordlist
|
||||
training/mftraining
|
||||
training/set_unicharset_properties
|
||||
training/shapeclustering
|
||||
training/text2image
|
||||
training/unicharset_extractor
|
||||
training/wordlist2dawg
|
||||
/doc/html/*
|
||||
/doc/*.1
|
||||
/doc/*.5
|
||||
/doc/*.html
|
||||
/doc/*.xml
|
||||
|
||||
# generated version file
|
||||
/src/api/tess_version.h
|
||||
|
||||
# executables
|
||||
/src/api/tesseract
|
||||
/src/training/ambiguous_words
|
||||
/src/training/classifier_tester
|
||||
/src/training/cntraining
|
||||
/src/training/combine_tessdata
|
||||
/src/training/dawg2wordlist
|
||||
/src/training/merge_unicharsets
|
||||
/src/training/mftraining
|
||||
/src/training/set_unicharset_properties
|
||||
/src/training/shapeclustering
|
||||
/src/training/text2image
|
||||
/src/training/unicharset_extractor
|
||||
/src/training/wordlist2dawg
|
||||
|
||||
*.patch
|
||||
|
||||
# files generated by libtool
|
||||
/src/training/combine_lang_model
|
||||
/src/training/lstmeval
|
||||
/src/training/lstmtraining
|
||||
|
||||
# ignore compilation files
|
||||
build/*
|
||||
/bin
|
||||
*/.deps/*
|
||||
*/.libs/*
|
||||
*/*/.deps/*
|
||||
*/*/.libs/*
|
||||
*.lo
|
||||
*.la
|
||||
*.o
|
||||
@ -61,10 +73,9 @@ training/wordlist2dawg
|
||||
*.a
|
||||
*.class
|
||||
*.jar
|
||||
__pycache__
|
||||
|
||||
# tessdata
|
||||
*.cube.*
|
||||
*.tesseract_cube.*
|
||||
*.traineddata
|
||||
|
||||
# OpenCL
|
||||
@ -73,4 +84,34 @@ kernel*.bin
|
||||
|
||||
# build dirs
|
||||
/build*
|
||||
/win*
|
||||
/.cppan
|
||||
/cppan
|
||||
/*.dll
|
||||
/*.lib
|
||||
/*.exe
|
||||
/*.lnk
|
||||
/win*
|
||||
.vs*
|
||||
.s*
|
||||
|
||||
# files generated by "make check"
|
||||
/tests/.dirstamp
|
||||
/unittest/*.trs
|
||||
|
||||
# test programs
|
||||
/unittest/*_test
|
||||
/unittest/primesbitvector
|
||||
/unittest/primesmap
|
||||
|
||||
# generated files from unlvtests
|
||||
times.txt
|
||||
/unlvtests/results*
|
||||
|
||||
# snap packaging specific rules
|
||||
/parts/
|
||||
/stage/
|
||||
/prime/
|
||||
/snap/.snapcraft/
|
||||
|
||||
/*.snap
|
||||
/*_source.tar.bz2
|
||||
|
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
[submodule "abseil"]
|
||||
path = abseil
|
||||
url = https://github.com/abseil/abseil-cpp.git
|
||||
[submodule "googletest"]
|
||||
path = googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "test"]
|
||||
path = test
|
||||
url = https://github.com/tesseract-ocr/test
|
18
.lgtm.yml
Normal file
18
.lgtm.yml
Normal file
@ -0,0 +1,18 @@
|
||||
extraction:
|
||||
cpp:
|
||||
prepare:
|
||||
packages:
|
||||
- libpango1.0-dev
|
||||
configure:
|
||||
command:
|
||||
- ./autogen.sh
|
||||
- mkdir _lgtm_build_dir
|
||||
- cd _lgtm_build_dir
|
||||
- ../configure
|
||||
index:
|
||||
build_command:
|
||||
- cd _lgtm_build_dir
|
||||
- make training
|
||||
python:
|
||||
python_setup:
|
||||
version: 3
|
54
.travis.yml
54
.travis.yml
@ -1,44 +1,52 @@
|
||||
# Travis CI configuration for Tesseract
|
||||
|
||||
language: cpp
|
||||
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
- LEPT_VER=1.74.2
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
sudo: required
|
||||
|
||||
sudo: false
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
#- osx
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
#- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.8
|
||||
- g++-4.8
|
||||
#- g++-6
|
||||
|
||||
#matrix:
|
||||
#include:
|
||||
#- os: osx
|
||||
#install:
|
||||
#script: brew install tesseract --HEAD
|
||||
#cache:
|
||||
#directories:
|
||||
#- $HOME/Library/Caches/Homebrew
|
||||
#allow_failures:
|
||||
#- script: brew install tesseract --HEAD
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- leptonica-$LEPT_VER
|
||||
|
||||
before_install:
|
||||
- if [[ $TRAVIS_OS_NAME == linux ]]; then LINUX=true; fi
|
||||
- if [[ $TRAVIS_OS_NAME == osx ]]; then OSX=true; fi
|
||||
|
||||
- if [[ $OSX ]]; then brew update; fi
|
||||
|
||||
- export LEPT_VER=1.73
|
||||
|
||||
install:
|
||||
- if [[ $OSX ]]; then brew install icu4c pango; brew link --force gettext; fi
|
||||
- if [[ $OSX ]]; then export ICU_ROOT=/usr/local/opt/icu4c ; fi
|
||||
- wget --no-check-certificate https://www.cmake.org/files/v3.4/cmake-3.4.1-Linux-x86_64.sh
|
||||
- sudo sh cmake-3.4.1-Linux-x86_64.sh --skip-license --prefix=/usr
|
||||
- wget -O leptonica.zip https://github.com/DanBloomberg/leptonica/archive/v$LEPT_VER.zip
|
||||
- unzip leptonica.zip -d .
|
||||
- cmake -Hleptonica-$LEPT_VER -Bleptonica-$LEPT_VER/build
|
||||
- make -C leptonica-$LEPT_VER/build
|
||||
- if [[ $LINUX && "$CXX" = "g++" ]]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
|
||||
#- if [[ $LINUX && "$CXX" = "g++" ]]; then export CXX="g++-6" CC="gcc-6"; fi
|
||||
- if test ! -d leptonica-$LEPT_VER/src; then curl -Ls https://github.com/DanBloomberg/leptonica/archive/$LEPT_VER.tar.gz | tar -xz; fi
|
||||
- if test ! -d leptonica-$LEPT_VER/usr; then cmake -Hleptonica-$LEPT_VER -Bleptonica-$LEPT_VER/build -DCMAKE_INSTALL_PREFIX=leptonica-$LEPT_VER/usr; fi
|
||||
- if test ! -e leptonica-$LEPT_VER/usr/lib/libleptonica.so; then make -C leptonica-$LEPT_VER/build install; fi
|
||||
|
||||
script:
|
||||
- mkdir build
|
||||
|
16
AUTHORS
16
AUTHORS
@ -2,12 +2,14 @@ Ray Smith (lead developer) <theraysmith@gmail.com>
|
||||
Ahmad Abdulkader
|
||||
Rika Antonova
|
||||
Nicholas Beato
|
||||
Jeff Breidenbach
|
||||
Samuel Charron
|
||||
Phil Cheatle
|
||||
Simon Crouch
|
||||
David Eger
|
||||
Sheelagh Huddleston
|
||||
Dan Johnson
|
||||
Rajesh Katikam
|
||||
Thomas Kielbus
|
||||
Dar-Shyang Lee
|
||||
Zongyi (Joe) Liu
|
||||
@ -26,3 +28,17 @@ Joern Wanke
|
||||
Ping Ping Xiu
|
||||
Andrew Ziem
|
||||
Oscar Zuniga
|
||||
|
||||
Community Contributors:
|
||||
Zdenko Podobný (Maintainer)
|
||||
Jim Regan (Maintainer)
|
||||
James R Barlow
|
||||
Amit Dovev
|
||||
Martin Ettl
|
||||
Shree Devi Kumar
|
||||
Noah Metzger
|
||||
Tom Morris
|
||||
Tobias Müller
|
||||
Egor Pugin
|
||||
Sundar M. Vaidya
|
||||
Stefan Weil
|
||||
|
389
CMakeLists.txt
389
CMakeLists.txt
@ -11,7 +11,7 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
# In-source builds are disabled.
|
||||
if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
message(FATAL_ERROR
|
||||
"CMake generation is not possible within the source directory!"
|
||||
"\n Remove the CMakeCache.txt file and try again from another folder, e.g.:"
|
||||
@ -23,7 +23,7 @@ if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_SOURCE_DIR}/cmake")
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}")
|
||||
@ -40,21 +40,18 @@ set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake Targets")
|
||||
|
||||
project(tesseract C CXX)
|
||||
|
||||
set(VERSION_MAJOR 3)
|
||||
set(VERSION_MINOR 05)
|
||||
set(VERSION_PLAIN ${VERSION_MAJOR}.${VERSION_MINOR})
|
||||
# Get version with components from VERSION file.
|
||||
file(STRINGS "VERSION" VERSION_PLAIN)
|
||||
string(REGEX REPLACE "^([^.]*)\\..*" "\\1" VERSION_MAJOR ${VERSION_PLAIN})
|
||||
string(REGEX REPLACE "^[^.]*\\.([^.]*)\\..*" "\\1" VERSION_MINOR ${VERSION_PLAIN})
|
||||
string(REGEX REPLACE "^[^.]*\\.[^.]*\\.([0-9]*).*" "\\1" VERSION_PATCH ${VERSION_PLAIN})
|
||||
|
||||
set(MINIMUM_LEPTONICA_VERSION 1.71)
|
||||
# Provide also same macro names as autoconf (see configure.ac).
|
||||
set(GENERIC_MAJOR_VERSION ${VERSION_MAJOR})
|
||||
set(GENERIC_MINOR_VERSION ${VERSION_MINOR})
|
||||
set(GENERIC_MICRO_VERSION ${VERSION_PATCH})
|
||||
|
||||
if (NOT Leptonica_DIR AND NOT MSVC)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(Leptonica REQUIRED lept)
|
||||
else()
|
||||
find_package(Leptonica ${MINIMUM_LEPTONICA_VERSION} REQUIRED CONFIG)
|
||||
endif()
|
||||
|
||||
find_package(OpenCL QUIET)
|
||||
find_package(PkgConfig)
|
||||
set(MINIMUM_LEPTONICA_VERSION 1.74)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -67,11 +64,19 @@ if (STATIC)
|
||||
set(LIBRARY_TYPE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CLANG 1)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
if (MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
if (CLANG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -fopenmp /utf-8")
|
||||
else()
|
||||
add_definitions(-DNOMINMAX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /openmp /utf-8")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LIB_Ws2_32 Ws2_32)
|
||||
@ -87,32 +92,64 @@ if (UNIX)
|
||||
set(LIB_pthread pthread)
|
||||
endif()
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# packages
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.cppan)
|
||||
if (NOT Leptonica_DIR AND NOT MSVC)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(Leptonica REQUIRED lept>=${MINIMUM_LEPTONICA_VERSION})
|
||||
link_directories(${Leptonica_LIBRARY_DIRS})
|
||||
else()
|
||||
find_package(Leptonica ${MINIMUM_LEPTONICA_VERSION} REQUIRED CONFIG)
|
||||
endif()
|
||||
else()
|
||||
if (STATIC)
|
||||
set(CPPAN_BUILD_SHARED_LIBS 0)
|
||||
else()
|
||||
set(CPPAN_BUILD_SHARED_LIBS 1)
|
||||
endif()
|
||||
add_subdirectory(.cppan)
|
||||
endif()
|
||||
|
||||
find_package(OpenCL QUIET)
|
||||
|
||||
option(BUILD_TRAINING_TOOLS "Build training tools" ON)
|
||||
option(BUILD_TESTS "Build tests" OFF)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# configure
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
set(AUTOCONFIG_SRC ${CMAKE_BINARY_DIR}/config_auto.h.in)
|
||||
set(AUTOCONFIG ${CMAKE_BINARY_DIR}/config_auto.h)
|
||||
set(AUTOCONFIG_SRC ${CMAKE_CURRENT_BINARY_DIR}/config_auto.h.in)
|
||||
set(AUTOCONFIG ${CMAKE_CURRENT_BINARY_DIR}/config_auto.h)
|
||||
|
||||
include(Configure)
|
||||
|
||||
configure_file(${AUTOCONFIG_SRC} ${AUTOCONFIG} @ONLY)
|
||||
|
||||
set(INCLUDE_DIR
|
||||
${CMAKE_SOURCE_DIR}/api
|
||||
${CMAKE_SOURCE_DIR}/ccmain
|
||||
${CMAKE_SOURCE_DIR}/ccstruct
|
||||
${CMAKE_SOURCE_DIR}/ccutil
|
||||
)
|
||||
set(INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include" "${CMAKE_INSTALL_PREFIX}/include/tesseract")
|
||||
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/templates/TesseractConfig-version.cmake.in
|
||||
${CMAKE_BINARY_DIR}/TesseractConfig-version.cmake @ONLY)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/api/tess_version.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/api/tess_version.h @ONLY)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/templates/TesseractConfig.cmake.in
|
||||
${CMAKE_BINARY_DIR}/TesseractConfig.cmake @ONLY)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vs2010/tesseract/tesseract.rc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/tesseract.rc @ONLY)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vs2010/tesseract/libtesseract.rc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/libtesseract.rc @ONLY)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/TesseractConfig-version.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig-version.cmake @ONLY)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/TesseractConfig.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig.cmake @ONLY)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -125,107 +162,255 @@ include(SourceGroups)
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
add_definitions(-D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS=1)
|
||||
add_definitions(-DUSE_STD_NAMESPACE=1)
|
||||
add_definitions(-DWINDLLNAME="libtesseract${VERSION_MAJOR}${VERSION_MINOR}.dll")
|
||||
|
||||
include_directories(${Leptonica_INCLUDE_DIRS})
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
include_directories(api)
|
||||
include_directories(ccmain)
|
||||
include_directories(ccstruct)
|
||||
include_directories(ccutil)
|
||||
include_directories(classify)
|
||||
include_directories(cube)
|
||||
include_directories(cutil)
|
||||
include_directories(dict)
|
||||
include_directories(neural_networks/runtime)
|
||||
include_directories(opencl)
|
||||
include_directories(textord)
|
||||
include_directories(vs2010/port)
|
||||
include_directories(viewer)
|
||||
include_directories(wordrec)
|
||||
include_directories(src/api)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/api)
|
||||
include_directories(src/arch)
|
||||
include_directories(src/ccmain)
|
||||
include_directories(src/ccstruct)
|
||||
include_directories(src/ccutil)
|
||||
include_directories(src/classify)
|
||||
include_directories(src/cutil)
|
||||
include_directories(src/dict)
|
||||
include_directories(src/lstm)
|
||||
include_directories(src/opencl)
|
||||
include_directories(src/textord)
|
||||
include_directories(src/viewer)
|
||||
include_directories(src/wordrec)
|
||||
|
||||
########################################
|
||||
# LIBRARY tesseract
|
||||
########################################
|
||||
|
||||
string(SUBSTRING ${VERSION_MINOR} 0 1 VERSION_MINOR_0)
|
||||
string(SUBSTRING ${VERSION_MINOR} 1 1 VERSION_MINOR_1)
|
||||
|
||||
file(GLOB tesseract_src
|
||||
"ccmain/*.cpp"
|
||||
"ccstruct/*.cpp"
|
||||
"ccutil/*.cpp"
|
||||
"classify/*.cpp"
|
||||
"cube/*.cpp"
|
||||
"cutil/*.cpp"
|
||||
"dict/*.cpp"
|
||||
"neural_networks/runtime/*.cpp"
|
||||
"opencl/*.cpp"
|
||||
"textord/*.cpp"
|
||||
"viewer/*.cpp"
|
||||
"wordrec/*.cpp"
|
||||
src/arch/*.cpp
|
||||
src/ccmain/*.cpp
|
||||
src/ccstruct/*.cpp
|
||||
src/ccutil/*.cpp
|
||||
src/classify/*.cpp
|
||||
src/cutil/*.cpp
|
||||
src/dict/*.cpp
|
||||
src/lstm/*.cpp
|
||||
src/opencl/*.cpp
|
||||
src/textord/*.cpp
|
||||
src/viewer/*.cpp
|
||||
src/wordrec/*.cpp
|
||||
)
|
||||
file(GLOB tesseract_hdr
|
||||
"api/*.h"
|
||||
"ccmain/*.h"
|
||||
"ccstruct/*.h"
|
||||
"ccutil/*.h"
|
||||
"classify/*.h"
|
||||
"cube/*.h"
|
||||
"cutil/*.h"
|
||||
"dict/*.h"
|
||||
"neural_networks/runtime/*.h"
|
||||
"opencl/*.h"
|
||||
"textord/*.h"
|
||||
"viewer/*.h"
|
||||
"wordrec/*.h"
|
||||
src/api/*.h
|
||||
src/arch/*.h
|
||||
src/ccmain/*.h
|
||||
src/ccstruct/*.h
|
||||
src/ccutil/*.h
|
||||
src/classify/*.h
|
||||
src/cutil/*.h
|
||||
src/dict/*.h
|
||||
src/lstm/*.h
|
||||
src/opencl/*.h
|
||||
src/textord/*.h
|
||||
src/viewer/*.h
|
||||
src/wordrec/*.h
|
||||
)
|
||||
if (WIN32)
|
||||
file(GLOB tesseract_win32_src "vs2010/port/*.cpp")
|
||||
file(GLOB tesseract_win32_hdr "vs2010/port/*.h")
|
||||
set(tesseract_src ${tesseract_src} ${tesseract_win32_src})
|
||||
set(tesseract_hdr ${tesseract_hdr} ${tesseract_win32_hdr})
|
||||
endif()
|
||||
|
||||
set(tesseract_src ${tesseract_src}
|
||||
api/baseapi.cpp
|
||||
api/capi.cpp
|
||||
api/renderer.cpp
|
||||
api/pdfrenderer.cpp
|
||||
src/api/baseapi.cpp
|
||||
src/api/capi.cpp
|
||||
src/api/renderer.cpp
|
||||
src/api/altorenderer.cpp
|
||||
src/api/hocrrenderer.cpp
|
||||
src/api/pdfrenderer.cpp
|
||||
)
|
||||
|
||||
add_library (tesseract ${LIBRARY_TYPE} ${tesseract_src} ${tesseract_hdr})
|
||||
if (NOT STATIC)
|
||||
target_compile_definitions (tesseract PUBLIC -DTESS_EXPORTS)
|
||||
endif()
|
||||
target_link_libraries (tesseract ${Leptonica_LIBRARIES} ${LIB_Ws2_32} ${LIB_pthread})
|
||||
set_target_properties (tesseract PROPERTIES VERSION ${VERSION_MAJOR}.${VERSION_MINOR_0}.${VERSION_MINOR_1})
|
||||
set_target_properties (tesseract PROPERTIES SOVERSION ${VERSION_MAJOR}.${VERSION_MINOR_0}.${VERSION_MINOR_1})
|
||||
if (WIN32)
|
||||
set_target_properties (tesseract PROPERTIES OUTPUT_NAME tesseract${VERSION_MAJOR}${VERSION_MINOR})
|
||||
set_target_properties (tesseract PROPERTIES DEBUG_OUTPUT_NAME tesseract${VERSION_MAJOR}${VERSION_MINOR}d)
|
||||
if (MSVC)
|
||||
include_directories(src/vs2010/tesseract)
|
||||
set(tesseract_hdr
|
||||
${tesseract_hdr}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vs2010/tesseract/resource.h)
|
||||
set(tesseract_rsc ${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/libtesseract.rc)
|
||||
if (NOT CLANG)
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/dotproductsse.cpp
|
||||
PROPERTIES COMPILE_DEFINITIONS __SSE4_1__)
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/intsimdmatrixsse.cpp
|
||||
PROPERTIES COMPILE_DEFINITIONS __SSE4_1__)
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/dotproductavx.cpp
|
||||
PROPERTIES COMPILE_FLAGS "/arch:AVX")
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/intsimdmatrixavx2.cpp
|
||||
PROPERTIES COMPILE_FLAGS "/arch:AVX2")
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/simdetect.cpp
|
||||
PROPERTIES COMPILE_FLAGS "/DAVX /DAVX2 /DSSE4_1")
|
||||
endif() # NOT CLANG
|
||||
endif() # MSVC
|
||||
else()
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/dotproductsse.cpp
|
||||
PROPERTIES COMPILE_FLAGS "-msse4.1")
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/intsimdmatrixsse.cpp
|
||||
PROPERTIES COMPILE_FLAGS "-msse4.1")
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/dotproductavx.cpp
|
||||
PROPERTIES COMPILE_FLAGS "-mavx")
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/intsimdmatrixavx2.cpp
|
||||
PROPERTIES COMPILE_FLAGS "-mavx2")
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/arch/simdetect.cpp
|
||||
PROPERTIES COMPILE_FLAGS "-DAVX -DAVX2 -DSSE4_1")
|
||||
endif()
|
||||
export(TARGETS tesseract FILE ${CMAKE_BINARY_DIR}/TesseractTargets.cmake)
|
||||
|
||||
add_library (libtesseract ${LIBRARY_TYPE} ${tesseract_src} ${tesseract_hdr}
|
||||
${tesseract_rsc}
|
||||
)
|
||||
if (NOT STATIC)
|
||||
target_compile_definitions (libtesseract
|
||||
PRIVATE -DTESS_EXPORTS
|
||||
INTERFACE -DTESS_IMPORTS
|
||||
)
|
||||
set_target_properties (libtesseract PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS True)
|
||||
endif()
|
||||
target_link_libraries (libtesseract ${LIB_Ws2_32} ${LIB_pthread})
|
||||
set_target_properties (libtesseract PROPERTIES VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
|
||||
set_target_properties (libtesseract PROPERTIES SOVERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
|
||||
if (WIN32)
|
||||
set_target_properties (libtesseract PROPERTIES OUTPUT_NAME tesseract${VERSION_MAJOR}${VERSION_MINOR})
|
||||
set_target_properties (libtesseract PROPERTIES DEBUG_OUTPUT_NAME tesseract${VERSION_MAJOR}${VERSION_MINOR}d)
|
||||
else()
|
||||
set_target_properties (libtesseract PROPERTIES OUTPUT_NAME tesseract)
|
||||
endif()
|
||||
|
||||
if (NOT CPPAN_BUILD)
|
||||
target_link_libraries (libtesseract ${Leptonica_LIBRARIES})
|
||||
export(TARGETS libtesseract FILE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake)
|
||||
else()
|
||||
target_link_libraries (libtesseract pvt.cppan.demo.danbloomberg.leptonica)
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake "include(${CMAKE_CURRENT_BINARY_DIR}/cppan.cmake)\n")
|
||||
export(TARGETS libtesseract APPEND FILE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake)
|
||||
endif()
|
||||
|
||||
if (WIN32 AND CLANG)
|
||||
# Workaround for "libomp.lib is not automatically added on Windows"
|
||||
# see: http://lists.llvm.org/pipermail/openmp-dev/2015-August/000857.html
|
||||
# TODO: Find better way how to set Clang OpenMP library for linking on Windows
|
||||
target_link_libraries (libtesseract "c:\\Program Files\\LLVM\\lib\\libomp.lib")
|
||||
endif()
|
||||
|
||||
########################################
|
||||
# EXECUTABLE tesseractmain
|
||||
########################################
|
||||
|
||||
set(tesseractmain_src
|
||||
api/tesseractmain.cpp
|
||||
vs2010/tesseract/resource.h
|
||||
vs2010/tesseract/tesseract.rc
|
||||
)
|
||||
add_executable (tesseractmain ${tesseractmain_src})
|
||||
target_link_libraries (tesseractmain tesseract)
|
||||
set_target_properties (tesseractmain PROPERTIES OUTPUT_NAME tesseract)
|
||||
set(tesseractmain_src src/api/tesseractmain.cpp)
|
||||
if (MSVC)
|
||||
set(tesseractmain_rsc ${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/tesseract.rc)
|
||||
endif()
|
||||
|
||||
add_executable (tesseract ${tesseractmain_src} ${tesseractmain_rsc})
|
||||
target_link_libraries (tesseract libtesseract)
|
||||
|
||||
########################################
|
||||
|
||||
add_subdirectory(training)
|
||||
if (BUILD_TESTS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/googletest/CMakeLists.txt)
|
||||
add_subdirectory(googletest)
|
||||
endif()
|
||||
|
||||
if (BUILD_TRAINING_TOOLS)
|
||||
add_subdirectory(src/training)
|
||||
endif()
|
||||
|
||||
get_target_property(tesseract_NAME libtesseract NAME)
|
||||
get_target_property(tesseract_VERSION libtesseract VERSION)
|
||||
get_target_property(tesseract_OUTPUT_NAME libtesseract OUTPUT_NAME)
|
||||
configure_file(tesseract.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/tesseract.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tesseract.pc DESTINATION lib/pkgconfig)
|
||||
install(TARGETS tesseract RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
|
||||
install(TARGETS libtesseract EXPORT TesseractTargets RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
|
||||
install(EXPORT TesseractTargets DESTINATION cmake)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig-version.cmake
|
||||
DESTINATION cmake)
|
||||
|
||||
install(FILES
|
||||
# from api/makefile.am
|
||||
src/api/apitypes.h
|
||||
src/api/baseapi.h
|
||||
src/api/capi.h
|
||||
src/api/renderer.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/api/tess_version.h
|
||||
|
||||
#from arch/makefile.am
|
||||
src/arch/dotproductavx.h
|
||||
src/arch/dotproductsse.h
|
||||
src/arch/intsimdmatrix.h
|
||||
src/arch/intsimdmatrixavx2.h
|
||||
src/arch/intsimdmatrixsse.h
|
||||
src/arch/simddetect.h
|
||||
|
||||
#from ccmain/makefile.am
|
||||
src/ccmain/thresholder.h
|
||||
src/ccmain/ltrresultiterator.h
|
||||
src/ccmain/pageiterator.h
|
||||
src/ccmain/resultiterator.h
|
||||
src/ccmain/osdetect.h
|
||||
|
||||
#from ccstruct/makefile.am
|
||||
src/ccstruct/publictypes.h
|
||||
|
||||
#from ccutil/makefile.am
|
||||
src/ccutil/basedir.h
|
||||
src/ccutil/errcode.h
|
||||
src/ccutil/fileerr.h
|
||||
src/ccutil/genericvector.h
|
||||
src/ccutil/helpers.h
|
||||
src/ccutil/host.h
|
||||
src/ccutil/params.h
|
||||
src/ccutil/ocrclass.h
|
||||
src/ccutil/platform.h
|
||||
src/ccutil/serialis.h
|
||||
src/ccutil/strngs.h
|
||||
src/ccutil/tesscallback.h
|
||||
src/ccutil/unichar.h
|
||||
src/ccutil/unicharcompress.h
|
||||
src/ccutil/unicharmap.h
|
||||
src/ccutil/unicharset.h
|
||||
|
||||
#from lstm/makefile.am
|
||||
src/lstm/convolve.h
|
||||
src/lstm/ctc.h
|
||||
src/lstm/fullyconnected.h
|
||||
src/lstm/functions.h
|
||||
src/lstm/input.h
|
||||
src/lstm/lstm.h
|
||||
src/lstm/lstmrecognizer.h
|
||||
src/lstm/lstmtrainer.h
|
||||
src/lstm/maxpool.h
|
||||
src/lstm/networkbuilder.h
|
||||
src/lstm/network.h
|
||||
src/lstm/networkio.h
|
||||
src/lstm/networkscratch.h
|
||||
src/lstm/parallel.h
|
||||
src/lstm/plumbing.h
|
||||
src/lstm/recodebeam.h
|
||||
src/lstm/reconfig.h
|
||||
src/lstm/reversed.h
|
||||
src/lstm/series.h
|
||||
src/lstm/static_shape.h
|
||||
src/lstm/stridemap.h
|
||||
src/lstm/tfnetwork.h
|
||||
src/lstm/weightmatrix.h
|
||||
|
||||
#${CMAKE_CURRENT_BINARY_DIR}/src/endianness.h
|
||||
DESTINATION include/tesseract)
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
@ -9,22 +9,22 @@ If you think you found a bug in Tesseract, please create an issue.
|
||||
Use the [users mailing-list](https://groups.google.com/d/forum/tesseract-ocr) instead of creating an Issue if ...
|
||||
* You have problems using Tesseract and need some help.
|
||||
* You have problems installing the software.
|
||||
* You are not satisfied with the accuracy of the OCR, and want to ask how you can improve it. Note: You should first read the [ImproveQuality](https://github.com/tesseract-ocr/tesseract/wiki/ImproveQuality) wiki page.
|
||||
* You are trying to train Tesseract and you have a problem and/or want to ask a question about the training process. Note: You should first read the **official** guides [[1]](https://github.com/tesseract-ocr/tesseract/wiki/tesstrain.sh) or [[2]](https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract) found in the project wiki.
|
||||
* You have a general question.
|
||||
* You are not satisfied with the accuracy of the OCR, and want to ask how you can improve it. Note: You should first read the [ImproveQuality](https://github.com/tesseract-ocr/tesseract/wiki/ImproveQuality) wiki page.
|
||||
* You are trying to train Tesseract and you have a problem and/or want to ask a question about the training process. Note: You should first read the **official** guides [[1]](https://github.com/tesseract-ocr/tesseract/wiki) or [[2]](https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract) found in the project wiki.
|
||||
* You have a general question.
|
||||
|
||||
An issue should only be reported if the platform you are using is one of these:
|
||||
* Linux (but not a version that is more than 4 years old)
|
||||
* Windows (Windows 7 or newer version)
|
||||
* Mac (last 3 releases)
|
||||
* macOS (last 3 releases)
|
||||
|
||||
For older versions or other operating systems, use the Tesseract forum.
|
||||
|
||||
When creating an issue, please report your operating system, including its specific version: "Ubuntu 16.04", "Windows 10", "OS X 10.11" etc.
|
||||
When creating an issue, please report your operating system, including its specific version: "Ubuntu 16.04", "Windows 10", "Mac OS X 10.11" etc.
|
||||
|
||||
Search through open and closed issues to see if similar issue has been reported already (and sometimes also has been solved).
|
||||
Search through open and closed issues to see if similar issue has been reported already (and sometimes also has been solved).
|
||||
|
||||
Similary, before you post your question in the forum, search through past threads to see if similar question has been asked already.
|
||||
Similarly, before you post your question in the forum, search through past threads to see if similar question has been asked already.
|
||||
|
||||
Read the [wiki](https://github.com/tesseract-ocr/tesseract/wiki) before you report your issue or ask a question in the forum.
|
||||
|
||||
@ -32,10 +32,10 @@ Only report an issue in the latest official release. Optionally, try to check if
|
||||
|
||||
Make sure you are able to replicate the problem with Tesseract command line program. For external programs that use Tesseract (including wrappers and your own program, if you are developer), report the issue to the developers of that software if it's possible. You can also try to find help in the Tesseract forum.
|
||||
|
||||
Each version of Tesseract has its own language data you need to obtain. You **must** obtain and install trained data for English (eng) and osd. Verify that Tesseract knows about these two files (and other trained data you installed) with this command:
|
||||
Each version of Tesseract has its own language data you need to obtain. You **must** obtain and install trained data for English (eng) and osd. Verify that Tesseract knows about these two files (and other trained data you installed) with this command:
|
||||
`tesseract --list-langs`.
|
||||
|
||||
Post example files to demonstrate the problem.
|
||||
Post example files to demonstrate the problem.
|
||||
BUT don't post files with private info (about yourself or others).
|
||||
|
||||
When attaching a file to the issue report / forum ...
|
||||
@ -44,25 +44,25 @@ When attaching a file to the issue report / forum ...
|
||||
|
||||
Do not attach programs or libraries to your issues/posts.
|
||||
|
||||
For large files or for programs, add a link to a iocation where they can be downloaded (your site, Git repo, Google Drive, Dropbox etc.)
|
||||
For large files or for programs, add a link to a location where they can be downloaded (your site, Git repo, Google Drive, Dropbox etc.)
|
||||
|
||||
Attaching a multi-page TIFF image is useful only if you have problem with multi-page functionality, otherwise attach only one or a few single page images.
|
||||
Attaching a multi-page TIFF image is useful only if you have problem with multi-page functionality, otherwise attach only one or a few single page images.
|
||||
|
||||
Copy the error message from the console instead of sending a screenshot of it.
|
||||
|
||||
Use the toolbar above the comment edit area to format your comment.
|
||||
|
||||
Add three backticks before and after a code sample or output of a command to format it (The 'Insert code' button can help you doing it).
|
||||
Add three backticks before and after a code sample or output of a command to format it (The `Insert code` button can help you doing it).
|
||||
|
||||
If your comment includes a code sample or output of a command that exceeds ~25 lines, post it as attached text file (filename.txt).
|
||||
If your comment includes a code sample or output of a command that exceeds ~25 lines, post it as attached text file (`filename.txt`).
|
||||
|
||||
Use 'Preview' before you send your issue. Read it again before sending.
|
||||
Use `Preview` before you send your issue. Read it again before sending.
|
||||
|
||||
Note that most of the people that respond to issues and answer questions are either other 'regular' users or **volunteers** developers. Please be nice to them :-)
|
||||
|
||||
The [tesseract developers](http://groups.google.com/group/tesseract-dev/) forum should be used to discuss Tesseract development: bug fixes, enhancements, add-ons for Tesseract.
|
||||
|
||||
Sometimes you will not get a respond to your issue or question. We apologize in advance! Please don't take it personally. There can be many reasons for this, including: time limits, no one knows the answer (at least not the ones that are available at that time) or just that
|
||||
Sometimes you will not get a respond to your issue or question. We apologize in advance! Please don't take it personally. There can be many reasons for this, including: time limits, no one knows the answer (at least not the ones that are available at that time) or just that
|
||||
your question has been asked (and has been answered) many times before...
|
||||
|
||||
## For Developers: Creating a Pull Request
|
||||
|
21
COPYING
21
COPYING
@ -1,21 +0,0 @@
|
||||
This package contains the Tesseract Open Source OCR Engine.
|
||||
Originally developed at Hewlett Packard Laboratories Bristol and
|
||||
at Hewlett Packard Co, Greeley Colorado, all the code
|
||||
in this distribution is now licensed under the Apache License:
|
||||
|
||||
** 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.
|
||||
|
||||
|
||||
Other Dependencies and Licenses:
|
||||
================================
|
||||
|
||||
Tesseract uses Leptonica library (http://leptonica.com/) with a very weakly
|
||||
restricted copyright license (http://leptonica.com/about-the-license.html)
|
53
ChangeLog
53
ChangeLog
@ -1,3 +1,48 @@
|
||||
2018-10-29 - V4.0.0
|
||||
* Added new neural network system based on LSTMs, with major accuracy gains.
|
||||
* Improvements to PDF rendering.
|
||||
* Fixes to trainingdata rendering.
|
||||
* Added LSTM models+lang models to 101 languages. (tessdata repository)
|
||||
* Improved multi-page TIFF handling.
|
||||
* Fixed damage to binary images when processing PDFs.
|
||||
* Fixes to training process to allow incremental training from a recognition model.
|
||||
* Made LSTM the default engine, pushed cube out.
|
||||
* Deleted cube code.
|
||||
* Changed OEModes --oem 0 for legacy tesseract engine, --oem 1 for LSTM, --oem 2 for both, --oem 3 for default.
|
||||
* Avoid use of Leptonica debug parameters or functions.
|
||||
* Fixed multi-language mode.
|
||||
* Removed support for VS2010.
|
||||
* Added Support for VS2015 and VS2017 with CPPAN.
|
||||
* Implemented invisible text only for PDF.
|
||||
* Added AVX / SSE support for Windows.
|
||||
* Enabled OpenMP support.
|
||||
* Parameter unlv_tilde_crunching change to false.
|
||||
* Miscellaneous Fixes.
|
||||
* Detailed Changelog can be foud at https://github.com/tesseract-ocr/tesseract/wiki/4.0x-Changelog and https://github.com/tesseract-ocr/tesseract/wiki/ReleaseNotes#tesseract-release-notes-oct-29-2018---v400
|
||||
|
||||
2017-02-16 - V3.05.00
|
||||
* Made some fine tuning to the hOCR output.
|
||||
* Added TSV as another optional output format.
|
||||
* Fixed ABI break introduced in 3.04.00 with the AnalyseLayout() method.
|
||||
* text2image tool - Enable all OpenType ligatures available in a font. This feature requires Pango 1.38 or newer.
|
||||
* Training tools - Replaced asserts with tprintf() and exit(1).
|
||||
* Fixed Cygwin compatibility.
|
||||
* Improved multipage tiff processing.
|
||||
* Improved the embedded pdf font (pdf.ttf).
|
||||
* Enable selection of OCR engine mode from command line.
|
||||
* Changed tesseract command line parameter '-psm' to '--psm'.
|
||||
* Write output of tesseract --help, --version and --list-langs to stdout instead of stderr.
|
||||
* Added new C API for orientation and script detection, removed the old one.
|
||||
* Increased minimum autoconf version to 2.59.
|
||||
* Removed dead code.
|
||||
* Require Leptonica 1.74 or higher.
|
||||
* Fixed many compiler warning.
|
||||
* Fixed memory and resource leaks.
|
||||
* Fixed some issues with the 'Cube' OCR engine.
|
||||
* Fixed some openCL issues.
|
||||
* Added option to build Tesseract with CMake build system.
|
||||
* Implemented CPPAN support for easy Windows building.
|
||||
|
||||
2016-02-17 - V3.04.01
|
||||
* Added OSD renderer for psm 0. Works for single page and multi-page images.
|
||||
* Improve tesstrain.sh script.
|
||||
@ -41,7 +86,7 @@
|
||||
text and truetype fonts.
|
||||
* Added support for PDF output with searchable text.
|
||||
* Removed entire IMAGE class and all code in image directory.
|
||||
* Tesseract executable: support for output to stdout; limited support for one
|
||||
* Tesseract executable: support for output to stdout; limited support for one
|
||||
page images from stdin (especially on Windows)
|
||||
* Added Renderer to API to allow document-level processing and output
|
||||
of document formats, like hOCR, PDF.
|
||||
@ -126,12 +171,12 @@
|
||||
* Added TessdataManager to combine data files into a single file.
|
||||
* Some dead code deleted.
|
||||
* VC++6 no longer supported. It can't cope with the use of templates.
|
||||
* Many more languages added.
|
||||
* Many more languages added.
|
||||
* Doxygenation of most of the function header comments.
|
||||
* Added man pages.
|
||||
* Added bash completion script (issue 247: thanks to neskiem)
|
||||
* Fix integer overview in thresholding (issue 366: thanks to Cyanide.Drake)
|
||||
* Add Danish Fraktur support (issues 300, 360: thanks to
|
||||
* Add Danish Fraktur support (issues 300, 360: thanks to
|
||||
dsl602230@vip.cybercity.dk)
|
||||
* Fix file pointer leak (issue 359, thanks to yukihiro.nakadaira)
|
||||
* Fix an error using user-words (Issue 345: thanks to max.markin)
|
||||
@ -140,7 +185,7 @@
|
||||
* Fix an automake error (Issue 318, thanks to ichanjz)
|
||||
* Fix a Win32 crash on fileFormatIsTiff() (Issues 304, 316, 317, 330, 347,
|
||||
349, 352: thanks to nguyenq87, max.markin, zdenop)
|
||||
* Fixed a number of errors in newer (stricter) versions of VC++ (Issues
|
||||
* Fixed a number of errors in newer (stricter) versions of VC++ (Issues
|
||||
301, among others)
|
||||
|
||||
2009-06-30 - V2.04
|
||||
|
13
Dockerfile
Executable file → Normal file
13
Dockerfile
Executable file → Normal file
@ -1,14 +1,17 @@
|
||||
# Dockerfile for local Travis build test
|
||||
|
||||
FROM ubuntu
|
||||
MAINTAINER Ian Blenke <ian@blenke.com>
|
||||
LABEL maintainer="Ian Blenke <ian@blenke.com>"
|
||||
|
||||
RUN apt-get update
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y git ruby bundler wget unzip
|
||||
RUN gem install travis --no-ri --no-rdoc
|
||||
RUN git clone https://github.com/travis-ci/travis-build ~/.travis/travis-build
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y cmake curl git ruby bundler wget unzip \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN gem install bundler travis --no-ri --no-rdoc
|
||||
RUN git clone --depth 1 https://github.com/travis-ci/travis-build ~/.travis/travis-build
|
||||
RUN bundle install --gemfile ~/.travis/travis-build/Gemfile
|
||||
|
||||
ADD . /tesseract
|
||||
WORKDIR /tesseract
|
||||
|
||||
RUN travis compile | sed -e "s/--branch\\\=\\\'\\\'/--branch=master/g" | bash
|
||||
|
||||
|
3
INSTALL
3
INSTALL
@ -45,7 +45,7 @@ The simplest way to compile this package is:
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
Running `configure' takes a while. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
@ -227,4 +227,3 @@ operates.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
|
@ -3,11 +3,15 @@
|
||||
If you have cloned Tesseract from GitHub, you must generate
|
||||
the configure script.
|
||||
|
||||
If you have tesseract 3.0x installation in your system, please remove it
|
||||
If you have tesseract 4.0x installation in your system, please remove it
|
||||
before new build.
|
||||
|
||||
You need Leptonica 1.74.2 (minimum) for Tesseract 4.0x.
|
||||
|
||||
Known dependencies for training tools (excluding leptonica):
|
||||
* compiler with c++ support
|
||||
* compiler with c++11 support
|
||||
* automake
|
||||
* pkg-config
|
||||
* pango-devel
|
||||
* cairo-devel
|
||||
* icu-devel
|
||||
@ -18,25 +22,33 @@ So, the steps for making Tesseract are:
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
||||
$ sudo ldconfig
|
||||
$ make training
|
||||
$ sudo make training-install
|
||||
|
||||
You need to install at least English language data file to TESSDATA_PREFIX
|
||||
directory. All language data files can be retrieved from git repository:
|
||||
You need to install at least English language and OSD traineddata files to
|
||||
`TESSDATA_PREFIX` directory.
|
||||
|
||||
You can retrieve single file with tools like [wget](https://www.gnu.org/software/wget/), [curl](https://curl.haxx.se/), [GithubDownloader](https://github.com/intezer/GithubDownloader) or browser.
|
||||
|
||||
All language data files can be retrieved from git repository (useful only for packagers!).
|
||||
(Repository is huge - more that 1.2 GB. You do NOT need to download traineddata files for
|
||||
all languages).
|
||||
|
||||
$ git clone https://github.com/tesseract-ocr/tessdata.git tesseract-ocr.tessdata
|
||||
|
||||
(Repository is huge - more that 1.2 GB. You do not need to download
|
||||
all languages)
|
||||
|
||||
To compile ScrollView.jar you need to download piccolo2d-core-3.0.jar
|
||||
and [piccolo2d-extras-3.0.jar](http://search.maven.org/#search|ga|1|g%3A%22org.piccolo2d%22) and place them to tesseract/java.
|
||||
You need an Internet connection and [curl](https://curl.haxx.se/) to compile `ScrollView.jar`
|
||||
because the build will automatically download
|
||||
[piccolo2d-core-3.0.jar](http://search.maven.org/remotecontent?filepath=org/piccolo2d/piccolo2d-core/3.0/piccolo2d-core-3.0.jar > piccolo2d-core-3.0.jar) and
|
||||
[piccolo2d-extras-3.0.jar](http://search.maven.org/remotecontent?filepath=org/piccolo2d/piccolo2d-extras/3.0/piccolo2d-extras-3.0.jar) and
|
||||
[jaxb-api-2.3.1.jar](http://search.maven.org/remotecontent?filepath=javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar) and place them to `tesseract/java`.
|
||||
|
||||
Then run:
|
||||
Just run:
|
||||
|
||||
$ make ScrollView.jar
|
||||
|
||||
and follow instruction on [Viewer Debugging wiki](https://github.com/tesseract-ocr/tesseract/wiki/ViewerDebugging).
|
||||
and follow the instruction on [Viewer Debugging wiki](https://github.com/tesseract-ocr/tesseract/wiki/ViewerDebugging).
|
||||
|
||||
|
||||
# CMAKE
|
||||
|
202
LICENSE
Normal file
202
LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
53
Makefile.am
53
Makefile.am
@ -2,48 +2,45 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
if ENABLE_TRAINING
|
||||
TRAINING_SUBDIR = training
|
||||
training:
|
||||
@cd "$(top_builddir)/training" && $(MAKE)
|
||||
training-install:
|
||||
@cd "$(top_builddir)/training" && $(MAKE) install
|
||||
TRAINING_SUBDIR = src/training
|
||||
training: all
|
||||
@$(MAKE) -C src/training
|
||||
training-install: training
|
||||
@$(MAKE) -C src/training install
|
||||
training-uninstall:
|
||||
@$(MAKE) -C src/training uninstall
|
||||
clean-local:
|
||||
@cd "$(top_builddir)/training" && $(MAKE) clean
|
||||
@$(MAKE) -C src/training clean
|
||||
else
|
||||
training:
|
||||
@echo "Need to reconfigure project, so there are no errors"
|
||||
endif
|
||||
|
||||
.PHONY: install-langs ScrollView.jar install-jars training
|
||||
.PHONY: doc install-langs ScrollView.jar install-jars training
|
||||
|
||||
SUBDIRS = ccutil viewer cutil opencl ccstruct dict classify wordrec textord
|
||||
if !NO_CUBE_BUILD
|
||||
SUBDIRS += neural_networks/runtime cube
|
||||
endif
|
||||
SUBDIRS += ccmain api . tessdata doc
|
||||
SUBDIRS = src/arch src/ccutil src/viewer src/cutil src/opencl src/ccstruct
|
||||
SUBDIRS += src/dict src/classify src/wordrec src/textord src/lstm
|
||||
SUBDIRS += src/ccmain src/api . tessdata doc unittest
|
||||
|
||||
EXTRA_DIST = README.md\
|
||||
aclocal.m4 config configure.ac autogen.sh contrib \
|
||||
tesseract.pc.in $(TRAINING_SUBDIR) java doc testing
|
||||
EXTRA_DIST = README.md LICENSE
|
||||
EXTRA_DIST += aclocal.m4 config configure.ac autogen.sh
|
||||
EXTRA_DIST += tesseract.pc.in $(TRAINING_SUBDIR) java doc
|
||||
EXTRA_DIST += CMakeLists.txt tesseract.pc.cmake cmake VERSION src/vs2010 cppan.yml
|
||||
|
||||
DIST_SUBDIRS = $(SUBDIRS) $(TRAINING_SUBDIR)
|
||||
DIST_SUBDIRS = $(SUBDIRS) $(TRAINING_SUBDIR)
|
||||
|
||||
uninstall-hook:
|
||||
rm -rf $(DESTDIR)$(includedir)
|
||||
rm -rf $(DESTDIR)$(pkgincludedir)
|
||||
|
||||
dist-hook:
|
||||
# Need to remove .svn directories from directories
|
||||
# added using EXTRA_DIST. $(distdir)/tessdata would in
|
||||
# theory suffice.
|
||||
rm -rf `find $(distdir) -name .svn`
|
||||
rm -rf `find $(distdir) -name .git`
|
||||
rm -rf `find $(distdir) -name .deps`
|
||||
rm -rf `find $(distdir) -name .libs`
|
||||
rm -rf `find $(distdir) -name *.o`
|
||||
rm -rf `find $(distdir) -name *.lo`
|
||||
rm -rf `find $(distdir) -name *.la`
|
||||
rm -rf `find $(distdir)/training -executable -type f`
|
||||
rm -rf $(distdir)/doc/html/*
|
||||
rm -rf `find $(distdir) -name .deps -type d`
|
||||
-rm -f $(distdir)/*/Makefile $(distdir)/*/*/Makefile
|
||||
rm -f `find $(distdir) -name '*~'`
|
||||
rm -rf $(find $(distdir)/src/training -executable -type f)
|
||||
rm -rf $(distdir)/doc/html/* $(distdir)/doc/*.log
|
||||
|
||||
ScrollView.jar:
|
||||
@cd "$(top_builddir)/java" && $(MAKE) $@
|
||||
@ -51,9 +48,7 @@ ScrollView.jar:
|
||||
install-jars:
|
||||
@cd "$(top_builddir)/java" && $(MAKE) $@
|
||||
|
||||
doc-dummy:
|
||||
|
||||
doc: doc-dummy
|
||||
doc:
|
||||
-srcdir="$(top_srcdir)" builddir="$(top_builddir)" \
|
||||
version="@PACKAGE_VERSION@" name="@PACKAGE_NAME@" \
|
||||
doxygen $(top_srcdir)/doc/Doxyfile
|
||||
|
109
README.md
109
README.md
@ -1,45 +1,91 @@
|
||||
# Tesseract OCR
|
||||
|
||||
[![Build Status](https://travis-ci.org/tesseract-ocr/tesseract.svg?branch=master)](https://travis-ci.org/tesseract-ocr/tesseract)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/miah0ikfsf0j3819?svg=true)](https://ci.appveyor.com/project/zdenop/tesseract/)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/miah0ikfsf0j3819/branch/master?svg=true)](https://ci.appveyor.com/project/zdenop/tesseract/)<br>
|
||||
[![Coverity Scan Build Status](https://scan.coverity.com/projects/tesseract-ocr/badge.svg)](https://scan.coverity.com/projects/tesseract-ocr)
|
||||
[![Code Quality: Cpp](https://img.shields.io/lgtm/grade/cpp/g/tesseract-ocr/tesseract.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/tesseract-ocr/tesseract/context:cpp)
|
||||
[![Total Alerts](https://img.shields.io/lgtm/alerts/g/tesseract-ocr/tesseract.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/tesseract-ocr/tesseract/alerts)<br/>
|
||||
[![GitHub license](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://raw.githubusercontent.com/tesseract-ocr/tesseract/master/LICENSE)
|
||||
[![Downloads](https://img.shields.io/badge/download-all%20releases-brightgreen.svg)](https://github.com/tesseract-ocr/tesseract/releases/)
|
||||
|
||||
For the latest online version of the README.md see:
|
||||
|
||||
https://github.com/tesseract-ocr/tesseract/blob/master/README.md
|
||||
## About
|
||||
|
||||
#About
|
||||
This package contains an **OCR engine** - `libtesseract` and a **command line program** - `tesseract`.
|
||||
Tesseract 4 adds a new neural net (LSTM) based OCR engine which is focused
|
||||
on line recognition, but also still supports the legacy Tesseract OCR engine of
|
||||
Tesseract 3 which works by recognizing character patterns. Compatibility with
|
||||
Tesseract 3 is enabled by using the Legacy OCR Engine mode (--oem 0).
|
||||
It also needs traineddata files which support the legacy engine, for example
|
||||
those from the tessdata repository.
|
||||
|
||||
This package contains an OCR engine - `libtesseract` and a command line program - `tesseract`.
|
||||
The lead developer is Ray Smith. The maintainer is Zdenko Podobny.
|
||||
For a list of contributors see [AUTHORS](https://github.com/tesseract-ocr/tesseract/blob/master/AUTHORS)
|
||||
and GitHub's log of [contributors](https://github.com/tesseract-ocr/tesseract/graphs/contributors).
|
||||
|
||||
The lead developer is Ray Smith. The maintainer is Zdenko Podobny.
|
||||
For a list of contributors see [AUTHORS](https://github.com/tesseract-ocr/tesseract/blob/master/AUTHORS) and github's log of [contributors](https://github.com/tesseract-ocr/tesseract/graphs/contributors).
|
||||
Tesseract has **unicode (UTF-8) support**, and can **recognize more than 100 languages** "out of the box".
|
||||
|
||||
Tesseract has unicode (UTF-8) support, and can recognize more than 100
|
||||
languages "out of the box". It can be trained to recognize other languages. See [Tesseract Training](https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract) for more information.
|
||||
Tesseract supports **various output formats**: plain text, hOCR (HTML), PDF, invisible-text-only PDF, TSV. The master branch also has experimental support for ALTO (XML) output.
|
||||
|
||||
Tesseract supports various output formats: plain-text, hocr(html), pdf.
|
||||
You should note that in many cases, in order to get better OCR results, you'll need to **[improve the quality](https://github.com/tesseract-ocr/tesseract/wiki/ImproveQuality) of the image** you are giving Tesseract.
|
||||
|
||||
This project does not include a GUI application. If you need one, please see the [3rdParty](https://github.com/tesseract-ocr/tesseract/wiki/3rdParty) wiki page.
|
||||
This project **does not include a GUI application**. If you need one, please see the [3rdParty](https://github.com/tesseract-ocr/tesseract/wiki/User-Projects-%E2%80%93-3rdParty) wiki page.
|
||||
|
||||
You should note that in many cases, in order to get better OCR results, you'll need to [improve the quality](https://github.com/tesseract-ocr/tesseract/wiki/ImproveQuality) of the image you are giving Tesseract.
|
||||
Tesseract **can be trained to recognize other languages**. See [Tesseract Training](https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract) for more information.
|
||||
|
||||
The latest stable version is 3.04.01, released in February 2016.
|
||||
|
||||
#Brief history
|
||||
## Brief history
|
||||
|
||||
Tesseract was originally developed at Hewlett-Packard Laboratories Bristol and
|
||||
at Hewlett-Packard Co, Greeley Colorado between 1985 and 1994, with some
|
||||
more changes made in 1996 to port to Windows, and some C++izing in 1998.
|
||||
|
||||
In 2005 Tesseract was open sourced by HP. Since 2006 it is developed by Google.
|
||||
|
||||
[Release Notes](https://github.com/tesseract-ocr/tesseract/wiki/ReleaseNotes)
|
||||
The latest (LSTM based) stable version is **[4.0.0](https://github.com/tesseract-ocr/tesseract/releases/tag/4.0.0)**, released on October 29, 2018. Latest source code for 4.0 is available from [master branch on GitHub](https://github.com/tesseract-ocr/tesseract/tree/master). Open issues can be found in [issue tracker](https://github.com/tesseract-ocr/tesseract/issues), and [Planning wiki](https://github.com/tesseract-ocr/tesseract/wiki/Planning#400).
|
||||
|
||||
#For developers
|
||||
The latest 3.5 version is **[3.05.02](https://github.com/tesseract-ocr/tesseract/releases/tag/3.05.02)**, released on June 19, 2018. Latest source code for 3.05 is available from [3.05 branch on GitHub](https://github.com/tesseract-ocr/tesseract/tree/3.05). There is no development for this version, but it can be used for special cases (e.g. see [Regression of features from 3.0x](https://github.com/tesseract-ocr/tesseract/wiki/Planning#regression-of-features-from-30x)).
|
||||
|
||||
Developers can use `libtesseract` [C](https://github.com/tesseract-ocr/tesseract/blob/master/api/capi.h) or [C++](https://github.com/tesseract-ocr/tesseract/blob/master/api/baseapi.h) API to build their own application. If you need bindings to `libtesseract` for other programming languages, please see the [wrapper](https://github.com/tesseract-ocr/tesseract/wiki/AddOns#tesseract-wrappers) section on AddOns wiki page.
|
||||
See **[Release Notes](https://github.com/tesseract-ocr/tesseract/wiki/ReleaseNotes)** and **[Change Log](https://github.com/tesseract-ocr/tesseract/blob/master/ChangeLog)** for more details of the releases.
|
||||
|
||||
## Installing Tesseract
|
||||
|
||||
You can either [Install Tesseract via pre-built binary package](https://github.com/tesseract-ocr/tesseract/wiki) or [build it from source](https://github.com/tesseract-ocr/tesseract/wiki/Compiling).
|
||||
|
||||
Supported Compilers are:
|
||||
|
||||
* GCC 4.8 and above
|
||||
* Clang 3.4 and above
|
||||
* MSVC 2015, 2017
|
||||
|
||||
Other compilers might work, but are not officially supported.
|
||||
|
||||
## Running Tesseract
|
||||
|
||||
Basic **[command line usage](https://github.com/tesseract-ocr/tesseract/wiki/Command-Line-Usage)**:
|
||||
|
||||
tesseract imagename outputbase [-l lang] [--oem ocrenginemode] [--psm pagesegmode] [configfiles...]
|
||||
|
||||
For more information about the various command line options use `tesseract --help` or `man tesseract`.
|
||||
|
||||
Examples can be found in the [wiki](https://github.com/tesseract-ocr/tesseract/wiki/Command-Line-Usage#simplest-invocation-to-ocr-an-image).
|
||||
|
||||
## For developers
|
||||
|
||||
Developers can use `libtesseract` [C](https://github.com/tesseract-ocr/tesseract/blob/master/src/api/capi.h) or [C++](https://github.com/tesseract-ocr/tesseract/blob/master/src/api/baseapi.h) API to build their own application. If you need bindings to `libtesseract` for other programming languages, please see the [wrapper](https://github.com/tesseract-ocr/tesseract/wiki/AddOns#tesseract-wrappers) section on AddOns wiki page.
|
||||
|
||||
Documentation of Tesseract generated from source code by doxygen can be found on [tesseract-ocr.github.io](http://tesseract-ocr.github.io/).
|
||||
|
||||
#License
|
||||
## Support
|
||||
|
||||
Before you submit an issue, please review **[the guidelines for this repository](https://github.com/tesseract-ocr/tesseract/blob/master/CONTRIBUTING.md)**.
|
||||
|
||||
For support, first read the [Wiki](https://github.com/tesseract-ocr/tesseract/wiki), particularly the [FAQ](https://github.com/tesseract-ocr/tesseract/wiki/FAQ) to see if your problem is addressed there. If not, search the [Tesseract user forum](https://groups.google.com/d/forum/tesseract-ocr), the [Tesseract developer forum](https://groups.google.com/d/forum/tesseract-dev) and [past issues](https://github.com/tesseract-ocr/tesseract/issues), and if you still can't find what you need, ask for support in the mailing-lists.
|
||||
|
||||
Mailing-lists:
|
||||
* [tesseract-ocr](https://groups.google.com/d/forum/tesseract-ocr) - For tesseract users.
|
||||
* [tesseract-dev](https://groups.google.com/d/forum/tesseract-dev) - For tesseract developers.
|
||||
|
||||
Please report an issue only for a **bug**, not for asking questions.
|
||||
|
||||
## License
|
||||
|
||||
The code in this repository is licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -55,22 +101,11 @@ Documentation of Tesseract generated from source code by doxygen can be found on
|
||||
|
||||
**NOTE**: This software depends on other packages that may be licensed under different open source licenses.
|
||||
|
||||
#Installing Tesseract
|
||||
Tesseract uses [Leptonica library](http://leptonica.com/) which essentially
|
||||
uses a [BSD 2-clause license](http://leptonica.com/about-the-license.html).
|
||||
|
||||
You can either [Install Tesseract via pre-built binary package](https://github.com/tesseract-ocr/tesseract/wiki) or [build it from source](https://github.com/tesseract-ocr/tesseract/wiki/Compiling).
|
||||
## Latest Version of README
|
||||
|
||||
#Running Tesseract
|
||||
For the latest online version of the README.md see:
|
||||
|
||||
Basic command line usage:
|
||||
|
||||
tesseract imagename outputbase [-l lang] [-psm pagesegmode] [configfiles...]
|
||||
|
||||
For more information about the various command line options use `tesseract --help` or `man tesseract`.
|
||||
|
||||
#Support
|
||||
|
||||
Mailing-lists:
|
||||
* [tesseract-ocr](https://groups.google.com/d/forum/tesseract-ocr) - For tesseract users.
|
||||
* [tesseract-dev](https://groups.google.com/d/forum/tesseract-dev) - For tesseract developers.
|
||||
|
||||
Please read the [FAQ](https://github.com/tesseract-ocr/tesseract/wiki/FAQ) before asking any question in the mailing-list or reporting an issue.
|
||||
https://github.com/tesseract-ocr/tesseract/blob/master/README.md
|
||||
|
1
abseil
Submodule
1
abseil
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit e821380d69a549dc64900693942789d21aa4df5e
|
@ -1,4 +1,4 @@
|
||||
<!--
|
||||
This file is needed by the android_native_library rule to determine the
|
||||
project directory for ndk-build.
|
||||
-->
|
||||
-->
|
||||
|
@ -4,7 +4,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := tesseract-$(APP_ABI)
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
mobile_base \
|
||||
base \
|
||||
leptonica-$(APP_ABI)
|
||||
|
||||
LOCAL_C_INCLUDES := $(APP_C_INCLUDES)
|
||||
@ -30,13 +30,8 @@ $(info local path=$(LOCAL_PATH))
|
||||
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/../../api/*.cpp $(LOCAL_PATH)/../../ccmain/*.cpp $(LOCAL_PATH)/../../ccstruct/*.cpp $(LOCAL_PATH)/../../ccutil/*.cpp $(LOCAL_PATH)/../../classify/*.cpp $(LOCAL_PATH)/../../cutil/*.cpp $(LOCAL_PATH)/../../dict/*.cpp $(LOCAL_PATH)/../../image/*.cpp $(LOCAL_PATH)/../../textord/*.cpp $(LOCAL_PATH)/../../viewer/*.cpp $(LOCAL_PATH)/../../wordrec/*.cpp)
|
||||
|
||||
EXPLICIT_SRC_EXCLUDES := \
|
||||
$(LOCAL_PATH)/../../ccmain/cubeclassifier.cpp \
|
||||
$(LOCAL_PATH)/../../ccmain/cubeclassifier.h \
|
||||
$(LOCAL_PATH)/../../ccmain/cube_control.cpp \
|
||||
$(LOCAL_PATH)/../../ccmain/cube_reco_context.cpp \
|
||||
$(LOCAL_PATH)/../../ccmain/cube_reco_context.h \
|
||||
$(LOCAL_PATH)/../../ccmain/tesseract_cube_combiner.cpp \
|
||||
$(LOCAL_PATH)/../../ccmain/tesseract_cube_combiner.h \
|
||||
$(LOCAL_PATH)/../../api/altorenderer.cpp \
|
||||
$(LOCAL_PATH)/../../api/hocrrenderer.cpp \
|
||||
$(LOCAL_PATH)/../../api/pdfrenderer.cpp \
|
||||
$(LOCAL_PATH)/../../api/tesseractmain.cpp \
|
||||
|
||||
@ -47,11 +42,10 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES:$(LOCAL_PATH)/%=%)
|
||||
$(info local src files = $(LOCAL_SRC_FILES))
|
||||
|
||||
LOCAL_LDLIBS := -ldl -llog -ljnigraphics
|
||||
LOCAL_CFLAGS := -DANDROID_BUILD -DNO_CUBE_BUILD -DGRAPHICS_DISABLED
|
||||
LOCAL_CFLAGS := -DANDROID_BUILD -DGRAPHICS_DISABLED
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
$(call import-module,mobile/base)
|
||||
$(call import-module,mobile/base)
|
||||
$(call import-module,base/port)
|
||||
$(call import-module,mobile/util/hash)
|
||||
$(call import-module,third_party/leptonica/android/jni)
|
||||
|
@ -7,7 +7,7 @@ else
|
||||
endif
|
||||
|
||||
# Specify the hash namespace that we're using, based on the APP_STL we're using.
|
||||
APP_CFLAGS += -Werror -DHASH_NAMESPACE=__gnu_cxx -Wno-error=deprecated-register
|
||||
APP_CFLAGS += -Werror -DHASH_NAMESPACE=__gnu_cxx
|
||||
APP_PLATFORM := android-16
|
||||
APP_STL := gnustl_static
|
||||
NDK_TOOLCHAIN_VERSION := clang
|
||||
|
@ -1,95 +0,0 @@
|
||||
AM_CPPFLAGS += -DLOCALEDIR=\"$(localedir)\"\
|
||||
-DUSE_STD_NAMESPACE \
|
||||
-I$(top_srcdir)/ccutil -I$(top_srcdir)/ccstruct -I$(top_srcdir)/cube \
|
||||
-I$(top_srcdir)/viewer \
|
||||
-I$(top_srcdir)/textord -I$(top_srcdir)/dict \
|
||||
-I$(top_srcdir)/classify -I$(top_srcdir)/ccmain \
|
||||
-I$(top_srcdir)/wordrec -I$(top_srcdir)/cutil \
|
||||
-I$(top_srcdir)/opencl
|
||||
|
||||
AM_CPPFLAGS += $(OPENCL_CPPFLAGS)
|
||||
|
||||
if VISIBILITY
|
||||
AM_CPPFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
endif
|
||||
|
||||
include_HEADERS = apitypes.h baseapi.h capi.h renderer.h
|
||||
lib_LTLIBRARIES =
|
||||
|
||||
if !USING_MULTIPLELIBS
|
||||
noinst_LTLIBRARIES = libtesseract_api.la
|
||||
else
|
||||
lib_LTLIBRARIES += libtesseract_api.la
|
||||
libtesseract_api_la_LDFLAGS = -version-info $(GENERIC_LIBRARY_VERSION)
|
||||
libtesseract_api_la_LIBADD = \
|
||||
../ccmain/libtesseract_main.la \
|
||||
../textord/libtesseract_textord.la \
|
||||
../wordrec/libtesseract_wordrec.la \
|
||||
../classify/libtesseract_classify.la \
|
||||
../dict/libtesseract_dict.la \
|
||||
../ccstruct/libtesseract_ccstruct.la \
|
||||
../cutil/libtesseract_cutil.la \
|
||||
../viewer/libtesseract_viewer.la \
|
||||
../ccutil/libtesseract_ccutil.la \
|
||||
../opencl/libtesseract_opencl.la
|
||||
if !NO_CUBE_BUILD
|
||||
libtesseract_api_la_LIBADD += ../cube/libtesseract_cube.la \
|
||||
../neural_networks/runtime/libtesseract_neural.la \
|
||||
endif
|
||||
endif
|
||||
|
||||
libtesseract_api_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
if VISIBILITY
|
||||
libtesseract_api_la_CPPFLAGS += -DTESS_EXPORTS
|
||||
endif
|
||||
libtesseract_api_la_SOURCES = baseapi.cpp capi.cpp renderer.cpp pdfrenderer.cpp
|
||||
|
||||
lib_LTLIBRARIES += libtesseract.la
|
||||
libtesseract_la_LDFLAGS =
|
||||
libtesseract_la_SOURCES =
|
||||
# Dummy C++ source to cause C++ linking.
|
||||
# see http://www.gnu.org/s/hello/manual/automake/Libtool-Convenience-Libraries.html#Libtool-Convenience-Libraries
|
||||
nodist_EXTRA_libtesseract_la_SOURCES = dummy.cxx
|
||||
libtesseract_la_LIBADD = \
|
||||
libtesseract_api.la \
|
||||
../ccmain/libtesseract_main.la \
|
||||
../textord/libtesseract_textord.la \
|
||||
../wordrec/libtesseract_wordrec.la \
|
||||
../classify/libtesseract_classify.la \
|
||||
../dict/libtesseract_dict.la \
|
||||
../ccstruct/libtesseract_ccstruct.la \
|
||||
../cutil/libtesseract_cutil.la \
|
||||
../viewer/libtesseract_viewer.la \
|
||||
../ccutil/libtesseract_ccutil.la \
|
||||
../opencl/libtesseract_opencl.la
|
||||
if !NO_CUBE_BUILD
|
||||
libtesseract_la_LIBADD += ../cube/libtesseract_cube.la \
|
||||
../neural_networks/runtime/libtesseract_neural.la
|
||||
endif
|
||||
|
||||
libtesseract_la_LDFLAGS += -version-info $(GENERIC_LIBRARY_VERSION) -no-undefined
|
||||
|
||||
bin_PROGRAMS = tesseract
|
||||
tesseract_SOURCES = tesseractmain.cpp
|
||||
tesseract_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
if VISIBILITY
|
||||
tesseract_CPPFLAGS += -DTESS_IMPORTS
|
||||
endif
|
||||
|
||||
tesseract_LDADD = libtesseract.la
|
||||
|
||||
|
||||
tesseract_LDFLAGS = $(OPENCL_LDFLAGS)
|
||||
|
||||
if OPENMP
|
||||
tesseract_LDADD += $(OPENMP_CFLAGS)
|
||||
endif
|
||||
|
||||
if T_WIN
|
||||
tesseract_LDADD += -lws2_32
|
||||
libtesseract_la_LDFLAGS += -no-undefined -Wl,--as-needed -lws2_32
|
||||
endif
|
||||
if ADD_RT
|
||||
tesseract_LDADD += -lrt
|
||||
endif
|
||||
|
@ -1,456 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: tessedit.cpp (Formerly tessedit.c)
|
||||
* Description: Main program for merge of tess and editor.
|
||||
* Author: Ray Smith
|
||||
* Created: Tue Jan 07 15:21:46 GMT 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 automatically generated configuration file if running autoconf
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config_auto.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "allheaders.h"
|
||||
#include "baseapi.h"
|
||||
#include "basedir.h"
|
||||
#include "renderer.h"
|
||||
#include "strngs.h"
|
||||
#include "tprintf.h"
|
||||
#include "openclwrapper.h"
|
||||
#include "osdetect.h"
|
||||
|
||||
void PrintVersionInfo() {
|
||||
char *versionStrP;
|
||||
|
||||
printf("tesseract %s\n", tesseract::TessBaseAPI::Version());
|
||||
|
||||
versionStrP = getLeptonicaVersion();
|
||||
printf(" %s\n", versionStrP);
|
||||
lept_free(versionStrP);
|
||||
|
||||
versionStrP = getImagelibVersions();
|
||||
printf(" %s\n", versionStrP);
|
||||
lept_free(versionStrP);
|
||||
|
||||
#ifdef USE_OPENCL
|
||||
cl_platform_id platform;
|
||||
cl_uint num_platforms;
|
||||
cl_device_id devices[2];
|
||||
cl_uint num_devices;
|
||||
char info[256];
|
||||
int i;
|
||||
|
||||
printf(" OpenCL info:\n");
|
||||
clGetPlatformIDs(1, &platform, &num_platforms);
|
||||
printf(" Found %d platforms.\n", num_platforms);
|
||||
clGetPlatformInfo(platform, CL_PLATFORM_NAME, 256, info, 0);
|
||||
printf(" Platform name: %s.\n", info);
|
||||
clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 256, info, 0);
|
||||
printf(" Version: %s.\n", info);
|
||||
clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 2, devices, &num_devices);
|
||||
printf(" Found %d devices.\n", num_devices);
|
||||
for (i = 0; i < num_devices; ++i) {
|
||||
clGetDeviceInfo(devices[i], CL_DEVICE_NAME, 256, info, 0);
|
||||
printf(" Device %d name: %s.\n", i+1, info);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrintUsage(const char* program) {
|
||||
printf(
|
||||
"Usage:\n"
|
||||
" %s --help | --help-psm | --version\n"
|
||||
" %s --list-langs [--tessdata-dir PATH]\n"
|
||||
" %s --print-parameters [options...] [configfile...]\n"
|
||||
" %s imagename|stdin outputbase|stdout [options...] [configfile...]\n",
|
||||
program, program, program, program);
|
||||
}
|
||||
|
||||
void PrintHelpForPSM() {
|
||||
const char* msg =
|
||||
"Page segmentation modes:\n"
|
||||
" 0 Orientation and script detection (OSD) only.\n"
|
||||
" 1 Automatic page segmentation with OSD.\n"
|
||||
" 2 Automatic page segmentation, but no OSD, or OCR.\n"
|
||||
" 3 Fully automatic page segmentation, but no OSD. (Default)\n"
|
||||
" 4 Assume a single column of text of variable sizes.\n"
|
||||
" 5 Assume a single uniform block of vertically aligned text.\n"
|
||||
" 6 Assume a single uniform block of text.\n"
|
||||
" 7 Treat the image as a single text line.\n"
|
||||
" 8 Treat the image as a single word.\n"
|
||||
" 9 Treat the image as a single word in a circle.\n"
|
||||
" 10 Treat the image as a single character.\n"
|
||||
|
||||
//TODO: Consider publishing these modes.
|
||||
#if 0
|
||||
" 11 Sparse text. Find as much text as possible in no"
|
||||
" particular order.\n"
|
||||
" 12 Sparse text with OSD.\n"
|
||||
" 13 Raw line. Treat the image as a single text line,\n"
|
||||
"\t\t\tbypassing hacks that are Tesseract-specific.\n"
|
||||
#endif
|
||||
;
|
||||
|
||||
printf("%s", msg);
|
||||
}
|
||||
|
||||
void PrintHelpMessage(const char* program) {
|
||||
PrintUsage(program);
|
||||
|
||||
const char* ocr_options =
|
||||
"OCR options:\n"
|
||||
" --tessdata-dir PATH Specify the location of tessdata path.\n"
|
||||
" --user-words PATH Specify the location of user words file.\n"
|
||||
" --user-patterns PATH Specify the location of user patterns file.\n"
|
||||
" -l LANG[+LANG] Specify language(s) used for OCR.\n"
|
||||
" -c VAR=VALUE Set value for config variables.\n"
|
||||
" Multiple -c arguments are allowed.\n"
|
||||
" -psm NUM Specify page segmentation mode.\n"
|
||||
"NOTE: These options must occur before any configfile.\n"
|
||||
;
|
||||
|
||||
printf("\n%s\n", ocr_options);
|
||||
PrintHelpForPSM();
|
||||
|
||||
const char *single_options =
|
||||
"Single options:\n"
|
||||
" -h, --help Show this help message.\n"
|
||||
" --help-psm Show page segmentation modes.\n"
|
||||
" -v, --version Show version information.\n"
|
||||
" --list-langs List available languages for tesseract engine.\n"
|
||||
" --print-parameters Print tesseract parameters to stdout.\n"
|
||||
;
|
||||
|
||||
printf("\n%s", single_options);
|
||||
}
|
||||
|
||||
void SetVariablesFromCLArgs(tesseract::TessBaseAPI* api, int argc, char** argv) {
|
||||
char opt1[256], opt2[255];
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-c") == 0 && i + 1 < argc) {
|
||||
strncpy(opt1, argv[i + 1], 255);
|
||||
opt1[255] = '\0';
|
||||
char *p = strchr(opt1, '=');
|
||||
if (!p) {
|
||||
fprintf(stderr, "Missing = in configvar assignment\n");
|
||||
exit(1);
|
||||
}
|
||||
*p = 0;
|
||||
strncpy(opt2, strchr(argv[i + 1], '=') + 1, 255);
|
||||
opt2[254] = 0;
|
||||
++i;
|
||||
|
||||
if (!api->SetVariable(opt1, opt2)) {
|
||||
fprintf(stderr, "Could not set option: %s=%s\n", opt1, opt2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintLangsList(tesseract::TessBaseAPI* api) {
|
||||
GenericVector<STRING> languages;
|
||||
api->GetAvailableLanguagesAsVector(&languages);
|
||||
printf("List of available languages (%d):\n", languages.size());
|
||||
for (int index = 0; index < languages.size(); ++index) {
|
||||
STRING& string = languages[index];
|
||||
printf("%s\n", string.string());
|
||||
}
|
||||
api->End();
|
||||
}
|
||||
|
||||
void PrintBanner() {
|
||||
tprintf("Tesseract Open Source OCR Engine v%s with Leptonica\n",
|
||||
tesseract::TessBaseAPI::Version());
|
||||
}
|
||||
|
||||
/**
|
||||
* We have 2 possible sources of pagesegmode: a config file and
|
||||
* the command line. For backwards compatibility reasons, the
|
||||
* default in tesseract is tesseract::PSM_SINGLE_BLOCK, but the
|
||||
* default for this program is tesseract::PSM_AUTO. We will let
|
||||
* the config file take priority, so the command-line default
|
||||
* can take priority over the tesseract default, so we use the
|
||||
* value from the command line only if the retrieved mode
|
||||
* is still tesseract::PSM_SINGLE_BLOCK, indicating no change
|
||||
* in any config file. Therefore the only way to force
|
||||
* tesseract::PSM_SINGLE_BLOCK is from the command line.
|
||||
* It would be simpler if we could set the value before Init,
|
||||
* but that doesn't work.
|
||||
*/
|
||||
void FixPageSegMode(tesseract::TessBaseAPI* api,
|
||||
tesseract::PageSegMode pagesegmode) {
|
||||
if (api->GetPageSegMode() == tesseract::PSM_SINGLE_BLOCK)
|
||||
api->SetPageSegMode(pagesegmode);
|
||||
}
|
||||
|
||||
// NOTE: arg_i is used here to avoid ugly *i so many times in this function
|
||||
void ParseArgs(const int argc, char** argv,
|
||||
const char** lang,
|
||||
const char** image,
|
||||
const char** outputbase,
|
||||
const char** datapath,
|
||||
bool* list_langs,
|
||||
bool* print_parameters,
|
||||
GenericVector<STRING>* vars_vec,
|
||||
GenericVector<STRING>* vars_values,
|
||||
int* arg_i,
|
||||
tesseract::PageSegMode* pagesegmode) {
|
||||
if (argc == 1) {
|
||||
PrintHelpMessage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
if ((strcmp(argv[1], "-h") == 0) ||
|
||||
(strcmp(argv[1], "--help") == 0)) {
|
||||
PrintHelpMessage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
if ((strcmp(argv[1], "--help-psm") == 0)) {
|
||||
PrintHelpForPSM();
|
||||
exit(0);
|
||||
}
|
||||
if ((strcmp(argv[1], "-v") == 0) ||
|
||||
(strcmp(argv[1], "--version") == 0)) {
|
||||
PrintVersionInfo();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool noocr = false;
|
||||
int i = 1;
|
||||
while (i < argc && (*outputbase == NULL || argv[i][0] == '-')) {
|
||||
if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) {
|
||||
*lang = argv[i + 1];
|
||||
++i;
|
||||
} else if (strcmp(argv[i], "--tessdata-dir") == 0 && i + 1 < argc) {
|
||||
*datapath = argv[i + 1];
|
||||
++i;
|
||||
} else if (strcmp(argv[i], "--user-words") == 0 && i + 1 < argc) {
|
||||
vars_vec->push_back("user_words_file");
|
||||
vars_values->push_back(argv[i + 1]);
|
||||
++i;
|
||||
} else if (strcmp(argv[i], "--user-patterns") == 0 && i + 1 < argc) {
|
||||
vars_vec->push_back("user_patterns_file");
|
||||
vars_values->push_back(argv[i + 1]);
|
||||
++i;
|
||||
} else if (strcmp(argv[i], "--list-langs") == 0) {
|
||||
noocr = true;
|
||||
*list_langs = true;
|
||||
} else if (strcmp(argv[i], "-psm") == 0 && i + 1 < argc) {
|
||||
*pagesegmode = static_cast<tesseract::PageSegMode>(atoi(argv[i + 1]));
|
||||
++i;
|
||||
} else if (strcmp(argv[i], "--print-parameters") == 0) {
|
||||
noocr = true;
|
||||
*print_parameters = true;
|
||||
} else if (strcmp(argv[i], "-c") == 0 && i + 1 < argc) {
|
||||
// handled properly after api init
|
||||
++i;
|
||||
} else if (*image == NULL) {
|
||||
*image = argv[i];
|
||||
} else if (*outputbase == NULL) {
|
||||
*outputbase = argv[i];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
*arg_i = i;
|
||||
|
||||
if (argc == 2 && strcmp(argv[1], "--list-langs") == 0) {
|
||||
*list_langs = true;
|
||||
noocr = true;
|
||||
}
|
||||
|
||||
if (*outputbase == NULL && noocr == false) {
|
||||
PrintHelpMessage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void PreloadRenderers(tesseract::TessBaseAPI* api,
|
||||
tesseract::PointerVector<tesseract::TessResultRenderer>* renderers,
|
||||
tesseract::PageSegMode pagesegmode,
|
||||
const char* outputbase) {
|
||||
if (pagesegmode == tesseract::PSM_OSD_ONLY) {
|
||||
renderers->push_back(new tesseract::TessOsdRenderer(outputbase));
|
||||
} else {
|
||||
bool b;
|
||||
api->GetBoolVariable("tessedit_create_hocr", &b);
|
||||
if (b) {
|
||||
bool font_info;
|
||||
api->GetBoolVariable("hocr_font_info", &font_info);
|
||||
renderers->push_back(
|
||||
new tesseract::TessHOcrRenderer(outputbase, font_info));
|
||||
}
|
||||
|
||||
api->GetBoolVariable("tessedit_create_tsv", &b);
|
||||
if (b) {
|
||||
bool font_info;
|
||||
api->GetBoolVariable("hocr_font_info", &font_info);
|
||||
renderers->push_back(
|
||||
new tesseract::TessTsvRenderer(outputbase, font_info));
|
||||
}
|
||||
|
||||
api->GetBoolVariable("tessedit_create_pdf", &b);
|
||||
if (b) {
|
||||
renderers->push_back(new tesseract::TessPDFRenderer(outputbase,
|
||||
api->GetDatapath()));
|
||||
}
|
||||
|
||||
api->GetBoolVariable("tessedit_write_unlv", &b);
|
||||
if (b) {
|
||||
renderers->push_back(new tesseract::TessUnlvRenderer(outputbase));
|
||||
}
|
||||
|
||||
api->GetBoolVariable("tessedit_create_boxfile", &b);
|
||||
if (b) {
|
||||
renderers->push_back(new tesseract::TessBoxTextRenderer(outputbase));
|
||||
}
|
||||
|
||||
api->GetBoolVariable("tessedit_create_txt", &b);
|
||||
if (b || renderers->empty()) {
|
||||
renderers->push_back(new tesseract::TessTextRenderer(outputbase));
|
||||
}
|
||||
}
|
||||
|
||||
if (!renderers->empty()) {
|
||||
// Since the PointerVector auto-deletes, null-out the renderers that are
|
||||
// added to the root, and leave the root in the vector.
|
||||
for (int r = 1; r < renderers->size(); ++r) {
|
||||
(*renderers)[0]->insert((*renderers)[r]);
|
||||
(*renderers)[r] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* main()
|
||||
*
|
||||
**********************************************************************/
|
||||
int main(int argc, char **argv) {
|
||||
const char* lang = "eng";
|
||||
const char* image = NULL;
|
||||
const char* outputbase = NULL;
|
||||
const char* datapath = NULL;
|
||||
bool list_langs = false;
|
||||
bool print_parameters = false;
|
||||
GenericVector<STRING> vars_vec, vars_values;
|
||||
int arg_i = 1;
|
||||
tesseract::PageSegMode pagesegmode = tesseract::PSM_AUTO;
|
||||
|
||||
ParseArgs(argc, argv,
|
||||
&lang, &image, &outputbase, &datapath,
|
||||
&list_langs, &print_parameters,
|
||||
&vars_vec, &vars_values, &arg_i, &pagesegmode);
|
||||
|
||||
bool banner = false;
|
||||
if (outputbase != NULL && strcmp(outputbase, "-") &&
|
||||
strcmp(outputbase, "stdout")) {
|
||||
banner = true;
|
||||
}
|
||||
|
||||
PERF_COUNT_START("Tesseract:main")
|
||||
tesseract::TessBaseAPI api;
|
||||
|
||||
api.SetOutputName(outputbase);
|
||||
|
||||
int init_failed = api.Init(datapath, lang, tesseract::OEM_DEFAULT,
|
||||
&(argv[arg_i]), argc - arg_i, &vars_vec, &vars_values, false);
|
||||
if (init_failed) {
|
||||
fprintf(stderr, "Could not initialize tesseract.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SetVariablesFromCLArgs(&api, argc, argv);
|
||||
|
||||
if (list_langs) {
|
||||
PrintLangsList(&api);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (print_parameters) {
|
||||
FILE* fout = stdout;
|
||||
fprintf(stdout, "Tesseract parameters:\n");
|
||||
api.PrintVariables(fout);
|
||||
api.End();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
FixPageSegMode(&api, pagesegmode);
|
||||
|
||||
if (pagesegmode == tesseract::PSM_AUTO_ONLY) {
|
||||
int ret_val = 0;
|
||||
|
||||
Pix* pixs = pixRead(image);
|
||||
if (!pixs) {
|
||||
fprintf(stderr, "Cannot open input file: %s\n", image);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
api.SetImage(pixs);
|
||||
|
||||
tesseract::Orientation orientation;
|
||||
tesseract::WritingDirection direction;
|
||||
tesseract::TextlineOrder order;
|
||||
float deskew_angle;
|
||||
|
||||
tesseract::PageIterator* it = api.AnalyseLayout();
|
||||
if (it) {
|
||||
it->Orientation(&orientation, &direction, &order, &deskew_angle);
|
||||
tprintf("Orientation: %d\nWritingDirection: %d\nTextlineOrder: %d\n" \
|
||||
"Deskew angle: %.4f\n",
|
||||
orientation, direction, order, deskew_angle);
|
||||
} else {
|
||||
ret_val = 1;
|
||||
}
|
||||
|
||||
delete it;
|
||||
|
||||
pixDestroy(&pixs);
|
||||
exit(ret_val);
|
||||
}
|
||||
|
||||
// set in_training_mode to true when using one of these configs:
|
||||
// ambigs.train, box.train, box.train.stderr, linebox, rebox
|
||||
bool b = false;
|
||||
bool in_training_mode =
|
||||
(api.GetBoolVariable("tessedit_ambigs_training", &b) && b) ||
|
||||
(api.GetBoolVariable("tessedit_resegment_from_boxes", &b) && b) ||
|
||||
(api.GetBoolVariable("tessedit_make_boxes_from_boxes", &b) && b);
|
||||
|
||||
tesseract::PointerVector<tesseract::TessResultRenderer> renderers;
|
||||
|
||||
|
||||
|
||||
if (in_training_mode) {
|
||||
renderers.push_back(NULL);
|
||||
} else {
|
||||
PreloadRenderers(&api, &renderers, pagesegmode, outputbase);
|
||||
}
|
||||
|
||||
if (!renderers.empty()) {
|
||||
if (banner) PrintBanner();
|
||||
bool succeed = api.ProcessPages(image, NULL, 0, renderers[0]);
|
||||
if (!succeed) {
|
||||
fprintf(stderr, "Error during processing.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
PERF_COUNT_END
|
||||
return 0; // Normal exit
|
||||
}
|
52
appveyor.yml
52
appveyor.yml
@ -1,27 +1,45 @@
|
||||
os: Visual Studio 2015
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
- Win64
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
vs_ver: 14 2015
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
vs_ver: 15 2017
|
||||
vs_platform: " Win64"
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
||||
cache:
|
||||
- c:/Users/appveyor/.cppan/storage
|
||||
|
||||
# for curl
|
||||
install:
|
||||
- set PATH=C:\Program Files\Git\mingw64\bin;%PATH%
|
||||
|
||||
before_build:
|
||||
- if %platform%==Win32 set generator=Visual Studio 14
|
||||
- if %platform%==Win64 set generator=Visual Studio 14 Win64
|
||||
- if %platform%==Win32 set vcplatform=Win32
|
||||
- if %platform%==Win64 set vcplatform=x64
|
||||
- curl -fsS -L -o cppan.zip https://cppan.org/client/cppan-master-Windows-client.zip
|
||||
- 7z x cppan.zip
|
||||
- set PATH=%PATH%;%cd%
|
||||
|
||||
- set LEPT_VER=1.73
|
||||
|
||||
- ps: Start-FileDownload "https://github.com/DanBloomberg/leptonica/archive/v$env:LEPT_VER.zip" -FileName leptonica.zip
|
||||
- 7z x leptonica.zip
|
||||
- cmake -Hleptonica-%LEPT_VER% -Bleptonica-%LEPT_VER%/build -G "%generator%"
|
||||
- msbuild leptonica-%LEPT_VER%/build/leptonica.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
- cppan # dummy run to create %USERPROFILE%\.cppan\cppan.yml
|
||||
- ps: 'Add-Content $env:USERPROFILE\.cppan\cppan.yml "`n`nbuild_warning_level: 0`n"'
|
||||
- ps: 'Add-Content $env:USERPROFILE\.cppan\cppan.yml "`n`nbuild_system_verbose: false`n"'
|
||||
- ps: 'Add-Content $env:USERPROFILE\.cppan\cppan.yml "`n`nvar_check_jobs: 1`n"'
|
||||
|
||||
build_script:
|
||||
- mkdir build
|
||||
- mkdir build\bin
|
||||
- mkdir build\bin\%CONFIGURATION%
|
||||
- cd build
|
||||
- cmake .. -G "%generator%" -DLeptonica_DIR=leptonica-%LEPT_VER%/build -DSTATIC=1
|
||||
- msbuild tesseract.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
#- cmd: 'echo local_settings: > cppan.yml'
|
||||
#- cmd: 'echo generator: %generator% >> cppan.yml'
|
||||
#- cmd: 'echo use_shared_libs: true >> cppan.yml'
|
||||
#- cppan --build ..
|
||||
- cmake .. -G "Visual Studio %vs_ver%%vs_platform%"
|
||||
#- cmake --build . --config %CONFIGURATION% > build\bin\%CONFIGURATION%\log.txt 2>&1
|
||||
- cmake --build . --config %CONFIGURATION%
|
||||
|
||||
artifacts:
|
||||
- path: build\bin\%CONFIGURATION%
|
||||
#- path: build
|
||||
name: tesseract-$(APPVEYOR_BUILD_VERSION)
|
||||
|
43
autogen.sh
43
autogen.sh
@ -1,4 +1,13 @@
|
||||
#!/bin/sh
|
||||
# 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.
|
||||
|
||||
# This is a simple script which is meant to help developers
|
||||
# better deal with the GNU autotools, specifically:
|
||||
@ -37,7 +46,20 @@ if [ "$1" = "clean" ]; then
|
||||
find . -iname "Makefile.in" -type f -exec rm '{}' +
|
||||
fi
|
||||
|
||||
# create m4 directory if it not exists
|
||||
# Prevent any errors that might result from failing to properly invoke
|
||||
# `libtoolize` or `glibtoolize,` whichever is present on your system,
|
||||
# from occurring by testing for its existence and capturing the absolute path to
|
||||
# its location for caching purposes prior to using it later on in 'Step 2:'
|
||||
if command -v libtoolize >/dev/null 2>&1; then
|
||||
LIBTOOLIZE="$(command -v libtoolize)"
|
||||
elif command -v glibtoolize >/dev/null 2>&1; then
|
||||
LIBTOOLIZE="$(command -v glibtoolize)"
|
||||
else
|
||||
echo "Unable to find a valid copy of libtoolize or glibtoolize in your PATH!"
|
||||
bail_out
|
||||
fi
|
||||
|
||||
# create m4 directory if it does not exist
|
||||
if [ ! -d m4 ]; then
|
||||
mkdir m4
|
||||
fi
|
||||
@ -45,13 +67,13 @@ fi
|
||||
bail_out()
|
||||
{
|
||||
echo
|
||||
echo " Something went wrong, bailing out!"
|
||||
echo " Something went wrong, bailing out!"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Step 1: Generate aclocal.m4 from:
|
||||
# . acinclude.m4
|
||||
# . acinclude.m4
|
||||
# . config/*.m4 (these files are referenced in acinclude.m4)
|
||||
|
||||
mkdir -p config
|
||||
@ -61,9 +83,9 @@ aclocal -I config || bail_out
|
||||
|
||||
# --- Step 2:
|
||||
|
||||
echo "Running libtoolize"
|
||||
libtoolize -f -c || glibtoolize -f -c || bail_out
|
||||
libtoolize --automake || glibtoolize --automake || bail_out
|
||||
echo "Running $LIBTOOLIZE"
|
||||
$LIBTOOLIZE -f -c || bail_out
|
||||
$LIBTOOLIZE --automake || bail_out
|
||||
|
||||
# --- Step 3: Generate config.h.in from:
|
||||
# . configure.ac (look for AM_CONFIG_HEADER tag or AC_CONFIG_HEADER tag)
|
||||
@ -82,7 +104,7 @@ autoheader -f || bail_out
|
||||
# they are copied from the system so they can be used in a distribution.
|
||||
|
||||
echo "Running automake --add-missing --copy"
|
||||
automake --add-missing -c -Wno-portability > /dev/null || bail_out
|
||||
automake --add-missing --copy --warnings=all || bail_out
|
||||
|
||||
# --- Step 5: Generate configure and include/miaconfig.h from:
|
||||
# . configure.ac
|
||||
@ -91,6 +113,13 @@ automake --add-missing -c -Wno-portability > /dev/null || bail_out
|
||||
echo "Running autoconf"
|
||||
autoconf || bail_out
|
||||
|
||||
if grep -q PKG_CHECK_MODULES configure; then
|
||||
# The generated configure is invalid because pkg-config is unavailable.
|
||||
rm configure
|
||||
echo "Missing pkg-config. Check the build requirements."
|
||||
bail_out
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All done."
|
||||
echo "To build the software now, do something like:"
|
||||
|
@ -1,63 +0,0 @@
|
||||
AM_CPPFLAGS += \
|
||||
-DUSE_STD_NAMESPACE \
|
||||
-I$(top_srcdir)/ccutil -I$(top_srcdir)/ccstruct \
|
||||
-I$(top_srcdir)/viewer \
|
||||
-I$(top_srcdir)/classify -I$(top_srcdir)/dict \
|
||||
-I$(top_srcdir)/wordrec -I$(top_srcdir)/cutil \
|
||||
-I$(top_srcdir)/textord -I$(top_srcdir)/opencl
|
||||
|
||||
AM_CPPFLAGS += $(OPENCL_CPPFLAGS)
|
||||
|
||||
if VISIBILITY
|
||||
AM_CPPFLAGS += -DTESS_EXPORTS \
|
||||
-fvisibility=hidden -fvisibility-inlines-hidden
|
||||
endif
|
||||
|
||||
include_HEADERS = \
|
||||
thresholder.h ltrresultiterator.h pageiterator.h resultiterator.h \
|
||||
osdetect.h
|
||||
noinst_HEADERS = \
|
||||
control.h docqual.h equationdetect.h fixspace.h mutableiterator.h \
|
||||
output.h paragraphs.h paragraphs_internal.h paramsd.h pgedit.h \
|
||||
reject.h tessbox.h tessedit.h tesseractclass.h tessvars.h werdit.h
|
||||
|
||||
if !USING_MULTIPLELIBS
|
||||
noinst_LTLIBRARIES = libtesseract_main.la
|
||||
else
|
||||
lib_LTLIBRARIES = libtesseract_main.la
|
||||
libtesseract_main_la_LDFLAGS = -version-info $(GENERIC_LIBRARY_VERSION)
|
||||
libtesseract_main_la_LIBADD = \
|
||||
../wordrec/libtesseract_wordrec.la \
|
||||
../textord/libtesseract_textord.la \
|
||||
../ccutil/libtesseract_ccutil.la \
|
||||
../ccstruct/libtesseract_ccstruct.la \
|
||||
../viewer/libtesseract_viewer.la \
|
||||
../dict/libtesseract_dict.la \
|
||||
../classify/libtesseract_classify.la \
|
||||
../cutil/libtesseract_cutil.la \
|
||||
../opencl/libtesseract_opencl.la
|
||||
if !NO_CUBE_BUILD
|
||||
libtesseract_main_la_LIBADD += ../cube/libtesseract_cube.la
|
||||
endif
|
||||
endif
|
||||
|
||||
libtesseract_main_la_SOURCES = \
|
||||
adaptions.cpp applybox.cpp control.cpp \
|
||||
docqual.cpp equationdetect.cpp fixspace.cpp fixxht.cpp \
|
||||
ltrresultiterator.cpp \
|
||||
osdetect.cpp output.cpp pageiterator.cpp pagesegmain.cpp \
|
||||
pagewalk.cpp par_control.cpp paragraphs.cpp paramsd.cpp pgedit.cpp recogtraining.cpp \
|
||||
reject.cpp resultiterator.cpp superscript.cpp \
|
||||
tessbox.cpp tessedit.cpp tesseractclass.cpp tessvars.cpp \
|
||||
tfacepp.cpp thresholder.cpp \
|
||||
werdit.cpp
|
||||
|
||||
if !NO_CUBE_BUILD
|
||||
AM_CPPFLAGS += \
|
||||
-I$(top_srcdir)/neural_networks/runtime -I$(top_srcdir)/cube
|
||||
noinst_HEADERS += \
|
||||
cube_reco_context.h cubeclassifier.h tesseract_cube_combiner.h
|
||||
libtesseract_main_la_SOURCES += \
|
||||
cube_control.cpp cube_reco_context.cpp cubeclassifier.cpp \
|
||||
tesseract_cube_combiner.cpp
|
||||
endif
|
@ -1,432 +0,0 @@
|
||||
/******************************************************************
|
||||
* File: cube_control.cpp
|
||||
* Description: Tesseract class methods for invoking cube convolutional
|
||||
* neural network word recognizer.
|
||||
* Author: Raquel Romano
|
||||
* Created: September 2009
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// Include automatically generated configuration file if running autoconf.
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config_auto.h"
|
||||
#endif
|
||||
|
||||
#include "allheaders.h"
|
||||
|
||||
#include "cube_object.h"
|
||||
#include "cube_reco_context.h"
|
||||
#include "tesseractclass.h"
|
||||
#include "tesseract_cube_combiner.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
/**
|
||||
* @name convert_prob_to_tess_certainty
|
||||
*
|
||||
* Normalize a probability in the range [0.0, 1.0] to a tesseract
|
||||
* certainty in the range [-20.0, 0.0]
|
||||
*/
|
||||
static float convert_prob_to_tess_certainty(float prob) {
|
||||
return (prob - 1.0) * 20.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name char_box_to_tbox
|
||||
*
|
||||
* Create a TBOX from a character bounding box. If nonzero, the
|
||||
* x_offset accounts for any additional padding of the word box that
|
||||
* should be taken into account.
|
||||
*
|
||||
*/
|
||||
TBOX char_box_to_tbox(Box* char_box, TBOX word_box, int x_offset) {
|
||||
l_int32 left;
|
||||
l_int32 top;
|
||||
l_int32 width;
|
||||
l_int32 height;
|
||||
l_int32 right;
|
||||
l_int32 bottom;
|
||||
|
||||
boxGetGeometry(char_box, &left, &top, &width, &height);
|
||||
left += word_box.left() - x_offset;
|
||||
right = left + width;
|
||||
top = word_box.bottom() + word_box.height() - top;
|
||||
bottom = top - height;
|
||||
return TBOX(left, bottom, right, top);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name extract_cube_state
|
||||
*
|
||||
* Extract CharSamp objects and character bounding boxes from the
|
||||
* CubeObject's state. The caller should free both structres.
|
||||
*
|
||||
*/
|
||||
bool Tesseract::extract_cube_state(CubeObject* cube_obj,
|
||||
int* num_chars,
|
||||
Boxa** char_boxes,
|
||||
CharSamp*** char_samples) {
|
||||
if (!cube_obj) {
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube WARNING (extract_cube_state): Invalid cube object "
|
||||
"passed to extract_cube_state\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note that the CubeObject accessors return either the deslanted or
|
||||
// regular objects search object or beam search object, whichever
|
||||
// was used in the last call to Recognize()
|
||||
CubeSearchObject* cube_search_obj = cube_obj->SrchObj();
|
||||
if (!cube_search_obj) {
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube WARNING (Extract_cube_state): Could not retrieve "
|
||||
"cube's search object in extract_cube_state.\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
BeamSearch *beam_search_obj = cube_obj->BeamObj();
|
||||
if (!beam_search_obj) {
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube WARNING (Extract_cube_state): Could not retrieve "
|
||||
"cube's beam search object in extract_cube_state.\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the character samples and bounding boxes by backtracking
|
||||
// through the beam search path
|
||||
int best_node_index = beam_search_obj->BestPresortedNodeIndex();
|
||||
*char_samples = beam_search_obj->BackTrack(
|
||||
cube_search_obj, best_node_index, num_chars, NULL, char_boxes);
|
||||
if (!*char_samples)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name create_cube_box_word
|
||||
*
|
||||
* Fill the given BoxWord with boxes from character bounding
|
||||
* boxes. The char_boxes have local coordinates w.r.t. the
|
||||
* word bounding box, i.e., the left-most character bbox of each word
|
||||
* has (0,0) left-top coord, but the BoxWord must be defined in page
|
||||
* coordinates.
|
||||
*/
|
||||
bool Tesseract::create_cube_box_word(Boxa *char_boxes,
|
||||
int num_chars,
|
||||
TBOX word_box,
|
||||
BoxWord* box_word) {
|
||||
if (!box_word) {
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube WARNING (create_cube_box_word): Invalid box_word.\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the x-coordinate of left-most char_box, which could be
|
||||
// nonzero if the word image was padded before recognition took place.
|
||||
int x_offset = -1;
|
||||
for (int i = 0; i < num_chars; ++i) {
|
||||
Box* char_box = boxaGetBox(char_boxes, i, L_CLONE);
|
||||
if (x_offset < 0 || char_box->x < x_offset) {
|
||||
x_offset = char_box->x;
|
||||
}
|
||||
boxDestroy(&char_box);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_chars; ++i) {
|
||||
Box* char_box = boxaGetBox(char_boxes, i, L_CLONE);
|
||||
TBOX tbox = char_box_to_tbox(char_box, word_box, x_offset);
|
||||
boxDestroy(&char_box);
|
||||
box_word->InsertBox(i, tbox);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name init_cube_objects
|
||||
*
|
||||
* Instantiates Tesseract object's CubeRecoContext and TesseractCubeCombiner.
|
||||
* Returns false if cube context could not be created or if load_combiner is
|
||||
* true, but the combiner could not be loaded.
|
||||
*/
|
||||
bool Tesseract::init_cube_objects(bool load_combiner,
|
||||
TessdataManager *tessdata_manager) {
|
||||
ASSERT_HOST(cube_cntxt_ == NULL);
|
||||
ASSERT_HOST(tess_cube_combiner_ == NULL);
|
||||
|
||||
// Create the cube context object
|
||||
cube_cntxt_ = CubeRecoContext::Create(this, tessdata_manager, &unicharset);
|
||||
if (cube_cntxt_ == NULL) {
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube WARNING (Tesseract::init_cube_objects()): Failed to "
|
||||
"instantiate CubeRecoContext\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the combiner object and load the combiner net for target languages.
|
||||
if (load_combiner) {
|
||||
tess_cube_combiner_ = new tesseract::TesseractCubeCombiner(cube_cntxt_);
|
||||
if (!tess_cube_combiner_ || !tess_cube_combiner_->LoadCombinerNet()) {
|
||||
delete cube_cntxt_;
|
||||
cube_cntxt_ = NULL;
|
||||
if (tess_cube_combiner_ != NULL) {
|
||||
delete tess_cube_combiner_;
|
||||
tess_cube_combiner_ = NULL;
|
||||
}
|
||||
if (cube_debug_level > 0)
|
||||
tprintf("Cube ERROR (Failed to instantiate TesseractCubeCombiner\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name run_cube_combiner
|
||||
*
|
||||
* Iterates through tesseract's results and calls cube on each word,
|
||||
* combining the results with the existing tesseract result.
|
||||
*/
|
||||
void Tesseract::run_cube_combiner(PAGE_RES *page_res) {
|
||||
if (page_res == NULL || tess_cube_combiner_ == NULL)
|
||||
return;
|
||||
PAGE_RES_IT page_res_it(page_res);
|
||||
// Iterate through the word results and call cube on each word.
|
||||
for (page_res_it.restart_page(); page_res_it.word () != NULL;
|
||||
page_res_it.forward()) {
|
||||
BLOCK* block = page_res_it.block()->block;
|
||||
if (block->poly_block() != NULL && !block->poly_block()->IsText())
|
||||
continue; // Don't deal with non-text blocks.
|
||||
WERD_RES* word = page_res_it.word();
|
||||
// Skip cube entirely if tesseract's certainty is greater than threshold.
|
||||
int combiner_run_thresh = convert_prob_to_tess_certainty(
|
||||
cube_cntxt_->Params()->CombinerRunThresh());
|
||||
if (word->best_choice->certainty() >= combiner_run_thresh) {
|
||||
continue;
|
||||
}
|
||||
// Use the same language as Tesseract used for the word.
|
||||
Tesseract* lang_tess = word->tesseract;
|
||||
|
||||
// Setup a trial WERD_RES in which to classify with cube.
|
||||
WERD_RES cube_word;
|
||||
cube_word.InitForRetryRecognition(*word);
|
||||
cube_word.SetupForRecognition(lang_tess->unicharset, this, BestPix(),
|
||||
OEM_CUBE_ONLY,
|
||||
NULL, false, false, false,
|
||||
page_res_it.row()->row,
|
||||
page_res_it.block()->block);
|
||||
CubeObject *cube_obj = lang_tess->cube_recognize_word(
|
||||
page_res_it.block()->block, &cube_word);
|
||||
if (cube_obj != NULL)
|
||||
lang_tess->cube_combine_word(cube_obj, &cube_word, word);
|
||||
delete cube_obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name cube_word_pass1
|
||||
*
|
||||
* Recognizes a single word using (only) cube. Compatible with
|
||||
* Tesseract's classify_word_pass1/classify_word_pass2.
|
||||
*/
|
||||
void Tesseract::cube_word_pass1(BLOCK* block, ROW *row, WERD_RES *word) {
|
||||
CubeObject *cube_obj = cube_recognize_word(block, word);
|
||||
delete cube_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name cube_recognize_word
|
||||
*
|
||||
* Cube recognizer to recognize a single word as with classify_word_pass1
|
||||
* but also returns the cube object in case the combiner is needed.
|
||||
*/
|
||||
CubeObject* Tesseract::cube_recognize_word(BLOCK* block, WERD_RES* word) {
|
||||
if (!cube_binary_ || !cube_cntxt_) {
|
||||
if (cube_debug_level > 0 && !cube_binary_)
|
||||
tprintf("Tesseract::run_cube(): NULL binary image.\n");
|
||||
word->SetupFake(unicharset);
|
||||
return NULL;
|
||||
}
|
||||
TBOX word_box = word->word->bounding_box();
|
||||
if (block != NULL && (block->re_rotation().x() != 1.0f ||
|
||||
block->re_rotation().y() != 0.0f)) {
|
||||
// TODO(rays) We have to rotate the bounding box to get the true coords.
|
||||
// This will be achieved in the future via DENORM.
|
||||
// In the mean time, cube can't process this word.
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube can't process rotated word at:");
|
||||
word_box.print();
|
||||
}
|
||||
word->SetupFake(unicharset);
|
||||
return NULL;
|
||||
}
|
||||
CubeObject* cube_obj = new tesseract::CubeObject(
|
||||
cube_cntxt_, cube_binary_, word_box.left(),
|
||||
pixGetHeight(cube_binary_) - word_box.top(),
|
||||
word_box.width(), word_box.height());
|
||||
if (!cube_recognize(cube_obj, block, word)) {
|
||||
delete cube_obj;
|
||||
return NULL;
|
||||
}
|
||||
return cube_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name cube_combine_word
|
||||
*
|
||||
* Combines the cube and tesseract results for a single word, leaving the
|
||||
* result in tess_word.
|
||||
*/
|
||||
void Tesseract::cube_combine_word(CubeObject* cube_obj, WERD_RES* cube_word,
|
||||
WERD_RES* tess_word) {
|
||||
float combiner_prob = tess_cube_combiner_->CombineResults(tess_word,
|
||||
cube_obj);
|
||||
// If combiner probability is greater than tess/cube combiner
|
||||
// classifier threshold, i.e. tesseract wins, then just return the
|
||||
// tesseract result unchanged, as the combiner knows nothing about how
|
||||
// correct the answer is. If cube and tesseract agree, then improve the
|
||||
// scores before returning.
|
||||
WERD_CHOICE* tess_best = tess_word->best_choice;
|
||||
WERD_CHOICE* cube_best = cube_word->best_choice;
|
||||
if (cube_debug_level || classify_debug_level) {
|
||||
tprintf("Combiner prob = %g vs threshold %g\n",
|
||||
combiner_prob, cube_cntxt_->Params()->CombinerClassifierThresh());
|
||||
}
|
||||
if (combiner_prob >=
|
||||
cube_cntxt_->Params()->CombinerClassifierThresh()) {
|
||||
if (tess_best->unichar_string() == cube_best->unichar_string()) {
|
||||
// Cube and tess agree, so improve the scores.
|
||||
tess_best->set_rating(tess_best->rating() / 2);
|
||||
tess_best->set_certainty(tess_best->certainty() / 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Cube wins.
|
||||
// It is better for the language combiner to have all tesseract scores,
|
||||
// so put them in the cube result.
|
||||
cube_best->set_rating(tess_best->rating());
|
||||
cube_best->set_certainty(tess_best->certainty());
|
||||
if (cube_debug_level || classify_debug_level) {
|
||||
tprintf("Cube INFO: tesseract result replaced by cube: %s -> %s\n",
|
||||
tess_best->unichar_string().string(),
|
||||
cube_best->unichar_string().string());
|
||||
}
|
||||
tess_word->ConsumeWordResults(cube_word);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name cube_recognize
|
||||
*
|
||||
* Call cube on the current word, and write the result to word.
|
||||
* Sets up a fake result and returns false if something goes wrong.
|
||||
*/
|
||||
bool Tesseract::cube_recognize(CubeObject *cube_obj, BLOCK* block,
|
||||
WERD_RES *word) {
|
||||
// Run cube
|
||||
WordAltList *cube_alt_list = cube_obj->RecognizeWord();
|
||||
if (!cube_alt_list || cube_alt_list->AltCount() <= 0) {
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube returned nothing for word at:");
|
||||
word->word->bounding_box().print();
|
||||
}
|
||||
word->SetupFake(unicharset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get cube's best result and its probability, mapped to tesseract's
|
||||
// certainty range
|
||||
char_32 *cube_best_32 = cube_alt_list->Alt(0);
|
||||
double cube_prob = CubeUtils::Cost2Prob(cube_alt_list->AltCost(0));
|
||||
float cube_certainty = convert_prob_to_tess_certainty(cube_prob);
|
||||
string cube_best_str;
|
||||
CubeUtils::UTF32ToUTF8(cube_best_32, &cube_best_str);
|
||||
|
||||
// Retrieve Cube's character bounding boxes and CharSamples,
|
||||
// corresponding to the most recent call to RecognizeWord().
|
||||
Boxa *char_boxes = NULL;
|
||||
CharSamp **char_samples = NULL;;
|
||||
int num_chars;
|
||||
if (!extract_cube_state(cube_obj, &num_chars, &char_boxes, &char_samples)
|
||||
&& cube_debug_level > 0) {
|
||||
tprintf("Cube WARNING (Tesseract::cube_recognize): Cannot extract "
|
||||
"cube state.\n");
|
||||
word->SetupFake(unicharset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert cube's character bounding boxes to a BoxWord.
|
||||
BoxWord cube_box_word;
|
||||
TBOX tess_word_box = word->word->bounding_box();
|
||||
if (word->denorm.block() != NULL)
|
||||
tess_word_box.rotate(word->denorm.block()->re_rotation());
|
||||
bool box_word_success = create_cube_box_word(char_boxes, num_chars,
|
||||
tess_word_box,
|
||||
&cube_box_word);
|
||||
boxaDestroy(&char_boxes);
|
||||
if (!box_word_success) {
|
||||
if (cube_debug_level > 0) {
|
||||
tprintf("Cube WARNING (Tesseract::cube_recognize): Could not "
|
||||
"create cube BoxWord\n");
|
||||
}
|
||||
word->SetupFake(unicharset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill tesseract result's fields with cube results
|
||||
fill_werd_res(cube_box_word, cube_best_str.c_str(), word);
|
||||
|
||||
// Create cube's best choice.
|
||||
BLOB_CHOICE** choices = new BLOB_CHOICE*[num_chars];
|
||||
for (int i = 0; i < num_chars; ++i) {
|
||||
UNICHAR_ID uch_id =
|
||||
cube_cntxt_->CharacterSet()->UnicharID(char_samples[i]->StrLabel());
|
||||
choices[i] = new BLOB_CHOICE(uch_id, -cube_certainty, cube_certainty,
|
||||
-1, 0.0f, 0.0f, 0.0f, BCC_STATIC_CLASSIFIER);
|
||||
}
|
||||
word->FakeClassifyWord(num_chars, choices);
|
||||
// within a word, cube recognizes the word in reading order.
|
||||
word->best_choice->set_unichars_in_script_order(true);
|
||||
delete [] choices;
|
||||
delete [] char_samples;
|
||||
|
||||
// Some sanity checks
|
||||
ASSERT_HOST(word->best_choice->length() == word->reject_map.length());
|
||||
|
||||
if (cube_debug_level || classify_debug_level) {
|
||||
tprintf("Cube result: %s r=%g, c=%g\n",
|
||||
word->best_choice->unichar_string().string(),
|
||||
word->best_choice->rating(),
|
||||
word->best_choice->certainty());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name fill_werd_res
|
||||
*
|
||||
* Fill Tesseract's word result fields with cube's.
|
||||
*
|
||||
*/
|
||||
void Tesseract::fill_werd_res(const BoxWord& cube_box_word,
|
||||
const char* cube_best_str,
|
||||
WERD_RES* tess_werd_res) {
|
||||
delete tess_werd_res->box_word;
|
||||
tess_werd_res->box_word = new BoxWord(cube_box_word);
|
||||
tess_werd_res->box_word->ClipToOriginalWord(tess_werd_res->denorm.block(),
|
||||
tess_werd_res->word);
|
||||
// Fill text and remaining fields
|
||||
tess_werd_res->word->set_text(cube_best_str);
|
||||
tess_werd_res->tess_failed = FALSE;
|
||||
tess_werd_res->tess_accepted = tess_acceptable_word(tess_werd_res);
|
||||
// There is no output word, so we can' call AdaptableWord, but then I don't
|
||||
// think we need to. Fudge the result with accepted.
|
||||
tess_werd_res->tess_would_adapt = tess_werd_res->tess_accepted;
|
||||
|
||||
// Set word to done, i.e., ignore all of tesseract's tests for rejection
|
||||
tess_werd_res->done = tess_werd_res->tess_accepted;
|
||||
}
|
||||
|
||||
} // namespace tesseract
|
@ -1,208 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: cube_reco_context.cpp
|
||||
* Description: Implementation of the Cube Recognition Context Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <string>
|
||||
#include <limits.h>
|
||||
|
||||
#include "cube_reco_context.h"
|
||||
|
||||
#include "classifier_factory.h"
|
||||
#include "cube_tuning_params.h"
|
||||
#include "dict.h"
|
||||
#include "feature_bmp.h"
|
||||
#include "tessdatamanager.h"
|
||||
#include "tesseractclass.h"
|
||||
#include "tess_lang_model.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
/**
|
||||
* Instantiate a CubeRecoContext object using a Tesseract object.
|
||||
* CubeRecoContext will not take ownership of tess_obj, but will
|
||||
* record the pointer to it and will make use of various Tesseract
|
||||
* components (language model, flags, etc). Thus the caller should
|
||||
* keep tess_obj alive so long as the instantiated CubeRecoContext is used.
|
||||
*/
|
||||
CubeRecoContext::CubeRecoContext(Tesseract *tess_obj) {
|
||||
tess_obj_ = tess_obj;
|
||||
lang_ = "";
|
||||
loaded_ = false;
|
||||
lang_mod_ = NULL;
|
||||
params_ = NULL;
|
||||
char_classifier_ = NULL;
|
||||
char_set_ = NULL;
|
||||
word_size_model_ = NULL;
|
||||
char_bigrams_ = NULL;
|
||||
word_unigrams_ = NULL;
|
||||
noisy_input_ = false;
|
||||
size_normalization_ = false;
|
||||
}
|
||||
|
||||
CubeRecoContext::~CubeRecoContext() {
|
||||
if (char_classifier_ != NULL) {
|
||||
delete char_classifier_;
|
||||
char_classifier_ = NULL;
|
||||
}
|
||||
|
||||
if (word_size_model_ != NULL) {
|
||||
delete word_size_model_;
|
||||
word_size_model_ = NULL;
|
||||
}
|
||||
|
||||
if (char_set_ != NULL) {
|
||||
delete char_set_;
|
||||
char_set_ = NULL;
|
||||
}
|
||||
|
||||
if (char_bigrams_ != NULL) {
|
||||
delete char_bigrams_;
|
||||
char_bigrams_ = NULL;
|
||||
}
|
||||
|
||||
if (word_unigrams_ != NULL) {
|
||||
delete word_unigrams_;
|
||||
word_unigrams_ = NULL;
|
||||
}
|
||||
|
||||
if (lang_mod_ != NULL) {
|
||||
delete lang_mod_;
|
||||
lang_mod_ = NULL;
|
||||
}
|
||||
|
||||
if (params_ != NULL) {
|
||||
delete params_;
|
||||
params_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the data files by looking up the TESSDATA_PREFIX
|
||||
* environment variable and appending a "tessdata" directory to it
|
||||
*/
|
||||
bool CubeRecoContext::GetDataFilePath(string *path) const {
|
||||
*path = tess_obj_->datadir.string();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object initialization function that loads all the necessary
|
||||
* components of a RecoContext. TessdataManager is used to load the
|
||||
* data from [lang].traineddata file. If TESSDATA_CUBE_UNICHARSET
|
||||
* component is present, Cube will be instantiated with the unicharset
|
||||
* specified in this component and the corresponding dictionary
|
||||
* (TESSDATA_CUBE_SYSTEM_DAWG), and will map Cube's unicharset to
|
||||
* Tesseract's. Otherwise, TessdataManager will assume that Cube will
|
||||
* be using Tesseract's unicharset and dawgs, and will load the
|
||||
* unicharset from the TESSDATA_UNICHARSET component and will load the
|
||||
* dawgs from TESSDATA_*_DAWG components.
|
||||
*/
|
||||
bool CubeRecoContext::Load(TessdataManager *tessdata_manager,
|
||||
UNICHARSET *tess_unicharset) {
|
||||
ASSERT_HOST(tess_obj_ != NULL);
|
||||
tess_unicharset_ = tess_unicharset;
|
||||
string data_file_path;
|
||||
|
||||
// Get the data file path.
|
||||
if (GetDataFilePath(&data_file_path) == false) {
|
||||
fprintf(stderr, "Unable to get data file path\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the language from the Tesseract object.
|
||||
lang_ = tess_obj_->lang.string();
|
||||
|
||||
// Create the char set.
|
||||
if ((char_set_ =
|
||||
CharSet::Create(tessdata_manager, tess_unicharset)) == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CubeRecoContext::Load): unable to load "
|
||||
"CharSet\n");
|
||||
return false;
|
||||
}
|
||||
// Create the language model.
|
||||
string lm_file_name = data_file_path + lang_ + ".cube.lm";
|
||||
string lm_params;
|
||||
if (!CubeUtils::ReadFileToString(lm_file_name, &lm_params)) {
|
||||
fprintf(stderr, "Cube ERROR (CubeRecoContext::Load): unable to read cube "
|
||||
"language model params from %s\n", lm_file_name.c_str());
|
||||
return false;
|
||||
}
|
||||
lang_mod_ = new TessLangModel(lm_params, data_file_path,
|
||||
tess_obj_->getDict().load_system_dawg,
|
||||
tessdata_manager, this);
|
||||
if (lang_mod_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CubeRecoContext::Load): unable to create "
|
||||
"TessLangModel\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the optional char bigrams object.
|
||||
char_bigrams_ = CharBigrams::Create(data_file_path, lang_);
|
||||
|
||||
// Create the optional word unigrams object.
|
||||
word_unigrams_ = WordUnigrams::Create(data_file_path, lang_);
|
||||
|
||||
// Create the optional size model.
|
||||
word_size_model_ = WordSizeModel::Create(data_file_path, lang_,
|
||||
char_set_, Contextual());
|
||||
|
||||
// Load tuning params.
|
||||
params_ = CubeTuningParams::Create(data_file_path, lang_);
|
||||
if (params_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CubeRecoContext::Load): unable to read "
|
||||
"CubeTuningParams from %s\n", data_file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the char classifier.
|
||||
char_classifier_ = CharClassifierFactory::Create(data_file_path, lang_,
|
||||
lang_mod_, char_set_,
|
||||
params_);
|
||||
if (char_classifier_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CubeRecoContext::Load): unable to load "
|
||||
"CharClassifierFactory object from %s\n", data_file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
loaded_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Creates a CubeRecoContext object using a tesseract object */
|
||||
CubeRecoContext * CubeRecoContext::Create(Tesseract *tess_obj,
|
||||
TessdataManager *tessdata_manager,
|
||||
UNICHARSET *tess_unicharset) {
|
||||
// create the object
|
||||
CubeRecoContext *cntxt = new CubeRecoContext(tess_obj);
|
||||
if (cntxt == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CubeRecoContext::Create): unable to create "
|
||||
"CubeRecoContext object\n");
|
||||
return NULL;
|
||||
}
|
||||
// load the necessary components
|
||||
if (cntxt->Load(tessdata_manager, tess_unicharset) == false) {
|
||||
fprintf(stderr, "Cube ERROR (CubeRecoContext::Create): unable to init "
|
||||
"CubeRecoContext object\n");
|
||||
delete cntxt;
|
||||
return NULL;
|
||||
}
|
||||
// success
|
||||
return cntxt;
|
||||
}
|
||||
} // tesseract}
|
@ -1,157 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: cube_reco_context.h
|
||||
* Description: Declaration of the Cube Recognition Context Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CubeRecoContext class abstracts the Cube OCR Engine. Typically a process
|
||||
// (or a thread) would create one CubeRecoContext object per language.
|
||||
// The CubeRecoContext object also provides methods to get and set the
|
||||
// different attribues of the Cube OCR Engine.
|
||||
|
||||
#ifndef CUBE_RECO_CONTEXT_H
|
||||
#define CUBE_RECO_CONTEXT_H
|
||||
|
||||
#include <string>
|
||||
#include "neural_net.h"
|
||||
#include "lang_model.h"
|
||||
#include "classifier_base.h"
|
||||
#include "feature_base.h"
|
||||
#include "char_set.h"
|
||||
#include "word_size_model.h"
|
||||
#include "char_bigrams.h"
|
||||
#include "word_unigrams.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class Tesseract;
|
||||
class TessdataManager;
|
||||
|
||||
class CubeRecoContext {
|
||||
public:
|
||||
// Reading order enum type
|
||||
enum ReadOrder {
|
||||
L2R,
|
||||
R2L
|
||||
};
|
||||
|
||||
// Instantiate using a Tesseract object
|
||||
CubeRecoContext(Tesseract *tess_obj);
|
||||
|
||||
~CubeRecoContext();
|
||||
|
||||
// accessor functions
|
||||
inline const string & Lang() const { return lang_; }
|
||||
inline CharSet *CharacterSet() const { return char_set_; }
|
||||
const UNICHARSET *TessUnicharset() const { return tess_unicharset_; }
|
||||
inline CharClassifier *Classifier() const { return char_classifier_; }
|
||||
inline WordSizeModel *SizeModel() const { return word_size_model_; }
|
||||
inline CharBigrams *Bigrams() const { return char_bigrams_; }
|
||||
inline WordUnigrams *WordUnigramsObj() const { return word_unigrams_; }
|
||||
inline TuningParams *Params() const { return params_; }
|
||||
inline LangModel *LangMod() const { return lang_mod_; }
|
||||
|
||||
// the reading order of the language
|
||||
inline ReadOrder ReadingOrder() const {
|
||||
return ((lang_ == "ara") ? R2L : L2R);
|
||||
}
|
||||
|
||||
// does the language support case
|
||||
inline bool HasCase() const {
|
||||
return (lang_ != "ara" && lang_ != "hin");
|
||||
}
|
||||
|
||||
inline bool Cursive() const {
|
||||
return (lang_ == "ara");
|
||||
}
|
||||
|
||||
inline bool HasItalics() const {
|
||||
return (lang_ != "ara" && lang_ != "hin");
|
||||
}
|
||||
|
||||
inline bool Contextual() const {
|
||||
return (lang_ == "ara");
|
||||
}
|
||||
|
||||
// RecoContext runtime flags accessor functions
|
||||
inline bool SizeNormalization() const { return size_normalization_; }
|
||||
inline bool NoisyInput() const { return noisy_input_; }
|
||||
inline bool OOD() const { return lang_mod_->OOD(); }
|
||||
inline bool Numeric() const { return lang_mod_->Numeric(); }
|
||||
inline bool WordList() const { return lang_mod_->WordList(); }
|
||||
inline bool Punc() const { return lang_mod_->Punc(); }
|
||||
inline bool CaseSensitive() const {
|
||||
return char_classifier_->CaseSensitive();
|
||||
}
|
||||
|
||||
inline void SetSizeNormalization(bool size_normalization) {
|
||||
size_normalization_ = size_normalization;
|
||||
}
|
||||
inline void SetNoisyInput(bool noisy_input) {
|
||||
noisy_input_ = noisy_input;
|
||||
}
|
||||
inline void SetOOD(bool ood_enabled) {
|
||||
lang_mod_->SetOOD(ood_enabled);
|
||||
}
|
||||
inline void SetNumeric(bool numeric_enabled) {
|
||||
lang_mod_->SetNumeric(numeric_enabled);
|
||||
}
|
||||
inline void SetWordList(bool word_list_enabled) {
|
||||
lang_mod_->SetWordList(word_list_enabled);
|
||||
}
|
||||
inline void SetPunc(bool punc_enabled) {
|
||||
lang_mod_->SetPunc(punc_enabled);
|
||||
}
|
||||
inline void SetCaseSensitive(bool case_sensitive) {
|
||||
char_classifier_->SetCaseSensitive(case_sensitive);
|
||||
}
|
||||
inline tesseract::Tesseract *TesseractObject() const {
|
||||
return tess_obj_;
|
||||
}
|
||||
|
||||
// Returns the path of the data files
|
||||
bool GetDataFilePath(string *path) const;
|
||||
// Creates a CubeRecoContext object using a tesseract object. Data
|
||||
// files are loaded via the tessdata_manager, and the tesseract
|
||||
// unicharset is provided in order to map Cube's unicharset to
|
||||
// Tesseract's in the case where the two unicharsets differ.
|
||||
static CubeRecoContext *Create(Tesseract *tess_obj,
|
||||
TessdataManager *tessdata_manager,
|
||||
UNICHARSET *tess_unicharset);
|
||||
|
||||
private:
|
||||
bool loaded_;
|
||||
string lang_;
|
||||
CharSet *char_set_;
|
||||
UNICHARSET *tess_unicharset_;
|
||||
WordSizeModel *word_size_model_;
|
||||
CharClassifier *char_classifier_;
|
||||
CharBigrams *char_bigrams_;
|
||||
WordUnigrams *word_unigrams_;
|
||||
TuningParams *params_;
|
||||
LangModel *lang_mod_;
|
||||
Tesseract *tess_obj_; // CubeRecoContext does not own this pointer
|
||||
bool size_normalization_;
|
||||
bool noisy_input_;
|
||||
|
||||
// Loads and initialized all the necessary components of a
|
||||
// CubeRecoContext. See .cpp for more details.
|
||||
bool Load(TessdataManager *tessdata_manager,
|
||||
UNICHARSET *tess_unicharset);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CUBE_RECO_CONTEXT_H
|
@ -1,134 +0,0 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
// Author: rays@google.com (Ray Smith)
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// File: cubeclassifier.cpp
|
||||
// Description: Cube implementation of a ShapeClassifier.
|
||||
// Author: Ray Smith
|
||||
// Created: Wed Nov 23 10:39:45 PST 2011
|
||||
//
|
||||
// (C) Copyright 2011, 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 "cubeclassifier.h"
|
||||
|
||||
#include "char_altlist.h"
|
||||
#include "char_set.h"
|
||||
#include "cube_object.h"
|
||||
#include "cube_reco_context.h"
|
||||
#include "tessclassifier.h"
|
||||
#include "tesseractclass.h"
|
||||
#include "trainingsample.h"
|
||||
#include "unicharset.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
CubeClassifier::CubeClassifier(tesseract::Tesseract* tesseract)
|
||||
: cube_cntxt_(tesseract->GetCubeRecoContext()),
|
||||
shape_table_(*tesseract->shape_table()) {
|
||||
}
|
||||
CubeClassifier::~CubeClassifier() {
|
||||
}
|
||||
|
||||
/// Classifies the given [training] sample, writing to results.
|
||||
/// See ShapeClassifier for a full description.
|
||||
int CubeClassifier::UnicharClassifySample(
|
||||
const TrainingSample& sample, Pix* page_pix, int debug,
|
||||
UNICHAR_ID keep_this, GenericVector<UnicharRating>* results) {
|
||||
results->clear();
|
||||
if (page_pix == NULL) return 0;
|
||||
|
||||
ASSERT_HOST(cube_cntxt_ != NULL);
|
||||
const TBOX& char_box = sample.bounding_box();
|
||||
CubeObject* cube_obj = new tesseract::CubeObject(
|
||||
cube_cntxt_, page_pix, char_box.left(),
|
||||
pixGetHeight(page_pix) - char_box.top(),
|
||||
char_box.width(), char_box.height());
|
||||
CharAltList* alt_list = cube_obj->RecognizeChar();
|
||||
if (alt_list != NULL) {
|
||||
alt_list->Sort();
|
||||
CharSet* char_set = cube_cntxt_->CharacterSet();
|
||||
for (int i = 0; i < alt_list->AltCount(); ++i) {
|
||||
// Convert cube representation to a shape_id.
|
||||
int alt_id = alt_list->Alt(i);
|
||||
int unichar_id = char_set->UnicharID(char_set->ClassString(alt_id));
|
||||
if (unichar_id >= 0)
|
||||
results->push_back(UnicharRating(unichar_id, alt_list->AltProb(i)));
|
||||
}
|
||||
delete alt_list;
|
||||
}
|
||||
delete cube_obj;
|
||||
return results->size();
|
||||
}
|
||||
|
||||
/** Provides access to the ShapeTable that this classifier works with. */
|
||||
const ShapeTable* CubeClassifier::GetShapeTable() const {
|
||||
return &shape_table_;
|
||||
}
|
||||
|
||||
CubeTessClassifier::CubeTessClassifier(tesseract::Tesseract* tesseract)
|
||||
: cube_cntxt_(tesseract->GetCubeRecoContext()),
|
||||
shape_table_(*tesseract->shape_table()),
|
||||
pruner_(new TessClassifier(true, tesseract)) {
|
||||
}
|
||||
CubeTessClassifier::~CubeTessClassifier() {
|
||||
delete pruner_;
|
||||
}
|
||||
|
||||
/// Classifies the given [training] sample, writing to results.
|
||||
/// See ShapeClassifier for a full description.
|
||||
int CubeTessClassifier::UnicharClassifySample(
|
||||
const TrainingSample& sample, Pix* page_pix, int debug,
|
||||
UNICHAR_ID keep_this, GenericVector<UnicharRating>* results) {
|
||||
int num_results = pruner_->UnicharClassifySample(sample, page_pix, debug,
|
||||
keep_this, results);
|
||||
if (page_pix == NULL) return num_results;
|
||||
|
||||
ASSERT_HOST(cube_cntxt_ != NULL);
|
||||
const TBOX& char_box = sample.bounding_box();
|
||||
CubeObject* cube_obj = new tesseract::CubeObject(
|
||||
cube_cntxt_, page_pix, char_box.left(),
|
||||
pixGetHeight(page_pix) - char_box.top(),
|
||||
char_box.width(), char_box.height());
|
||||
CharAltList* alt_list = cube_obj->RecognizeChar();
|
||||
CharSet* char_set = cube_cntxt_->CharacterSet();
|
||||
if (alt_list != NULL) {
|
||||
for (int r = 0; r < num_results; ++r) {
|
||||
// Get the best cube probability of the unichar in the result.
|
||||
double best_prob = 0.0;
|
||||
for (int i = 0; i < alt_list->AltCount(); ++i) {
|
||||
int alt_id = alt_list->Alt(i);
|
||||
int unichar_id = char_set->UnicharID(char_set->ClassString(alt_id));
|
||||
if (unichar_id == (*results)[r].unichar_id &&
|
||||
alt_list->AltProb(i) > best_prob) {
|
||||
best_prob = alt_list->AltProb(i);
|
||||
}
|
||||
}
|
||||
(*results)[r].rating = best_prob;
|
||||
}
|
||||
delete alt_list;
|
||||
// Re-sort by rating.
|
||||
results->sort(&UnicharRating::SortDescendingRating);
|
||||
}
|
||||
delete cube_obj;
|
||||
return results->size();
|
||||
}
|
||||
|
||||
/** Provides access to the ShapeTable that this classifier works with. */
|
||||
const ShapeTable* CubeTessClassifier::GetShapeTable() const {
|
||||
return &shape_table_;
|
||||
}
|
||||
|
||||
} // namespace tesseract
|
||||
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
// Author: rays@google.com (Ray Smith)
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// File: cubeclassifier.h
|
||||
// Description: Cube implementation of a ShapeClassifier.
|
||||
// Author: Ray Smith
|
||||
// Created: Wed Nov 23 10:36:32 PST 2011
|
||||
//
|
||||
// (C) Copyright 2011, 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef THIRD_PARTY_TESSERACT_CCMAIN_CUBECLASSIFIER_H_
|
||||
#define THIRD_PARTY_TESSERACT_CCMAIN_CUBECLASSIFIER_H_
|
||||
|
||||
#include "shapeclassifier.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class Classify;
|
||||
class CubeRecoContext;
|
||||
class ShapeTable;
|
||||
class TessClassifier;
|
||||
class Tesseract;
|
||||
class TrainingSample;
|
||||
struct UnicharRating;
|
||||
|
||||
// Cube implementation of a ShapeClassifier.
|
||||
class CubeClassifier : public ShapeClassifier {
|
||||
public:
|
||||
explicit CubeClassifier(Tesseract* tesseract);
|
||||
virtual ~CubeClassifier();
|
||||
|
||||
// Classifies the given [training] sample, writing to results.
|
||||
// See ShapeClassifier for a full description.
|
||||
virtual int UnicharClassifySample(const TrainingSample& sample, Pix* page_pix,
|
||||
int debug, UNICHAR_ID keep_this,
|
||||
GenericVector<UnicharRating>* results);
|
||||
// Provides access to the ShapeTable that this classifier works with.
|
||||
virtual const ShapeTable* GetShapeTable() const;
|
||||
|
||||
private:
|
||||
// Cube objects.
|
||||
CubeRecoContext* cube_cntxt_;
|
||||
const ShapeTable& shape_table_;
|
||||
};
|
||||
|
||||
// Combination of Tesseract class pruner with scoring by cube.
|
||||
class CubeTessClassifier : public ShapeClassifier {
|
||||
public:
|
||||
explicit CubeTessClassifier(Tesseract* tesseract);
|
||||
virtual ~CubeTessClassifier();
|
||||
|
||||
// Classifies the given [training] sample, writing to results.
|
||||
// See ShapeClassifier for a full description.
|
||||
virtual int UnicharClassifySample(const TrainingSample& sample, Pix* page_pix,
|
||||
int debug, UNICHAR_ID keep_this,
|
||||
GenericVector<UnicharRating>* results);
|
||||
// Provides access to the ShapeTable that this classifier works with.
|
||||
virtual const ShapeTable* GetShapeTable() const;
|
||||
|
||||
private:
|
||||
// Cube objects.
|
||||
CubeRecoContext* cube_cntxt_;
|
||||
const ShapeTable& shape_table_;
|
||||
TessClassifier* pruner_;
|
||||
};
|
||||
|
||||
} // namespace tesseract
|
||||
|
||||
#endif /* THIRD_PARTY_TESSERACT_CCMAIN_CUBECLASSIFIER_H_ */
|
@ -1,31 +0,0 @@
|
||||
/******************************************************************
|
||||
* File: fixspace.h (Formerly fixspace.h)
|
||||
* Description: Implements a pass over the page res, exploring the alternative
|
||||
* spacing possibilities, trying to use context to improve the
|
||||
word spacing
|
||||
* Author: Phil Cheatle
|
||||
* Created: Thu Oct 21 11:38:43 BST 1993
|
||||
*
|
||||
* (C) Copyright 1993, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef FIXSPACE_H
|
||||
#define FIXSPACE_H
|
||||
|
||||
#include "pageres.h"
|
||||
#include "params.h"
|
||||
|
||||
void initialise_search(WERD_RES_LIST &src_list, WERD_RES_LIST &new_list);
|
||||
void transform_to_next_perm(WERD_RES_LIST &words);
|
||||
void fixspace_dbg(WERD_RES *word);
|
||||
#endif
|
@ -1,28 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: tessbox.h (Formerly tessbox.h)
|
||||
* Description: Black boxed Tess for developing a resaljet.
|
||||
* Author: Ray Smith
|
||||
* Created: Thu Apr 23 11:03:36 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef TESSBOX_H
|
||||
#define TESSBOX_H
|
||||
|
||||
#include "ratngs.h"
|
||||
#include "tesseractclass.h"
|
||||
|
||||
// TODO(ocr-team): Delete this along with other empty header files.
|
||||
|
||||
#endif
|
@ -1,306 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: tesseract_cube_combiner.h
|
||||
* Description: Declaration of the Tesseract & Cube results combiner Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2008
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The TesseractCubeCombiner class provides the functionality of combining
|
||||
// the recognition results of Tesseract and Cube at the word level
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wctype.h>
|
||||
|
||||
#include "tesseract_cube_combiner.h"
|
||||
|
||||
#include "cube_object.h"
|
||||
#include "cube_reco_context.h"
|
||||
#include "cube_utils.h"
|
||||
#include "neural_net.h"
|
||||
#include "tesseractclass.h"
|
||||
#include "word_altlist.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
TesseractCubeCombiner::TesseractCubeCombiner(CubeRecoContext *cube_cntxt) {
|
||||
cube_cntxt_ = cube_cntxt;
|
||||
combiner_net_ = NULL;
|
||||
}
|
||||
|
||||
TesseractCubeCombiner::~TesseractCubeCombiner() {
|
||||
if (combiner_net_ != NULL) {
|
||||
delete combiner_net_;
|
||||
combiner_net_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool TesseractCubeCombiner::LoadCombinerNet() {
|
||||
ASSERT_HOST(cube_cntxt_);
|
||||
// Compute the path of the combiner net
|
||||
string data_path;
|
||||
cube_cntxt_->GetDataFilePath(&data_path);
|
||||
string net_file_name = data_path + cube_cntxt_->Lang() +
|
||||
".tesseract_cube.nn";
|
||||
|
||||
// Return false if file does not exist
|
||||
FILE *fp = fopen(net_file_name.c_str(), "rb");
|
||||
if (fp == NULL)
|
||||
return false;
|
||||
else
|
||||
fclose(fp);
|
||||
|
||||
// Load and validate net
|
||||
combiner_net_ = NeuralNet::FromFile(net_file_name);
|
||||
if (combiner_net_ == NULL) {
|
||||
tprintf("Could not read combiner net file %s", net_file_name.c_str());
|
||||
return false;
|
||||
} else if (combiner_net_->out_cnt() != 2) {
|
||||
tprintf("Invalid combiner net file %s! Output count != 2\n",
|
||||
net_file_name.c_str());
|
||||
delete combiner_net_;
|
||||
combiner_net_ = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Normalize a UTF-8 string. Converts the UTF-8 string to UTF32 and optionally
|
||||
// strips punc and/or normalizes case and then converts back
|
||||
string TesseractCubeCombiner::NormalizeString(const string &str,
|
||||
bool remove_punc,
|
||||
bool norm_case) {
|
||||
// convert to UTF32
|
||||
string_32 str32;
|
||||
CubeUtils::UTF8ToUTF32(str.c_str(), &str32);
|
||||
// strip punc and normalize
|
||||
string_32 new_str32;
|
||||
for (int idx = 0; idx < str32.length(); idx++) {
|
||||
// if no punc removal is required or not a punctuation character
|
||||
if (!remove_punc || iswpunct(str32[idx]) == 0) {
|
||||
char_32 norm_char = str32[idx];
|
||||
// normalize case if required
|
||||
if (norm_case && iswalpha(norm_char)) {
|
||||
norm_char = towlower(norm_char);
|
||||
}
|
||||
new_str32.push_back(norm_char);
|
||||
}
|
||||
}
|
||||
// convert back to UTF8
|
||||
string new_str;
|
||||
CubeUtils::UTF32ToUTF8(new_str32.c_str(), &new_str);
|
||||
return new_str;
|
||||
}
|
||||
|
||||
// Compares 2 strings optionally ignoring punctuation
|
||||
int TesseractCubeCombiner::CompareStrings(const string &str1,
|
||||
const string &str2,
|
||||
bool ignore_punc,
|
||||
bool ignore_case) {
|
||||
if (!ignore_punc && !ignore_case) {
|
||||
return str1.compare(str2);
|
||||
}
|
||||
string norm_str1 = NormalizeString(str1, ignore_punc, ignore_case);
|
||||
string norm_str2 = NormalizeString(str2, ignore_punc, ignore_case);
|
||||
return norm_str1.compare(norm_str2);
|
||||
}
|
||||
|
||||
// Check if a string is a valid Tess dict word or not
|
||||
bool TesseractCubeCombiner::ValidWord(const string &str) {
|
||||
return (cube_cntxt_->TesseractObject()->getDict().valid_word(str.c_str())
|
||||
> 0);
|
||||
}
|
||||
|
||||
// Public method for computing the combiner features. The agreement
|
||||
// output parameter will be true if both answers are identical,
|
||||
// and false otherwise.
|
||||
bool TesseractCubeCombiner::ComputeCombinerFeatures(const string &tess_str,
|
||||
int tess_confidence,
|
||||
CubeObject *cube_obj,
|
||||
WordAltList *cube_alt_list,
|
||||
vector<double> *features,
|
||||
bool *agreement) {
|
||||
features->clear();
|
||||
*agreement = false;
|
||||
if (cube_alt_list == NULL || cube_alt_list->AltCount() <= 0)
|
||||
return false;
|
||||
|
||||
// Get Cube's best string; return false if empty
|
||||
char_32 *cube_best_str32 = cube_alt_list->Alt(0);
|
||||
if (cube_best_str32 == NULL || CubeUtils::StrLen(cube_best_str32) < 1)
|
||||
return false;
|
||||
string cube_best_str;
|
||||
int cube_best_cost = cube_alt_list->AltCost(0);
|
||||
int cube_best_bigram_cost = 0;
|
||||
bool cube_best_bigram_cost_valid = true;
|
||||
if (cube_cntxt_->Bigrams())
|
||||
cube_best_bigram_cost = cube_cntxt_->Bigrams()->
|
||||
Cost(cube_best_str32, cube_cntxt_->CharacterSet());
|
||||
else
|
||||
cube_best_bigram_cost_valid = false;
|
||||
CubeUtils::UTF32ToUTF8(cube_best_str32, &cube_best_str);
|
||||
|
||||
// Get Tesseract's UTF32 string
|
||||
string_32 tess_str32;
|
||||
CubeUtils::UTF8ToUTF32(tess_str.c_str(), &tess_str32);
|
||||
|
||||
// Compute agreement flag
|
||||
*agreement = (tess_str.compare(cube_best_str) == 0);
|
||||
|
||||
// Get Cube's second best string; if empty, return false
|
||||
char_32 *cube_next_best_str32;
|
||||
string cube_next_best_str;
|
||||
int cube_next_best_cost = WORST_COST;
|
||||
if (cube_alt_list->AltCount() > 1) {
|
||||
cube_next_best_str32 = cube_alt_list->Alt(1);
|
||||
if (cube_next_best_str32 == NULL ||
|
||||
CubeUtils::StrLen(cube_next_best_str32) == 0) {
|
||||
return false;
|
||||
}
|
||||
cube_next_best_cost = cube_alt_list->AltCost(1);
|
||||
CubeUtils::UTF32ToUTF8(cube_next_best_str32, &cube_next_best_str);
|
||||
}
|
||||
// Rank of Tesseract's top result in Cube's alternate list
|
||||
int tess_rank = 0;
|
||||
for (tess_rank = 0; tess_rank < cube_alt_list->AltCount(); tess_rank++) {
|
||||
string alt_str;
|
||||
CubeUtils::UTF32ToUTF8(cube_alt_list->Alt(tess_rank), &alt_str);
|
||||
if (alt_str == tess_str)
|
||||
break;
|
||||
}
|
||||
|
||||
// Cube's cost for tesseract's result. Note that this modifies the
|
||||
// state of cube_obj, including its alternate list by calling RecognizeWord()
|
||||
int tess_cost = cube_obj->WordCost(tess_str.c_str());
|
||||
// Cube's bigram cost of Tesseract's string
|
||||
int tess_bigram_cost = 0;
|
||||
int tess_bigram_cost_valid = true;
|
||||
if (cube_cntxt_->Bigrams())
|
||||
tess_bigram_cost = cube_cntxt_->Bigrams()->
|
||||
Cost(tess_str32.c_str(), cube_cntxt_->CharacterSet());
|
||||
else
|
||||
tess_bigram_cost_valid = false;
|
||||
|
||||
// Tesseract confidence
|
||||
features->push_back(tess_confidence);
|
||||
// Cube cost of Tesseract string
|
||||
features->push_back(tess_cost);
|
||||
// Cube Rank of Tesseract string
|
||||
features->push_back(tess_rank);
|
||||
// length of Tesseract OCR string
|
||||
features->push_back(tess_str.length());
|
||||
// Tesseract OCR string in dictionary
|
||||
features->push_back(ValidWord(tess_str));
|
||||
if (tess_bigram_cost_valid) {
|
||||
// bigram cost of Tesseract string
|
||||
features->push_back(tess_bigram_cost);
|
||||
}
|
||||
// Cube tess_cost of Cube best string
|
||||
features->push_back(cube_best_cost);
|
||||
// Cube tess_cost of Cube next best string
|
||||
features->push_back(cube_next_best_cost);
|
||||
// length of Cube string
|
||||
features->push_back(cube_best_str.length());
|
||||
// Cube string in dictionary
|
||||
features->push_back(ValidWord(cube_best_str));
|
||||
if (cube_best_bigram_cost_valid) {
|
||||
// bigram cost of Cube string
|
||||
features->push_back(cube_best_bigram_cost);
|
||||
}
|
||||
// case-insensitive string comparison, including punctuation
|
||||
int compare_nocase_punc = CompareStrings(cube_best_str,
|
||||
tess_str, false, true);
|
||||
features->push_back(compare_nocase_punc == 0);
|
||||
// case-sensitive string comparison, ignoring punctuation
|
||||
int compare_case_nopunc = CompareStrings(cube_best_str,
|
||||
tess_str, true, false);
|
||||
features->push_back(compare_case_nopunc == 0);
|
||||
// case-insensitive string comparison, ignoring punctuation
|
||||
int compare_nocase_nopunc = CompareStrings(cube_best_str,
|
||||
tess_str, true, true);
|
||||
features->push_back(compare_nocase_nopunc == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The CubeObject parameter is used for 2 purposes: 1) to retrieve
|
||||
// cube's alt list, and 2) to compute cube's word cost for the
|
||||
// tesseract result. The call to CubeObject::WordCost() modifies
|
||||
// the object's alternate list, so previous state will be lost.
|
||||
float TesseractCubeCombiner::CombineResults(WERD_RES *tess_res,
|
||||
CubeObject *cube_obj) {
|
||||
// If no combiner is loaded or the cube object is undefined,
|
||||
// tesseract wins with probability 1.0
|
||||
if (combiner_net_ == NULL || cube_obj == NULL) {
|
||||
tprintf("Cube WARNING (TesseractCubeCombiner::CombineResults): "
|
||||
"Cube objects not initialized; defaulting to Tesseract\n");
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// Retrieve the alternate list from the CubeObject's current state.
|
||||
// If the alt list empty, tesseract wins with probability 1.0
|
||||
WordAltList *cube_alt_list = cube_obj->AlternateList();
|
||||
if (cube_alt_list == NULL)
|
||||
cube_alt_list = cube_obj->RecognizeWord();
|
||||
if (cube_alt_list == NULL || cube_alt_list->AltCount() <= 0) {
|
||||
tprintf("Cube WARNING (TesseractCubeCombiner::CombineResults): "
|
||||
"Cube returned no results; defaulting to Tesseract\n");
|
||||
return 1.0;
|
||||
}
|
||||
return CombineResults(tess_res, cube_obj, cube_alt_list);
|
||||
}
|
||||
|
||||
// The alt_list parameter is expected to have been extracted from the
|
||||
// CubeObject that recognized the word to be combined. The cube_obj
|
||||
// parameter passed may be either same instance or a separate instance to
|
||||
// be used only by the combiner. In both cases, its alternate
|
||||
// list will be modified by an internal call to RecognizeWord().
|
||||
float TesseractCubeCombiner::CombineResults(WERD_RES *tess_res,
|
||||
CubeObject *cube_obj,
|
||||
WordAltList *cube_alt_list) {
|
||||
// If no combiner is loaded or the cube object is undefined, or the
|
||||
// alt list is empty, tesseract wins with probability 1.0
|
||||
if (combiner_net_ == NULL || cube_obj == NULL ||
|
||||
cube_alt_list == NULL || cube_alt_list->AltCount() <= 0) {
|
||||
tprintf("Cube WARNING (TesseractCubeCombiner::CombineResults): "
|
||||
"Cube result cannot be retrieved; defaulting to Tesseract\n");
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// Tesseract result string, tesseract confidence, and cost of
|
||||
// tesseract result according to cube
|
||||
string tess_str = tess_res->best_choice->unichar_string().string();
|
||||
// Map certainty [-20.0, 0.0] to confidence [0, 100]
|
||||
int tess_confidence = MIN(100, MAX(1, static_cast<int>(
|
||||
100 + (5 * tess_res->best_choice->certainty()))));
|
||||
|
||||
// Compute the combiner features. If feature computation fails or
|
||||
// answers are identical, tesseract wins with probability 1.0
|
||||
vector<double> features;
|
||||
bool agreement;
|
||||
bool combiner_success = ComputeCombinerFeatures(tess_str, tess_confidence,
|
||||
cube_obj, cube_alt_list,
|
||||
&features, &agreement);
|
||||
if (!combiner_success || agreement)
|
||||
return 1.0;
|
||||
|
||||
// Classify combiner feature vector and return output (probability
|
||||
// of tesseract class).
|
||||
double net_out[2];
|
||||
if (!combiner_net_->FeedForward(&features[0], net_out))
|
||||
return 1.0;
|
||||
return net_out[1];
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: tesseract_cube_combiner.h
|
||||
* Description: Declaration of the Tesseract & Cube results combiner Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2008
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The TesseractCubeCombiner class provides the functionality of combining
|
||||
// the recognition results of Tesseract and Cube at the word level
|
||||
|
||||
#ifndef TESSERACT_CCMAIN_TESSERACT_CUBE_COMBINER_H
|
||||
#define TESSERACT_CCMAIN_TESSERACT_CUBE_COMBINER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "pageres.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#ifdef USE_STD_NAMESPACE
|
||||
using std::string;
|
||||
using std::vector;
|
||||
#endif
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class CubeObject;
|
||||
class NeuralNet;
|
||||
class CubeRecoContext;
|
||||
class WordAltList;
|
||||
|
||||
class TesseractCubeCombiner {
|
||||
public:
|
||||
explicit TesseractCubeCombiner(CubeRecoContext *cube_cntxt);
|
||||
virtual ~TesseractCubeCombiner();
|
||||
|
||||
// There are 2 public methods for combining the results of tesseract
|
||||
// and cube. Both return the probability that the Tesseract result is
|
||||
// correct. The difference between the two interfaces is in how the
|
||||
// passed-in CubeObject is used.
|
||||
|
||||
// The CubeObject parameter is used for 2 purposes: 1) to retrieve
|
||||
// cube's alt list, and 2) to compute cube's word cost for the
|
||||
// tesseract result. Both uses may modify the state of the
|
||||
// CubeObject (including the BeamSearch state) with a call to
|
||||
// RecognizeWord().
|
||||
float CombineResults(WERD_RES *tess_res, CubeObject *cube_obj);
|
||||
|
||||
// The alt_list parameter is expected to have been extracted from the
|
||||
// CubeObject that recognized the word to be combined. The cube_obj
|
||||
// parameter passed in is a separate instance to be used only by
|
||||
// the combiner.
|
||||
float CombineResults(WERD_RES *tess_res, CubeObject *cube_obj,
|
||||
WordAltList *alt_list);
|
||||
|
||||
// Public method for computing the combiner features. The agreement
|
||||
// output parameter will be true if both answers are identical,
|
||||
// false otherwise. Modifies the cube_alt_list, so no assumptions
|
||||
// should be made about its state upon return.
|
||||
bool ComputeCombinerFeatures(const string &tess_res,
|
||||
int tess_confidence,
|
||||
CubeObject *cube_obj,
|
||||
WordAltList *cube_alt_list,
|
||||
vector<double> *features,
|
||||
bool *agreement);
|
||||
|
||||
// Is the word valid according to Tesseract's language model
|
||||
bool ValidWord(const string &str);
|
||||
|
||||
// Loads the combiner neural network from file, using cube_cntxt_
|
||||
// to find path.
|
||||
bool LoadCombinerNet();
|
||||
private:
|
||||
// Normalize a UTF-8 string. Converts the UTF-8 string to UTF32 and optionally
|
||||
// strips punc and/or normalizes case and then converts back
|
||||
string NormalizeString(const string &str, bool remove_punc, bool norm_case);
|
||||
|
||||
// Compares 2 strings after optionally normalizing them and or stripping
|
||||
// punctuation
|
||||
int CompareStrings(const string &str1, const string &str2, bool ignore_punc,
|
||||
bool norm_case);
|
||||
|
||||
NeuralNet *combiner_net_; // pointer to the combiner NeuralNet object
|
||||
CubeRecoContext *cube_cntxt_; // used for language ID and data paths
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TESSERACT_CCMAIN_TESSERACT_CUBE_COMBINER_H
|
@ -1,29 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: blckerr.h (Formerly blockerr.h)
|
||||
* Description: Error codes for the page block classes.
|
||||
* Author: Ray Smith
|
||||
* Created: Tue Mar 19 17:43:30 GMT 1991
|
||||
*
|
||||
* (C) Copyright 1991, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef BLCKERR_H
|
||||
#define BLCKERR_H
|
||||
|
||||
#include "errcode.h"
|
||||
|
||||
const ERRCODE BADBLOCKLINE = "Y coordinate in block out of bounds";
|
||||
const ERRCODE LOSTBLOCKLINE = "Can't find rectangle for line";
|
||||
const ERRCODE ILLEGAL_GRADIENT = "Gradient wrong side of edge step!";
|
||||
const ERRCODE WRONG_WORD = "Word doesn't have blobs of that type";
|
||||
#endif
|
@ -1,38 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: genblob.cpp (Formerly gblob.c)
|
||||
* Description: Generic Blob processing routines
|
||||
* Author: Phil Cheatle
|
||||
* Created: Mon Nov 25 10:53:26 GMT 1991
|
||||
*
|
||||
* (C) Copyright 1991, 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 "genblob.h"
|
||||
#include "stepblob.h"
|
||||
|
||||
/**********************************************************************
|
||||
* c_blob_comparator()
|
||||
*
|
||||
* Blob comparator used to sort a blob list so that blobs are in increasing
|
||||
* order of left edge.
|
||||
**********************************************************************/
|
||||
|
||||
int c_blob_comparator( // sort blobs
|
||||
const void *blob1p, // ptr to ptr to blob1
|
||||
const void *blob2p // ptr to ptr to blob2
|
||||
) {
|
||||
C_BLOB *blob1 = *(C_BLOB **) blob1p;
|
||||
C_BLOB *blob2 = *(C_BLOB **) blob2p;
|
||||
|
||||
return blob1->bounding_box ().left () - blob2->bounding_box ().left ();
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: genblob.h (Formerly gblob.h)
|
||||
* Description: Generic Blob processing routines
|
||||
* Author: Phil Cheatle
|
||||
* Created: Mon Nov 25 10:53:26 GMT 1991
|
||||
*
|
||||
* (C) Copyright 1991, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef GENBLOB_H
|
||||
#define GENBLOB_H
|
||||
|
||||
// Sort function to sort blobs by ascending left edge.
|
||||
int c_blob_comparator(const void *blob1p, // ptr to ptr to blob1
|
||||
const void *blob2p);
|
||||
|
||||
#endif
|
@ -1,8 +0,0 @@
|
||||
#ifndef HPDSIZES_H
|
||||
#define HPDSIZES_H
|
||||
|
||||
#define NUM_TEXT_ATTR 10
|
||||
#define NUM_BLOCK_ATTR 7
|
||||
#define MAXLENGTH 128
|
||||
#define NUM_BACKGROUNDS 8
|
||||
#endif
|
@ -1,498 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// File: imagedata.h
|
||||
// Description: Class to hold information about a single multi-page tiff
|
||||
// training file and its corresponding boxes or text file.
|
||||
// Author: Ray Smith
|
||||
// Created: Tue May 28 08:56:06 PST 2013
|
||||
//
|
||||
// (C) Copyright 2013, 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 automatically generated configuration file if running autoconf.
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config_auto.h"
|
||||
#endif
|
||||
|
||||
#include "imagedata.h"
|
||||
|
||||
#include "allheaders.h"
|
||||
#include "boxread.h"
|
||||
#include "callcpp.h"
|
||||
#include "helpers.h"
|
||||
#include "tprintf.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
WordFeature::WordFeature() : x_(0), y_(0), dir_(0) {
|
||||
}
|
||||
|
||||
WordFeature::WordFeature(const FCOORD& fcoord, uinT8 dir)
|
||||
: x_(IntCastRounded(fcoord.x())),
|
||||
y_(ClipToRange(IntCastRounded(fcoord.y()), 0, MAX_UINT8)),
|
||||
dir_(dir) {
|
||||
}
|
||||
|
||||
// Computes the maximum x and y value in the features.
|
||||
void WordFeature::ComputeSize(const GenericVector<WordFeature>& features,
|
||||
int* max_x, int* max_y) {
|
||||
*max_x = 0;
|
||||
*max_y = 0;
|
||||
for (int f = 0; f < features.size(); ++f) {
|
||||
if (features[f].x_ > *max_x) *max_x = features[f].x_;
|
||||
if (features[f].y_ > *max_y) *max_y = features[f].y_;
|
||||
}
|
||||
}
|
||||
|
||||
// Draws the features in the given window.
|
||||
void WordFeature::Draw(const GenericVector<WordFeature>& features,
|
||||
ScrollView* window) {
|
||||
#ifndef GRAPHICS_DISABLED
|
||||
for (int f = 0; f < features.size(); ++f) {
|
||||
FCOORD pos(features[f].x_, features[f].y_);
|
||||
FCOORD dir;
|
||||
dir.from_direction(features[f].dir_);
|
||||
dir *= 8.0f;
|
||||
window->SetCursor(IntCastRounded(pos.x() - dir.x()),
|
||||
IntCastRounded(pos.y() - dir.y()));
|
||||
window->DrawTo(IntCastRounded(pos.x() + dir.x()),
|
||||
IntCastRounded(pos.y() + dir.y()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Writes to the given file. Returns false in case of error.
|
||||
bool WordFeature::Serialize(FILE* fp) const {
|
||||
if (fwrite(&x_, sizeof(x_), 1, fp) != 1) return false;
|
||||
if (fwrite(&y_, sizeof(y_), 1, fp) != 1) return false;
|
||||
if (fwrite(&dir_, sizeof(dir_), 1, fp) != 1) return false;
|
||||
return true;
|
||||
}
|
||||
// Reads from the given file. Returns false in case of error.
|
||||
// If swap is true, assumes a big/little-endian swap is needed.
|
||||
bool WordFeature::DeSerialize(bool swap, FILE* fp) {
|
||||
if (fread(&x_, sizeof(x_), 1, fp) != 1) return false;
|
||||
if (swap) ReverseN(&x_, sizeof(x_));
|
||||
if (fread(&y_, sizeof(y_), 1, fp) != 1) return false;
|
||||
if (fread(&dir_, sizeof(dir_), 1, fp) != 1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FloatWordFeature::FromWordFeatures(
|
||||
const GenericVector<WordFeature>& word_features,
|
||||
GenericVector<FloatWordFeature>* float_features) {
|
||||
for (int i = 0; i < word_features.size(); ++i) {
|
||||
FloatWordFeature f;
|
||||
f.x = word_features[i].x();
|
||||
f.y = word_features[i].y();
|
||||
f.dir = word_features[i].dir();
|
||||
f.x_bucket = 0; // Will set it later.
|
||||
float_features->push_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort function to sort first by x-bucket, then by y.
|
||||
/* static */
|
||||
int FloatWordFeature::SortByXBucket(const void* v1, const void* v2) {
|
||||
const FloatWordFeature* f1 = reinterpret_cast<const FloatWordFeature*>(v1);
|
||||
const FloatWordFeature* f2 = reinterpret_cast<const FloatWordFeature*>(v2);
|
||||
int x_diff = f1->x_bucket - f2->x_bucket;
|
||||
if (x_diff == 0) return f1->y - f2->y;
|
||||
return x_diff;
|
||||
}
|
||||
|
||||
ImageData::ImageData() : page_number_(-1), vertical_text_(false) {
|
||||
}
|
||||
// Takes ownership of the pix and destroys it.
|
||||
ImageData::ImageData(bool vertical, Pix* pix)
|
||||
: page_number_(0), vertical_text_(vertical) {
|
||||
SetPix(pix);
|
||||
}
|
||||
ImageData::~ImageData() {
|
||||
}
|
||||
|
||||
// Builds and returns an ImageData from the basic data. Note that imagedata,
|
||||
// truth_text, and box_text are all the actual file data, NOT filenames.
|
||||
ImageData* ImageData::Build(const char* name, int page_number, const char* lang,
|
||||
const char* imagedata, int imagedatasize,
|
||||
const char* truth_text, const char* box_text) {
|
||||
ImageData* image_data = new ImageData();
|
||||
image_data->imagefilename_ = name;
|
||||
image_data->page_number_ = page_number;
|
||||
image_data->language_ = lang;
|
||||
// Save the imagedata.
|
||||
image_data->image_data_.init_to_size(imagedatasize, 0);
|
||||
memcpy(&image_data->image_data_[0], imagedata, imagedatasize);
|
||||
if (!image_data->AddBoxes(box_text)) {
|
||||
if (truth_text == NULL || truth_text[0] == '\0') {
|
||||
tprintf("Error: No text corresponding to page %d from image %s!\n",
|
||||
page_number, name);
|
||||
delete image_data;
|
||||
return NULL;
|
||||
}
|
||||
image_data->transcription_ = truth_text;
|
||||
// If we have no boxes, the transcription is in the 0th box_texts_.
|
||||
image_data->box_texts_.push_back(truth_text);
|
||||
// We will create a box for the whole image on PreScale, to save unpacking
|
||||
// the image now.
|
||||
} else if (truth_text != NULL && truth_text[0] != '\0' &&
|
||||
image_data->transcription_ != truth_text) {
|
||||
// Save the truth text as it is present and disagrees with the box text.
|
||||
image_data->transcription_ = truth_text;
|
||||
}
|
||||
return image_data;
|
||||
}
|
||||
|
||||
// Writes to the given file. Returns false in case of error.
|
||||
bool ImageData::Serialize(TFile* fp) const {
|
||||
if (!imagefilename_.Serialize(fp)) return false;
|
||||
if (fp->FWrite(&page_number_, sizeof(page_number_), 1) != 1) return false;
|
||||
if (!image_data_.Serialize(fp)) return false;
|
||||
if (!transcription_.Serialize(fp)) return false;
|
||||
// WARNING: Will not work across different endian machines.
|
||||
if (!boxes_.Serialize(fp)) return false;
|
||||
if (!box_texts_.SerializeClasses(fp)) return false;
|
||||
inT8 vertical = vertical_text_;
|
||||
if (fp->FWrite(&vertical, sizeof(vertical), 1) != 1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads from the given file. Returns false in case of error.
|
||||
// If swap is true, assumes a big/little-endian swap is needed.
|
||||
bool ImageData::DeSerialize(bool swap, TFile* fp) {
|
||||
if (!imagefilename_.DeSerialize(swap, fp)) return false;
|
||||
if (fp->FRead(&page_number_, sizeof(page_number_), 1) != 1) return false;
|
||||
if (swap) ReverseN(&page_number_, sizeof(page_number_));
|
||||
if (!image_data_.DeSerialize(swap, fp)) return false;
|
||||
if (!transcription_.DeSerialize(swap, fp)) return false;
|
||||
// WARNING: Will not work across different endian machines.
|
||||
if (!boxes_.DeSerialize(swap, fp)) return false;
|
||||
if (!box_texts_.DeSerializeClasses(swap, fp)) return false;
|
||||
inT8 vertical = 0;
|
||||
if (fp->FRead(&vertical, sizeof(vertical), 1) != 1) return false;
|
||||
vertical_text_ = vertical != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Saves the given Pix as a PNG-encoded string and destroys it.
|
||||
void ImageData::SetPix(Pix* pix) {
|
||||
SetPixInternal(pix, &image_data_);
|
||||
}
|
||||
|
||||
// Returns the Pix image for *this. Must be pixDestroyed after use.
|
||||
Pix* ImageData::GetPix() const {
|
||||
return GetPixInternal(image_data_);
|
||||
}
|
||||
|
||||
// Gets anything and everything with a non-NULL pointer, prescaled to a
|
||||
// given target_height (if 0, then the original image height), and aligned.
|
||||
// Also returns (if not NULL) the width and height of the scaled image.
|
||||
// The return value is the scale factor that was applied to the image to
|
||||
// achieve the target_height.
|
||||
float ImageData::PreScale(int target_height, Pix** pix,
|
||||
int* scaled_width, int* scaled_height,
|
||||
GenericVector<TBOX>* boxes) const {
|
||||
int input_width = 0;
|
||||
int input_height = 0;
|
||||
Pix* src_pix = GetPix();
|
||||
ASSERT_HOST(src_pix != NULL);
|
||||
input_width = pixGetWidth(src_pix);
|
||||
input_height = pixGetHeight(src_pix);
|
||||
if (target_height == 0)
|
||||
target_height = input_height;
|
||||
float im_factor = static_cast<float>(target_height) / input_height;
|
||||
if (scaled_width != NULL)
|
||||
*scaled_width = IntCastRounded(im_factor * input_width);
|
||||
if (scaled_height != NULL)
|
||||
*scaled_height = target_height;
|
||||
if (pix != NULL) {
|
||||
// Get the scaled image.
|
||||
pixDestroy(pix);
|
||||
*pix = pixScale(src_pix, im_factor, im_factor);
|
||||
if (*pix == NULL) {
|
||||
tprintf("Scaling pix of size %d, %d by factor %g made null pix!!\n",
|
||||
input_width, input_height, im_factor);
|
||||
}
|
||||
if (scaled_width != NULL)
|
||||
*scaled_width = pixGetWidth(*pix);
|
||||
if (scaled_height != NULL)
|
||||
*scaled_height = pixGetHeight(*pix);
|
||||
}
|
||||
pixDestroy(&src_pix);
|
||||
if (boxes != NULL) {
|
||||
// Get the boxes.
|
||||
boxes->truncate(0);
|
||||
for (int b = 0; b < boxes_.size(); ++b) {
|
||||
TBOX box = boxes_[b];
|
||||
box.scale(im_factor);
|
||||
boxes->push_back(box);
|
||||
}
|
||||
if (boxes->empty()) {
|
||||
// Make a single box for the whole image.
|
||||
TBOX box(0, 0, im_factor * input_width, target_height);
|
||||
boxes->push_back(box);
|
||||
}
|
||||
}
|
||||
return im_factor;
|
||||
}
|
||||
|
||||
int ImageData::MemoryUsed() const {
|
||||
return image_data_.size();
|
||||
}
|
||||
|
||||
// Draws the data in a new window.
|
||||
void ImageData::Display() const {
|
||||
#ifndef GRAPHICS_DISABLED
|
||||
const int kTextSize = 64;
|
||||
// Draw the image.
|
||||
Pix* pix = GetPix();
|
||||
if (pix == NULL) return;
|
||||
int width = pixGetWidth(pix);
|
||||
int height = pixGetHeight(pix);
|
||||
ScrollView* win = new ScrollView("Imagedata", 100, 100,
|
||||
2 * (width + 2 * kTextSize),
|
||||
2 * (height + 4 * kTextSize),
|
||||
width + 10, height + 3 * kTextSize, true);
|
||||
win->Image(pix, 0, height - 1);
|
||||
pixDestroy(&pix);
|
||||
// Draw the boxes.
|
||||
win->Pen(ScrollView::RED);
|
||||
win->Brush(ScrollView::NONE);
|
||||
win->TextAttributes("Arial", kTextSize, false, false, false);
|
||||
for (int b = 0; b < boxes_.size(); ++b) {
|
||||
boxes_[b].plot(win);
|
||||
win->Text(boxes_[b].left(), height + kTextSize, box_texts_[b].string());
|
||||
TBOX scaled(boxes_[b]);
|
||||
scaled.scale(256.0 / height);
|
||||
scaled.plot(win);
|
||||
}
|
||||
// The full transcription.
|
||||
win->Pen(ScrollView::CYAN);
|
||||
win->Text(0, height + kTextSize * 2, transcription_.string());
|
||||
// Add the features.
|
||||
win->Pen(ScrollView::GREEN);
|
||||
win->Update();
|
||||
window_wait(win);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Adds the supplied boxes and transcriptions that correspond to the correct
|
||||
// page number.
|
||||
void ImageData::AddBoxes(const GenericVector<TBOX>& boxes,
|
||||
const GenericVector<STRING>& texts,
|
||||
const GenericVector<int>& box_pages) {
|
||||
// Copy the boxes and make the transcription.
|
||||
for (int i = 0; i < box_pages.size(); ++i) {
|
||||
if (page_number_ >= 0 && box_pages[i] != page_number_) continue;
|
||||
transcription_ += texts[i];
|
||||
boxes_.push_back(boxes[i]);
|
||||
box_texts_.push_back(texts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Saves the given Pix as a PNG-encoded string and destroys it.
|
||||
void ImageData::SetPixInternal(Pix* pix, GenericVector<char>* image_data) {
|
||||
l_uint8* data;
|
||||
size_t size;
|
||||
pixWriteMem(&data, &size, pix, IFF_PNG);
|
||||
pixDestroy(&pix);
|
||||
image_data->init_to_size(size, 0);
|
||||
memcpy(&(*image_data)[0], data, size);
|
||||
free(data);
|
||||
}
|
||||
|
||||
// Returns the Pix image for the image_data. Must be pixDestroyed after use.
|
||||
Pix* ImageData::GetPixInternal(const GenericVector<char>& image_data) {
|
||||
Pix* pix = NULL;
|
||||
if (!image_data.empty()) {
|
||||
// Convert the array to an image.
|
||||
const unsigned char* u_data =
|
||||
reinterpret_cast<const unsigned char*>(&image_data[0]);
|
||||
pix = pixReadMem(u_data, image_data.size());
|
||||
}
|
||||
return pix;
|
||||
}
|
||||
|
||||
// Parses the text string as a box file and adds any discovered boxes that
|
||||
// match the page number. Returns false on error.
|
||||
bool ImageData::AddBoxes(const char* box_text) {
|
||||
if (box_text != NULL && box_text[0] != '\0') {
|
||||
GenericVector<TBOX> boxes;
|
||||
GenericVector<STRING> texts;
|
||||
GenericVector<int> box_pages;
|
||||
if (ReadMemBoxes(page_number_, false, box_text, &boxes,
|
||||
&texts, NULL, &box_pages)) {
|
||||
AddBoxes(boxes, texts, box_pages);
|
||||
return true;
|
||||
} else {
|
||||
tprintf("Error: No boxes for page %d from image %s!\n",
|
||||
page_number_, imagefilename_.string());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DocumentData::DocumentData(const STRING& name)
|
||||
: document_name_(name), pages_offset_(0), total_pages_(0),
|
||||
memory_used_(0), max_memory_(0), reader_(NULL) {}
|
||||
|
||||
DocumentData::~DocumentData() {}
|
||||
|
||||
// Reads all the pages in the given lstmf filename to the cache. The reader
|
||||
// is used to read the file.
|
||||
bool DocumentData::LoadDocument(const char* filename, const char* lang,
|
||||
int start_page, inT64 max_memory,
|
||||
FileReader reader) {
|
||||
document_name_ = filename;
|
||||
lang_ = lang;
|
||||
pages_offset_ = start_page;
|
||||
max_memory_ = max_memory;
|
||||
reader_ = reader;
|
||||
return ReCachePages();
|
||||
}
|
||||
|
||||
// Writes all the pages to the given filename. Returns false on error.
|
||||
bool DocumentData::SaveDocument(const char* filename, FileWriter writer) {
|
||||
TFile fp;
|
||||
fp.OpenWrite(NULL);
|
||||
if (!pages_.Serialize(&fp) || !fp.CloseWrite(filename, writer)) {
|
||||
tprintf("Serialize failed: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool DocumentData::SaveToBuffer(GenericVector<char>* buffer) {
|
||||
TFile fp;
|
||||
fp.OpenWrite(buffer);
|
||||
return pages_.Serialize(&fp);
|
||||
}
|
||||
|
||||
// Returns a pointer to the page with the given index, modulo the total
|
||||
// number of pages, recaching if needed.
|
||||
const ImageData* DocumentData::GetPage(int index) {
|
||||
index = Modulo(index, total_pages_);
|
||||
if (index < pages_offset_ || index >= pages_offset_ + pages_.size()) {
|
||||
pages_offset_ = index;
|
||||
if (!ReCachePages()) return NULL;
|
||||
}
|
||||
return pages_[index - pages_offset_];
|
||||
}
|
||||
|
||||
// Loads as many pages can fit in max_memory_ starting at index pages_offset_.
|
||||
bool DocumentData::ReCachePages() {
|
||||
// Read the file.
|
||||
TFile fp;
|
||||
if (!fp.Open(document_name_, reader_)) return false;
|
||||
memory_used_ = 0;
|
||||
if (!pages_.DeSerialize(false, &fp)) {
|
||||
tprintf("Deserialize failed: %s\n", document_name_.string());
|
||||
pages_.truncate(0);
|
||||
return false;
|
||||
}
|
||||
total_pages_ = pages_.size();
|
||||
pages_offset_ %= total_pages_;
|
||||
// Delete pages before the first one we want, and relocate the rest.
|
||||
int page;
|
||||
for (page = 0; page < pages_.size(); ++page) {
|
||||
if (page < pages_offset_) {
|
||||
delete pages_[page];
|
||||
pages_[page] = NULL;
|
||||
} else {
|
||||
ImageData* image_data = pages_[page];
|
||||
if (max_memory_ > 0 && page > pages_offset_ &&
|
||||
memory_used_ + image_data->MemoryUsed() > max_memory_)
|
||||
break; // Don't go over memory quota unless the first image.
|
||||
if (image_data->imagefilename().length() == 0) {
|
||||
image_data->set_imagefilename(document_name_);
|
||||
image_data->set_page_number(page);
|
||||
}
|
||||
image_data->set_language(lang_);
|
||||
memory_used_ += image_data->MemoryUsed();
|
||||
if (pages_offset_ != 0) {
|
||||
pages_[page - pages_offset_] = image_data;
|
||||
pages_[page] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
pages_.truncate(page - pages_offset_);
|
||||
tprintf("Loaded %d/%d pages (%d-%d) of document %s\n",
|
||||
pages_.size(), total_pages_, pages_offset_,
|
||||
pages_offset_ + pages_.size(), document_name_.string());
|
||||
return !pages_.empty();
|
||||
}
|
||||
|
||||
// Adds the given page data to this document, counting up memory.
|
||||
void DocumentData::AddPageToDocument(ImageData* page) {
|
||||
pages_.push_back(page);
|
||||
memory_used_ += page->MemoryUsed();
|
||||
}
|
||||
|
||||
// A collection of DocumentData that knows roughly how much memory it is using.
|
||||
DocumentCache::DocumentCache(inT64 max_memory)
|
||||
: total_pages_(0), memory_used_(0), max_memory_(max_memory) {}
|
||||
DocumentCache::~DocumentCache() {}
|
||||
|
||||
// Adds all the documents in the list of filenames, counting memory.
|
||||
// The reader is used to read the files.
|
||||
bool DocumentCache::LoadDocuments(const GenericVector<STRING>& filenames,
|
||||
const char* lang, FileReader reader) {
|
||||
inT64 fair_share_memory = max_memory_ / filenames.size();
|
||||
for (int arg = 0; arg < filenames.size(); ++arg) {
|
||||
STRING filename = filenames[arg];
|
||||
DocumentData* document = new DocumentData(filename);
|
||||
if (document->LoadDocument(filename.string(), lang, 0,
|
||||
fair_share_memory, reader)) {
|
||||
AddToCache(document);
|
||||
} else {
|
||||
tprintf("Failed to load image %s!\n", filename.string());
|
||||
delete document;
|
||||
}
|
||||
}
|
||||
tprintf("Loaded %d pages, total %gMB\n",
|
||||
total_pages_, memory_used_ / 1048576.0);
|
||||
return total_pages_ > 0;
|
||||
}
|
||||
|
||||
// Adds document to the cache, throwing out other documents if needed.
|
||||
bool DocumentCache::AddToCache(DocumentData* data) {
|
||||
inT64 new_memory = data->memory_used();
|
||||
memory_used_ += new_memory;
|
||||
documents_.push_back(data);
|
||||
total_pages_ += data->NumPages();
|
||||
// Delete the first item in the array, and other pages of the same name
|
||||
// while memory is full.
|
||||
while (memory_used_ >= max_memory_ && max_memory_ > 0) {
|
||||
tprintf("Memory used=%lld vs max=%lld, discarding doc of size %lld\n",
|
||||
memory_used_ , max_memory_, documents_[0]->memory_used());
|
||||
memory_used_ -= documents_[0]->memory_used();
|
||||
total_pages_ -= documents_[0]->NumPages();
|
||||
documents_.remove(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finds and returns a document by name.
|
||||
DocumentData* DocumentCache::FindDocument(const STRING& document_name) const {
|
||||
for (int i = 0; i < documents_.size(); ++i) {
|
||||
if (documents_[i]->document_name() == document_name)
|
||||
return documents_[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Returns a page by serial number, selecting them in a round-robin fashion
|
||||
// from all the documents.
|
||||
const ImageData* DocumentCache::GetPageBySerial(int serial) {
|
||||
int document_index = serial % documents_.size();
|
||||
return documents_[document_index]->GetPage(serial / documents_.size());
|
||||
}
|
||||
|
||||
} // namespace tesseract.
|
@ -1,352 +0,0 @@
|
||||
/* -*-C-*-
|
||||
******************************************************************************
|
||||
*
|
||||
* File: matrix.h (Formerly matrix.h)
|
||||
* Description: Ratings matrix code. (Used by associator)
|
||||
* Author: Mark Seaman, OCR Technology
|
||||
* Created: Wed May 16 13:22:06 1990
|
||||
* Modified: Tue Mar 19 16:00:20 1991 (Mark Seaman) marks@hpgrlt
|
||||
* Language: C
|
||||
* Package: N/A
|
||||
* Status: Experimental (Do Not Distribute)
|
||||
*
|
||||
* (c) Copyright 1990, Hewlett-Packard Company.
|
||||
** 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.
|
||||
*
|
||||
*********************************************************************************/
|
||||
#ifndef TESSERACT_CCSTRUCT_MATRIX_H__
|
||||
#define TESSERACT_CCSTRUCT_MATRIX_H__
|
||||
|
||||
#include "kdpair.h"
|
||||
#include "unicharset.h"
|
||||
|
||||
class BLOB_CHOICE_LIST;
|
||||
|
||||
#define NOT_CLASSIFIED reinterpret_cast<BLOB_CHOICE_LIST*>(0)
|
||||
|
||||
// A generic class to hold a 2-D matrix with entries of type T, but can also
|
||||
// act as a base class for other implementations, such as a triangular or
|
||||
// banded matrix.
|
||||
template <class T>
|
||||
class GENERIC_2D_ARRAY {
|
||||
public:
|
||||
// Initializes the array size, and empty element, but cannot allocate memory
|
||||
// for the subclasses or initialize because calls to the num_elements
|
||||
// member will be routed to the base class implementation. Subclasses can
|
||||
// either pass the memory in, or allocate after by calling Resize().
|
||||
GENERIC_2D_ARRAY(int dim1, int dim2, const T& empty, T* array)
|
||||
: empty_(empty), dim1_(dim1), dim2_(dim2), array_(array) {
|
||||
}
|
||||
// Original constructor for a full rectangular matrix DOES allocate memory
|
||||
// and initialize it to empty.
|
||||
GENERIC_2D_ARRAY(int dim1, int dim2, const T& empty)
|
||||
: empty_(empty), dim1_(dim1), dim2_(dim2) {
|
||||
array_ = new T[dim1_ * dim2_];
|
||||
for (int x = 0; x < dim1_; x++)
|
||||
for (int y = 0; y < dim2_; y++)
|
||||
this->put(x, y, empty_);
|
||||
}
|
||||
virtual ~GENERIC_2D_ARRAY() { delete[] array_; }
|
||||
|
||||
// Reallocate the array to the given size. Does not keep old data.
|
||||
void Resize(int size1, int size2, const T& empty) {
|
||||
empty_ = empty;
|
||||
if (size1 != dim1_ || size2 != dim2_) {
|
||||
dim1_ = size1;
|
||||
dim2_ = size2;
|
||||
delete [] array_;
|
||||
array_ = new T[dim1_ * dim2_];
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
// Reallocate the array to the given size, keeping old data.
|
||||
void ResizeWithCopy(int size1, int size2) {
|
||||
if (size1 != dim1_ || size2 != dim2_) {
|
||||
T* new_array = new T[size1 * size2];
|
||||
for (int col = 0; col < size1; ++col) {
|
||||
for (int row = 0; row < size2; ++row) {
|
||||
int old_index = col * dim2() + row;
|
||||
int new_index = col * size2 + row;
|
||||
if (col < dim1_ && row < dim2_) {
|
||||
new_array[new_index] = array_[old_index];
|
||||
} else {
|
||||
new_array[new_index] = empty_;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] array_;
|
||||
array_ = new_array;
|
||||
dim1_ = size1;
|
||||
dim2_ = size2;
|
||||
}
|
||||
}
|
||||
|
||||
// Sets all the elements of the array to the empty value.
|
||||
void Clear() {
|
||||
int total_size = num_elements();
|
||||
for (int i = 0; i < total_size; ++i)
|
||||
array_[i] = empty_;
|
||||
}
|
||||
|
||||
// Writes to the given file. Returns false in case of error.
|
||||
// Only works with bitwise-serializeable types!
|
||||
bool Serialize(FILE* fp) const {
|
||||
if (!SerializeSize(fp)) return false;
|
||||
if (fwrite(&empty_, sizeof(empty_), 1, fp) != 1) return false;
|
||||
int size = num_elements();
|
||||
if (fwrite(array_, sizeof(*array_), size, fp) != size) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads from the given file. Returns false in case of error.
|
||||
// Only works with bitwise-serializeable typ
|
||||
// If swap is true, assumes a big/little-endian swap is needed.
|
||||
bool DeSerialize(bool swap, FILE* fp) {
|
||||
if (!DeSerializeSize(swap, fp)) return false;
|
||||
if (fread(&empty_, sizeof(empty_), 1, fp) != 1) return false;
|
||||
if (swap) ReverseN(&empty_, sizeof(empty_));
|
||||
int size = num_elements();
|
||||
if (fread(array_, sizeof(*array_), size, fp) != size) return false;
|
||||
if (swap) {
|
||||
for (int i = 0; i < size; ++i)
|
||||
ReverseN(&array_[i], sizeof(array_[i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes to the given file. Returns false in case of error.
|
||||
// Assumes a T::Serialize(FILE*) const function.
|
||||
bool SerializeClasses(FILE* fp) const {
|
||||
if (!SerializeSize(fp)) return false;
|
||||
if (!empty_.Serialize(fp)) return false;
|
||||
int size = num_elements();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (!array_[i].Serialize(fp)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads from the given file. Returns false in case of error.
|
||||
// Assumes a T::DeSerialize(bool swap, FILE*) function.
|
||||
// If swap is true, assumes a big/little-endian swap is needed.
|
||||
bool DeSerializeClasses(bool swap, FILE* fp) {
|
||||
if (!DeSerializeSize(swap, fp)) return false;
|
||||
if (!empty_.DeSerialize(swap, fp)) return false;
|
||||
int size = num_elements();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (!array_[i].DeSerialize(swap, fp)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Provide the dimensions of this rectangular matrix.
|
||||
int dim1() const { return dim1_; }
|
||||
int dim2() const { return dim2_; }
|
||||
// Returns the number of elements in the array.
|
||||
// Banded/triangular matrices may override.
|
||||
virtual int num_elements() const { return dim1_ * dim2_; }
|
||||
|
||||
// Expression to select a specific location in the matrix. The matrix is
|
||||
// stored COLUMN-major, so the left-most index is the most significant.
|
||||
// This allows [][] access to use indices in the same order as (,).
|
||||
virtual int index(int column, int row) const {
|
||||
return (column * dim2_ + row);
|
||||
}
|
||||
|
||||
// Put a list element into the matrix at a specific location.
|
||||
void put(int column, int row, const T& thing) {
|
||||
array_[this->index(column, row)] = thing;
|
||||
}
|
||||
|
||||
// Get the item at a specified location from the matrix.
|
||||
T get(int column, int row) const {
|
||||
return array_[this->index(column, row)];
|
||||
}
|
||||
// Return a reference to the element at the specified location.
|
||||
const T& operator()(int column, int row) const {
|
||||
return array_[this->index(column, row)];
|
||||
}
|
||||
T& operator()(int column, int row) {
|
||||
return array_[this->index(column, row)];
|
||||
}
|
||||
// Allow access using array[column][row]. NOTE that the indices are
|
||||
// in the same left-to-right order as the () indexing.
|
||||
T* operator[](int column) {
|
||||
return &array_[this->index(column, 0)];
|
||||
}
|
||||
const T* operator[](int column) const {
|
||||
return &array_[this->index(column, 0)];
|
||||
}
|
||||
|
||||
// Delete objects pointed to by array_[i].
|
||||
void delete_matrix_pointers() {
|
||||
int size = num_elements();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
T matrix_cell = array_[i];
|
||||
if (matrix_cell != empty_)
|
||||
delete matrix_cell;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// Factored helper to serialize the size.
|
||||
bool SerializeSize(FILE* fp) const {
|
||||
inT32 size = dim1_;
|
||||
if (fwrite(&size, sizeof(size), 1, fp) != 1) return false;
|
||||
size = dim2_;
|
||||
if (fwrite(&size, sizeof(size), 1, fp) != 1) return false;
|
||||
return true;
|
||||
}
|
||||
// Factored helper to deserialize the size.
|
||||
// If swap is true, assumes a big/little-endian swap is needed.
|
||||
bool DeSerializeSize(bool swap, FILE* fp) {
|
||||
inT32 size1, size2;
|
||||
if (fread(&size1, sizeof(size1), 1, fp) != 1) return false;
|
||||
if (fread(&size2, sizeof(size2), 1, fp) != 1) return false;
|
||||
if (swap) {
|
||||
ReverseN(&size1, sizeof(size1));
|
||||
ReverseN(&size2, sizeof(size2));
|
||||
}
|
||||
Resize(size1, size2, empty_);
|
||||
return true;
|
||||
}
|
||||
|
||||
T* array_;
|
||||
T empty_; // The unused cell.
|
||||
int dim1_; // Size of the 1st dimension in indexing functions.
|
||||
int dim2_; // Size of the 2nd dimension in indexing functions.
|
||||
};
|
||||
|
||||
// A generic class to store a banded triangular matrix with entries of type T.
|
||||
// In this array, the nominally square matrix is dim1_ x dim1_, and dim2_ is
|
||||
// the number of bands, INCLUDING the diagonal. The storage is thus of size
|
||||
// dim1_ * dim2_ and index(col, row) = col * dim2_ + row - col, and an
|
||||
// assert will fail if row < col or row - col >= dim2.
|
||||
template <class T>
|
||||
class BandTriMatrix : public GENERIC_2D_ARRAY<T> {
|
||||
public:
|
||||
// Allocate a piece of memory to hold a 2d-array of the given dimension.
|
||||
// Initialize all the elements of the array to empty instead of assuming
|
||||
// that a default constructor can be used.
|
||||
BandTriMatrix(int dim1, int dim2, const T& empty)
|
||||
: GENERIC_2D_ARRAY<T>(dim1, dim2, empty) {
|
||||
}
|
||||
// The default destructor will do.
|
||||
|
||||
// Provide the dimensions of this matrix.
|
||||
// dimension is the size of the nominally square matrix.
|
||||
int dimension() const { return this->dim1_; }
|
||||
// bandwidth is the number of bands in the matrix, INCLUDING the diagonal.
|
||||
int bandwidth() const { return this->dim2_; }
|
||||
|
||||
// Expression to select a specific location in the matrix. The matrix is
|
||||
// stored COLUMN-major, so the left-most index is the most significant.
|
||||
// This allows [][] access to use indices in the same order as (,).
|
||||
virtual int index(int column, int row) const {
|
||||
ASSERT_HOST(row >= column);
|
||||
ASSERT_HOST(row - column < this->dim2_);
|
||||
return column * this->dim2_ + row - column;
|
||||
}
|
||||
|
||||
// Appends array2 corner-to-corner to *this, making an array of dimension
|
||||
// equal to the sum of the individual dimensions.
|
||||
// array2 is not destroyed, but is left empty, as all elements are moved
|
||||
// to *this.
|
||||
void AttachOnCorner(BandTriMatrix<T>* array2) {
|
||||
int new_dim1 = this->dim1_ + array2->dim1_;
|
||||
int new_dim2 = MAX(this->dim2_, array2->dim2_);
|
||||
T* new_array = new T[new_dim1 * new_dim2];
|
||||
for (int col = 0; col < new_dim1; ++col) {
|
||||
for (int j = 0; j < new_dim2; ++j) {
|
||||
int new_index = col * new_dim2 + j;
|
||||
if (col < this->dim1_ && j < this->dim2_) {
|
||||
new_array[new_index] = this->get(col, col + j);
|
||||
} else if (col >= this->dim1_ && j < array2->dim2_) {
|
||||
new_array[new_index] = array2->get(col - this->dim1_,
|
||||
col - this->dim1_ + j);
|
||||
array2->put(col - this->dim1_, col - this->dim1_ + j, NULL);
|
||||
} else {
|
||||
new_array[new_index] = this->empty_;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] this->array_;
|
||||
this->array_ = new_array;
|
||||
this->dim1_ = new_dim1;
|
||||
this->dim2_ = new_dim2;
|
||||
}
|
||||
};
|
||||
|
||||
class MATRIX : public BandTriMatrix<BLOB_CHOICE_LIST *> {
|
||||
public:
|
||||
MATRIX(int dimension, int bandwidth)
|
||||
: BandTriMatrix<BLOB_CHOICE_LIST *>(dimension, bandwidth, NOT_CLASSIFIED) {}
|
||||
|
||||
// Returns true if there are any real classification results.
|
||||
bool Classified(int col, int row, int wildcard_id) const;
|
||||
|
||||
// Expands the existing matrix in-place to make the band wider, without
|
||||
// losing any existing data.
|
||||
void IncreaseBandSize(int bandwidth);
|
||||
|
||||
// Returns a bigger MATRIX with a new column and row in the matrix in order
|
||||
// to split the blob at the given (ind,ind) diagonal location.
|
||||
// Entries are relocated to the new MATRIX using the transformation defined
|
||||
// by MATRIX_COORD::MapForSplit.
|
||||
// Transfers the pointer data to the new MATRIX and deletes *this.
|
||||
MATRIX* ConsumeAndMakeBigger(int ind);
|
||||
|
||||
// Makes and returns a deep copy of *this, including all the BLOB_CHOICEs
|
||||
// on the lists, but not any LanguageModelState that may be attached to the
|
||||
// BLOB_CHOICEs.
|
||||
MATRIX* DeepCopy() const;
|
||||
|
||||
// Print a shortened version of the contents of the matrix.
|
||||
void print(const UNICHARSET &unicharset) const;
|
||||
};
|
||||
|
||||
struct MATRIX_COORD {
|
||||
static void Delete(void *arg) {
|
||||
MATRIX_COORD *c = static_cast<MATRIX_COORD *>(arg);
|
||||
delete c;
|
||||
}
|
||||
// Default constructor required by GenericHeap.
|
||||
MATRIX_COORD() : col(0), row(0) {}
|
||||
MATRIX_COORD(int c, int r): col(c), row(r) {}
|
||||
~MATRIX_COORD() {}
|
||||
|
||||
bool Valid(const MATRIX &m) const {
|
||||
return 0 <= col && col < m.dimension() &&
|
||||
col <= row && row < col + m.bandwidth() && row < m.dimension();
|
||||
}
|
||||
|
||||
// Remaps the col,row pair to split the blob at the given (ind,ind) diagonal
|
||||
// location.
|
||||
// Entries at (i,j) for i in [0,ind] and j in [ind,dim) move to (i,j+1),
|
||||
// making a new row at ind.
|
||||
// Entries at (i,j) for i in [ind+1,dim) and j in [i,dim) move to (i+i,j+1),
|
||||
// making a new column at ind+1.
|
||||
void MapForSplit(int ind) {
|
||||
ASSERT_HOST(row >= col);
|
||||
if (col > ind) ++col;
|
||||
if (row >= ind) ++row;
|
||||
ASSERT_HOST(row >= col);
|
||||
}
|
||||
|
||||
int col;
|
||||
int row;
|
||||
};
|
||||
|
||||
// The MatrixCoordPair contains a MATRIX_COORD and its priority.
|
||||
typedef tesseract::KDPairInc<float, MATRIX_COORD> MatrixCoordPair;
|
||||
|
||||
#endif // TESSERACT_CCSTRUCT_MATRIX_H__
|
@ -1,323 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: points.h (Formerly coords.h)
|
||||
* Description: Coordinate class definitions.
|
||||
* Author: Ray Smith
|
||||
* Created: Fri Mar 15 08:32:45 GMT 1991
|
||||
*
|
||||
* (C) Copyright 1991, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef POINTS_H
|
||||
#define POINTS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "elst.h"
|
||||
|
||||
class FCOORD;
|
||||
|
||||
///integer coordinate
|
||||
class ICOORD
|
||||
{
|
||||
friend class FCOORD;
|
||||
|
||||
public:
|
||||
///empty constructor
|
||||
ICOORD() {
|
||||
xcoord = ycoord = 0; //default zero
|
||||
}
|
||||
///constructor
|
||||
///@param xin x value
|
||||
///@param yin y value
|
||||
ICOORD(inT16 xin,
|
||||
inT16 yin) {
|
||||
xcoord = xin;
|
||||
ycoord = yin;
|
||||
}
|
||||
///destructor
|
||||
~ICOORD () {
|
||||
}
|
||||
|
||||
///access function
|
||||
inT16 x() const {
|
||||
return xcoord;
|
||||
}
|
||||
///access_function
|
||||
inT16 y() const {
|
||||
return ycoord;
|
||||
}
|
||||
|
||||
///rewrite function
|
||||
void set_x(inT16 xin) {
|
||||
xcoord = xin; //write new value
|
||||
}
|
||||
///rewrite function
|
||||
void set_y(inT16 yin) { //value to set
|
||||
ycoord = yin;
|
||||
}
|
||||
|
||||
/// Set from the given x,y, shrinking the vector to fit if needed.
|
||||
void set_with_shrink(int x, int y);
|
||||
|
||||
///find sq length
|
||||
float sqlength() const {
|
||||
return (float) (xcoord * xcoord + ycoord * ycoord);
|
||||
}
|
||||
|
||||
///find length
|
||||
float length() const {
|
||||
return (float) sqrt (sqlength ());
|
||||
}
|
||||
|
||||
///sq dist between pts
|
||||
float pt_to_pt_sqdist(const ICOORD &pt) const {
|
||||
ICOORD gap;
|
||||
|
||||
gap.xcoord = xcoord - pt.xcoord;
|
||||
gap.ycoord = ycoord - pt.ycoord;
|
||||
return gap.sqlength ();
|
||||
}
|
||||
|
||||
///Distance between pts
|
||||
float pt_to_pt_dist(const ICOORD &pt) const {
|
||||
return (float) sqrt (pt_to_pt_sqdist (pt));
|
||||
}
|
||||
|
||||
///find angle
|
||||
float angle() const {
|
||||
return (float) atan2 ((double) ycoord, (double) xcoord);
|
||||
}
|
||||
|
||||
///test equality
|
||||
BOOL8 operator== (const ICOORD & other) const {
|
||||
return xcoord == other.xcoord && ycoord == other.ycoord;
|
||||
}
|
||||
///test inequality
|
||||
BOOL8 operator!= (const ICOORD & other) const {
|
||||
return xcoord != other.xcoord || ycoord != other.ycoord;
|
||||
}
|
||||
///rotate 90 deg anti
|
||||
friend ICOORD operator! (const ICOORD &);
|
||||
///unary minus
|
||||
friend ICOORD operator- (const ICOORD &);
|
||||
///add
|
||||
friend ICOORD operator+ (const ICOORD &, const ICOORD &);
|
||||
///add
|
||||
friend ICOORD & operator+= (ICOORD &, const ICOORD &);
|
||||
///subtract
|
||||
friend ICOORD operator- (const ICOORD &, const ICOORD &);
|
||||
///subtract
|
||||
friend ICOORD & operator-= (ICOORD &, const ICOORD &);
|
||||
///scalar product
|
||||
friend inT32 operator% (const ICOORD &, const ICOORD &);
|
||||
///cross product
|
||||
friend inT32 operator *(const ICOORD &,
|
||||
const ICOORD &);
|
||||
///multiply
|
||||
friend ICOORD operator *(const ICOORD &,
|
||||
inT16);
|
||||
///multiply
|
||||
friend ICOORD operator *(inT16,
|
||||
const ICOORD &);
|
||||
///multiply
|
||||
friend ICOORD & operator*= (ICOORD &, inT16);
|
||||
///divide
|
||||
friend ICOORD operator/ (const ICOORD &, inT16);
|
||||
///divide
|
||||
friend ICOORD & operator/= (ICOORD &, inT16);
|
||||
///rotate
|
||||
///@param vec by vector
|
||||
void rotate(const FCOORD& vec);
|
||||
|
||||
/// Setup for iterating over the pixels in a vector by the well-known
|
||||
/// Bresenham rendering algorithm.
|
||||
/// Starting with major/2 in the accumulator, on each step move by
|
||||
/// major_step, and then add minor to the accumulator. When
|
||||
/// accumulator >= major subtract major and also move by minor_step.
|
||||
void setup_render(ICOORD* major_step, ICOORD* minor_step,
|
||||
int* major, int* minor) const;
|
||||
|
||||
// Writes to the given file. Returns false in case of error.
|
||||
bool Serialize(FILE* fp) const;
|
||||
// Reads from the given file. Returns false in case of error.
|
||||
// If swap is true, assumes a big/little-endian swap is needed.
|
||||
bool DeSerialize(bool swap, FILE* fp);
|
||||
|
||||
protected:
|
||||
inT16 xcoord; //< x value
|
||||
inT16 ycoord; //< y value
|
||||
};
|
||||
|
||||
class DLLSYM ICOORDELT:public ELIST_LINK, public ICOORD
|
||||
//embedded coord list
|
||||
{
|
||||
public:
|
||||
///empty constructor
|
||||
ICOORDELT() {
|
||||
}
|
||||
///constructor from ICOORD
|
||||
ICOORDELT (ICOORD icoord):ICOORD (icoord) {
|
||||
}
|
||||
///constructor
|
||||
///@param xin x value
|
||||
///@param yin y value
|
||||
ICOORDELT(inT16 xin,
|
||||
inT16 yin) {
|
||||
xcoord = xin;
|
||||
ycoord = yin;
|
||||
}
|
||||
|
||||
static ICOORDELT* deep_copy(const ICOORDELT* src) {
|
||||
ICOORDELT* elt = new ICOORDELT;
|
||||
*elt = *src;
|
||||
return elt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ELISTIZEH (ICOORDELT)
|
||||
class DLLSYM FCOORD
|
||||
{
|
||||
public:
|
||||
///empty constructor
|
||||
FCOORD() {
|
||||
}
|
||||
///constructor
|
||||
///@param xvalue x value
|
||||
///@param yvalue y value
|
||||
FCOORD(float xvalue,
|
||||
float yvalue) {
|
||||
xcoord = xvalue; //set coords
|
||||
ycoord = yvalue;
|
||||
}
|
||||
FCOORD( //make from ICOORD
|
||||
ICOORD icoord) { //coords to set
|
||||
xcoord = icoord.xcoord;
|
||||
ycoord = icoord.ycoord;
|
||||
}
|
||||
|
||||
float x() const { //get coords
|
||||
return xcoord;
|
||||
}
|
||||
float y() const {
|
||||
return ycoord;
|
||||
}
|
||||
///rewrite function
|
||||
void set_x(float xin) {
|
||||
xcoord = xin; //write new value
|
||||
}
|
||||
///rewrite function
|
||||
void set_y(float yin) { //value to set
|
||||
ycoord = yin;
|
||||
}
|
||||
|
||||
///find sq length
|
||||
float sqlength() const {
|
||||
return xcoord * xcoord + ycoord * ycoord;
|
||||
}
|
||||
|
||||
///find length
|
||||
float length() const {
|
||||
return (float) sqrt (sqlength ());
|
||||
}
|
||||
|
||||
///sq dist between pts
|
||||
float pt_to_pt_sqdist(const FCOORD &pt) const {
|
||||
FCOORD gap;
|
||||
|
||||
gap.xcoord = xcoord - pt.xcoord;
|
||||
gap.ycoord = ycoord - pt.ycoord;
|
||||
return gap.sqlength ();
|
||||
}
|
||||
|
||||
///Distance between pts
|
||||
float pt_to_pt_dist(const FCOORD &pt) const {
|
||||
return (float) sqrt (pt_to_pt_sqdist (pt));
|
||||
}
|
||||
|
||||
///find angle
|
||||
float angle() const {
|
||||
return (float) atan2 (ycoord, xcoord);
|
||||
}
|
||||
// Returns the standard feature direction corresponding to this.
|
||||
// See binary_angle_plus_pi below for a description of the direction.
|
||||
uinT8 to_direction() const;
|
||||
// Sets this with a unit vector in the given standard feature direction.
|
||||
void from_direction(uinT8 direction);
|
||||
|
||||
// Converts an angle in radians (from ICOORD::angle or FCOORD::angle) to a
|
||||
// standard feature direction as an unsigned angle in 256ths of a circle
|
||||
// measured anticlockwise from (-1, 0).
|
||||
static uinT8 binary_angle_plus_pi(double angle);
|
||||
// Inverse of binary_angle_plus_pi returns an angle in radians for the
|
||||
// given standard feature direction.
|
||||
static double angle_from_direction(uinT8 direction);
|
||||
// Returns the point on the given line nearest to this, ie the point such
|
||||
// that the vector point->this is perpendicular to the line.
|
||||
// The line is defined as a line_point and a dir_vector for its direction.
|
||||
// dir_vector need not be a unit vector.
|
||||
FCOORD nearest_pt_on_line(const FCOORD& line_point,
|
||||
const FCOORD& dir_vector) const;
|
||||
|
||||
///Convert to unit vec
|
||||
bool normalise();
|
||||
|
||||
///test equality
|
||||
BOOL8 operator== (const FCOORD & other) {
|
||||
return xcoord == other.xcoord && ycoord == other.ycoord;
|
||||
}
|
||||
///test inequality
|
||||
BOOL8 operator!= (const FCOORD & other) {
|
||||
return xcoord != other.xcoord || ycoord != other.ycoord;
|
||||
}
|
||||
///rotate 90 deg anti
|
||||
friend FCOORD operator! (const FCOORD &);
|
||||
///unary minus
|
||||
friend FCOORD operator- (const FCOORD &);
|
||||
///add
|
||||
friend FCOORD operator+ (const FCOORD &, const FCOORD &);
|
||||
///add
|
||||
friend FCOORD & operator+= (FCOORD &, const FCOORD &);
|
||||
///subtract
|
||||
friend FCOORD operator- (const FCOORD &, const FCOORD &);
|
||||
///subtract
|
||||
friend FCOORD & operator-= (FCOORD &, const FCOORD &);
|
||||
///scalar product
|
||||
friend float operator% (const FCOORD &, const FCOORD &);
|
||||
///cross product
|
||||
friend float operator *(const FCOORD &, const FCOORD &);
|
||||
///multiply
|
||||
friend FCOORD operator *(const FCOORD &, float);
|
||||
///multiply
|
||||
friend FCOORD operator *(float, const FCOORD &);
|
||||
|
||||
///multiply
|
||||
friend FCOORD & operator*= (FCOORD &, float);
|
||||
///divide
|
||||
friend FCOORD operator/ (const FCOORD &, float);
|
||||
///rotate
|
||||
///@param vec by vector
|
||||
void rotate(const FCOORD vec);
|
||||
// unrotate - undo a rotate(vec)
|
||||
// @param vec by vector
|
||||
void unrotate(const FCOORD &vec);
|
||||
///divide
|
||||
friend FCOORD & operator/= (FCOORD &, float);
|
||||
|
||||
private:
|
||||
float xcoord; //2 floating coords
|
||||
float ycoord;
|
||||
};
|
||||
|
||||
#include "ipoints.h" /*do inline funcs */
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
SUBDIRS =
|
||||
AM_CXXFLAGS =
|
||||
|
||||
if !NO_TESSDATA_PREFIX
|
||||
AM_CXXFLAGS += -DTESSDATA_PREFIX=@datadir@/
|
||||
endif
|
||||
|
||||
if VISIBILITY
|
||||
AM_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
AM_CPPFLAGS += -DTESS_EXPORTS
|
||||
endif
|
||||
|
||||
include_HEADERS = \
|
||||
basedir.h errcode.h fileerr.h genericvector.h helpers.h host.h memry.h \
|
||||
ndminx.h params.h ocrclass.h platform.h serialis.h strngs.h \
|
||||
tesscallback.h unichar.h unicharmap.h unicharset.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
ambigs.h bits16.h bitvector.h ccutil.h clst.h doubleptr.h elst2.h \
|
||||
elst.h genericheap.h globaloc.h hashfn.h indexmapbidi.h kdpair.h lsterr.h \
|
||||
nwmain.h object_cache.h qrsequence.h sorthelper.h stderr.h \
|
||||
scanutils.h tessdatamanager.h tprintf.h unicity_table.h unicodes.h \
|
||||
universalambigs.h
|
||||
|
||||
if !USING_MULTIPLELIBS
|
||||
noinst_LTLIBRARIES = libtesseract_ccutil.la
|
||||
else
|
||||
lib_LTLIBRARIES = libtesseract_ccutil.la
|
||||
libtesseract_ccutil_la_LDFLAGS = -version-info $(GENERIC_LIBRARY_VERSION)
|
||||
endif
|
||||
|
||||
libtesseract_ccutil_la_SOURCES = \
|
||||
ambigs.cpp basedir.cpp bits16.cpp bitvector.cpp \
|
||||
ccutil.cpp clst.cpp \
|
||||
elst2.cpp elst.cpp errcode.cpp \
|
||||
globaloc.cpp indexmapbidi.cpp \
|
||||
mainblk.cpp memry.cpp \
|
||||
serialis.cpp strngs.cpp scanutils.cpp \
|
||||
tessdatamanager.cpp tprintf.cpp \
|
||||
unichar.cpp unicharmap.cpp unicharset.cpp unicodes.cpp \
|
||||
params.cpp universalambigs.cpp
|
||||
|
||||
if T_WIN
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/vs2010/port -DWINDLLNAME=\"lib@GENERIC_LIBRARY_NAME@\"
|
||||
noinst_HEADERS += ../vs2010/port/strtok_r.h
|
||||
libtesseract_ccutil_la_SOURCES += ../vs2010/port/strtok_r.cpp
|
||||
endif
|
@ -1,29 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: bits16.h (Formerly bits8.h)
|
||||
* Description: Code for 8 bit field class.
|
||||
* Author: Phil Cheatle
|
||||
* Created: Thu Oct 17 10:10:05 BST 1991
|
||||
*
|
||||
* (C) Copyright 1991, 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 "bits16.h"
|
||||
|
||||
/**********************************************************************
|
||||
* Constructor. Something to get it past the compiler as almost all inlined.
|
||||
*
|
||||
**********************************************************************/
|
||||
BITS16::BITS16( // constructor
|
||||
uinT16 init) { // initial val
|
||||
val = init;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: hashfn.h (Formerly hash.h)
|
||||
* Description: Portability hacks for hash_map, hash_set and unique_ptr.
|
||||
* Author: Ray Smith
|
||||
* Created: Wed Jan 08 14:08:25 PST 2014
|
||||
*
|
||||
* (C) Copyright 2014, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef HASHFN_H
|
||||
#define HASHFN_H
|
||||
|
||||
#ifdef USE_STD_NAMESPACE
|
||||
#if (__cplusplus >= 201103L) || defined(_MSC_VER) // Visual Studio
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#define hash_map std::unordered_map
|
||||
#if (_MSC_VER >= 1500 && _MSC_VER < 1600) // Visual Studio 2008
|
||||
using namespace std::tr1;
|
||||
#else // _MSC_VER
|
||||
using std::unordered_map;
|
||||
using std::unordered_set;
|
||||
#include <memory>
|
||||
#define SmartPtr std::unique_ptr
|
||||
#define HAVE_UNIQUE_PTR
|
||||
#endif // _MSC_VER
|
||||
#elif (defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ > 0)) || \
|
||||
__GNUC__ >= 4)) // gcc
|
||||
// hash_set is deprecated in gcc
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
using __gnu_cxx::hash_map;
|
||||
using __gnu_cxx::hash_set;
|
||||
#define unordered_map hash_map
|
||||
#define unordered_set hash_set
|
||||
#else
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#endif // gcc
|
||||
#elif (__clang__)
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#define hash_map std::unordered_map
|
||||
#define unordered_set std::unordered_set
|
||||
#else // USE_STD_NAMESPACE
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#define unordered_map hash_map
|
||||
#define unordered_set hash_set
|
||||
#endif // USE_STD_NAMESPACE
|
||||
|
||||
#ifndef HAVE_UNIQUE_PTR
|
||||
// Trivial smart ptr. Expand to add features of std::unique_ptr as required.
|
||||
template<class T> class SmartPtr {
|
||||
public:
|
||||
SmartPtr() : ptr_(NULL) {}
|
||||
explicit SmartPtr(T* ptr) : ptr_(ptr) {}
|
||||
~SmartPtr() {
|
||||
delete ptr_;
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return ptr_;
|
||||
}
|
||||
void reset(T* ptr) {
|
||||
if (ptr_ != NULL) delete ptr_;
|
||||
ptr_ = ptr;
|
||||
}
|
||||
bool operator==(const T* ptr) const {
|
||||
return ptr_ == ptr;
|
||||
}
|
||||
T* operator->() const {
|
||||
return ptr_;
|
||||
}
|
||||
private:
|
||||
T* ptr_;
|
||||
};
|
||||
#endif // HAVE_UNIQUE_PTR
|
||||
|
||||
#endif // HASHFN_H
|
149
ccutil/host.h
149
ccutil/host.h
@ -1,149 +0,0 @@
|
||||
/******************************************************************************
|
||||
** Filename: Host.h
|
||||
** Purpose: This is the system independent typedefs and defines
|
||||
** Author: MN, JG, MD
|
||||
** Version: 5.4.1
|
||||
** History: 11/7/94 MCD received the modification that Lennart made
|
||||
** to port to 32 bit world and modify this file so that it
|
||||
** will be shared between platform.
|
||||
** 11/9/94 MCD Make MSW32 subset of MSW. Now MSW means
|
||||
** MicroSoft Window and MSW32 means the 32 bit worlds
|
||||
** of MicroSoft Window. Therefore you want the environment
|
||||
** to be MicroSoft Window and in the 32 bit world -
|
||||
** _WIN32 must be defined by your compiler.
|
||||
** 11/30/94 MCD Incorporated comments received for more
|
||||
** readability and the missing typedef for FLOAT.
|
||||
** 12/1/94 MCD Added PFVOID typedef
|
||||
** 5/1/95 MCD. Made many changes based on the inputs.
|
||||
** Changes:
|
||||
** 1) Rearrange the #ifdef so that there're definitions for
|
||||
** particular platforms.
|
||||
** 2) Took out the #define for computer and environment
|
||||
** that developer can uncomment
|
||||
** 3) Added __OLDCODE__ where the defines will be
|
||||
** obsoleted in the next version and advise not to use.
|
||||
** 4) Added the definitions for the following:
|
||||
** FILE_HANDLE, MEMORY_HANDLE, BOOL8,
|
||||
** MAX_INT8, MAX_INT16, MAX_INT32, MAX_UINT8
|
||||
** MAX_UINT16, MAX_UINT32, MAX_FLOAT32
|
||||
** 06/19/96 MCD. Took out MAX_FLOAT32
|
||||
** 07/15/96 MCD. Fixed the comments error
|
||||
** Add back BOOL8.
|
||||
**
|
||||
** (c) Copyright Hewlett-Packard Company, 1988-1996.
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifndef __HOST__
|
||||
#define __HOST__
|
||||
|
||||
/******************************************************************************
|
||||
** IMPORTANT!!! **
|
||||
** **
|
||||
** Defines either _WIN32, __MAC__, __UNIX__, __OS2__, __PM__ to
|
||||
** use the specified definitions indicated below in the preprocessor settings. **
|
||||
** **
|
||||
** Also define either __FarProc__ or __FarData__ and __MOTO__ to use the
|
||||
** specified definitions indicated below in the preprocessor settings. **
|
||||
** **
|
||||
** If a preprocessor settings is not allow in the compiler that is being use,
|
||||
** then it is recommended that a "platform.h" is created with the definition
|
||||
** of the computer and/or operating system.
|
||||
******************************************************************************/
|
||||
|
||||
#include "platform.h"
|
||||
/* _WIN32 */
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winbase.h> // winbase.h contains windows.h
|
||||
#endif
|
||||
|
||||
/********************************************************/
|
||||
/* __MAC__ */
|
||||
#ifdef __MAC__
|
||||
#include <Types.h>
|
||||
/*----------------------------*/
|
||||
/*----------------------------*/
|
||||
#endif
|
||||
/********************************************************/
|
||||
#if defined(__UNIX__) || defined( __DOS__ ) || defined(__OS2__) || defined(__PM__)
|
||||
/*----------------------------*/
|
||||
/* FarProc and FarData */
|
||||
/*----------------------------*/
|
||||
/*----------------------------*/
|
||||
#endif
|
||||
/*****************************************************************************
|
||||
**
|
||||
** Standard GHC Definitions
|
||||
**
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef __MOTO__
|
||||
#define __NATIVE__ MOTO
|
||||
#else
|
||||
#define __NATIVE__ INTEL
|
||||
#endif
|
||||
|
||||
//typedef HANDLE FD* PHANDLE;
|
||||
|
||||
// definitions of portable data types (numbers and characters)
|
||||
typedef SIGNED char inT8;
|
||||
typedef unsigned char uinT8;
|
||||
typedef short inT16;
|
||||
typedef unsigned short uinT16;
|
||||
typedef int inT32;
|
||||
typedef unsigned int uinT32;
|
||||
#if (_MSC_VER >= 1200) //%%% vkr for VC 6.0
|
||||
typedef INT64 inT64;
|
||||
typedef UINT64 uinT64;
|
||||
#else
|
||||
typedef long long int inT64;
|
||||
typedef unsigned long long int uinT64;
|
||||
#endif //%%% vkr for VC 6.0
|
||||
typedef float FLOAT32;
|
||||
typedef double FLOAT64;
|
||||
typedef unsigned char BOOL8;
|
||||
|
||||
#define INT32FORMAT "%d"
|
||||
#define INT64FORMAT "%lld"
|
||||
|
||||
#define MAX_INT8 0x7f
|
||||
#define MAX_INT16 0x7fff
|
||||
#define MAX_INT32 0x7fffffff
|
||||
#define MAX_UINT8 0xff
|
||||
#define MAX_UINT16 0xffff
|
||||
#define MAX_UINT32 0xffffffff
|
||||
#define MAX_FLOAT32 ((float)3.40282347e+38)
|
||||
|
||||
#define MIN_INT8 0x80
|
||||
#define MIN_INT16 0x8000
|
||||
#define MIN_INT32 static_cast<int>(0x80000000)
|
||||
#define MIN_UINT8 0x00
|
||||
#define MIN_UINT16 0x0000
|
||||
#define MIN_UINT32 0x00000000
|
||||
#define MIN_FLOAT32 ((float)1.17549435e-38)
|
||||
|
||||
// Defines
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
// Return true if x is within tolerance of y
|
||||
template<class T> bool NearlyEqual(T x, T y, T tolerance) {
|
||||
T diff = x - y;
|
||||
return diff <= tolerance && -diff <= tolerance;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: memry.c (Formerly memory.c)
|
||||
* Description: Memory allocation with builtin safety checks.
|
||||
* Author: Ray Smith
|
||||
* Created: Wed Jan 22 09:43:33 GMT 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 "memry.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// With improvements in OS memory allocators, internal memory management
|
||||
// is no longer required, so all these functions now map to their malloc
|
||||
// family equivalents.
|
||||
|
||||
// TODO(rays) further cleanup by redirecting calls to new and creating proper
|
||||
// constructors.
|
||||
|
||||
char *alloc_string(inT32 count) {
|
||||
// Round up the amount allocated to a multiple of 4
|
||||
return static_cast<char*>(malloc((count + 3) & ~3));
|
||||
}
|
||||
|
||||
void free_string(char *string) {
|
||||
free(string);
|
||||
}
|
||||
|
||||
void* alloc_struct(inT32 count, const char *) {
|
||||
return malloc(count);
|
||||
}
|
||||
|
||||
void free_struct(void *deadstruct, inT32, const char *) {
|
||||
free(deadstruct);
|
||||
}
|
||||
|
||||
void *alloc_mem(inT32 count) {
|
||||
return malloc(static_cast<size_t>(count));
|
||||
}
|
||||
|
||||
void *alloc_big_zeros(inT32 count) {
|
||||
return calloc(static_cast<size_t>(count), 1);
|
||||
}
|
||||
|
||||
void free_mem(void *oldchunk) {
|
||||
free(oldchunk);
|
||||
}
|
||||
|
||||
void free_big_mem(void *oldchunk) {
|
||||
free(oldchunk);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: memry.h (Formerly memory.h)
|
||||
* Description: Header file for basic memory allocation/deallocation.
|
||||
* Author: Ray Smith
|
||||
* Created: Tue May 8 16:03:48 BST 1990
|
||||
*
|
||||
* (C) Copyright 1990, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MEMRY_H
|
||||
#define MEMRY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "host.h"
|
||||
|
||||
// allocate string
|
||||
extern char *alloc_string(inT32 count);
|
||||
// free a string.
|
||||
extern void free_string(char *string);
|
||||
// allocate memory
|
||||
extern void *alloc_struct(inT32 count, const char *name = NULL);
|
||||
// free a structure.
|
||||
extern void free_struct(void *deadstruct, inT32, const char *name = NULL);
|
||||
// get some memory
|
||||
extern void *alloc_mem(inT32 count);
|
||||
// get some memory initialized to 0.
|
||||
extern void *alloc_big_zeros(inT32 count);
|
||||
// free mem from alloc_mem
|
||||
extern void free_mem(void *oldchunk);
|
||||
// free mem from alloc_big_zeros
|
||||
extern void free_big_mem(void *oldchunk);
|
||||
|
||||
#endif
|
175
ccutil/nwmain.h
175
ccutil/nwmain.h
@ -1,175 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: nwmain.h
|
||||
* Description: Tool to declare main, making windows invisible.
|
||||
* Author: Ray Smith
|
||||
* Created: Fri Sep 07 13:27:50 MDT 1995
|
||||
*
|
||||
* (C) Copyright 1995, Hewlett-Packard Co.
|
||||
** 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef RUNMAIN_H
|
||||
#define RUNMAIN_H
|
||||
|
||||
#include "host.h"
|
||||
#include "params.h"
|
||||
|
||||
#define DECLARE_MAIN(ARGC,ARGV)\
|
||||
STRING_VAR(init_config_file,"config","Config file to read on startup");\
|
||||
REALLY_DECLARE_MAIN(ARGC,ARGV)
|
||||
|
||||
#define DECLARE_MAIN_CONFIG(ARGC,ARGV,NAME)\
|
||||
STRING_VAR(init_config_file,NAME,"Config file to read on startup");\
|
||||
REALLY_DECLARE_MAIN(ARGC,ARGV)
|
||||
|
||||
#ifndef __UNIX__
|
||||
|
||||
#define REALLY_DECLARE_MAIN(ARGC,ARGV)\
|
||||
\
|
||||
/**********************************************************************\
|
||||
* parse_args\
|
||||
*\
|
||||
* Turn a list of args into a new list of args with each separate\
|
||||
* whitespace spaced string being an arg.\
|
||||
**********************************************************************/\
|
||||
\
|
||||
inT32 parse_args( /*refine arg list*/\
|
||||
inT32 argc, /*no of input args*/\
|
||||
char *argv[], /*input args*/\
|
||||
char *arglist[] /*output args*/\
|
||||
)\
|
||||
{\
|
||||
inT32 argcount; /*converted argc*/\
|
||||
char *testchar; /*char in option string*/\
|
||||
inT32 arg; /*current argument*/\
|
||||
\
|
||||
argcount=0; /*no of options*/\
|
||||
for (arg=0;arg<argc;arg++)\
|
||||
{\
|
||||
testchar=argv[arg]; /*start of arg*/\
|
||||
do\
|
||||
{\
|
||||
while (*testchar\
|
||||
&& (*testchar==' ' || *testchar=='"' || *testchar=='\n' || *testchar=='\t'))\
|
||||
testchar++; /*skip white space*/\
|
||||
if (*testchar)\
|
||||
{\
|
||||
arglist[argcount++]=testchar; /*new arg*/\
|
||||
do\
|
||||
{\
|
||||
for (testchar++;*testchar\
|
||||
&& *testchar!=' ' && *testchar!='"' && *testchar!='\n' && *testchar!='\t';\
|
||||
testchar++); /*skip to white space*/\
|
||||
}\
|
||||
while (*testchar=='"' && testchar[1]!=' ' && testchar[1]!='\0' && testchar[1]!='\n' && testchar[1]!='\t');\
|
||||
if (*testchar)\
|
||||
*testchar++='\0'; /*turn to separate args*/\
|
||||
}\
|
||||
}\
|
||||
while (*testchar);\
|
||||
}\
|
||||
return argcount; /*new number of args*/\
|
||||
}\
|
||||
\
|
||||
inT32 global_exit_code;\
|
||||
inT32 real_main(inT32,const char**);\
|
||||
\
|
||||
inT32 run_main( /*the main thread*/\
|
||||
CWinApp* theapp /*arguments*/\
|
||||
)\
|
||||
{\
|
||||
char **argv;\
|
||||
char *argsin[2];\
|
||||
inT32 argc;\
|
||||
inT32 exit_code;\
|
||||
\
|
||||
argsin[0]=strdup(theapp->m_pszExeName);\
|
||||
argsin[1]=strdup(theapp->m_lpCmdLine);\
|
||||
/*allocate memory for the args. There can never be more than half*/\
|
||||
/*the total number of characters in the arguments.*/\
|
||||
argv=(char**)malloc(((strlen(argsin[0])+strlen(argsin[1]))/2+1)*sizeof(char*));\
|
||||
\
|
||||
/*now construct argv as it should be for C.*/\
|
||||
argc=parse_args(2,argsin,argv);\
|
||||
\
|
||||
/*call main(argc,argv) here*/\
|
||||
exit_code=real_main(argc,(const char **)argv);\
|
||||
\
|
||||
\
|
||||
/*now get rid of the main app window*/\
|
||||
if (theapp!=NULL && theapp->m_pMainWnd!=NULL)\
|
||||
PostMessage(theapp->m_pMainWnd->m_hWnd,WM_QUIT,0,0);\
|
||||
free(argsin[0]);\
|
||||
free(argsin[1]);\
|
||||
free(argv);\
|
||||
global_exit_code=exit_code;\
|
||||
return exit_code;\
|
||||
}\
|
||||
\
|
||||
inT32 real_main(inT32 ARGC,const char* ARGV[])\
|
||||
|
||||
#else
|
||||
|
||||
#define REALLY_DECLARE_MAIN(ARGC,ARGV)\
|
||||
\
|
||||
/**********************************************************************\
|
||||
* parse_args\
|
||||
*\
|
||||
* Turn a list of args into a new list of args with each separate\
|
||||
* whitespace spaced string being an arg.\
|
||||
**********************************************************************/\
|
||||
\
|
||||
inT32 parse_args( /*refine arg list*/\
|
||||
inT32 argc, /*no of input args*/\
|
||||
char *argv[], /*input args*/\
|
||||
char *arglist[] /*output args*/\
|
||||
)\
|
||||
{\
|
||||
inT32 argcount; /*converted argc*/\
|
||||
char *testchar; /*char in option string*/\
|
||||
inT32 arg; /*current argument*/\
|
||||
\
|
||||
argcount=0; /*no of options*/\
|
||||
for (arg=0;arg<argc;arg++)\
|
||||
{\
|
||||
testchar=argv[arg]; /*start of arg*/\
|
||||
do\
|
||||
{\
|
||||
while (*testchar\
|
||||
&& (*testchar==' ' || *testchar=='"' || *testchar=='\n' || *testchar=='\t'))\
|
||||
testchar++; /*skip white space*/\
|
||||
if (*testchar)\
|
||||
{\
|
||||
arglist[argcount++]=testchar; /*new arg*/\
|
||||
do\
|
||||
{\
|
||||
for (testchar++;*testchar\
|
||||
&& *testchar!=' ' && *testchar!='"' && *testchar!='\n' && *testchar!='\t';\
|
||||
testchar++); /*skip to white space*/\
|
||||
}\
|
||||
while (*testchar=='"' && testchar[1]!=' ' && testchar[1]!='\0' && testchar[1]!='\n' && testchar[1]!='\t');\
|
||||
if (*testchar)\
|
||||
*testchar++='\0'; /*turn to separate args*/\
|
||||
}\
|
||||
}\
|
||||
while (*testchar);\
|
||||
}\
|
||||
return argcount; /*new number of args*/\
|
||||
}\
|
||||
\
|
||||
inT32 main(inT32 ARGC,const char* ARGV[])\
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "NOT allowed to include nwmain.h or runmain.h twice!!"
|
||||
#endif
|
@ -1,145 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: serialis.h (Formerly serialmac.h)
|
||||
* Description: Inline routines and macros for serialisation functions
|
||||
* Author: Phil Cheatle
|
||||
* Created: Tue Oct 08 08:33:12 BST 1991
|
||||
*
|
||||
* (C) Copyright 1990, 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 "serialis.h"
|
||||
#include <stdio.h>
|
||||
#include "genericvector.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
TFile::TFile()
|
||||
: offset_(0), data_(NULL), data_is_owned_(false), is_writing_(false) {
|
||||
}
|
||||
|
||||
TFile::~TFile() {
|
||||
if (data_is_owned_)
|
||||
delete data_;
|
||||
}
|
||||
|
||||
bool TFile::Open(const STRING& filename, FileReader reader) {
|
||||
if (!data_is_owned_) {
|
||||
data_ = new GenericVector<char>;
|
||||
data_is_owned_ = true;
|
||||
}
|
||||
offset_ = 0;
|
||||
is_writing_ = false;
|
||||
if (reader == NULL)
|
||||
return LoadDataFromFile(filename, data_);
|
||||
else
|
||||
return (*reader)(filename, data_);
|
||||
}
|
||||
|
||||
bool TFile::Open(const char* data, int size) {
|
||||
offset_ = 0;
|
||||
if (!data_is_owned_) {
|
||||
data_ = new GenericVector<char>;
|
||||
data_is_owned_ = true;
|
||||
}
|
||||
is_writing_ = false;
|
||||
data_->init_to_size(size, 0);
|
||||
memcpy(&(*data_)[0], data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TFile::Open(FILE* fp, inT64 end_offset) {
|
||||
offset_ = 0;
|
||||
inT64 current_pos = ftell(fp);
|
||||
if (end_offset < 0) {
|
||||
if (fseek(fp, 0, SEEK_END))
|
||||
return false;
|
||||
end_offset = ftell(fp);
|
||||
if (fseek(fp, current_pos, SEEK_SET))
|
||||
return false;
|
||||
}
|
||||
int size = end_offset - current_pos;
|
||||
is_writing_ = false;
|
||||
if (!data_is_owned_) {
|
||||
data_ = new GenericVector<char>;
|
||||
data_is_owned_ = true;
|
||||
}
|
||||
data_->init_to_size(size, 0);
|
||||
return static_cast<int>(fread(&(*data_)[0], 1, size, fp)) == size;
|
||||
}
|
||||
|
||||
char* TFile::FGets(char* buffer, int buffer_size) {
|
||||
ASSERT_HOST(!is_writing_);
|
||||
int size = 0;
|
||||
while (size + 1 < buffer_size && offset_ < data_->size()) {
|
||||
buffer[size++] = (*data_)[offset_++];
|
||||
if ((*data_)[offset_ - 1] == '\n') break;
|
||||
}
|
||||
if (size < buffer_size) buffer[size] = '\0';
|
||||
return size > 0 ? buffer : NULL;
|
||||
}
|
||||
|
||||
int TFile::FRead(void* buffer, int size, int count) {
|
||||
ASSERT_HOST(!is_writing_);
|
||||
int required_size = size * count;
|
||||
if (required_size <= 0) return 0;
|
||||
char* char_buffer = reinterpret_cast<char*>(buffer);
|
||||
if (data_->size() - offset_ < required_size)
|
||||
required_size = data_->size() - offset_;
|
||||
if (required_size > 0)
|
||||
memcpy(char_buffer, &(*data_)[offset_], required_size);
|
||||
offset_ += required_size;
|
||||
return required_size / size;
|
||||
}
|
||||
|
||||
void TFile::Rewind() {
|
||||
ASSERT_HOST(!is_writing_);
|
||||
offset_ = 0;
|
||||
}
|
||||
|
||||
void TFile::OpenWrite(GenericVector<char>* data) {
|
||||
offset_ = 0;
|
||||
if (data != NULL) {
|
||||
if (data_is_owned_) delete data_;
|
||||
data_ = data;
|
||||
data_is_owned_ = false;
|
||||
} else if (!data_is_owned_) {
|
||||
data_ = new GenericVector<char>;
|
||||
data_is_owned_ = true;
|
||||
}
|
||||
is_writing_ = true;
|
||||
data_->truncate(0);
|
||||
}
|
||||
|
||||
bool TFile::CloseWrite(const STRING& filename, FileWriter writer) {
|
||||
ASSERT_HOST(is_writing_);
|
||||
if (writer == NULL)
|
||||
return SaveDataToFile(*data_, filename);
|
||||
else
|
||||
return (*writer)(*data_, filename);
|
||||
}
|
||||
|
||||
int TFile::FWrite(const void* buffer, int size, int count) {
|
||||
ASSERT_HOST(is_writing_);
|
||||
int total = size * count;
|
||||
if (total <= 0) return 0;
|
||||
const char* buf = reinterpret_cast<const char*>(buffer);
|
||||
// This isn't very efficient, but memory is so fast compared to disk
|
||||
// that it is relatively unimportant, and very simple.
|
||||
for (int i = 0; i < total; ++i)
|
||||
data_->push_back(buf[i]);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
} // namespace tesseract.
|
||||
|
@ -1,99 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: serialis.h (Formerly serialmac.h)
|
||||
* Description: Inline routines and macros for serialisation functions
|
||||
* Author: Phil Cheatle
|
||||
* Created: Tue Oct 08 08:33:12 BST 1991
|
||||
*
|
||||
* (C) Copyright 1990, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SERIALIS_H
|
||||
#define SERIALIS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "host.h"
|
||||
|
||||
template <typename T> class GenericVector;
|
||||
class STRING;
|
||||
|
||||
/***********************************************************************
|
||||
QUOTE_IT MACRO DEFINITION
|
||||
===========================
|
||||
Replace <parm> with "<parm>". <parm> may be an arbitrary number of tokens
|
||||
***********************************************************************/
|
||||
|
||||
#define QUOTE_IT( parm ) #parm
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// Function to read a GenericVector<char> from a whole file.
|
||||
// Returns false on failure.
|
||||
typedef bool (*FileReader)(const STRING& filename, GenericVector<char>* data);
|
||||
// Function to write a GenericVector<char> to a whole file.
|
||||
// Returns false on failure.
|
||||
typedef bool (*FileWriter)(const GenericVector<char>& data,
|
||||
const STRING& filename);
|
||||
|
||||
// Simple file class.
|
||||
// Allows for portable file input from memory and from foreign file systems.
|
||||
class TFile {
|
||||
public:
|
||||
TFile();
|
||||
~TFile();
|
||||
|
||||
// All the Open methods load the whole file into memory for reading.
|
||||
// Opens a file with a supplied reader, or NULL to use the default.
|
||||
// Note that mixed read/write is not supported.
|
||||
bool Open(const STRING& filename, FileReader reader);
|
||||
// From an existing memory buffer.
|
||||
bool Open(const char* data, int size);
|
||||
// From an open file and an end offset.
|
||||
bool Open(FILE* fp, inT64 end_offset);
|
||||
|
||||
// Reads a line like fgets. Returns NULL on EOF, otherwise buffer.
|
||||
// Reads at most buffer_size bytes, including '\0' terminator, even if
|
||||
// the line is longer. Does nothing if buffer_size <= 0.
|
||||
// To use fscanf use FGets and sscanf.
|
||||
char* FGets(char* buffer, int buffer_size);
|
||||
// Replicates fread, returning the number of items read.
|
||||
int FRead(void* buffer, int size, int count);
|
||||
// Resets the TFile as if it has been Opened, but nothing read.
|
||||
// Only allowed while reading!
|
||||
void Rewind();
|
||||
|
||||
// Open for writing. Either supply a non-NULL data with OpenWrite before
|
||||
// calling FWrite, (no close required), or supply a NULL data to OpenWrite
|
||||
// and call CloseWrite to write to a file after the FWrites.
|
||||
void OpenWrite(GenericVector<char>* data);
|
||||
bool CloseWrite(const STRING& filename, FileWriter writer);
|
||||
|
||||
// Replicates fwrite, returning the number of items written.
|
||||
// To use fprintf, use snprintf and FWrite.
|
||||
int FWrite(const void* buffer, int size, int count);
|
||||
|
||||
private:
|
||||
// The number of bytes used so far.
|
||||
int offset_;
|
||||
// The buffered data from the file.
|
||||
GenericVector<char>* data_;
|
||||
// True if the data_ pointer is owned by *this.
|
||||
bool data_is_owned_;
|
||||
// True if the TFile is open for writing.
|
||||
bool is_writing_;
|
||||
};
|
||||
|
||||
} // namespace tesseract.
|
||||
|
||||
#endif
|
@ -1,26 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: stderr.h (Formerly stderrs.h)
|
||||
* Description: File defining error messages fundamental of commonly used.
|
||||
* Author: Ray Smith
|
||||
* Created: Fri Aug 10 15:23:14 BST 1990
|
||||
*
|
||||
* (C) Copyright 1990, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef STDERR_H
|
||||
#define STDERR_H
|
||||
|
||||
#include "errcode.h"
|
||||
|
||||
const ERRCODE MEMORY_OUT = "Out of memory";
|
||||
#endif
|
@ -1,279 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// File: tessdatamanager.cpp
|
||||
// Description: Functions to handle loading/combining tesseract data files.
|
||||
// Author: Daria Antonova
|
||||
// Created: Wed Jun 03 11:26:43 PST 2009
|
||||
//
|
||||
// (C) Copyright 2009, 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4244) // Conversion warnings
|
||||
#endif
|
||||
|
||||
#include "tessdatamanager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "helpers.h"
|
||||
#include "serialis.h"
|
||||
#include "strngs.h"
|
||||
#include "tprintf.h"
|
||||
#include "params.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
bool TessdataManager::Init(const char *data_file_name, int debug_level) {
|
||||
int i;
|
||||
debug_level_ = debug_level;
|
||||
data_file_name_ = data_file_name;
|
||||
data_file_ = fopen(data_file_name, "rb");
|
||||
if (data_file_ == NULL) {
|
||||
tprintf("Error opening data file %s\n", data_file_name);
|
||||
tprintf("Please make sure the TESSDATA_PREFIX environment variable is set "
|
||||
"to the parent directory of your \"tessdata\" directory.\n");
|
||||
return false;
|
||||
}
|
||||
fread(&actual_tessdata_num_entries_, sizeof(inT32), 1, data_file_);
|
||||
swap_ = (actual_tessdata_num_entries_ > kMaxNumTessdataEntries);
|
||||
if (swap_) {
|
||||
ReverseN(&actual_tessdata_num_entries_,
|
||||
sizeof(actual_tessdata_num_entries_));
|
||||
}
|
||||
if (actual_tessdata_num_entries_ > TESSDATA_NUM_ENTRIES) {
|
||||
// For forward compatibility, truncate to the number we can handle.
|
||||
actual_tessdata_num_entries_ = TESSDATA_NUM_ENTRIES;
|
||||
}
|
||||
fread(offset_table_, sizeof(inT64),
|
||||
actual_tessdata_num_entries_, data_file_);
|
||||
if (swap_) {
|
||||
for (i = 0 ; i < actual_tessdata_num_entries_; ++i) {
|
||||
ReverseN(&offset_table_[i], sizeof(offset_table_[i]));
|
||||
}
|
||||
}
|
||||
if (debug_level_) {
|
||||
tprintf("TessdataManager loaded %d types of tesseract data files.\n",
|
||||
actual_tessdata_num_entries_);
|
||||
for (i = 0; i < actual_tessdata_num_entries_; ++i) {
|
||||
tprintf("Offset for type %d is %lld\n", i, offset_table_[i]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TessdataManager::CopyFile(FILE *input_file, FILE *output_file,
|
||||
bool newline_end, inT64 num_bytes_to_copy) {
|
||||
if (num_bytes_to_copy == 0) return;
|
||||
int buffer_size = 1024;
|
||||
if (num_bytes_to_copy > 0 && buffer_size > num_bytes_to_copy) {
|
||||
buffer_size = num_bytes_to_copy;
|
||||
}
|
||||
inT64 num_bytes_copied = 0;
|
||||
char *chunk = new char[buffer_size];
|
||||
int bytes_read;
|
||||
char last_char = 0x0;
|
||||
while ((bytes_read = fread(chunk, sizeof(char),
|
||||
buffer_size, input_file))) {
|
||||
fwrite(chunk, sizeof(char), bytes_read, output_file);
|
||||
last_char = chunk[bytes_read-1];
|
||||
if (num_bytes_to_copy > 0) {
|
||||
num_bytes_copied += bytes_read;
|
||||
if (num_bytes_copied == num_bytes_to_copy) break;
|
||||
if (num_bytes_copied + buffer_size > num_bytes_to_copy) {
|
||||
buffer_size = num_bytes_to_copy - num_bytes_copied;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newline_end) ASSERT_HOST(last_char == '\n');
|
||||
delete[] chunk;
|
||||
}
|
||||
|
||||
bool TessdataManager::WriteMetadata(inT64 *offset_table,
|
||||
const char * language_data_path_prefix,
|
||||
FILE *output_file) {
|
||||
inT32 num_entries = TESSDATA_NUM_ENTRIES;
|
||||
bool result = true;
|
||||
if (fseek(output_file, 0, SEEK_SET) != 0 ||
|
||||
fwrite(&num_entries, sizeof(inT32), 1, output_file) != 1 ||
|
||||
fwrite(offset_table, sizeof(inT64), TESSDATA_NUM_ENTRIES,
|
||||
output_file) != TESSDATA_NUM_ENTRIES) {
|
||||
fclose(output_file);
|
||||
result = false;
|
||||
tprintf("WriteMetadata failed in TessdataManager!\n");
|
||||
} else if (fclose(output_file)) {
|
||||
result = false;
|
||||
tprintf("WriteMetadata failed to close file!\n");
|
||||
} else {
|
||||
tprintf("TessdataManager combined tesseract data files.\n");
|
||||
for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
|
||||
tprintf("Offset for type %2d (%s%-22s) is %lld\n", i,
|
||||
language_data_path_prefix, kTessdataFileSuffixes[i],
|
||||
offset_table[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TessdataManager::CombineDataFiles(
|
||||
const char *language_data_path_prefix,
|
||||
const char *output_filename) {
|
||||
int i;
|
||||
inT64 offset_table[TESSDATA_NUM_ENTRIES];
|
||||
for (i = 0; i < TESSDATA_NUM_ENTRIES; ++i) offset_table[i] = -1;
|
||||
FILE *output_file = fopen(output_filename, "wb");
|
||||
if (output_file == NULL) {
|
||||
tprintf("Error opening %s for writing\n", output_filename);
|
||||
return false;
|
||||
}
|
||||
// Leave some space for recording the offset_table.
|
||||
if (fseek(output_file,
|
||||
sizeof(inT32) + sizeof(inT64) * TESSDATA_NUM_ENTRIES, SEEK_SET)) {
|
||||
tprintf("Error seeking %s\n", output_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
TessdataType type = TESSDATA_NUM_ENTRIES;
|
||||
bool text_file = false;
|
||||
FILE *file_ptr[TESSDATA_NUM_ENTRIES];
|
||||
|
||||
// Load individual tessdata components from files.
|
||||
for (i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
|
||||
ASSERT_HOST(TessdataTypeFromFileSuffix(
|
||||
kTessdataFileSuffixes[i], &type, &text_file));
|
||||
STRING filename = language_data_path_prefix;
|
||||
filename += kTessdataFileSuffixes[i];
|
||||
file_ptr[i] = fopen(filename.string(), "rb");
|
||||
if (file_ptr[i] != NULL) {
|
||||
offset_table[type] = ftell(output_file);
|
||||
CopyFile(file_ptr[i], output_file, text_file, -1);
|
||||
fclose(file_ptr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the required components are present.
|
||||
if (file_ptr[TESSDATA_UNICHARSET] == NULL) {
|
||||
tprintf("Error opening %sunicharset file\n", language_data_path_prefix);
|
||||
fclose(output_file);
|
||||
return false;
|
||||
}
|
||||
if (file_ptr[TESSDATA_INTTEMP] != NULL &&
|
||||
(file_ptr[TESSDATA_PFFMTABLE] == NULL ||
|
||||
file_ptr[TESSDATA_NORMPROTO] == NULL)) {
|
||||
tprintf("Error opening %spffmtable and/or %snormproto files"
|
||||
" while %sinttemp file was present\n", language_data_path_prefix,
|
||||
language_data_path_prefix, language_data_path_prefix);
|
||||
fclose(output_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
return WriteMetadata(offset_table, language_data_path_prefix, output_file);
|
||||
}
|
||||
|
||||
bool TessdataManager::OverwriteComponents(
|
||||
const char *new_traineddata_filename,
|
||||
char **component_filenames,
|
||||
int num_new_components) {
|
||||
int i;
|
||||
inT64 offset_table[TESSDATA_NUM_ENTRIES];
|
||||
TessdataType type = TESSDATA_NUM_ENTRIES;
|
||||
bool text_file = false;
|
||||
FILE *file_ptr[TESSDATA_NUM_ENTRIES];
|
||||
for (i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
|
||||
offset_table[i] = -1;
|
||||
file_ptr[i] = NULL;
|
||||
}
|
||||
FILE *output_file = fopen(new_traineddata_filename, "wb");
|
||||
if (output_file == NULL) {
|
||||
tprintf("Error opening %s for writing\n", new_traineddata_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Leave some space for recording the offset_table.
|
||||
if (fseek(output_file,
|
||||
sizeof(inT32) + sizeof(inT64) * TESSDATA_NUM_ENTRIES, SEEK_SET)) {
|
||||
fclose(output_file);
|
||||
tprintf("Error seeking %s\n", new_traineddata_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the files with the new components.
|
||||
for (i = 0; i < num_new_components; ++i) {
|
||||
if (TessdataTypeFromFileName(component_filenames[i], &type, &text_file))
|
||||
file_ptr[type] = fopen(component_filenames[i], "rb");
|
||||
}
|
||||
|
||||
// Write updated data to the output traineddata file.
|
||||
for (i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
|
||||
if (file_ptr[i] != NULL) {
|
||||
// Get the data from the opened component file.
|
||||
offset_table[i] = ftell(output_file);
|
||||
CopyFile(file_ptr[i], output_file, kTessdataFileIsText[i], -1);
|
||||
fclose(file_ptr[i]);
|
||||
} else {
|
||||
// Get this data component from the loaded data file.
|
||||
if (SeekToStart(static_cast<TessdataType>(i))) {
|
||||
offset_table[i] = ftell(output_file);
|
||||
CopyFile(data_file_, output_file, kTessdataFileIsText[i],
|
||||
GetEndOffset(static_cast<TessdataType>(i)) -
|
||||
ftell(data_file_) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
const char *language_data_path_prefix = strchr(new_traineddata_filename, '.');
|
||||
return WriteMetadata(offset_table, language_data_path_prefix, output_file);
|
||||
}
|
||||
|
||||
bool TessdataManager::TessdataTypeFromFileSuffix(
|
||||
const char *suffix, TessdataType *type, bool *text_file) {
|
||||
for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
|
||||
if (strcmp(kTessdataFileSuffixes[i], suffix) == 0) {
|
||||
*type = static_cast<TessdataType>(i);
|
||||
*text_file = kTessdataFileIsText[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
tprintf("TessdataManager can't determine which tessdata"
|
||||
" component is represented by %s\n", suffix);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TessdataManager::TessdataTypeFromFileName(
|
||||
const char *filename, TessdataType *type, bool *text_file) {
|
||||
// Get the file suffix (extension)
|
||||
const char *suffix = strrchr(filename, '.');
|
||||
if (suffix == NULL || *(++suffix) == '\0') return false;
|
||||
return TessdataTypeFromFileSuffix(suffix, type, text_file);
|
||||
}
|
||||
|
||||
bool TessdataManager::ExtractToFile(const char *filename) {
|
||||
TessdataType type = TESSDATA_NUM_ENTRIES;
|
||||
bool text_file = false;
|
||||
ASSERT_HOST(tesseract::TessdataManager::TessdataTypeFromFileName(
|
||||
filename, &type, &text_file));
|
||||
if (!SeekToStart(type)) return false;
|
||||
|
||||
FILE *output_file = fopen(filename, "wb");
|
||||
if (output_file == NULL) {
|
||||
tprintf("Error opening %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
inT64 begin_offset = ftell(GetDataFilePtr());
|
||||
inT64 end_offset = GetEndOffset(type);
|
||||
tesseract::TessdataManager::CopyFile(
|
||||
GetDataFilePtr(), output_file, text_file,
|
||||
end_offset - begin_offset + 1);
|
||||
fclose(output_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace tesseract
|
@ -1,299 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// File: tessdatamanager.h
|
||||
// Description: Functions to handle loading/combining tesseract data files.
|
||||
// Author: Daria Antonova
|
||||
// Created: Wed Jun 03 11:26:43 PST 2009
|
||||
//
|
||||
// (C) Copyright 2009, 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TESSERACT_CCUTIL_TESSDATAMANAGER_H_
|
||||
#define TESSERACT_CCUTIL_TESSDATAMANAGER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "host.h"
|
||||
#include "strngs.h"
|
||||
#include "tprintf.h"
|
||||
|
||||
static const char kTrainedDataSuffix[] = "traineddata";
|
||||
|
||||
// When adding new tessdata types and file suffixes, please make sure to
|
||||
// update TessdataType enum, kTessdataFileSuffixes and kTessdataFileIsText.
|
||||
static const char kLangConfigFileSuffix[] = "config";
|
||||
static const char kUnicharsetFileSuffix[] = "unicharset";
|
||||
static const char kAmbigsFileSuffix[] = "unicharambigs";
|
||||
static const char kBuiltInTemplatesFileSuffix[] = "inttemp";
|
||||
static const char kBuiltInCutoffsFileSuffix[] = "pffmtable";
|
||||
static const char kNormProtoFileSuffix[] = "normproto";
|
||||
static const char kPuncDawgFileSuffix[] = "punc-dawg";
|
||||
static const char kSystemDawgFileSuffix[] = "word-dawg";
|
||||
static const char kNumberDawgFileSuffix[] = "number-dawg";
|
||||
static const char kFreqDawgFileSuffix[] = "freq-dawg";
|
||||
static const char kFixedLengthDawgsFileSuffix[] = "fixed-length-dawgs";
|
||||
static const char kCubeUnicharsetFileSuffix[] = "cube-unicharset";
|
||||
static const char kCubeSystemDawgFileSuffix[] = "cube-word-dawg";
|
||||
static const char kShapeTableFileSuffix[] = "shapetable";
|
||||
static const char kBigramDawgFileSuffix[] = "bigram-dawg";
|
||||
static const char kUnambigDawgFileSuffix[] = "unambig-dawg";
|
||||
static const char kParamsModelFileSuffix[] = "params-model";
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
enum TessdataType {
|
||||
TESSDATA_LANG_CONFIG, // 0
|
||||
TESSDATA_UNICHARSET, // 1
|
||||
TESSDATA_AMBIGS, // 2
|
||||
TESSDATA_INTTEMP, // 3
|
||||
TESSDATA_PFFMTABLE, // 4
|
||||
TESSDATA_NORMPROTO, // 5
|
||||
TESSDATA_PUNC_DAWG, // 6
|
||||
TESSDATA_SYSTEM_DAWG, // 7
|
||||
TESSDATA_NUMBER_DAWG, // 8
|
||||
TESSDATA_FREQ_DAWG, // 9
|
||||
TESSDATA_FIXED_LENGTH_DAWGS, // 10 // deprecated
|
||||
TESSDATA_CUBE_UNICHARSET, // 11
|
||||
TESSDATA_CUBE_SYSTEM_DAWG, // 12
|
||||
TESSDATA_SHAPE_TABLE, // 13
|
||||
TESSDATA_BIGRAM_DAWG, // 14
|
||||
TESSDATA_UNAMBIG_DAWG, // 15
|
||||
TESSDATA_PARAMS_MODEL, // 16
|
||||
|
||||
TESSDATA_NUM_ENTRIES
|
||||
};
|
||||
|
||||
/**
|
||||
* kTessdataFileSuffixes[i] indicates the file suffix for
|
||||
* tessdata of type i (from TessdataType enum).
|
||||
*/
|
||||
static const char * const kTessdataFileSuffixes[] = {
|
||||
kLangConfigFileSuffix, // 0
|
||||
kUnicharsetFileSuffix, // 1
|
||||
kAmbigsFileSuffix, // 2
|
||||
kBuiltInTemplatesFileSuffix, // 3
|
||||
kBuiltInCutoffsFileSuffix, // 4
|
||||
kNormProtoFileSuffix, // 5
|
||||
kPuncDawgFileSuffix, // 6
|
||||
kSystemDawgFileSuffix, // 7
|
||||
kNumberDawgFileSuffix, // 8
|
||||
kFreqDawgFileSuffix, // 9
|
||||
kFixedLengthDawgsFileSuffix, // 10 // deprecated
|
||||
kCubeUnicharsetFileSuffix, // 11
|
||||
kCubeSystemDawgFileSuffix, // 12
|
||||
kShapeTableFileSuffix, // 13
|
||||
kBigramDawgFileSuffix, // 14
|
||||
kUnambigDawgFileSuffix, // 15
|
||||
kParamsModelFileSuffix, // 16
|
||||
};
|
||||
|
||||
/**
|
||||
* If kTessdataFileIsText[i] is true - the tessdata component
|
||||
* of type i (from TessdataType enum) is text, and is binary otherwise.
|
||||
*/
|
||||
static const bool kTessdataFileIsText[] = {
|
||||
true, // 0
|
||||
true, // 1
|
||||
true, // 2
|
||||
false, // 3
|
||||
true, // 4
|
||||
true, // 5
|
||||
false, // 6
|
||||
false, // 7
|
||||
false, // 8
|
||||
false, // 9
|
||||
false, // 10 // deprecated
|
||||
true, // 11
|
||||
false, // 12
|
||||
false, // 13
|
||||
false, // 14
|
||||
false, // 15
|
||||
true, // 16
|
||||
};
|
||||
|
||||
/**
|
||||
* TessdataType could be updated to contain more entries, however
|
||||
* we do not expect that number to be astronomically high.
|
||||
* In order to automatically detect endianness TessdataManager will
|
||||
* flip the bits if actual_tessdata_num_entries_ is larger than
|
||||
* kMaxNumTessdataEntries.
|
||||
*/
|
||||
static const int kMaxNumTessdataEntries = 1000;
|
||||
|
||||
|
||||
class TessdataManager {
|
||||
public:
|
||||
TessdataManager() {
|
||||
data_file_ = NULL;
|
||||
actual_tessdata_num_entries_ = 0;
|
||||
for (int i = 0; i < TESSDATA_NUM_ENTRIES; ++i) {
|
||||
offset_table_[i] = -1;
|
||||
}
|
||||
}
|
||||
~TessdataManager() {}
|
||||
int DebugLevel() { return debug_level_; }
|
||||
|
||||
/**
|
||||
* Opens the given data file and reads the offset table.
|
||||
* @return true on success.
|
||||
*/
|
||||
bool Init(const char *data_file_name, int debug_level);
|
||||
|
||||
// Return the name of the underlying data file.
|
||||
const STRING &GetDataFileName() const { return data_file_name_; }
|
||||
|
||||
/** Returns data file pointer. */
|
||||
inline FILE *GetDataFilePtr() const { return data_file_; }
|
||||
|
||||
/**
|
||||
* Returns false if there is no data of the given type.
|
||||
* Otherwise does a seek on the data_file_ to position the pointer
|
||||
* at the start of the data of the given type.
|
||||
*/
|
||||
inline bool SeekToStart(TessdataType tessdata_type) {
|
||||
if (debug_level_) {
|
||||
tprintf("TessdataManager: seek to offset %lld - start of tessdata"
|
||||
"type %d (%s))\n", offset_table_[tessdata_type],
|
||||
tessdata_type, kTessdataFileSuffixes[tessdata_type]);
|
||||
}
|
||||
if (offset_table_[tessdata_type] < 0) {
|
||||
return false;
|
||||
} else {
|
||||
ASSERT_HOST(fseek(data_file_,
|
||||
static_cast<size_t>(offset_table_[tessdata_type]),
|
||||
SEEK_SET) == 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/** Returns the end offset for the given tesseract data file type. */
|
||||
inline inT64 GetEndOffset(TessdataType tessdata_type) const {
|
||||
int index = tessdata_type + 1;
|
||||
while (index < actual_tessdata_num_entries_ && offset_table_[index] == -1) {
|
||||
++index; // skip tessdata types not present in the combined file
|
||||
}
|
||||
if (debug_level_) {
|
||||
tprintf("TessdataManager: end offset for type %d is %lld\n",
|
||||
tessdata_type,
|
||||
(index == actual_tessdata_num_entries_) ? -1
|
||||
: offset_table_[index]);
|
||||
}
|
||||
return (index == actual_tessdata_num_entries_) ? -1 : offset_table_[index] - 1;
|
||||
}
|
||||
/** Closes data_file_ (if it was opened by Init()). */
|
||||
inline void End() {
|
||||
if (data_file_ != NULL) {
|
||||
fclose(data_file_);
|
||||
data_file_ = NULL;
|
||||
}
|
||||
}
|
||||
bool swap() const {
|
||||
return swap_;
|
||||
}
|
||||
|
||||
/** Writes the number of entries and the given offset table to output_file.
|
||||
* Returns false on error.
|
||||
*/
|
||||
static bool WriteMetadata(inT64 *offset_table,
|
||||
const char *language_data_path_prefix,
|
||||
FILE *output_file);
|
||||
|
||||
/**
|
||||
* Reads all the standard tesseract config and data files for a language
|
||||
* at the given path and bundles them up into one binary data file.
|
||||
* Returns true if the combined traineddata file was successfully written.
|
||||
*/
|
||||
static bool CombineDataFiles(const char *language_data_path_prefix,
|
||||
const char *output_filename);
|
||||
|
||||
/**
|
||||
* Gets the individual components from the data_file_ with which the class was
|
||||
* initialized. Overwrites the components specified by component_filenames.
|
||||
* Writes the updated traineddata file to new_traineddata_filename.
|
||||
*/
|
||||
bool OverwriteComponents(const char *new_traineddata_filename,
|
||||
char **component_filenames,
|
||||
int num_new_components);
|
||||
|
||||
/**
|
||||
* Extracts tessdata component implied by the name of the input file from
|
||||
* the combined traineddata loaded into TessdataManager.
|
||||
* Writes the extracted component to the file indicated by the file name.
|
||||
* E.g. if the filename given is somepath/somelang.unicharset, unicharset
|
||||
* will be extracted from the data loaded into the TessdataManager and will
|
||||
* be written to somepath/somelang.unicharset.
|
||||
* @return true if the component was successfully extracted, false if the
|
||||
* component was not present in the traineddata loaded into TessdataManager.
|
||||
*/
|
||||
bool ExtractToFile(const char *filename);
|
||||
|
||||
/**
|
||||
* Copies data from the given input file to the output_file provided.
|
||||
* If num_bytes_to_copy is >= 0, only num_bytes_to_copy is copied from
|
||||
* the input file, otherwise all the data in the input file is copied.
|
||||
*/
|
||||
static void CopyFile(FILE *input_file, FILE *output_file,
|
||||
bool newline_end, inT64 num_bytes_to_copy);
|
||||
|
||||
/**
|
||||
* Fills type with TessdataType of the tessdata component represented by the
|
||||
* given file name. E.g. tessdata/eng.unicharset -> TESSDATA_UNICHARSET.
|
||||
* Sets *text_file to true if the component is in text format (e.g.
|
||||
* unicharset, unichar ambigs, config, etc).
|
||||
* @return true if the tessdata component type could be determined
|
||||
* from the given file name.
|
||||
*/
|
||||
static bool TessdataTypeFromFileSuffix(const char *suffix,
|
||||
TessdataType *type,
|
||||
bool *text_file);
|
||||
|
||||
/**
|
||||
* Tries to determine tessdata component file suffix from filename,
|
||||
* returns true on success.
|
||||
*/
|
||||
static bool TessdataTypeFromFileName(const char *filename,
|
||||
TessdataType *type,
|
||||
bool *text_file);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Opens the file whose name is a concatenation of language_data_path_prefix
|
||||
* and file_suffix. Returns a file pointer to the opened file.
|
||||
*/
|
||||
static FILE *GetFilePtr(const char *language_data_path_prefix,
|
||||
const char *file_suffix, bool text_file);
|
||||
|
||||
/**
|
||||
* Each offset_table_[i] contains a file offset in the combined data file
|
||||
* where the data of TessdataFileType i is stored.
|
||||
*/
|
||||
inT64 offset_table_[TESSDATA_NUM_ENTRIES];
|
||||
/**
|
||||
* Actual number of entries in the tessdata table. This value can only be
|
||||
* same or smaller than TESSDATA_NUM_ENTRIES, but can never be larger,
|
||||
* since then it would be impossible to interpret the type of tessdata at
|
||||
* indices same and higher than TESSDATA_NUM_ENTRIES.
|
||||
* This parameter is used to allow for backward compatibility
|
||||
* when new tessdata types are introduced.
|
||||
*/
|
||||
inT32 actual_tessdata_num_entries_;
|
||||
STRING data_file_name_; // name of the data file.
|
||||
FILE *data_file_; ///< pointer to the data file.
|
||||
int debug_level_;
|
||||
// True if the bytes need swapping.
|
||||
bool swap_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace tesseract
|
||||
|
||||
#endif // TESSERACT_CCUTIL_TESSDATAMANAGER_H_
|
@ -1,50 +0,0 @@
|
||||
AM_CPPFLAGS += \
|
||||
-I$(top_srcdir)/cutil -I$(top_srcdir)/ccutil \
|
||||
-I$(top_srcdir)/ccstruct -I$(top_srcdir)/dict \
|
||||
-I$(top_srcdir)/viewer
|
||||
|
||||
if VISIBILITY
|
||||
AM_CPPFLAGS += -DTESS_EXPORTS \
|
||||
-fvisibility=hidden -fvisibility-inlines-hidden
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
adaptive.h blobclass.h \
|
||||
classify.h cluster.h clusttool.h cutoffs.h \
|
||||
errorcounter.h \
|
||||
featdefs.h float2int.h fpoint.h \
|
||||
intfeaturedist.h intfeaturemap.h intfeaturespace.h \
|
||||
intfx.h intmatcher.h intproto.h kdtree.h \
|
||||
mastertrainer.h mf.h mfdefs.h mfoutline.h mfx.h \
|
||||
normfeat.h normmatch.h \
|
||||
ocrfeatures.h outfeat.h picofeat.h protos.h \
|
||||
sampleiterator.h shapeclassifier.h shapetable.h \
|
||||
tessclassifier.h trainingsample.h trainingsampleset.h
|
||||
|
||||
if !USING_MULTIPLELIBS
|
||||
noinst_LTLIBRARIES = libtesseract_classify.la
|
||||
else
|
||||
lib_LTLIBRARIES = libtesseract_classify.la
|
||||
libtesseract_classify_la_LDFLAGS = -version-info $(GENERIC_LIBRARY_VERSION)
|
||||
libtesseract_classify_la_LIBADD = \
|
||||
../ccutil/libtesseract_ccutil.la \
|
||||
../cutil/libtesseract_cutil.la \
|
||||
../ccstruct/libtesseract_ccstruct.la \
|
||||
../dict/libtesseract_dict.la \
|
||||
../viewer/libtesseract_viewer.la
|
||||
endif
|
||||
|
||||
libtesseract_classify_la_SOURCES = \
|
||||
adaptive.cpp adaptmatch.cpp blobclass.cpp \
|
||||
classify.cpp cluster.cpp clusttool.cpp cutoffs.cpp \
|
||||
errorcounter.cpp \
|
||||
featdefs.cpp float2int.cpp fpoint.cpp \
|
||||
intfeaturedist.cpp intfeaturemap.cpp intfeaturespace.cpp \
|
||||
intfx.cpp intmatcher.cpp intproto.cpp kdtree.cpp \
|
||||
mastertrainer.cpp mf.cpp mfdefs.cpp mfoutline.cpp mfx.cpp \
|
||||
normfeat.cpp normmatch.cpp \
|
||||
ocrfeatures.cpp outfeat.cpp picofeat.cpp protos.cpp \
|
||||
sampleiterator.cpp shapeclassifier.cpp shapetable.cpp \
|
||||
tessclassifier.cpp trainingsample.cpp trainingsampleset.cpp
|
||||
|
||||
|
@ -1,471 +0,0 @@
|
||||
/******************************************************************************
|
||||
** Filename: clustertool.c
|
||||
** Purpose: Misc. tools for use with the clustering routines
|
||||
** Author: Dan Johnson
|
||||
** History: 6/6/89, DSJ, Created.
|
||||
**
|
||||
** (c) Copyright Hewlett-Packard Company, 1988.
|
||||
** 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 Files----------------------------------
|
||||
#include "clusttool.h"
|
||||
#include "const.h"
|
||||
#include "danerror.h"
|
||||
#include "emalloc.h"
|
||||
#include "scanutils.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
//---------------Global Data Definitions and Declarations--------------------
|
||||
#define TOKENSIZE 80 //< max size of tokens read from an input file
|
||||
#define MAXSAMPLESIZE 65535 //< max num of dimensions in feature space
|
||||
//#define MAXBLOCKSIZE 65535 //< max num of samples in a character (block size)
|
||||
|
||||
/**
|
||||
* This routine reads a single integer from the specified
|
||||
* file and checks to ensure that it is between 0 and
|
||||
* MAXSAMPLESIZE.
|
||||
* @param File open text file to read sample size from
|
||||
* @return Sample size
|
||||
* @note Globals: None
|
||||
* @note Exceptions: ILLEGALSAMPLESIZE illegal format or range
|
||||
* @note History: 6/6/89, DSJ, Created.
|
||||
*/
|
||||
uinT16 ReadSampleSize(FILE *File) {
|
||||
int SampleSize;
|
||||
|
||||
if ((tfscanf(File, "%d", &SampleSize) != 1) ||
|
||||
(SampleSize < 0) || (SampleSize > MAXSAMPLESIZE))
|
||||
DoError (ILLEGALSAMPLESIZE, "Illegal sample size");
|
||||
return (SampleSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine reads textual descriptions of sets of parameters
|
||||
* which describe the characteristics of feature dimensions.
|
||||
*
|
||||
* Exceptions:
|
||||
* - ILLEGALCIRCULARSPEC
|
||||
* - ILLEGALESSENTIALSPEC
|
||||
* - ILLEGALMINMAXSPEC
|
||||
* @param File open text file to read N parameter descriptions from
|
||||
* @param N number of parameter descriptions to read
|
||||
* @return Pointer to an array of parameter descriptors.
|
||||
* @note Globals: None
|
||||
* @note History: 6/6/89, DSJ, Created.
|
||||
*/
|
||||
PARAM_DESC *ReadParamDesc(FILE *File, uinT16 N) {
|
||||
int i;
|
||||
PARAM_DESC *ParamDesc;
|
||||
char Token[TOKENSIZE];
|
||||
|
||||
ParamDesc = (PARAM_DESC *) Emalloc (N * sizeof (PARAM_DESC));
|
||||
for (i = 0; i < N; i++) {
|
||||
if (tfscanf(File, "%s", Token) != 1)
|
||||
DoError (ILLEGALCIRCULARSPEC,
|
||||
"Illegal circular/linear specification");
|
||||
if (Token[0] == 'c')
|
||||
ParamDesc[i].Circular = TRUE;
|
||||
else
|
||||
ParamDesc[i].Circular = FALSE;
|
||||
|
||||
if (tfscanf(File, "%s", Token) != 1)
|
||||
DoError (ILLEGALESSENTIALSPEC,
|
||||
"Illegal essential/non-essential spec");
|
||||
if (Token[0] == 'e')
|
||||
ParamDesc[i].NonEssential = FALSE;
|
||||
else
|
||||
ParamDesc[i].NonEssential = TRUE;
|
||||
if (tfscanf(File, "%f%f", &(ParamDesc[i].Min), &(ParamDesc[i].Max)) != 2)
|
||||
DoError (ILLEGALMINMAXSPEC, "Illegal min or max specification");
|
||||
ParamDesc[i].Range = ParamDesc[i].Max - ParamDesc[i].Min;
|
||||
ParamDesc[i].HalfRange = ParamDesc[i].Range / 2;
|
||||
ParamDesc[i].MidRange = (ParamDesc[i].Max + ParamDesc[i].Min) / 2;
|
||||
}
|
||||
return (ParamDesc);
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine reads a textual description of a prototype from
|
||||
* the specified file.
|
||||
*
|
||||
* Exceptions:
|
||||
* - ILLEGALSIGNIFICANCESPEC
|
||||
* - ILLEGALSAMPLECOUNT
|
||||
* - ILLEGALMEANSPEC
|
||||
* - ILLEGALVARIANCESPEC
|
||||
* - ILLEGALDISTRIBUTION
|
||||
* @param File open text file to read prototype from
|
||||
* @param N number of dimensions used in prototype
|
||||
* @return List of prototypes
|
||||
* @note Globals: None
|
||||
* @note History: 6/6/89, DSJ, Created.
|
||||
*/
|
||||
PROTOTYPE *ReadPrototype(FILE *File, uinT16 N) {
|
||||
char Token[TOKENSIZE];
|
||||
int Status;
|
||||
PROTOTYPE *Proto;
|
||||
int SampleCount;
|
||||
int i;
|
||||
|
||||
if ((Status = tfscanf(File, "%s", Token)) == 1) {
|
||||
Proto = (PROTOTYPE *) Emalloc (sizeof (PROTOTYPE));
|
||||
Proto->Cluster = NULL;
|
||||
if (Token[0] == 's')
|
||||
Proto->Significant = TRUE;
|
||||
else
|
||||
Proto->Significant = FALSE;
|
||||
|
||||
Proto->Style = ReadProtoStyle (File);
|
||||
|
||||
if ((tfscanf(File, "%d", &SampleCount) != 1) || (SampleCount < 0))
|
||||
DoError (ILLEGALSAMPLECOUNT, "Illegal sample count");
|
||||
Proto->NumSamples = SampleCount;
|
||||
|
||||
Proto->Mean = ReadNFloats (File, N, NULL);
|
||||
if (Proto->Mean == NULL)
|
||||
DoError (ILLEGALMEANSPEC, "Illegal prototype mean");
|
||||
|
||||
switch (Proto->Style) {
|
||||
case spherical:
|
||||
if (ReadNFloats (File, 1, &(Proto->Variance.Spherical)) == NULL)
|
||||
DoError (ILLEGALVARIANCESPEC, "Illegal prototype variance");
|
||||
Proto->Magnitude.Spherical =
|
||||
1.0 / sqrt ((double) (2.0 * PI * Proto->Variance.Spherical));
|
||||
Proto->TotalMagnitude =
|
||||
pow (Proto->Magnitude.Spherical, (float) N);
|
||||
Proto->LogMagnitude = log ((double) Proto->TotalMagnitude);
|
||||
Proto->Weight.Spherical = 1.0 / Proto->Variance.Spherical;
|
||||
Proto->Distrib = NULL;
|
||||
break;
|
||||
case elliptical:
|
||||
Proto->Variance.Elliptical = ReadNFloats (File, N, NULL);
|
||||
if (Proto->Variance.Elliptical == NULL)
|
||||
DoError (ILLEGALVARIANCESPEC, "Illegal prototype variance");
|
||||
Proto->Magnitude.Elliptical =
|
||||
(FLOAT32 *) Emalloc (N * sizeof (FLOAT32));
|
||||
Proto->Weight.Elliptical =
|
||||
(FLOAT32 *) Emalloc (N * sizeof (FLOAT32));
|
||||
Proto->TotalMagnitude = 1.0;
|
||||
for (i = 0; i < N; i++) {
|
||||
Proto->Magnitude.Elliptical[i] =
|
||||
1.0 /
|
||||
sqrt ((double) (2.0 * PI * Proto->Variance.Elliptical[i]));
|
||||
Proto->Weight.Elliptical[i] =
|
||||
1.0 / Proto->Variance.Elliptical[i];
|
||||
Proto->TotalMagnitude *= Proto->Magnitude.Elliptical[i];
|
||||
}
|
||||
Proto->LogMagnitude = log ((double) Proto->TotalMagnitude);
|
||||
Proto->Distrib = NULL;
|
||||
break;
|
||||
case mixed:
|
||||
Proto->Distrib =
|
||||
(DISTRIBUTION *) Emalloc (N * sizeof (DISTRIBUTION));
|
||||
for (i = 0; i < N; i++) {
|
||||
if (tfscanf(File, "%s", Token) != 1)
|
||||
DoError (ILLEGALDISTRIBUTION,
|
||||
"Illegal prototype distribution");
|
||||
switch (Token[0]) {
|
||||
case 'n':
|
||||
Proto->Distrib[i] = normal;
|
||||
break;
|
||||
case 'u':
|
||||
Proto->Distrib[i] = uniform;
|
||||
break;
|
||||
case 'r':
|
||||
Proto->Distrib[i] = D_random;
|
||||
break;
|
||||
default:
|
||||
DoError (ILLEGALDISTRIBUTION,
|
||||
"Illegal prototype distribution");
|
||||
}
|
||||
}
|
||||
Proto->Variance.Elliptical = ReadNFloats (File, N, NULL);
|
||||
if (Proto->Variance.Elliptical == NULL)
|
||||
DoError (ILLEGALVARIANCESPEC, "Illegal prototype variance");
|
||||
Proto->Magnitude.Elliptical =
|
||||
(FLOAT32 *) Emalloc (N * sizeof (FLOAT32));
|
||||
Proto->Weight.Elliptical =
|
||||
(FLOAT32 *) Emalloc (N * sizeof (FLOAT32));
|
||||
Proto->TotalMagnitude = 1.0;
|
||||
for (i = 0; i < N; i++) {
|
||||
switch (Proto->Distrib[i]) {
|
||||
case normal:
|
||||
Proto->Magnitude.Elliptical[i] = 1.0 /
|
||||
sqrt ((double)
|
||||
(2.0 * PI * Proto->Variance.Elliptical[i]));
|
||||
Proto->Weight.Elliptical[i] =
|
||||
1.0 / Proto->Variance.Elliptical[i];
|
||||
break;
|
||||
case uniform:
|
||||
case D_random:
|
||||
Proto->Magnitude.Elliptical[i] = 1.0 /
|
||||
(2.0 * Proto->Variance.Elliptical[i]);
|
||||
break;
|
||||
case DISTRIBUTION_COUNT:
|
||||
ASSERT_HOST(!"Distribution count not allowed!");
|
||||
}
|
||||
Proto->TotalMagnitude *= Proto->Magnitude.Elliptical[i];
|
||||
}
|
||||
Proto->LogMagnitude = log ((double) Proto->TotalMagnitude);
|
||||
break;
|
||||
}
|
||||
return (Proto);
|
||||
}
|
||||
else if (Status == EOF)
|
||||
return (NULL);
|
||||
else {
|
||||
DoError (ILLEGALSIGNIFICANCESPEC, "Illegal significance specification");
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine reads an single token from the specified
|
||||
* text file and interprets it as a prototype specification.
|
||||
* @param File open text file to read prototype style from
|
||||
* @return Prototype style read from text file
|
||||
* @note Globals: None
|
||||
* @note Exceptions: ILLEGALSTYLESPEC illegal prototype style specification
|
||||
* @note History: 6/8/89, DSJ, Created.
|
||||
*/
|
||||
PROTOSTYLE ReadProtoStyle(FILE *File) {
|
||||
char Token[TOKENSIZE];
|
||||
PROTOSTYLE Style;
|
||||
|
||||
if (tfscanf(File, "%s", Token) != 1)
|
||||
DoError (ILLEGALSTYLESPEC, "Illegal prototype style specification");
|
||||
switch (Token[0]) {
|
||||
case 's':
|
||||
Style = spherical;
|
||||
break;
|
||||
case 'e':
|
||||
Style = elliptical;
|
||||
break;
|
||||
case 'm':
|
||||
Style = mixed;
|
||||
break;
|
||||
case 'a':
|
||||
Style = automatic;
|
||||
break;
|
||||
default:
|
||||
Style = elliptical;
|
||||
DoError (ILLEGALSTYLESPEC, "Illegal prototype style specification");
|
||||
}
|
||||
return (Style);
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine reads N floats from the specified text file
|
||||
* and places them into Buffer. If Buffer is NULL, a buffer
|
||||
* is created and passed back to the caller. If EOF is
|
||||
* encountered before any floats can be read, NULL is
|
||||
* returned.
|
||||
* @param File open text file to read floats from
|
||||
* @param N number of floats to read
|
||||
* @param Buffer pointer to buffer to place floats into
|
||||
* @return Pointer to buffer holding floats or NULL if EOF
|
||||
* @note Globals: None
|
||||
* @note Exceptions: ILLEGALFLOAT
|
||||
* @note History: 6/6/89, DSJ, Created.
|
||||
*/
|
||||
FLOAT32* ReadNFloats(FILE * File, uinT16 N, FLOAT32 Buffer[]) {
|
||||
bool needs_free = false;
|
||||
int i;
|
||||
int NumFloatsRead;
|
||||
|
||||
if (Buffer == NULL) {
|
||||
Buffer = reinterpret_cast<FLOAT32*>(Emalloc(N * sizeof(FLOAT32)));
|
||||
needs_free = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
NumFloatsRead = tfscanf(File, "%f", &(Buffer[i]));
|
||||
if (NumFloatsRead != 1) {
|
||||
if ((NumFloatsRead == EOF) && (i == 0)) {
|
||||
if (needs_free) {
|
||||
Efree(Buffer);
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
DoError(ILLEGALFLOAT, "Illegal float specification");
|
||||
}
|
||||
}
|
||||
}
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine writes an array of dimension descriptors to
|
||||
* the specified text file.
|
||||
* @param File open text file to write param descriptors to
|
||||
* @param N number of param descriptors to write
|
||||
* @param ParamDesc array of param descriptors to write
|
||||
* @return None
|
||||
* @note Globals: None
|
||||
* @note Exceptions: None
|
||||
* @note History: 6/6/89, DSJ, Created.
|
||||
*/
|
||||
void
|
||||
WriteParamDesc (FILE * File, uinT16 N, PARAM_DESC ParamDesc[]) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
if (ParamDesc[i].Circular)
|
||||
fprintf (File, "circular ");
|
||||
else
|
||||
fprintf (File, "linear ");
|
||||
|
||||
if (ParamDesc[i].NonEssential)
|
||||
fprintf (File, "non-essential ");
|
||||
else
|
||||
fprintf (File, "essential ");
|
||||
|
||||
fprintf (File, "%10.6f %10.6f\n", ParamDesc[i].Min, ParamDesc[i].Max);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine writes a textual description of a prototype
|
||||
* to the specified text file.
|
||||
* @param File open text file to write prototype to
|
||||
* @param N number of dimensions in feature space
|
||||
* @param Proto prototype to write out
|
||||
* @return None
|
||||
* @note Globals: None
|
||||
* @note Exceptions: None
|
||||
* @note History: 6/12/89, DSJ, Created.
|
||||
*/
|
||||
void WritePrototype(FILE *File, uinT16 N, PROTOTYPE *Proto) {
|
||||
int i;
|
||||
|
||||
if (Proto->Significant)
|
||||
fprintf (File, "significant ");
|
||||
else
|
||||
fprintf (File, "insignificant ");
|
||||
WriteProtoStyle (File, (PROTOSTYLE) Proto->Style);
|
||||
fprintf (File, "%6d\n\t", Proto->NumSamples);
|
||||
WriteNFloats (File, N, Proto->Mean);
|
||||
fprintf (File, "\t");
|
||||
|
||||
switch (Proto->Style) {
|
||||
case spherical:
|
||||
WriteNFloats (File, 1, &(Proto->Variance.Spherical));
|
||||
break;
|
||||
case elliptical:
|
||||
WriteNFloats (File, N, Proto->Variance.Elliptical);
|
||||
break;
|
||||
case mixed:
|
||||
for (i = 0; i < N; i++)
|
||||
switch (Proto->Distrib[i]) {
|
||||
case normal:
|
||||
fprintf (File, " %9s", "normal");
|
||||
break;
|
||||
case uniform:
|
||||
fprintf (File, " %9s", "uniform");
|
||||
break;
|
||||
case D_random:
|
||||
fprintf (File, " %9s", "random");
|
||||
break;
|
||||
case DISTRIBUTION_COUNT:
|
||||
ASSERT_HOST(!"Distribution count not allowed!");
|
||||
}
|
||||
fprintf (File, "\n\t");
|
||||
WriteNFloats (File, N, Proto->Variance.Elliptical);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine writes a text representation of N floats from
|
||||
* an array to a file. All of the floats are placed on one line.
|
||||
* @param File open text file to write N floats to
|
||||
* @param N number of floats to write
|
||||
* @param Array array of floats to write
|
||||
* @return None
|
||||
* @note Globals: None
|
||||
* @note Exceptions: None
|
||||
* @note History: 6/6/89, DSJ, Created.
|
||||
*/
|
||||
void WriteNFloats(FILE * File, uinT16 N, FLOAT32 Array[]) {
|
||||
for (int i = 0; i < N; i++)
|
||||
fprintf(File, " %9.6f", Array[i]);
|
||||
fprintf(File, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine writes to the specified text file a word
|
||||
* which represents the ProtoStyle. It does not append
|
||||
* a carriage return to the end.
|
||||
* @param File open text file to write prototype style to
|
||||
* @param ProtoStyle prototype style to write
|
||||
* @return None
|
||||
* @note Globals: None
|
||||
* @note Exceptions: None
|
||||
* @note History: 6/8/89, DSJ, Created.
|
||||
*/
|
||||
void WriteProtoStyle(FILE *File, PROTOSTYLE ProtoStyle) {
|
||||
switch (ProtoStyle) {
|
||||
case spherical:
|
||||
fprintf (File, "spherical");
|
||||
break;
|
||||
case elliptical:
|
||||
fprintf (File, "elliptical");
|
||||
break;
|
||||
case mixed:
|
||||
fprintf (File, "mixed");
|
||||
break;
|
||||
case automatic:
|
||||
fprintf (File, "automatic");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine writes a textual description of each prototype
|
||||
* in the prototype list to the specified file. It also
|
||||
* writes a file header which includes the number of dimensions
|
||||
* in feature space and the descriptions for each dimension.
|
||||
* @param File open text file to write prototypes to
|
||||
* @param N number of dimensions in feature space
|
||||
* @param ParamDesc descriptions for each dimension
|
||||
* @param ProtoList list of prototypes to be written
|
||||
* @param WriteSigProtos TRUE to write out significant prototypes
|
||||
* @param WriteInsigProtos TRUE to write out insignificants
|
||||
* @note Globals: None
|
||||
* @return None
|
||||
* @note Exceptions: None
|
||||
* @note History: 6/12/89, DSJ, Created.
|
||||
*/
|
||||
|
||||
void WriteProtoList(
|
||||
FILE *File,
|
||||
uinT16 N,
|
||||
PARAM_DESC ParamDesc[],
|
||||
LIST ProtoList,
|
||||
BOOL8 WriteSigProtos,
|
||||
BOOL8 WriteInsigProtos)
|
||||
{
|
||||
PROTOTYPE *Proto;
|
||||
|
||||
/* write file header */
|
||||
fprintf(File,"%0d\n",N);
|
||||
WriteParamDesc(File,N,ParamDesc);
|
||||
|
||||
/* write prototypes */
|
||||
iterate(ProtoList)
|
||||
{
|
||||
Proto = (PROTOTYPE *) first_node ( ProtoList );
|
||||
if (( Proto->Significant && WriteSigProtos ) ||
|
||||
( ! Proto->Significant && WriteInsigProtos ) )
|
||||
WritePrototype( File, N, Proto );
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/******************************************************************************
|
||||
** Filename: clusttool.h
|
||||
** Purpose: Definition of clustering utility tools
|
||||
** Author: Dan Johnson
|
||||
** History: 6/6/89, DSJ, Created.
|
||||
**
|
||||
** (c) Copyright Hewlett-Packard Company, 1988.
|
||||
** 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.
|
||||
******************************************************************************/
|
||||
#ifndef __CLUSTERTOOL__
|
||||
#define __CLUSTERTOOL__
|
||||
|
||||
//--------------------------Include Files---------------------------------------
|
||||
#include "host.h"
|
||||
#include "cluster.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Public Function Prototype
|
||||
--------------------------------------------------------------------------*/
|
||||
uinT16 ReadSampleSize(FILE *File);
|
||||
|
||||
PARAM_DESC *ReadParamDesc(FILE *File, uinT16 N);
|
||||
|
||||
PROTOTYPE *ReadPrototype(FILE *File, uinT16 N);
|
||||
|
||||
PROTOSTYLE ReadProtoStyle(FILE *File);
|
||||
|
||||
FLOAT32 *ReadNFloats (FILE * File, uinT16 N, FLOAT32 Buffer[]);
|
||||
|
||||
void WriteParamDesc (FILE * File, uinT16 N, PARAM_DESC ParamDesc[]);
|
||||
|
||||
void WritePrototype(FILE *File, uinT16 N, PROTOTYPE *Proto);
|
||||
|
||||
void WriteNFloats (FILE * File, uinT16 N, FLOAT32 Array[]);
|
||||
|
||||
void WriteProtoStyle(FILE *File, PROTOSTYLE ProtoStyle);
|
||||
|
||||
void WriteProtoList(
|
||||
FILE *File,
|
||||
uinT16 N,
|
||||
PARAM_DESC ParamDesc[],
|
||||
LIST ProtoList,
|
||||
BOOL8 WriteSigProtos,
|
||||
BOOL8 WriteInsigProtos);
|
||||
|
||||
//--------------Global Data Definitions and Declarations---------------------
|
||||
// define errors that can be trapped
|
||||
#define ILLEGALSAMPLESIZE 5000
|
||||
#define ILLEGALCIRCULARSPEC 5001
|
||||
#define ILLEGALMINMAXSPEC 5002
|
||||
#define ILLEGALSIGNIFICANCESPEC 5003
|
||||
#define ILLEGALSTYLESPEC 5004
|
||||
#define ILLEGALSAMPLECOUNT 5005
|
||||
#define ILLEGALMEANSPEC 5006
|
||||
#define ILLEGALVARIANCESPEC 5007
|
||||
#define ILLEGALDISTRIBUTION 5008
|
||||
#define ILLEGALFLOAT 5009
|
||||
#define ILLEGALESSENTIALSPEC 5013
|
||||
#endif
|
@ -1,179 +0,0 @@
|
||||
/* -*-C-*-
|
||||
********************************************************************************
|
||||
*
|
||||
* File: protos.h (Formerly protos.h)
|
||||
* Description:
|
||||
* Author: Mark Seaman, SW Productivity
|
||||
* Created: Fri Oct 16 14:37:00 1987
|
||||
* Modified: Fri Jul 12 10:06:55 1991 (Dan Johnson) danj@hpgrlj
|
||||
* Language: C
|
||||
* Package: N/A
|
||||
* Status: Reusable Software Component
|
||||
*
|
||||
* (c) Copyright 1987, Hewlett-Packard Company.
|
||||
** 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.
|
||||
*
|
||||
*********************************************************************************/
|
||||
#ifndef PROTOS_H
|
||||
#define PROTOS_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
I n c l u d e s
|
||||
----------------------------------------------------------------------*/
|
||||
#include "bitvec.h"
|
||||
#include "cutil.h"
|
||||
#include "unichar.h"
|
||||
#include "unicity_table.h"
|
||||
#include "params.h"
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
T y p e s
|
||||
----------------------------------------------------------------------*/
|
||||
typedef BIT_VECTOR *CONFIGS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FLOAT32 A;
|
||||
FLOAT32 B;
|
||||
FLOAT32 C;
|
||||
FLOAT32 X;
|
||||
FLOAT32 Y;
|
||||
FLOAT32 Angle;
|
||||
FLOAT32 Length;
|
||||
} PROTO_STRUCT;
|
||||
typedef PROTO_STRUCT *PROTO;
|
||||
|
||||
struct CLASS_STRUCT {
|
||||
CLASS_STRUCT()
|
||||
: NumProtos(0), MaxNumProtos(0), Prototypes(NULL),
|
||||
NumConfigs(0), MaxNumConfigs(0), Configurations(NULL) {
|
||||
}
|
||||
inT16 NumProtos;
|
||||
inT16 MaxNumProtos;
|
||||
PROTO Prototypes;
|
||||
inT16 NumConfigs;
|
||||
inT16 MaxNumConfigs;
|
||||
CONFIGS Configurations;
|
||||
UnicityTableEqEq<int> font_set;
|
||||
};
|
||||
typedef CLASS_STRUCT *CLASS_TYPE;
|
||||
typedef CLASS_STRUCT *CLASSES;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
C o n s t a n t s
|
||||
----------------------------------------------------------------------*/
|
||||
#define NUMBER_OF_CLASSES MAX_NUM_CLASSES
|
||||
#define Y_OFFSET -40.0
|
||||
#define FEATURE_SCALE 100.0
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
V a r i a b l e s
|
||||
----------------------------------------------------------------------*/
|
||||
extern CLASS_STRUCT TrainingData[];
|
||||
|
||||
extern STRING_VAR_H(classify_training_file, "MicroFeatures", "Training file");
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
M a c r o s
|
||||
----------------------------------------------------------------------*/
|
||||
/**
|
||||
* AddProtoToConfig
|
||||
*
|
||||
* Set a single proto bit in the specified configuration.
|
||||
*/
|
||||
|
||||
#define AddProtoToConfig(Pid,Config) \
|
||||
(SET_BIT (Config, Pid))
|
||||
|
||||
/**
|
||||
* RemoveProtoFromConfig
|
||||
*
|
||||
* Clear a single proto bit in the specified configuration.
|
||||
*/
|
||||
|
||||
#define RemoveProtoFromConfig(Pid,Config) \
|
||||
(reset_bit (Config, Pid))
|
||||
|
||||
/**
|
||||
* ClassOfChar
|
||||
*
|
||||
* Return the class of a particular ASCII character value.
|
||||
*/
|
||||
|
||||
#define ClassOfChar(Char) \
|
||||
((TrainingData [Char].NumProtos) ? \
|
||||
(& TrainingData [Char]) : \
|
||||
NO_CLASS)
|
||||
|
||||
/**
|
||||
* ProtoIn
|
||||
*
|
||||
* Choose the selected prototype in this class record. Return the
|
||||
* pointer to it (type PROTO).
|
||||
*/
|
||||
|
||||
#define ProtoIn(Class,Pid) \
|
||||
(& (Class)->Prototypes [Pid])
|
||||
|
||||
/**
|
||||
* PrintProto
|
||||
*
|
||||
* Print out the contents of a prototype. The 'Proto' argument is of
|
||||
* type 'PROTO'.
|
||||
*/
|
||||
|
||||
#define PrintProto(Proto) \
|
||||
(tprintf("X=%4.2f, Y=%4.2f, Length=%4.2f, Angle=%4.2f", \
|
||||
Proto->X, \
|
||||
Proto->Y, \
|
||||
Proto->Length, \
|
||||
Proto->Angle)) \
|
||||
|
||||
|
||||
/**
|
||||
* PrintProtoLine
|
||||
*
|
||||
* Print out the contents of a prototype. The 'Proto' argument is of
|
||||
* type 'PROTO'.
|
||||
*/
|
||||
|
||||
#define PrintProtoLine(Proto) \
|
||||
(cprintf ("A=%4.2f, B=%4.2f, C=%4.2f", \
|
||||
Proto->A, \
|
||||
Proto->B, \
|
||||
Proto->C)) \
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
F u n c t i o n s
|
||||
----------------------------------------------------------------------*/
|
||||
int AddConfigToClass(CLASS_TYPE Class);
|
||||
|
||||
int AddProtoToClass(CLASS_TYPE Class);
|
||||
|
||||
FLOAT32 ClassConfigLength(CLASS_TYPE Class, BIT_VECTOR Config);
|
||||
|
||||
FLOAT32 ClassProtoLength(CLASS_TYPE Class);
|
||||
|
||||
void CopyProto(PROTO Src, PROTO Dest);
|
||||
|
||||
void FillABC(PROTO Proto);
|
||||
|
||||
void FreeClass(CLASS_TYPE Class);
|
||||
|
||||
void FreeClassFields(CLASS_TYPE Class);
|
||||
|
||||
void InitPrototypes();
|
||||
|
||||
CLASS_TYPE NewClass(int NumProtos, int NumConfigs);
|
||||
|
||||
void PrintProtos(CLASS_TYPE Class);
|
||||
|
||||
#endif
|
@ -1,3 +1,12 @@
|
||||
# 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.
|
||||
################################################################################
|
||||
#
|
||||
# macros and functions
|
||||
|
@ -1,3 +1,12 @@
|
||||
# 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.
|
||||
################################################################################
|
||||
#
|
||||
# configure
|
||||
@ -79,26 +88,24 @@ set(include_files_list
|
||||
stdbool.h
|
||||
stdint.h
|
||||
stdlib.h
|
||||
strings.h
|
||||
string.h
|
||||
sys/ipc.h
|
||||
sys/shm.h
|
||||
sys/stat.h
|
||||
sys/types.h
|
||||
sys/wait.h
|
||||
tiffio.h
|
||||
unistd.h
|
||||
|
||||
|
||||
cairo/cairo-version.h
|
||||
CL/cl.h
|
||||
OpenCL/cl.h
|
||||
pango-1.0/pango/pango-features.h
|
||||
tiffio.h
|
||||
unicode/uchar.h
|
||||
)
|
||||
check_includes(include_files_list)
|
||||
|
||||
set(functions_list
|
||||
getline
|
||||
snprintf
|
||||
)
|
||||
check_functions(functions_list)
|
||||
@ -112,22 +119,18 @@ set(types_list
|
||||
)
|
||||
check_types(types_list)
|
||||
|
||||
check_c_source_compiles("#include <sys/time.h>\n#include <time.h>\nmain(){}" TIME_WITH_SYS_TIME)
|
||||
set(PACKAGE_VERSION "${VERSION_PLAIN}")
|
||||
file(APPEND ${AUTOCONFIG_SRC} "
|
||||
/* Version number */
|
||||
#cmakedefine PACKAGE_VERSION \"${VERSION_PLAIN}\"
|
||||
")
|
||||
|
||||
test_big_endian(WORDS_BIGENDIAN)
|
||||
|
||||
set(STDC_HEADERS 1)
|
||||
|
||||
file(APPEND ${AUTOCONFIG_SRC} "
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#cmakedefine STDC_HEADERS 1
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#cmakedefine WORDS_BIGENDIAN 1
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#cmakedefine TIME_WITH_SYS_TIME 1
|
||||
")
|
||||
|
||||
########################################
|
||||
|
@ -1,314 +0,0 @@
|
||||
# This module can find the International Components for Unicode (ICU) Library
|
||||
#
|
||||
# Requirements:
|
||||
# - CMake >= 2.8.3 (for new version of find_package_handle_standard_args)
|
||||
#
|
||||
# The following variables will be defined for your use:
|
||||
# - ICU_FOUND : were all of your specified components found (include dependencies)?
|
||||
# - ICU_INCLUDE_DIRS : ICU include directory
|
||||
# - ICU_LIBRARIES : ICU libraries
|
||||
# - ICU_VERSION : complete version of ICU (x.y.z)
|
||||
# - ICU_MAJOR_VERSION : major version of ICU
|
||||
# - ICU_MINOR_VERSION : minor version of ICU
|
||||
# - ICU_PATCH_VERSION : patch version of ICU
|
||||
# - ICU_<COMPONENT>_FOUND : were <COMPONENT> found? (FALSE for non specified component if it is not a dependency)
|
||||
#
|
||||
# For windows or non standard installation, define ICU_ROOT variable to point to the root installation of ICU. Two ways:
|
||||
# - run cmake with -DICU_ROOT=<PATH>
|
||||
# - define an environment variable with the same name before running cmake
|
||||
# With cmake-gui, before pressing "Configure":
|
||||
# 1) Press "Add Entry" button
|
||||
# 2) Add a new entry defined as:
|
||||
# - Name: ICU_ROOT
|
||||
# - Type: choose PATH in the selection list
|
||||
# - Press "..." button and select the root installation of ICU
|
||||
#
|
||||
# Example Usage:
|
||||
#
|
||||
# 1. Copy this file in the root of your project source directory
|
||||
# 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt:
|
||||
# set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
|
||||
# 3. Finally call find_package() once, here are some examples to pick from
|
||||
#
|
||||
# Require ICU 4.4 or later
|
||||
# find_package(ICU 4.4 REQUIRED)
|
||||
#
|
||||
# if(ICU_FOUND)
|
||||
# include_directories(${ICU_INCLUDE_DIRS})
|
||||
# add_executable(myapp myapp.c)
|
||||
# target_link_libraries(myapp ${ICU_LIBRARIES})
|
||||
# endif(ICU_FOUND)
|
||||
|
||||
#=============================================================================
|
||||
# Copyright (c) 2011-2013, julp
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#=============================================================================
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
########## Private ##########
|
||||
if(NOT DEFINED ICU_PUBLIC_VAR_NS)
|
||||
set(ICU_PUBLIC_VAR_NS "ICU") # Prefix for all ICU relative public variables
|
||||
endif(NOT DEFINED ICU_PUBLIC_VAR_NS)
|
||||
if(NOT DEFINED ICU_PRIVATE_VAR_NS)
|
||||
set(ICU_PRIVATE_VAR_NS "_${ICU_PUBLIC_VAR_NS}") # Prefix for all ICU relative internal variables
|
||||
endif(NOT DEFINED ICU_PRIVATE_VAR_NS)
|
||||
if(NOT DEFINED PC_ICU_PRIVATE_VAR_NS)
|
||||
set(PC_ICU_PRIVATE_VAR_NS "_PC${ICU_PRIVATE_VAR_NS}") # Prefix for all pkg-config relative internal variables
|
||||
endif(NOT DEFINED PC_ICU_PRIVATE_VAR_NS)
|
||||
|
||||
function(icudebug _VARNAME)
|
||||
if(${ICU_PUBLIC_VAR_NS}_DEBUG)
|
||||
if(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
|
||||
message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = ${${ICU_PUBLIC_VAR_NS}_${_VARNAME}}")
|
||||
else(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
|
||||
message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = <UNDEFINED>")
|
||||
endif(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
|
||||
endif(${ICU_PUBLIC_VAR_NS}_DEBUG)
|
||||
endfunction(icudebug)
|
||||
|
||||
set(${ICU_PRIVATE_VAR_NS}_ROOT "")
|
||||
if(DEFINED ENV{ICU_ROOT})
|
||||
set(${ICU_PRIVATE_VAR_NS}_ROOT "$ENV{ICU_ROOT}")
|
||||
endif(DEFINED ENV{ICU_ROOT})
|
||||
if (DEFINED ICU_ROOT)
|
||||
set(${ICU_PRIVATE_VAR_NS}_ROOT "${ICU_ROOT}")
|
||||
endif(DEFINED ICU_ROOT)
|
||||
|
||||
set(${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES )
|
||||
set(${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES )
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin64")
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib64")
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin")
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib")
|
||||
|
||||
set(${ICU_PRIVATE_VAR_NS}_COMPONENTS )
|
||||
# <icu component name> <library name 1> ... <library name N>
|
||||
macro(icu_declare_component _NAME)
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_COMPONENTS ${_NAME})
|
||||
set("${ICU_PRIVATE_VAR_NS}_COMPONENTS_${_NAME}" ${ARGN})
|
||||
endmacro(icu_declare_component)
|
||||
|
||||
icu_declare_component(data icudata)
|
||||
icu_declare_component(uc icuuc) # Common and Data libraries
|
||||
icu_declare_component(i18n icui18n icuin) # Internationalization library
|
||||
icu_declare_component(io icuio ustdio) # Stream and I/O Library
|
||||
icu_declare_component(le icule) # Layout library
|
||||
icu_declare_component(lx iculx) # Paragraph Layout library
|
||||
|
||||
########## Public ##########
|
||||
set(${ICU_PUBLIC_VAR_NS}_FOUND TRUE)
|
||||
set(${ICU_PUBLIC_VAR_NS}_LIBRARIES )
|
||||
set(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS )
|
||||
set(${ICU_PUBLIC_VAR_NS}_C_FLAGS "")
|
||||
set(${ICU_PUBLIC_VAR_NS}_CXX_FLAGS "")
|
||||
set(${ICU_PUBLIC_VAR_NS}_CPP_FLAGS "")
|
||||
set(${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS "")
|
||||
set(${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS "")
|
||||
set(${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS "")
|
||||
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS})
|
||||
string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
|
||||
set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) # may be done in the icu_declare_component macro
|
||||
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
|
||||
|
||||
# Check components
|
||||
if(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) # uc required at least
|
||||
set(${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc)
|
||||
else(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
|
||||
list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc)
|
||||
list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
|
||||
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
|
||||
if(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
|
||||
message(FATAL_ERROR "Unknown ICU component: ${${ICU_PRIVATE_VAR_NS}_COMPONENT}")
|
||||
endif(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
|
||||
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
|
||||
endif(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
|
||||
|
||||
# Includes
|
||||
find_path(
|
||||
${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS
|
||||
NAMES unicode/utypes.h utypes.h
|
||||
HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT}
|
||||
PATH_SUFFIXES "include"
|
||||
DOC "Include directories for ICU"
|
||||
)
|
||||
|
||||
if(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
|
||||
########## <part to keep synced with tests/version/CMakeLists.txt> ##########
|
||||
if(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h") # ICU >= 4
|
||||
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
|
||||
elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h") # ICU [2;4[
|
||||
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
|
||||
elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h") # ICU [1.4;2[
|
||||
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
|
||||
elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h") # ICU 1.3
|
||||
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
|
||||
else()
|
||||
message(FATAL_ERROR "ICU version header not found")
|
||||
endif()
|
||||
|
||||
if(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *ICU_VERSION *\"([0-9]+)\".*") # ICU 1.3
|
||||
# [1.3;1.4[ as #define ICU_VERSION "3" (no patch version, ie all 1.3.X versions will be detected as 1.3.0)
|
||||
set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "1")
|
||||
set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_1}")
|
||||
set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0")
|
||||
elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION_MAJOR_NUM *([0-9]+).*")
|
||||
#
|
||||
# Since version 4.9.1, ICU release version numbering was totaly changed, see:
|
||||
# - http://site.icu-project.org/download/49
|
||||
# - http://userguide.icu-project.org/design#TOC-Version-Numbers-in-ICU
|
||||
#
|
||||
set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}")
|
||||
string(REGEX REPLACE ".*# *define *U_ICU_VERSION_MINOR_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}")
|
||||
string(REGEX REPLACE ".*# *define *U_ICU_VERSION_PATCHLEVEL_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}")
|
||||
elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION *\"(([0-9]+)(\\.[0-9]+)*)\".*") # ICU [1.4;1.8[
|
||||
# [1.4;1.8[ as #define U_ICU_VERSION "1.4.1.2" but it seems that some 1.4.1(?:\.\d)? have releasing error and appears as 1.4.0
|
||||
set(${ICU_PRIVATE_VAR_NS}_FULL_VERSION "${CMAKE_MATCH_1}") # copy CMAKE_MATCH_1, no longer valid on the following if
|
||||
if(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)$")
|
||||
set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}")
|
||||
set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}")
|
||||
set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0")
|
||||
elseif(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
||||
set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}")
|
||||
set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}")
|
||||
set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${CMAKE_MATCH_3}")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "failed to detect ICU version")
|
||||
endif()
|
||||
set(${ICU_PUBLIC_VAR_NS}_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_MINOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_PATCH_VERSION}")
|
||||
########## </part to keep synced with tests/version/CMakeLists.txt> ##########
|
||||
|
||||
# Check dependencies (implies pkg-config)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
set(${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
|
||||
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP})
|
||||
pkg_check_modules(PC_ICU_PRIVATE_VAR_NS "icu-${${ICU_PRIVATE_VAR_NS}_COMPONENT}" QUIET)
|
||||
|
||||
if(${PC_ICU_PRIVATE_VAR_NS}_FOUND)
|
||||
foreach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY ${PC_ICU_LIBRARIES})
|
||||
string(REGEX REPLACE "^icu" "" ${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY ${${PC_ICU_PRIVATE_VAR_NS}_LIBRARY})
|
||||
list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS ${${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY})
|
||||
endforeach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY)
|
||||
endif(${PC_ICU_PRIVATE_VAR_NS}_FOUND)
|
||||
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
|
||||
list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
|
||||
endif(PKG_CONFIG_FOUND)
|
||||
|
||||
# Check libraries
|
||||
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
|
||||
set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES )
|
||||
set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES )
|
||||
foreach(${ICU_PRIVATE_VAR_NS}_BASE_NAME ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}})
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}")
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}d")
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}")
|
||||
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}d")
|
||||
endforeach(${ICU_PRIVATE_VAR_NS}_BASE_NAME)
|
||||
|
||||
find_library(
|
||||
${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}
|
||||
NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES}
|
||||
HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT}
|
||||
PATH_SUFFIXES ${_ICU_LIB_SUFFIXES}
|
||||
DOC "Release libraries for ICU"
|
||||
)
|
||||
find_library(
|
||||
${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}
|
||||
NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES}
|
||||
HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT}
|
||||
PATH_SUFFIXES ${_ICU_LIB_SUFFIXES}
|
||||
DOC "Debug libraries for ICU"
|
||||
)
|
||||
|
||||
string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
|
||||
if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # both not found
|
||||
set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE)
|
||||
set("${ICU_PUBLIC_VAR_NS}_FOUND" FALSE)
|
||||
else(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # one or both found
|
||||
set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" TRUE)
|
||||
if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # release not found => we are in debug
|
||||
set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}")
|
||||
elseif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # debug not found => we are in release
|
||||
set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}")
|
||||
else() # both found
|
||||
set(
|
||||
${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT}
|
||||
optimized ${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}
|
||||
debug ${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}
|
||||
)
|
||||
endif()
|
||||
list(APPEND ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT}})
|
||||
endif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
|
||||
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
|
||||
|
||||
# Try to find out compiler flags
|
||||
find_program(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE icu-config HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT})
|
||||
if(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE)
|
||||
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE)
|
||||
|
||||
# Check find_package arguments
|
||||
include(FindPackageHandleStandardArgs)
|
||||
if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
|
||||
find_package_handle_standard_args(
|
||||
${ICU_PUBLIC_VAR_NS}
|
||||
REQUIRED_VARS ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS
|
||||
VERSION_VAR ${ICU_PUBLIC_VAR_NS}_VERSION
|
||||
)
|
||||
else(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
|
||||
find_package_handle_standard_args(${ICU_PUBLIC_VAR_NS} "ICU not found" ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
|
||||
endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
|
||||
else(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
|
||||
set("${ICU_PUBLIC_VAR_NS}_FOUND" FALSE)
|
||||
if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
|
||||
message(FATAL_ERROR "Could not find ICU include directory")
|
||||
endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
|
||||
endif(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(
|
||||
${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS
|
||||
${ICU_PUBLIC_VAR_NS}_LIBRARIES
|
||||
)
|
||||
|
||||
# IN (args)
|
||||
icudebug("FIND_COMPONENTS")
|
||||
icudebug("FIND_REQUIRED")
|
||||
icudebug("FIND_QUIETLY")
|
||||
icudebug("FIND_VERSION")
|
||||
# OUT
|
||||
# Found
|
||||
icudebug("FOUND")
|
||||
icudebug("UC_FOUND")
|
||||
icudebug("I18N_FOUND")
|
||||
icudebug("IO_FOUND")
|
||||
icudebug("LE_FOUND")
|
||||
icudebug("LX_FOUND")
|
||||
icudebug("DATA_FOUND")
|
||||
# Flags
|
||||
icudebug("C_FLAGS")
|
||||
icudebug("CPP_FLAGS")
|
||||
icudebug("CXX_FLAGS")
|
||||
icudebug("C_SHARED_FLAGS")
|
||||
icudebug("CPP_SHARED_FLAGS")
|
||||
icudebug("CXX_SHARED_FLAGS")
|
||||
# Linking
|
||||
icudebug("INCLUDE_DIRS")
|
||||
icudebug("LIBRARIES")
|
||||
# Version
|
||||
icudebug("MAJOR_VERSION")
|
||||
icudebug("MINOR_VERSION")
|
||||
icudebug("PATCH_VERSION")
|
||||
icudebug("VERSION")
|
@ -1,3 +1,12 @@
|
||||
# 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(SourceGroups)
|
||||
|
||||
set(SSRC ${CMAKE_SOURCE_DIR})
|
||||
@ -14,16 +23,15 @@ set(H_CPP "(${H}|${CPP})")
|
||||
source_group("Resource files" ".*\\.(rc|ico)")
|
||||
|
||||
source_group("api" "${SSRC}/api/${H_CPP}")
|
||||
source_group("arch" "${SSRC}/arch/${H_CPP}")
|
||||
source_group("ccmain" "${SSRC}/ccmain/${H_CPP}")
|
||||
source_group("ccstruct" "${SSRC}/ccstruct/${H_CPP}")
|
||||
source_group("ccutil" "${SSRC}/ccutil/${H_CPP}")
|
||||
source_group("classify" "${SSRC}/classify/${H_CPP}")
|
||||
source_group("cube" "${SSRC}/cube/${H_CPP}")
|
||||
source_group("cutil" "${SSRC}/cutil/${H_CPP}")
|
||||
source_group("dict" "${SSRC}/dict/${H_CPP}")
|
||||
source_group("neural" "${SSRC}/neural_networks/runtime/${H_CPP}")
|
||||
source_group("lstm" "${SSRC}/lstm/${H_CPP}")
|
||||
source_group("opencl" "${SSRC}/opencl/${H_CPP}")
|
||||
source_group("textord" "${SSRC}/textord/${H_CPP}")
|
||||
source_group("viewer" "${SSRC}/viewer/${H_CPP}")
|
||||
source_group("port" "${SSRC}/vs2010/port/${H_CPP}")
|
||||
source_group("wordrec" "${SSRC}/wordrec/${H_CPP}")
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/TesseractTargets.cmake)
|
||||
|
||||
find_package(Leptonica REQUIRED)
|
||||
|
||||
# ======================================================
|
||||
# Version variables:
|
||||
# ======================================================
|
||||
@ -40,4 +42,4 @@ set(Tesseract_INCLUDE_DIRS @INCLUDE_DIR@)
|
||||
# Link libraries:
|
||||
# ====================================================================
|
||||
|
||||
set(Tesseract_LIBRARIES tesseract)
|
||||
set(Tesseract_LIBRARIES libtesseract)
|
||||
|
356
configure.ac
356
configure.ac
@ -5,29 +5,29 @@
|
||||
# ----------------------------------------
|
||||
# Initialization
|
||||
# ----------------------------------------
|
||||
AC_PREREQ([2.50])
|
||||
AC_INIT([tesseract], [3.05.00dev], [https://github.com/tesseract-ocr/tesseract/issues])
|
||||
AC_PREREQ([2.63])
|
||||
AC_INIT([tesseract],
|
||||
[m4_esyscmd_s([test -d .git && git describe --abbrev=4 || cat VERSION])],
|
||||
[https://github.com/tesseract-ocr/tesseract/issues],,
|
||||
[https://github.com/tesseract-ocr/tesseract/])
|
||||
AC_PROG_CXX([g++ clang++])
|
||||
AC_LANG([C++])
|
||||
AC_LANG_COMPILER_REQUIRE
|
||||
CXXFLAGS=${CXXFLAGS:-""}
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_AUX_DIR([config])
|
||||
AC_CONFIG_SRCDIR([api/tesseractmain.cpp])
|
||||
AC_CONFIG_SRCDIR([src/api/tesseractmain.cpp])
|
||||
AC_PREFIX_DEFAULT([/usr/local])
|
||||
|
||||
# Automake configuration. Do not require README file (we use README.md).
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
|
||||
# Define date of package, etc. Could be useful in auto-generated
|
||||
# documentation.
|
||||
PACKAGE_YEAR=2015
|
||||
PACKAGE_DATE="07/11"
|
||||
PACKAGE_YEAR=2018
|
||||
PACKAGE_DATE="10/29"
|
||||
|
||||
abs_top_srcdir=`AS_DIRNAME([$0])`
|
||||
gitrev="`git --git-dir=${abs_top_srcdir}/.git --work-tree=${abs_top_srcdir} describe --always --tags`"
|
||||
if test -n "${gitrev}" ; then
|
||||
AC_REVISION(["${gitrev}"])
|
||||
AC_DEFINE_UNQUOTED([GIT_REV], ["${gitrev}"], [Define to be the git revision])
|
||||
echo "Using git revision: ${gitrev}"
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED([PACKAGE_NAME], ["${PACKAGE_NAME}"], [Name of package])
|
||||
AC_DEFINE_UNQUOTED([PACKAGE_VERSION], ["${PACKAGE_VERSION}"], [Version number])
|
||||
@ -41,16 +41,19 @@ AC_SUBST([PACKAGE_DATE])
|
||||
|
||||
GENERIC_LIBRARY_NAME=tesseract
|
||||
|
||||
# Release versioning
|
||||
GENERIC_MAJOR_VERSION=3
|
||||
GENERIC_MINOR_VERSION=4
|
||||
GENERIC_MICRO_VERSION=0
|
||||
# Release versioning. Get versions from PACKAGE_VERSION.
|
||||
AX_SPLIT_VERSION
|
||||
GENERIC_MAJOR_VERSION=$(echo "$AX_MAJOR_VERSION" | $SED 's/^[[^0-9]]*//')
|
||||
GENERIC_MINOR_VERSION=$AX_MINOR_VERSION
|
||||
GENERIC_MICRO_VERSION=`echo "$AX_POINT_VERSION" | $SED 's/^\([[0-9]][[0-9]]*\).*/\1/'`
|
||||
|
||||
# API version (often = GENERIC_MAJOR_VERSION.GENERIC_MINOR_VERSION)
|
||||
GENERIC_API_VERSION=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION
|
||||
GENERIC_LIBRARY_VERSION=$GENERIC_MAJOR_VERSION:$GENERIC_MINOR_VERSION
|
||||
AC_SUBST([GENERIC_API_VERSION])
|
||||
AC_SUBST([GENERIC_MAJOR_VERSION])
|
||||
AC_SUBST([GENERIC_MINOR_VERSION])
|
||||
AC_SUBST([GENERIC_MICRO_VERSION])
|
||||
|
||||
AC_SUBST([GENERIC_LIBRARY_VERSION])
|
||||
PACKAGE=$GENERIC_LIBRARY_NAME
|
||||
@ -61,20 +64,13 @@ GENERIC_RELEASE=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION
|
||||
AC_SUBST([GENERIC_RELEASE])
|
||||
AC_SUBST([GENERIC_VERSION])
|
||||
|
||||
# ----------------------------------------
|
||||
# Automake configuration
|
||||
# ----------------------------------------
|
||||
|
||||
# Do not require README file (we use README.md)
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
AC_CONFIG_HEADERS([config_auto.h:config/config.h.in])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
# default conditional
|
||||
AM_CONDITIONAL([T_WIN], false)
|
||||
AM_CONDITIONAL([MINGW], false)
|
||||
AM_CONDITIONAL([OSX], false)
|
||||
AM_CONDITIONAL([GRAPHICS_DISABLED], false)
|
||||
AC_SUBST([AM_CPPFLAGS])
|
||||
|
||||
OPENCL_INC="/opt/AMDAPP/include"
|
||||
OPENCL_LIBS="-lOpenCL"
|
||||
@ -86,15 +82,13 @@ OPENCL_LIBS="-lOpenCL"
|
||||
AC_CANONICAL_HOST
|
||||
case "${host_os}" in
|
||||
mingw*)
|
||||
AC_DEFINE_UNQUOTED([MINGW], 1, [This is a MinGW system])
|
||||
AM_CONDITIONAL([T_WIN], true)
|
||||
AM_CONDITIONAL([MINGW], true)
|
||||
AM_CONDITIONAL([ADD_RT], false)
|
||||
AC_SUBST([AM_LDFLAGS], ['-Wl,-no-undefined -Wl,--as-needed'])
|
||||
;;
|
||||
cygwin*)
|
||||
AM_CONDITIONAL([ADD_RT], false)
|
||||
AC_SUBST([AM_LDFLAGS], ['-Wl,-no-undefined -Wl,--as-needed'])
|
||||
AC_SUBST([NOUNDEFINED], ['-no-undefined'])
|
||||
;;
|
||||
solaris*)
|
||||
LIBS="-lsocket -lnsl -lrt -lxnet"
|
||||
@ -105,6 +99,9 @@ case "${host_os}" in
|
||||
OPENCL_INC=""
|
||||
AM_CONDITIONAL([ADD_RT], false)
|
||||
;;
|
||||
*android*)
|
||||
AM_CONDITIONAL([ADD_RT], false)
|
||||
;;
|
||||
powerpc-*-darwin*)
|
||||
OPENCL_LIBS=""
|
||||
;;
|
||||
@ -114,10 +111,34 @@ case "${host_os}" in
|
||||
;;
|
||||
esac
|
||||
|
||||
includedir="${includedir}/tesseract"
|
||||
## Checks for supported compiler options.
|
||||
AM_CONDITIONAL([AVX_OPT], false)
|
||||
AM_CONDITIONAL([AVX2_OPT], false)
|
||||
AM_CONDITIONAL([SSE41_OPT], false)
|
||||
AM_CONDITIONAL([MARCH_NATIVE_OPT], false)
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-mavx], [avx=true], [avx=false])
|
||||
if $avx; then
|
||||
AM_CONDITIONAL([AVX_OPT], true)
|
||||
fi
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-mavx2], [avx2=true], [avx2=false])
|
||||
if $avx2; then
|
||||
AM_CONDITIONAL([AVX2_OPT], true)
|
||||
fi
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-msse4.1], [sse41=true], [sse41=false])
|
||||
if $sse41; then
|
||||
AM_CONDITIONAL([SSE41_OPT], true)
|
||||
fi
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-march=native], [arch_native=true], [arch_native=false])
|
||||
if $arch_native; then
|
||||
AM_CONDITIONAL([MARCH_NATIVE_OPT], true)
|
||||
fi
|
||||
|
||||
AC_ARG_WITH([extra-includes],
|
||||
[AC_HELP_STRING([--with-extra-includes=DIR],
|
||||
[AS_HELP_STRING([--with-extra-includes=DIR],
|
||||
[Define an additional directory for include files])],
|
||||
[if test -d "$withval" ; then
|
||||
CFLAGS="$CFLAGS -I$withval"
|
||||
@ -126,7 +147,7 @@ AC_ARG_WITH([extra-includes],
|
||||
fi])
|
||||
|
||||
AC_ARG_WITH([extra-libraries],
|
||||
[AC_HELP_STRING([--with-extra-libraries=DIR],
|
||||
[AS_HELP_STRING([--with-extra-libraries=DIR],
|
||||
[Define an additional directory for library files])],
|
||||
[if test -d "$withval" ; then
|
||||
LDFLAGS="$LDFLAGS -L$withval"
|
||||
@ -136,64 +157,48 @@ AC_ARG_WITH([extra-libraries],
|
||||
|
||||
AC_MSG_CHECKING([--enable-graphics argument])
|
||||
AC_ARG_ENABLE([graphics],
|
||||
[AC_HELP_STRING([--enable-graphics],[enable graphics (ScrollView) (default)])
|
||||
AC_HELP_STRING([--disable-graphics],[disable graphics (ScrollView)])],
|
||||
[enable_graphics=$enableval],
|
||||
[enable_graphics="yes"])
|
||||
AS_HELP_STRING([--disable-graphics], [disable graphics (ScrollView)]))
|
||||
AC_MSG_RESULT([$enable_graphics])
|
||||
if test "$enable_graphics" = "no"; then
|
||||
AC_DEFINE([GRAPHICS_DISABLED], [], [Disable graphics])
|
||||
AM_CONDITIONAL([GRAPHICS_DISABLED], true)
|
||||
fi
|
||||
|
||||
# Check if cube should be disabled
|
||||
AC_MSG_CHECKING([whether to disable cube])
|
||||
AC_ARG_ENABLE([cube],
|
||||
[AC_HELP_STRING([--disable-cube], [don't build cube support (experimental)])],
|
||||
[disable_cube="yes"], [disable_cube="no"])
|
||||
AC_MSG_RESULT([$disable_cube])
|
||||
AM_CONDITIONAL([NO_CUBE_BUILD], [test "$disable_cube" = "yes"])
|
||||
if test "$disable_cube" = "yes"; then
|
||||
AC_SUBST([AM_CPPFLAGS], [-DNO_CUBE_BUILD])
|
||||
fi
|
||||
AC_MSG_CHECKING([--enable-legacy argument])
|
||||
AC_ARG_ENABLE([legacy],
|
||||
AS_HELP_STRING([--disable-legacy], [disable the legacy OCR engine]))
|
||||
AC_MSG_RESULT([$enable_legacy])
|
||||
AM_CONDITIONAL([DISABLED_LEGACY_ENGINE], test "$enable_legacy" = "no")
|
||||
|
||||
# check whether to build embedded version
|
||||
AC_MSG_CHECKING([--enable-embedded argument])
|
||||
AC_ARG_ENABLE([embedded],
|
||||
[ --enable-embedded enable embedded build (default=no)],
|
||||
[enable_embedded=$enableval],
|
||||
[enable_embedded="no"])
|
||||
AS_HELP_STRING([--enable-embedded], [enable embedded build [default=no]]))
|
||||
AC_MSG_RESULT([$enable_embedded])
|
||||
AM_CONDITIONAL([EMBEDDED], [test "$enable_embedded" = "yes"])
|
||||
if test "$enable_embedded" = "yes"; then
|
||||
AC_SUBST([AM_CPPFLAGS], [-DEMBEDDED])
|
||||
AM_CPPFLAGS="-DEMBEDDED $AM_CPPFLAGS"
|
||||
fi
|
||||
|
||||
# check whether to build OpenMP support
|
||||
AM_CONDITIONAL([OPENMP], false)
|
||||
AC_OPENMP
|
||||
AS_IF([test "x$OPENMP_CFLAGS" != "x"],
|
||||
[AM_CONDITIONAL([OPENMP], true)
|
||||
AC_SUBST([AM_CPPFLAGS], ["$OPENMP_CXXFLAGS"])
|
||||
AC_DEFINE([OPENMP], [], [Defined when compiled with OpenMP support])]
|
||||
)
|
||||
|
||||
have_tiff=false
|
||||
# Note that the first usage of AC_CHECK_HEADERS must be unconditional.
|
||||
AC_CHECK_HEADERS([tiffio.h], [have_tiff=true], [have_tiff=false])
|
||||
|
||||
# check whether to build opencl version
|
||||
AC_MSG_CHECKING([--enable-opencl argument])
|
||||
AC_ARG_ENABLE([opencl],
|
||||
[ --enable-opencl enable opencl build (default=no)],
|
||||
[enable_opencl=$enableval],
|
||||
[enable_opencl="no"])
|
||||
AS_HELP_STRING([--enable-opencl], [enable opencl build [default=no]]))
|
||||
AC_MSG_RESULT([$enable_opencl])
|
||||
# check for opencl header
|
||||
have_opencl=false
|
||||
AC_CHECK_HEADERS([CL/cl.h], [have_opencl=true], [
|
||||
AC_CHECK_HEADERS(OpenCL/cl.h, have_opencl=true, have_opencl=false)
|
||||
])
|
||||
|
||||
have_tiff=false
|
||||
AC_CHECK_HEADERS([tiffio.h], [have_tiff=true], [have_tiff=false])
|
||||
if test "$enable_opencl" = "yes"; then
|
||||
AC_CHECK_HEADERS([CL/cl.h], [have_opencl=true], [
|
||||
AC_CHECK_HEADERS(OpenCL/cl.h, [have_opencl=true], [have_opencl=false])
|
||||
])
|
||||
fi
|
||||
|
||||
# https://lists.apple.com/archives/unix-porting/2009/Jan/msg00026.html
|
||||
m4_define([MY_CHECK_FRAMEWORK],
|
||||
@ -227,26 +232,23 @@ case "${host_os}" in
|
||||
if !($have_opencl_lib); then
|
||||
AC_MSG_ERROR([Required OpenCL library not found!])
|
||||
fi
|
||||
AC_SUBST([AM_CPPFLAGS], [-DUSE_OPENCL])
|
||||
AM_CPPFLAGS="-DUSE_OPENCL $AM_CPPFLAGS"
|
||||
OPENCL_CPPFLAGS=""
|
||||
OPENCL_LDFLAGS="-framework OpenCL"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# default
|
||||
AC_CHECK_LIB([OpenCL], [clGetPlatformIDs],
|
||||
[have_opencl_lib=true], [have_opencl_lib=false])
|
||||
if test "$enable_opencl" = "yes"; then
|
||||
AC_CHECK_LIB([OpenCL], [clGetPlatformIDs],
|
||||
[have_opencl_lib=true], [have_opencl_lib=false])
|
||||
if !($have_opencl); then
|
||||
AC_MSG_ERROR([Required OpenCL headers not found!])
|
||||
fi
|
||||
if !($have_opencl_lib); then
|
||||
AC_MSG_ERROR([Required OpenCL library not found!])
|
||||
fi
|
||||
if !($have_tiff); then
|
||||
AC_MSG_ERROR([Required TIFF headers not found! Try to install libtiff-dev?? package.])
|
||||
fi
|
||||
AC_SUBST([AM_CPPFLAGS], [-DUSE_OPENCL])
|
||||
AM_CPPFLAGS="-DUSE_OPENCL $AM_CPPFLAGS"
|
||||
OPENCL_CPPFLAGS="-I${OPENCL_INC}"
|
||||
OPENCL_LDFLAGS="${OPENCL_LIBS}"
|
||||
fi
|
||||
@ -261,44 +263,31 @@ AC_SUBST([OPENCL_LDFLAGS])
|
||||
# http://groups.google.com/group/tesseract-dev/browse_thread/thread/976645ae98189127
|
||||
AC_MSG_CHECKING([--enable-visibility argument])
|
||||
AC_ARG_ENABLE([visibility],
|
||||
[AC_HELP_STRING([--enable-visibility],[enable experimental build with fvisibility (default=no)])],
|
||||
[enable_visibility=$enableval],
|
||||
[enable_visibility="no"])
|
||||
AS_HELP_STRING([--enable-visibility],
|
||||
[enable experimental build with -fvisibility [default=no]]))
|
||||
AC_MSG_RESULT([$enable_visibility])
|
||||
AM_CONDITIONAL([VISIBILITY], [test "$enable_visibility" = "yes"])
|
||||
|
||||
# check whether to build multiple libraries
|
||||
AC_MSG_CHECKING([--enable-multiple-libraries argument])
|
||||
AC_ARG_ENABLE([multiple-libraries],
|
||||
[AC_HELP_STRING([--enable-multiple-libraries],[enable multiple libraries (default=no)])],
|
||||
[enable_mlibs=$enableval],
|
||||
[enable_mlibs="no"])
|
||||
AC_MSG_RESULT([$enable_mlibs])
|
||||
AM_CONDITIONAL([USING_MULTIPLELIBS], [test "$enable_mlibs" = "yes"])
|
||||
|
||||
# Check if tessdata-prefix is disabled
|
||||
AC_MSG_CHECKING([whether to use tessdata-prefix])
|
||||
AC_ARG_ENABLE([tessdata-prefix],
|
||||
[AC_HELP_STRING([--disable-tessdata-prefix],
|
||||
[AS_HELP_STRING([--disable-tessdata-prefix],
|
||||
[don't set TESSDATA-PREFIX during compile])],
|
||||
[tessdata_prefix="no"], [tessdata_prefix="yes"])
|
||||
AC_MSG_RESULT([$tessdata_prefix])
|
||||
AM_CONDITIONAL([NO_TESSDATA_PREFIX], [test "$tessdata_prefix" = "no"])
|
||||
|
||||
# Check whether enable debuging
|
||||
# Check whether to enable debugging
|
||||
AC_MSG_CHECKING([whether to enable debugging])
|
||||
AC_ARG_ENABLE([debug],
|
||||
[AC_HELP_STRING([--enable-debug],
|
||||
[turn on debugging (default=no)])],
|
||||
[debug=$enableval],
|
||||
[debug="no"])
|
||||
AC_MSG_RESULT([$debug])
|
||||
if test x"$debug" = x"yes"; then
|
||||
AM_CXXFLAGS="$AM_CXXFLAGS -g -Wall -Wno-uninitialized -O0 -DDEBUG"
|
||||
AM_CPPFLAGS="$AM_CPPFLAGS -g -Wall -Wno-uninitialized -O0 -DDEBUG"
|
||||
AS_HELP_STRING([--enable-debug], [turn on debugging [default=no]]))
|
||||
AC_MSG_RESULT([$enable_debug])
|
||||
if test x"$enable_debug" = x"yes"; then
|
||||
AM_CXXFLAGS="$AM_CXXFLAGS -g -Wall -O0 -DDEBUG"
|
||||
AM_CPPFLAGS="$AM_CPPFLAGS -g -Wall -DDEBUG"
|
||||
else
|
||||
AM_CXXFLAGS="$AM_CXXFLAGS -O2 -DNDEBUG"
|
||||
AM_CPPFLAGS="$AM_CPPFLAGS -O2 -DNDEBUG"
|
||||
AM_CPPFLAGS="$AM_CPPFLAGS -DNDEBUG"
|
||||
fi
|
||||
|
||||
#localedir='${prefix}/share/locale'
|
||||
@ -312,30 +301,18 @@ if test -d $curwd/gnu/lib ; then
|
||||
LDFLAGS="$LDFLAGS -L$curwd/gnu/lib"
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
# Check Compiler Characteristics and
|
||||
# configure automake. The two appear to
|
||||
# be intimately linked...
|
||||
# ----------------------------------------
|
||||
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
# ----------------------------------------
|
||||
# Additional checking of compiler characteristics
|
||||
# ----------------------------------------
|
||||
|
||||
# Check Endianness. If Big Endian, this will define WORDS_BIGENDIAN
|
||||
# See also at end of this file, where we define INTEL_BYTE_ORDER
|
||||
# or MOTOROLA_BYTE_ORDER.
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
|
||||
# ----------------------------------------
|
||||
# Check for programs we need
|
||||
# Init libtool
|
||||
# ----------------------------------------
|
||||
|
||||
# Check where all the following programs are and set
|
||||
# variables accordingly:
|
||||
LT_INIT
|
||||
|
||||
|
||||
@ -343,8 +320,6 @@ LT_INIT
|
||||
# C++ related options
|
||||
# ----------------------------------------
|
||||
|
||||
AC_LANG_CPLUSPLUS
|
||||
|
||||
AC_MSG_CHECKING([if compiling with clang])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([], [[
|
||||
@ -373,15 +348,35 @@ AC_COMPILE_IFELSE(
|
||||
]])
|
||||
], [
|
||||
AC_MSG_RESULT(yes)
|
||||
has_cpp11=yes
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
has_cpp11=no
|
||||
AC_MSG_ERROR([Your compiler does not have the necessary c++11 support! Cannot proceed.])
|
||||
])
|
||||
AC_CHECK_FUNCS([snprintf],, [snprintfworks=yes])
|
||||
CXXFLAGS="$OLD_CXXFLAGS"
|
||||
|
||||
|
||||
# set c++11 support based on platform/compiler
|
||||
case "${host_os}" in
|
||||
cygwin*)
|
||||
CXXFLAGS="$CXXFLAGS -std=gnu++11"
|
||||
;;
|
||||
*-darwin* | *-macos10*)
|
||||
if test "x$CLANG" = "xyes"; then
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11 "
|
||||
LDFLAGS="$LDFLAGS -stdlib=libc++"
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# default
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# ----------------------------------------
|
||||
# Check for libraries
|
||||
# ----------------------------------------
|
||||
@ -401,11 +396,16 @@ AC_CHECK_HEADERS([limits.h malloc.h])
|
||||
# Enable use of system-defined bool type if available:
|
||||
AC_HEADER_STDBOOL
|
||||
|
||||
# Misc
|
||||
AC_SYS_INTERPRETER
|
||||
AC_SYS_LARGEFILE
|
||||
# ----------------------------------------
|
||||
# Check for programs needed to build documentation.
|
||||
# ----------------------------------------
|
||||
|
||||
AC_CHECK_FUNCS([getline])
|
||||
AC_CHECK_PROG([have_asciidoc], asciidoc, true, false)
|
||||
if $have_asciidoc; then
|
||||
AM_CONDITIONAL([ASCIIDOC], true)
|
||||
else
|
||||
AM_CONDITIONAL([ASCIIDOC], false)
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
@ -420,59 +420,35 @@ AC_CHECK_TYPES([mbstate_t],,, [#include "wchar.h"])
|
||||
# Test auxiliary packages
|
||||
# ----------------------------------------
|
||||
|
||||
# Check location of leptonica/liblept headers.
|
||||
AC_MSG_CHECKING([for leptonica])
|
||||
AC_ARG_VAR([LIBLEPT_HEADERSDIR], [Leptonica headers directory])
|
||||
|
||||
have_lept=no
|
||||
if test "$LIBLEPT_HEADERSDIR" = "" ; then
|
||||
LIBLEPT_HEADERSDIR="/usr/local/include /usr/include /opt/local/include/leptonica"
|
||||
fi
|
||||
for incd in $LIBLEPT_HEADERSDIR
|
||||
do
|
||||
for lept in . leptonica liblept
|
||||
do
|
||||
if test -r "$incd/$lept/allheaders.h" ; then
|
||||
CPPFLAGS="$CPPFLAGS -I$incd/$lept"
|
||||
have_lept=yes
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
if test "$have_lept" = yes ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_CHECK_LIB([lept], [l_generateCIDataForPdf], [],
|
||||
[AC_MSG_ERROR([leptonica library with pdf support (>= 1.71) is missing])])
|
||||
PKG_CHECK_MODULES([LEPTONICA], [lept >= 1.74], [have_lept=true], [have_lept=false])
|
||||
if $have_lept; then
|
||||
CPPFLAGS="$CPPFLAGS $LEPTONICA_CFLAGS"
|
||||
else
|
||||
AC_MSG_ERROR([leptonica not found])
|
||||
AC_MSG_ERROR([Leptonica 1.74 or higher is required. Try to install libleptonica-dev package.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([leptonica headers version >= 1.71])
|
||||
AC_PREPROC_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include "allheaders.h"],
|
||||
[#if (LIBLEPT_MAJOR_VERSION >= 1) && (LIBLEPT_MINOR_VERSION >= 71)
|
||||
int i = 0;
|
||||
#else
|
||||
#error You need to upgrade your leptonica library!
|
||||
#endif])],
|
||||
[AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_FAILURE([leptonica 1.71 or higher is required])])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_TRAINING], true)
|
||||
|
||||
# Check location of icu headers
|
||||
have_icu=false
|
||||
AC_CHECK_HEADERS([unicode/uchar.h], [have_icu=true], [have_icu=false])
|
||||
if !($have_icu); then
|
||||
AC_MSG_WARN([Training tools WILL NOT be built because of missing icu library.])
|
||||
PKG_CHECK_MODULES([ICU_UC], [icu-uc >= 52.1], [have_icu_uc=true], [have_icu_uc=false])
|
||||
PKG_CHECK_MODULES([ICU_I18N], [icu-i18n >= 52.1], [have_icu_i18n=true], [have_icu_i18n=false])
|
||||
if !($have_icu_uc && $have_icu_i18n); then
|
||||
AC_CHECK_HEADERS([unicode/uchar.h], [have_icu=true], [have_icu=false])
|
||||
if !($have_icu); then
|
||||
AC_MSG_WARN([icu 52.1 or higher is required, but was not found.])
|
||||
AC_MSG_WARN([Training tools WILL NOT be built.])
|
||||
AC_MSG_WARN([Try to install libicu-devel package.])
|
||||
AM_CONDITIONAL([ENABLE_TRAINING], false)
|
||||
else
|
||||
ICU_UC_LIBS="-licui18n -licuuc"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check location of pango headers
|
||||
PKG_CHECK_MODULES([pango], [pango], [have_pango=true], [have_pango=false])
|
||||
PKG_CHECK_MODULES([pango], [pango >= 1.22.0], [have_pango=true], [have_pango=false])
|
||||
if !($have_pango); then
|
||||
AC_MSG_WARN([Training tools WILL NOT be built because of missing pango library.])
|
||||
AC_MSG_WARN([pango 1.22.0 or higher is required, but was not found.])
|
||||
AC_MSG_WARN([Training tools WILL NOT be built.])
|
||||
AC_MSG_WARN([Try to install libpango1.0-dev package.])
|
||||
AM_CONDITIONAL([ENABLE_TRAINING], false)
|
||||
else
|
||||
@ -489,29 +465,6 @@ else
|
||||
CPPFLAGS="$CPPFLAGS $cairo_CFLAGS"
|
||||
fi
|
||||
|
||||
# set c++11 support based on platform/compiler
|
||||
if test "x$has_cpp11" = "xyes"; then
|
||||
case "${host_os}" in
|
||||
cygwin*)
|
||||
CXXFLAGS="$CXXFLAGS -std=gnu++11"
|
||||
;;
|
||||
*-darwin* | *-macos10*)
|
||||
if test "x$CLANG" = "xyes"; then
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11 "
|
||||
LDFLAGS="$LDFLAGS -stdlib=libc++"
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# default
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
AC_MSG_WARN([Training tools WILL NOT be built because of missing c++11 support.])
|
||||
AM_CONDITIONAL([ENABLE_TRAINING], false)
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
# Final Tasks and Output
|
||||
@ -519,23 +472,24 @@ fi
|
||||
|
||||
# Output files
|
||||
AC_CONFIG_FILES([Makefile tesseract.pc])
|
||||
AC_CONFIG_FILES([api/Makefile])
|
||||
AC_CONFIG_FILES([ccmain/Makefile])
|
||||
AC_CONFIG_FILES([opencl/Makefile])
|
||||
AC_CONFIG_FILES([ccstruct/Makefile])
|
||||
AC_CONFIG_FILES([ccutil/Makefile])
|
||||
AC_CONFIG_FILES([classify/Makefile])
|
||||
AC_CONFIG_FILES([cube/Makefile])
|
||||
AC_CONFIG_FILES([cutil/Makefile])
|
||||
AC_CONFIG_FILES([dict/Makefile])
|
||||
AC_CONFIG_FILES([neural_networks/runtime/Makefile])
|
||||
AC_CONFIG_FILES([textord/Makefile])
|
||||
AC_CONFIG_FILES([viewer/Makefile])
|
||||
AC_CONFIG_FILES([wordrec/Makefile])
|
||||
AC_CONFIG_FILES([src/api/Makefile])
|
||||
AC_CONFIG_FILES([src/api/tess_version.h])
|
||||
AC_CONFIG_FILES([src/arch/Makefile])
|
||||
AC_CONFIG_FILES([src/ccmain/Makefile])
|
||||
AC_CONFIG_FILES([src/opencl/Makefile])
|
||||
AC_CONFIG_FILES([src/ccstruct/Makefile])
|
||||
AC_CONFIG_FILES([src/ccutil/Makefile])
|
||||
AC_CONFIG_FILES([src/classify/Makefile])
|
||||
AC_CONFIG_FILES([src/cutil/Makefile])
|
||||
AC_CONFIG_FILES([src/dict/Makefile])
|
||||
AC_CONFIG_FILES([src/lstm/Makefile])
|
||||
AC_CONFIG_FILES([src/textord/Makefile])
|
||||
AC_CONFIG_FILES([src/viewer/Makefile])
|
||||
AC_CONFIG_FILES([src/wordrec/Makefile])
|
||||
AC_CONFIG_FILES([tessdata/Makefile])
|
||||
AC_CONFIG_FILES([tessdata/configs/Makefile])
|
||||
AC_CONFIG_FILES([tessdata/tessconfigs/Makefile])
|
||||
AC_CONFIG_FILES([testing/Makefile])
|
||||
AC_CONFIG_FILES([unittest/Makefile])
|
||||
AC_CONFIG_FILES([java/Makefile])
|
||||
AC_CONFIG_FILES([java/com/Makefile])
|
||||
AC_CONFIG_FILES([java/com/google/Makefile])
|
||||
@ -543,7 +497,7 @@ AC_CONFIG_FILES([java/com/google/scrollview/Makefile])
|
||||
AC_CONFIG_FILES([java/com/google/scrollview/events/Makefile])
|
||||
AC_CONFIG_FILES([java/com/google/scrollview/ui/Makefile])
|
||||
AC_CONFIG_FILES([doc/Makefile])
|
||||
AM_COND_IF([ENABLE_TRAINING], [AC_CONFIG_FILES(training/Makefile)])
|
||||
AM_COND_IF([ENABLE_TRAINING], [AC_CONFIG_FILES(src/training/Makefile)])
|
||||
AC_OUTPUT
|
||||
|
||||
# Final message
|
||||
@ -553,18 +507,30 @@ echo "You can now build and install $PACKAGE_NAME by running:"
|
||||
echo ""
|
||||
echo "$ make"
|
||||
echo "$ sudo make install"
|
||||
echo "$ sudo ldconfig"
|
||||
echo ""
|
||||
|
||||
AM_COND_IF([ASCIIDOC],
|
||||
[
|
||||
echo "This will also build the documentation."
|
||||
], [
|
||||
echo "Documentation will not be built because asciidoc is missing."
|
||||
]
|
||||
)
|
||||
|
||||
# echo "$ sudo make install LANGS=\"eng ara deu\""
|
||||
# echo " Or:"
|
||||
# echo "$ sudo make install-langs"
|
||||
echo ""
|
||||
|
||||
AM_COND_IF([ENABLE_TRAINING],
|
||||
[echo ""
|
||||
echo "Training tools can be build and installed (after building of $PACKAGE_NAME) with:"
|
||||
[
|
||||
echo "Training tools can be built and installed with:"
|
||||
echo ""
|
||||
echo "$ make training"
|
||||
echo "$ sudo make training-install"
|
||||
echo ""],
|
||||
[echo ""
|
||||
[
|
||||
echo "You can not build training tools because of missing dependency."
|
||||
echo "Check configure output for details."
|
||||
echo ""]
|
||||
|
@ -1,74 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2012 Zdenko Podobný
|
||||
# Author: Zdenko Podobný
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Simple python demo script of tesseract-ocr 3.02 c-api
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import ctypes
|
||||
|
||||
# Demo variables
|
||||
lang = "eng"
|
||||
filename = "../phototest.tif"
|
||||
libpath = "/usr/local/lib64/"
|
||||
libpath_w = "../vs2010/DLL_Release/"
|
||||
TESSDATA_PREFIX = os.environ.get('TESSDATA_PREFIX')
|
||||
if not TESSDATA_PREFIX:
|
||||
TESSDATA_PREFIX = "../"
|
||||
|
||||
if sys.platform == "win32":
|
||||
libname = libpath_w + "libtesseract302.dll"
|
||||
libname_alt = "libtesseract302.dll"
|
||||
os.environ["PATH"] += os.pathsep + libpath_w
|
||||
else:
|
||||
libname = libpath + "libtesseract.so.3.0.2"
|
||||
libname_alt = "libtesseract.so.3"
|
||||
|
||||
try:
|
||||
tesseract = ctypes.cdll.LoadLibrary(libname)
|
||||
except:
|
||||
try:
|
||||
tesseract = ctypes.cdll.LoadLibrary(libname_alt)
|
||||
except WindowsError, err:
|
||||
print("Trying to load '%s'..." % libname)
|
||||
print("Trying to load '%s'..." % libname_alt)
|
||||
print(err)
|
||||
exit(1)
|
||||
|
||||
tesseract.TessVersion.restype = ctypes.c_char_p
|
||||
tesseract_version = tesseract.TessVersion()[:4]
|
||||
|
||||
# We need to check library version because libtesseract.so.3 is symlink
|
||||
# and can point to other version than 3.02
|
||||
if float(tesseract_version) < 3.02:
|
||||
print("Found tesseract-ocr library version %s." % tesseract_version)
|
||||
print("C-API is present only in version 3.02!")
|
||||
exit(2)
|
||||
|
||||
api = tesseract.TessBaseAPICreate()
|
||||
rc = tesseract.TessBaseAPIInit3(api, TESSDATA_PREFIX, lang);
|
||||
if (rc):
|
||||
tesseract.TessBaseAPIDelete(api)
|
||||
print("Could not initialize tesseract.\n")
|
||||
exit(3)
|
||||
|
||||
text_out = tesseract.TessBaseAPIProcessPages(api, filename, None , 0);
|
||||
result_text = ctypes.string_at(text_out)
|
||||
print result_text
|
@ -1,39 +0,0 @@
|
||||
#-*- mode: shell-script;-*-
|
||||
#
|
||||
# bash completion support for tesseract
|
||||
#
|
||||
# Copyright (C) 2009 Neskie A. Manuel <neskiem@gmail.com>
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
#
|
||||
|
||||
_tesseract_languages()
|
||||
{
|
||||
local TESSDATA="/usr/share/tesseract-ocr/tessdata/"
|
||||
local langs="$(ls $TESSDATA | grep traineddata | cut -d \. -f 1)"
|
||||
|
||||
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W "$langs" -- "$cur") )
|
||||
}
|
||||
|
||||
_tesseract()
|
||||
{
|
||||
local cur prev
|
||||
COMPREPLY=()
|
||||
cur="$2"
|
||||
prev="$3"
|
||||
|
||||
case "$prev" in
|
||||
tesseract)
|
||||
COMPREPLY=($(compgen -f -X "!*.+(tif)" -- "$cur") )
|
||||
;;
|
||||
*.tif)
|
||||
COMPREPLY=($(compgen -W "$(basename $prev .tif)" ) )
|
||||
;;
|
||||
-l)
|
||||
_tesseract_languages
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "-l" ) )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
complete -F _tesseract -o nospace tesseract
|
@ -1,35 +0,0 @@
|
||||
bul Bulgarian
|
||||
cat Catalan
|
||||
ces Czech
|
||||
chi_sim Simplified Chinese
|
||||
chi_tra Traditional Chinese
|
||||
dan-frak Danish (Fraktur)
|
||||
dan Danish
|
||||
deu German
|
||||
ell Greek
|
||||
eng English
|
||||
fin Finnish
|
||||
fra French
|
||||
hun Hungarian
|
||||
ind Indonesian
|
||||
ita Italian
|
||||
jpn Japanese
|
||||
kor Korean
|
||||
lav Latvian
|
||||
lit Lithuanian
|
||||
nld Dutch
|
||||
nor Norwegian
|
||||
pol Polish
|
||||
por Portuguese
|
||||
ron Romanian
|
||||
rus Russian
|
||||
slk Slovakian
|
||||
slv Slovenian
|
||||
spa Spanish
|
||||
srp Serbian
|
||||
swe Swedish
|
||||
tgl Tagalog
|
||||
tha Thai
|
||||
tur Turkish
|
||||
ukr Ukrainian
|
||||
vie Vietnamese
|
275
cppan.yml
Normal file
275
cppan.yml
Normal file
@ -0,0 +1,275 @@
|
||||
local_settings:
|
||||
#use_shared_libs: true
|
||||
#short_local_names: true
|
||||
#use_cache: false
|
||||
#generator: Visual Studio 14 2015 Win64
|
||||
silent: false
|
||||
#copy_import_libs: true
|
||||
#build:
|
||||
#c_flags: /W0
|
||||
#cxx_flags: /W0
|
||||
builds:
|
||||
vs2017:
|
||||
generator: Visual Studio 15 2017
|
||||
vs2017_64:
|
||||
generator: Visual Studio 15 2017 Win64
|
||||
|
||||
dependencies:
|
||||
pvt.cppan.demo.danbloomberg.leptonica: 1
|
||||
pvt.cppan.demo.unicode.icu.i18n: "*"
|
||||
|
||||
root_project: pvt.cppan.demo.google.tesseract
|
||||
|
||||
common_settings:
|
||||
c++: 11
|
||||
|
||||
options:
|
||||
any:
|
||||
compile_options:
|
||||
msvc:
|
||||
private:
|
||||
- /openmp
|
||||
|
||||
projects:
|
||||
libtesseract:
|
||||
type: lib
|
||||
export_all_symbols: true
|
||||
files:
|
||||
- src/api/tess_version.h.in
|
||||
- src/api/.*\.cpp
|
||||
- src/arch/.*\.cpp
|
||||
- src/ccmain/.*\.cpp
|
||||
- src/ccstruct/.*\.cpp
|
||||
- src/ccutil/.*\.cpp
|
||||
- src/classify/.*\.cpp
|
||||
- src/cutil/.*\.cpp
|
||||
- src/dict/.*\.cpp
|
||||
- src/lstm/.*\.cpp
|
||||
- src/opencl/.*\.cpp
|
||||
- src/textord/.*\.cpp
|
||||
- src/viewer/.*\.cpp
|
||||
- src/wordrec/.*\.cpp
|
||||
|
||||
- src/api/.*\.h
|
||||
- src/arch/.*\.h
|
||||
- src/ccmain/.*\.h
|
||||
- src/ccstruct/.*\.h
|
||||
- src/ccutil/.*\.h
|
||||
- src/classify/.*\.h
|
||||
- src/cutil/.*\.h
|
||||
- src/dict/.*\.h
|
||||
- src/lstm/.*\.h
|
||||
- src/opencl/.*\.h
|
||||
- src/textord/.*\.h
|
||||
- src/viewer/.*\.h
|
||||
- src/wordrec/.*\.h
|
||||
|
||||
exclude_from_build:
|
||||
- src/api/tesseractmain.cpp
|
||||
- src/viewer/svpaint.cpp
|
||||
|
||||
include_directories:
|
||||
public:
|
||||
#private:
|
||||
- src/arch
|
||||
- src/classify
|
||||
- src/cutil
|
||||
- src/ccutil
|
||||
- src/dict
|
||||
- src/lstm
|
||||
- src/opencl
|
||||
- src/textord
|
||||
- src/viewer
|
||||
- src/wordrec
|
||||
#public:
|
||||
- src/api
|
||||
- src/ccmain
|
||||
- src/ccstruct
|
||||
- src/ccutil
|
||||
|
||||
check_symbol_exists:
|
||||
snprintf: stdio.h
|
||||
|
||||
check_include_exists:
|
||||
- dlfcn.h
|
||||
- inttypes.h
|
||||
- limits.h
|
||||
- malloc.h
|
||||
- memory.h
|
||||
- stdbool.h
|
||||
- stdint.h
|
||||
- stdlib.h
|
||||
- string.h
|
||||
- sys/ipc.h
|
||||
- sys/shm.h
|
||||
- sys/stat.h
|
||||
- sys/types.h
|
||||
- sys/wait.h
|
||||
- tiffio.h
|
||||
- unistd.h
|
||||
|
||||
check_type_size:
|
||||
- long long int
|
||||
- off_t
|
||||
- mbstate_t
|
||||
- wchar_t
|
||||
- _Bool
|
||||
|
||||
pre_sources: |
|
||||
file_write_once(${BDIR}/config_auto.h "")
|
||||
|
||||
post_sources: |
|
||||
configure_file(
|
||||
${SDIR}/src/api/tess_version.h.in
|
||||
${BDIR}/tess_version.h @ONLY)
|
||||
if (WIN32)
|
||||
if (MSVC)
|
||||
set_source_files_properties(
|
||||
${SDIR}/src/arch/dotproductsse.cpp
|
||||
PROPERTIES COMPILE_DEFINITIONS __SSE4_1__)
|
||||
set_source_files_properties(
|
||||
${SDIR}/src/arch/intsimdmatrixsse.cpp
|
||||
PROPERTIES COMPILE_DEFINITIONS __SSE4_1__)
|
||||
set_source_files_properties(
|
||||
${SDIR}/src/arch/dotproductavx.cpp
|
||||
PROPERTIES COMPILE_FLAGS "/arch:AVX")
|
||||
set_source_files_properties(
|
||||
${SDIR}/src/arch/intsimdmatrixavx2.cpp
|
||||
PROPERTIES COMPILE_FLAGS "/arch:AVX2")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
options:
|
||||
any:
|
||||
definitions:
|
||||
public:
|
||||
- HAVE_CONFIG_H
|
||||
- _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS=1
|
||||
- WINDLLNAME="tesseract"
|
||||
shared:
|
||||
definitions:
|
||||
private:
|
||||
- TESS_EXPORTS
|
||||
interface:
|
||||
- TESS_IMPORTS
|
||||
|
||||
dependencies:
|
||||
pvt.cppan.demo.danbloomberg.leptonica: 1
|
||||
|
||||
tesseract:
|
||||
files: src/api/tesseractmain.cpp
|
||||
dependencies:
|
||||
- libtesseract
|
||||
|
||||
tessopt:
|
||||
type: lib
|
||||
static_only: true
|
||||
files: src/training/tessopt.*
|
||||
include_directories: training
|
||||
dependencies: libtesseract
|
||||
|
||||
common_training:
|
||||
type: lib
|
||||
static_only: true
|
||||
files:
|
||||
- src/training/commandlineflags.cpp
|
||||
- src/training/commandlineflags.h
|
||||
- src/training/commontraining.cpp
|
||||
- src/training/commontraining.h
|
||||
include_directories: training
|
||||
dependencies:
|
||||
- tessopt
|
||||
|
||||
ambiguous_words:
|
||||
files: src/training/ambiguous_words.cpp
|
||||
dependencies:
|
||||
- libtesseract
|
||||
|
||||
classifier_tester:
|
||||
files: src/training/classifier_tester.cpp
|
||||
dependencies: common_training
|
||||
|
||||
combine_lang_model:
|
||||
files: src/training/combine_lang_model.cpp
|
||||
dependencies: unicharset_training
|
||||
|
||||
combine_tessdata:
|
||||
files: src/training/combine_tessdata.cpp
|
||||
dependencies: libtesseract
|
||||
|
||||
cntraining:
|
||||
files: src/training/cntraining.cpp
|
||||
dependencies: common_training
|
||||
|
||||
dawg2wordlist:
|
||||
files: src/training/dawg2wordlist.cpp
|
||||
dependencies: libtesseract
|
||||
|
||||
mftraining:
|
||||
files:
|
||||
- src/training/mftraining.cpp
|
||||
- src/training/mergenf.*
|
||||
dependencies: common_training
|
||||
|
||||
shapeclustering:
|
||||
files: src/training/shapeclustering.cpp
|
||||
dependencies: common_training
|
||||
|
||||
unicharset_extractor:
|
||||
files: src/training/unicharset_extractor.cpp
|
||||
dependencies: unicharset_training
|
||||
|
||||
wordlist2dawg:
|
||||
files: src/training/wordlist2dawg.cpp
|
||||
dependencies: libtesseract
|
||||
|
||||
unicharset_training:
|
||||
type: lib
|
||||
static_only: true
|
||||
files:
|
||||
- src/training/fileio.*
|
||||
- src/training/icuerrorcode.*
|
||||
- src/training/lang_model_helpers.*
|
||||
- src/training/lstmtester.*
|
||||
- src/training/normstrngs.*
|
||||
- src/training/unicharset_training_utils.*
|
||||
- src/training/validat.*
|
||||
include_directories: training
|
||||
dependencies:
|
||||
- common_training
|
||||
- pvt.cppan.demo.unicode.icu.i18n
|
||||
|
||||
lstmeval:
|
||||
files: src/training/lstmeval.cpp
|
||||
dependencies: unicharset_training
|
||||
|
||||
lstmtraining:
|
||||
files: src/training/lstmtraining.cpp
|
||||
dependencies: unicharset_training
|
||||
|
||||
set_unicharset_properties:
|
||||
files: src/training/set_unicharset_properties.cpp
|
||||
dependencies: unicharset_training
|
||||
|
||||
text2image:
|
||||
files:
|
||||
- src/training/text2image.cpp
|
||||
- src/training/boxchar.cpp
|
||||
- src/training/boxchar.h
|
||||
- src/training/degradeimage.cpp
|
||||
- src/training/degradeimage.h
|
||||
- src/training/ligature_table.cpp
|
||||
- src/training/ligature_table.h
|
||||
- src/training/normstrngs.cpp
|
||||
- src/training/normstrngs.h
|
||||
- src/training/pango_font_info.cpp
|
||||
- src/training/pango_font_info.h
|
||||
- src/training/stringrenderer.cpp
|
||||
- src/training/stringrenderer.h
|
||||
- src/training/tlog.cpp
|
||||
- src/training/tlog.h
|
||||
- src/training/util.h
|
||||
|
||||
dependencies:
|
||||
- unicharset_training
|
||||
- pvt.cppan.demo.gnome.pango.pangocairo: 1
|
@ -1,55 +0,0 @@
|
||||
AM_CPPFLAGS += \
|
||||
-DUSE_STD_NAMESPACE \
|
||||
-I$(top_srcdir)/cutil -I$(top_srcdir)/ccutil \
|
||||
-I$(top_srcdir)/ccstruct -I$(top_srcdir)/dict \
|
||||
-I$(top_srcdir)/ccmain -I$(top_srcdir)/classify \
|
||||
-I$(top_srcdir)/textord -I$(top_srcdir)/wordrec \
|
||||
-I$(top_srcdir)/neural_networks/runtime \
|
||||
-I$(top_srcdir)/viewer
|
||||
|
||||
if VISIBILITY
|
||||
AM_CPPFLAGS += -DTESS_EXPORTS \
|
||||
-fvisibility=hidden -fvisibility-inlines-hidden
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
altlist.h beam_search.h bmp_8.h cached_file.h \
|
||||
char_altlist.h char_bigrams.h char_samp.h char_samp_enum.h \
|
||||
char_samp_set.h char_set.h classifier_base.h classifier_factory.h \
|
||||
con_comp.h cube_const.h conv_net_classifier.h cube_line_object.h \
|
||||
cube_line_segmenter.h cube_object.h cube_search_object.h \
|
||||
cube_tuning_params.h cube_utils.h feature_base.h feature_bmp.h \
|
||||
feature_chebyshev.h feature_hybrid.h hybrid_neural_net_classifier.h \
|
||||
lang_mod_edge.h lang_model.h search_column.h search_node.h \
|
||||
search_object.h string_32.h tess_lang_mod_edge.h tess_lang_model.h \
|
||||
tuning_params.h word_altlist.h word_list_lang_model.h word_size_model.h \
|
||||
word_unigrams.h
|
||||
|
||||
if !USING_MULTIPLELIBS
|
||||
noinst_LTLIBRARIES = libtesseract_cube.la
|
||||
else
|
||||
lib_LTLIBRARIES = libtesseract_cube.la
|
||||
libtesseract_cube_la_LDFLAGS = -version-info $(GENERIC_LIBRARY_VERSION)
|
||||
libtesseract_cube_la_LIBADD = \
|
||||
../ccstruct/libtesseract_ccstruct.la \
|
||||
../ccutil/libtesseract_ccutil.la \
|
||||
../neural_networks/runtime/libtesseract_neural.la \
|
||||
../viewer/libtesseract_viewer.la \
|
||||
../wordrec/libtesseract_wordrec.la \
|
||||
../cutil/libtesseract_cutil.la \
|
||||
../classify/libtesseract_classify.la \
|
||||
../dict/libtesseract_dict.la
|
||||
endif
|
||||
|
||||
libtesseract_cube_la_SOURCES = \
|
||||
altlist.cpp beam_search.cpp bmp_8.cpp cached_file.cpp \
|
||||
char_altlist.cpp char_bigrams.cpp char_samp.cpp char_samp_enum.cpp \
|
||||
char_samp_set.cpp char_set.cpp classifier_factory.cpp \
|
||||
con_comp.cpp conv_net_classifier.cpp cube_line_object.cpp \
|
||||
cube_line_segmenter.cpp cube_object.cpp cube_search_object.cpp \
|
||||
cube_tuning_params.cpp cube_utils.cpp feature_bmp.cpp \
|
||||
feature_chebyshev.cpp feature_hybrid.cpp hybrid_neural_net_classifier.cpp \
|
||||
search_column.cpp search_node.cpp \
|
||||
tess_lang_mod_edge.cpp tess_lang_model.cpp \
|
||||
word_altlist.cpp word_list_lang_model.cpp word_size_model.cpp \
|
||||
word_unigrams.cpp
|
@ -1,60 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: alt_list.cpp
|
||||
* Description: Class to abstarct a list of alternate results
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 "altlist.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
AltList::AltList(int max_alt) {
|
||||
max_alt_ = max_alt;
|
||||
alt_cnt_ = 0;
|
||||
alt_cost_ = NULL;
|
||||
alt_tag_ = NULL;
|
||||
}
|
||||
|
||||
AltList::~AltList() {
|
||||
if (alt_cost_ != NULL) {
|
||||
delete []alt_cost_;
|
||||
alt_cost_ = NULL;
|
||||
}
|
||||
|
||||
if (alt_tag_ != NULL) {
|
||||
delete []alt_tag_;
|
||||
alt_tag_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// return the best possible cost and index of corresponding alternate
|
||||
int AltList::BestCost(int *best_alt) const {
|
||||
if (alt_cnt_ <= 0) {
|
||||
(*best_alt) = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int best_alt_idx = 0;
|
||||
for (int alt_idx = 1; alt_idx < alt_cnt_; alt_idx++) {
|
||||
if (alt_cost_[alt_idx] < alt_cost_[best_alt_idx]) {
|
||||
best_alt_idx = alt_idx;
|
||||
}
|
||||
}
|
||||
(*best_alt) = best_alt_idx;
|
||||
return alt_cost_[best_alt_idx];
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: alt_list.h
|
||||
* Description: Class to abstarct a list of alternate results
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The AltList class is the base class for the list of alternate recognition
|
||||
// results. Each alternate has a cost an an optional tag associated with it
|
||||
|
||||
#ifndef ALT_LIST_H
|
||||
#define ALT_LIST_H
|
||||
|
||||
#include <math.h>
|
||||
#include "cube_utils.h"
|
||||
|
||||
namespace tesseract {
|
||||
class AltList {
|
||||
public:
|
||||
explicit AltList(int max_alt);
|
||||
virtual ~AltList();
|
||||
// sort the list of alternates based
|
||||
virtual void Sort() = 0;
|
||||
// return the best possible cost and index of corresponding alternate
|
||||
int BestCost (int *best_alt) const;
|
||||
// return the count of alternates
|
||||
inline int AltCount() const { return alt_cnt_; }
|
||||
// returns the cost (-ve log prob) of an alternate
|
||||
inline int AltCost(int alt_idx) const { return alt_cost_[alt_idx]; }
|
||||
// returns the prob of an alternate
|
||||
inline double AltProb(int alt_idx) const {
|
||||
return CubeUtils::Cost2Prob(AltCost(alt_idx));
|
||||
}
|
||||
// returns the alternate tag
|
||||
inline void *AltTag(int alt_idx) const { return alt_tag_[alt_idx]; }
|
||||
|
||||
protected:
|
||||
// max number of alternates the list can hold
|
||||
int max_alt_;
|
||||
// actual alternate count
|
||||
int alt_cnt_;
|
||||
// array of alternate costs
|
||||
int *alt_cost_;
|
||||
// array of alternate tags
|
||||
void **alt_tag_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ALT_LIST_H
|
@ -1,487 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: beam_search.cpp
|
||||
* Description: Class to implement Beam Word Search Algorithm
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <algorithm>
|
||||
|
||||
#include "beam_search.h"
|
||||
#include "tesseractclass.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
BeamSearch::BeamSearch(CubeRecoContext *cntxt, bool word_mode) {
|
||||
cntxt_ = cntxt;
|
||||
seg_pt_cnt_ = 0;
|
||||
col_cnt_ = 1;
|
||||
col_ = NULL;
|
||||
word_mode_ = word_mode;
|
||||
}
|
||||
|
||||
// Cleanup the lattice corresponding to the last search
|
||||
void BeamSearch::Cleanup() {
|
||||
if (col_ != NULL) {
|
||||
for (int col = 0; col < col_cnt_; col++) {
|
||||
if (col_[col])
|
||||
delete col_[col];
|
||||
}
|
||||
delete []col_;
|
||||
}
|
||||
col_ = NULL;
|
||||
}
|
||||
|
||||
BeamSearch::~BeamSearch() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
// Creates a set of children nodes emerging from a parent node based on
|
||||
// the character alternate list and the language model.
|
||||
void BeamSearch::CreateChildren(SearchColumn *out_col, LangModel *lang_mod,
|
||||
SearchNode *parent_node,
|
||||
LangModEdge *lm_parent_edge,
|
||||
CharAltList *char_alt_list, int extra_cost) {
|
||||
// get all the edges from this parent
|
||||
int edge_cnt;
|
||||
LangModEdge **lm_edges = lang_mod->GetEdges(char_alt_list,
|
||||
lm_parent_edge, &edge_cnt);
|
||||
if (lm_edges) {
|
||||
// add them to the ending column with the appropriate parent
|
||||
for (int edge = 0; edge < edge_cnt; edge++) {
|
||||
// add a node to the column if the current column is not the
|
||||
// last one, or if the lang model edge indicates it is valid EOW
|
||||
if (!cntxt_->NoisyInput() && out_col->ColIdx() >= seg_pt_cnt_ &&
|
||||
!lm_edges[edge]->IsEOW()) {
|
||||
// free edge since no object is going to own it
|
||||
delete lm_edges[edge];
|
||||
continue;
|
||||
}
|
||||
|
||||
// compute the recognition cost of this node
|
||||
int recognition_cost = MIN_PROB_COST;
|
||||
if (char_alt_list && char_alt_list->AltCount() > 0) {
|
||||
recognition_cost = MAX(0, char_alt_list->ClassCost(
|
||||
lm_edges[edge]->ClassID()));
|
||||
// Add the no space cost. This should zero in word mode
|
||||
recognition_cost += extra_cost;
|
||||
}
|
||||
|
||||
// Note that the edge will be freed inside the column if
|
||||
// AddNode is called
|
||||
if (recognition_cost >= 0) {
|
||||
out_col->AddNode(lm_edges[edge], recognition_cost, parent_node,
|
||||
cntxt_);
|
||||
} else {
|
||||
delete lm_edges[edge];
|
||||
}
|
||||
} // edge
|
||||
// free edge array
|
||||
delete []lm_edges;
|
||||
} // lm_edges
|
||||
}
|
||||
|
||||
// Performs a beam search in the specified search using the specified
|
||||
// language model; returns an alternate list of possible words as a result.
|
||||
WordAltList * BeamSearch::Search(SearchObject *srch_obj, LangModel *lang_mod) {
|
||||
// verifications
|
||||
if (!lang_mod)
|
||||
lang_mod = cntxt_->LangMod();
|
||||
if (!lang_mod) {
|
||||
fprintf(stderr, "Cube ERROR (BeamSearch::Search): could not construct "
|
||||
"LangModel\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// free existing state
|
||||
Cleanup();
|
||||
|
||||
// get seg pt count
|
||||
seg_pt_cnt_ = srch_obj->SegPtCnt();
|
||||
if (seg_pt_cnt_ < 0) {
|
||||
return NULL;
|
||||
}
|
||||
col_cnt_ = seg_pt_cnt_ + 1;
|
||||
|
||||
// disregard suspicious cases
|
||||
if (seg_pt_cnt_ > 128) {
|
||||
fprintf(stderr, "Cube ERROR (BeamSearch::Search): segment point count is "
|
||||
"suspiciously high; bailing out\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// alloc memory for columns
|
||||
col_ = new SearchColumn *[col_cnt_];
|
||||
if (!col_) {
|
||||
fprintf(stderr, "Cube ERROR (BeamSearch::Search): could not construct "
|
||||
"SearchColumn array\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(col_, 0, col_cnt_ * sizeof(*col_));
|
||||
|
||||
// for all possible segments
|
||||
for (int end_seg = 1; end_seg <= (seg_pt_cnt_ + 1); end_seg++) {
|
||||
// create a search column
|
||||
col_[end_seg - 1] = new SearchColumn(end_seg - 1,
|
||||
cntxt_->Params()->BeamWidth());
|
||||
if (!col_[end_seg - 1]) {
|
||||
fprintf(stderr, "Cube ERROR (BeamSearch::Search): could not construct "
|
||||
"SearchColumn for column %d\n", end_seg - 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// for all possible start segments
|
||||
int init_seg = MAX(0, end_seg - cntxt_->Params()->MaxSegPerChar());
|
||||
for (int strt_seg = init_seg; strt_seg < end_seg; strt_seg++) {
|
||||
int parent_nodes_cnt;
|
||||
SearchNode **parent_nodes;
|
||||
|
||||
// for the root segment, we do not have a parent
|
||||
if (strt_seg == 0) {
|
||||
parent_nodes_cnt = 1;
|
||||
parent_nodes = NULL;
|
||||
} else {
|
||||
// for all the existing nodes in the starting column
|
||||
parent_nodes_cnt = col_[strt_seg - 1]->NodeCount();
|
||||
parent_nodes = col_[strt_seg - 1]->Nodes();
|
||||
}
|
||||
|
||||
// run the shape recognizer
|
||||
CharAltList *char_alt_list = srch_obj->RecognizeSegment(strt_seg - 1,
|
||||
end_seg - 1);
|
||||
// for all the possible parents
|
||||
for (int parent_idx = 0; parent_idx < parent_nodes_cnt; parent_idx++) {
|
||||
// point to the parent node
|
||||
SearchNode *parent_node = !parent_nodes ? NULL
|
||||
: parent_nodes[parent_idx];
|
||||
LangModEdge *lm_parent_edge = !parent_node ? lang_mod->Root()
|
||||
: parent_node->LangModelEdge();
|
||||
|
||||
// compute the cost of not having spaces within the segment range
|
||||
int contig_cost = srch_obj->NoSpaceCost(strt_seg - 1, end_seg - 1);
|
||||
|
||||
// In phrase mode, compute the cost of not having a space before
|
||||
// this character
|
||||
int no_space_cost = 0;
|
||||
if (!word_mode_ && strt_seg > 0) {
|
||||
no_space_cost = srch_obj->NoSpaceCost(strt_seg - 1);
|
||||
}
|
||||
|
||||
// if the no space cost is low enough
|
||||
if ((contig_cost + no_space_cost) < MIN_PROB_COST) {
|
||||
// Add the children nodes
|
||||
CreateChildren(col_[end_seg - 1], lang_mod, parent_node,
|
||||
lm_parent_edge, char_alt_list,
|
||||
contig_cost + no_space_cost);
|
||||
}
|
||||
|
||||
// In phrase mode and if not starting at the root
|
||||
if (!word_mode_ && strt_seg > 0) { // parent_node must be non-NULL
|
||||
// consider starting a new word for nodes that are valid EOW
|
||||
if (parent_node->LangModelEdge()->IsEOW()) {
|
||||
// get the space cost
|
||||
int space_cost = srch_obj->SpaceCost(strt_seg - 1);
|
||||
// if the space cost is low enough
|
||||
if ((contig_cost + space_cost) < MIN_PROB_COST) {
|
||||
// Restart the language model and add nodes as children to the
|
||||
// space node.
|
||||
CreateChildren(col_[end_seg - 1], lang_mod, parent_node, NULL,
|
||||
char_alt_list, contig_cost + space_cost);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // parent
|
||||
} // strt_seg
|
||||
|
||||
// prune the column nodes
|
||||
col_[end_seg - 1]->Prune();
|
||||
|
||||
// Free the column hash table. No longer needed
|
||||
col_[end_seg - 1]->FreeHashTable();
|
||||
} // end_seg
|
||||
|
||||
WordAltList *alt_list = CreateWordAltList(srch_obj);
|
||||
return alt_list;
|
||||
}
|
||||
|
||||
// Creates a Word alternate list from the results in the lattice.
|
||||
WordAltList *BeamSearch::CreateWordAltList(SearchObject *srch_obj) {
|
||||
// create an alternate list of all the nodes in the last column
|
||||
int node_cnt = col_[col_cnt_ - 1]->NodeCount();
|
||||
SearchNode **srch_nodes = col_[col_cnt_ - 1]->Nodes();
|
||||
CharBigrams *bigrams = cntxt_->Bigrams();
|
||||
WordUnigrams *word_unigrams = cntxt_->WordUnigramsObj();
|
||||
|
||||
// Save the index of the best-cost node before the alt list is
|
||||
// sorted, so that we can retrieve it from the node list when backtracking.
|
||||
best_presorted_node_idx_ = 0;
|
||||
int best_cost = -1;
|
||||
|
||||
if (node_cnt <= 0)
|
||||
return NULL;
|
||||
|
||||
// start creating the word alternate list
|
||||
WordAltList *alt_list = new WordAltList(node_cnt + 1);
|
||||
for (int node_idx = 0; node_idx < node_cnt; node_idx++) {
|
||||
// recognition cost
|
||||
int recognition_cost = srch_nodes[node_idx]->BestCost();
|
||||
// compute the size cost of the alternate
|
||||
char_32 *ch_buff = NULL;
|
||||
int size_cost = SizeCost(srch_obj, srch_nodes[node_idx], &ch_buff);
|
||||
// accumulate other costs
|
||||
if (ch_buff) {
|
||||
int cost = 0;
|
||||
// char bigram cost
|
||||
int bigram_cost = !bigrams ? 0 :
|
||||
bigrams->Cost(ch_buff, cntxt_->CharacterSet());
|
||||
// word unigram cost
|
||||
int unigram_cost = !word_unigrams ? 0 :
|
||||
word_unigrams->Cost(ch_buff, cntxt_->LangMod(),
|
||||
cntxt_->CharacterSet());
|
||||
// overall cost
|
||||
cost = static_cast<int>(
|
||||
(size_cost * cntxt_->Params()->SizeWgt()) +
|
||||
(bigram_cost * cntxt_->Params()->CharBigramWgt()) +
|
||||
(unigram_cost * cntxt_->Params()->WordUnigramWgt()) +
|
||||
(recognition_cost * cntxt_->Params()->RecoWgt()));
|
||||
|
||||
// insert into word alt list
|
||||
alt_list->Insert(ch_buff, cost,
|
||||
static_cast<void *>(srch_nodes[node_idx]));
|
||||
// Note that strict < is necessary because WordAltList::Sort()
|
||||
// uses it in a bubble sort to swap entries.
|
||||
if (best_cost < 0 || cost < best_cost) {
|
||||
best_presorted_node_idx_ = node_idx;
|
||||
best_cost = cost;
|
||||
}
|
||||
delete []ch_buff;
|
||||
}
|
||||
}
|
||||
|
||||
// sort the alternates based on cost
|
||||
alt_list->Sort();
|
||||
return alt_list;
|
||||
}
|
||||
|
||||
// Returns the lattice column corresponding to the specified column index.
|
||||
SearchColumn *BeamSearch::Column(int col) const {
|
||||
if (col < 0 || col >= col_cnt_ || !col_)
|
||||
return NULL;
|
||||
return col_[col];
|
||||
}
|
||||
|
||||
// Returns the best node in the last column of last performed search.
|
||||
SearchNode *BeamSearch::BestNode() const {
|
||||
if (col_cnt_ < 1 || !col_ || !col_[col_cnt_ - 1])
|
||||
return NULL;
|
||||
|
||||
int node_cnt = col_[col_cnt_ - 1]->NodeCount();
|
||||
SearchNode **srch_nodes = col_[col_cnt_ - 1]->Nodes();
|
||||
if (node_cnt < 1 || !srch_nodes || !srch_nodes[0])
|
||||
return NULL;
|
||||
return srch_nodes[0];
|
||||
}
|
||||
|
||||
// Returns the string corresponding to the specified alt.
|
||||
char_32 *BeamSearch::Alt(int alt) const {
|
||||
// get the last column of the lattice
|
||||
if (col_cnt_ <= 0)
|
||||
return NULL;
|
||||
|
||||
SearchColumn *srch_col = col_[col_cnt_ - 1];
|
||||
if (!srch_col)
|
||||
return NULL;
|
||||
|
||||
// point to the last node in the selected path
|
||||
if (alt >= srch_col->NodeCount() || srch_col->Nodes() == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SearchNode *srch_node = srch_col->Nodes()[alt];
|
||||
if (!srch_node)
|
||||
return NULL;
|
||||
|
||||
// get string
|
||||
char_32 *str32 = srch_node->PathString();
|
||||
if (!str32)
|
||||
return NULL;
|
||||
|
||||
return str32;
|
||||
}
|
||||
|
||||
// Backtracks from the specified node index and returns the corresponding
|
||||
// character mapped segments and character count. Optional return
|
||||
// arguments are the char_32 result string and character bounding
|
||||
// boxes, if non-NULL values are passed in.
|
||||
CharSamp **BeamSearch::BackTrack(SearchObject *srch_obj, int node_index,
|
||||
int *char_cnt, char_32 **str32,
|
||||
Boxa **char_boxes) const {
|
||||
// get the last column of the lattice
|
||||
if (col_cnt_ <= 0)
|
||||
return NULL;
|
||||
SearchColumn *srch_col = col_[col_cnt_ - 1];
|
||||
if (!srch_col)
|
||||
return NULL;
|
||||
|
||||
// point to the last node in the selected path
|
||||
if (node_index >= srch_col->NodeCount() || !srch_col->Nodes())
|
||||
return NULL;
|
||||
|
||||
SearchNode *srch_node = srch_col->Nodes()[node_index];
|
||||
if (!srch_node)
|
||||
return NULL;
|
||||
return BackTrack(srch_obj, srch_node, char_cnt, str32, char_boxes);
|
||||
}
|
||||
|
||||
// Backtracks from the specified node index and returns the corresponding
|
||||
// character mapped segments and character count. Optional return
|
||||
// arguments are the char_32 result string and character bounding
|
||||
// boxes, if non-NULL values are passed in.
|
||||
CharSamp **BeamSearch::BackTrack(SearchObject *srch_obj, SearchNode *srch_node,
|
||||
int *char_cnt, char_32 **str32,
|
||||
Boxa **char_boxes) const {
|
||||
if (!srch_node)
|
||||
return NULL;
|
||||
|
||||
if (str32) {
|
||||
if (*str32)
|
||||
delete [](*str32); // clear existing value
|
||||
*str32 = srch_node->PathString();
|
||||
if (!*str32)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (char_boxes && *char_boxes) {
|
||||
boxaDestroy(char_boxes); // clear existing value
|
||||
}
|
||||
|
||||
CharSamp **chars;
|
||||
chars = SplitByNode(srch_obj, srch_node, char_cnt, char_boxes);
|
||||
if (!chars && str32)
|
||||
delete []*str32;
|
||||
return chars;
|
||||
}
|
||||
|
||||
// Backtracks from the given lattice node and return the corresponding
|
||||
// char mapped segments and character count. The character bounding
|
||||
// boxes are optional return arguments, if non-NULL values are passed in.
|
||||
CharSamp **BeamSearch::SplitByNode(SearchObject *srch_obj,
|
||||
SearchNode *srch_node,
|
||||
int *char_cnt,
|
||||
Boxa **char_boxes) const {
|
||||
// Count the characters (could be less than the path length when in
|
||||
// phrase mode)
|
||||
*char_cnt = 0;
|
||||
SearchNode *node = srch_node;
|
||||
while (node) {
|
||||
node = node->ParentNode();
|
||||
(*char_cnt)++;
|
||||
}
|
||||
|
||||
if (*char_cnt == 0)
|
||||
return NULL;
|
||||
|
||||
// Allocate box array
|
||||
if (char_boxes) {
|
||||
if (*char_boxes)
|
||||
boxaDestroy(char_boxes); // clear existing value
|
||||
*char_boxes = boxaCreate(*char_cnt);
|
||||
if (*char_boxes == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for CharSamp array.
|
||||
CharSamp **chars = new CharSamp *[*char_cnt];
|
||||
if (!chars) {
|
||||
if (char_boxes)
|
||||
boxaDestroy(char_boxes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ch_idx = *char_cnt - 1;
|
||||
int seg_pt_cnt = srch_obj->SegPtCnt();
|
||||
bool success=true;
|
||||
while (srch_node && ch_idx >= 0) {
|
||||
// Parent node (could be null)
|
||||
SearchNode *parent_node = srch_node->ParentNode();
|
||||
|
||||
// Get the seg pts corresponding to the search node
|
||||
int st_col = !parent_node ? 0 : parent_node->ColIdx() + 1;
|
||||
int st_seg_pt = st_col <= 0 ? -1 : st_col - 1;
|
||||
int end_col = srch_node->ColIdx();
|
||||
int end_seg_pt = end_col >= seg_pt_cnt ? seg_pt_cnt : end_col;
|
||||
|
||||
// Get a char sample corresponding to the segmentation points
|
||||
CharSamp *samp = srch_obj->CharSample(st_seg_pt, end_seg_pt);
|
||||
if (!samp) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
samp->SetLabel(srch_node->NodeString());
|
||||
chars[ch_idx] = samp;
|
||||
if (char_boxes) {
|
||||
// Create the corresponding character bounding box
|
||||
Box *char_box = boxCreate(samp->Left(), samp->Top(),
|
||||
samp->Width(), samp->Height());
|
||||
if (!char_box) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
boxaAddBox(*char_boxes, char_box, L_INSERT);
|
||||
}
|
||||
srch_node = parent_node;
|
||||
ch_idx--;
|
||||
}
|
||||
if (!success) {
|
||||
delete []chars;
|
||||
if (char_boxes)
|
||||
boxaDestroy(char_boxes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Reverse the order of boxes.
|
||||
if (char_boxes) {
|
||||
int char_boxa_size = boxaGetCount(*char_boxes);
|
||||
int limit = char_boxa_size / 2;
|
||||
for (int i = 0; i < limit; ++i) {
|
||||
int box1_idx = i;
|
||||
int box2_idx = char_boxa_size - 1 - i;
|
||||
Box *box1 = boxaGetBox(*char_boxes, box1_idx, L_CLONE);
|
||||
Box *box2 = boxaGetBox(*char_boxes, box2_idx, L_CLONE);
|
||||
boxaReplaceBox(*char_boxes, box2_idx, box1);
|
||||
boxaReplaceBox(*char_boxes, box1_idx, box2);
|
||||
}
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
// Returns the size cost of a string for a lattice path that
|
||||
// ends at the specified lattice node.
|
||||
int BeamSearch::SizeCost(SearchObject *srch_obj, SearchNode *node,
|
||||
char_32 **str32) const {
|
||||
CharSamp **chars = NULL;
|
||||
int char_cnt = 0;
|
||||
if (!node)
|
||||
return 0;
|
||||
// Backtrack to get string and character segmentation
|
||||
chars = BackTrack(srch_obj, node, &char_cnt, str32, NULL);
|
||||
if (!chars)
|
||||
return WORST_COST;
|
||||
int size_cost = (cntxt_->SizeModel() == NULL) ? 0 :
|
||||
cntxt_->SizeModel()->Cost(chars, char_cnt);
|
||||
delete []chars;
|
||||
return size_cost;
|
||||
}
|
||||
} // namespace tesesract
|
@ -1,126 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: beam_search.h
|
||||
* Description: Declaration of Beam Word Search Algorithm Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The Beam Search class implements a Beam Search algorithm for the
|
||||
// N-best paths through the lattice of a search object using a language model
|
||||
// The search object is a segmented bitmap of a word image. The language model
|
||||
// is a state machine that defines valid sequences of characters
|
||||
// The cost of each path is the combined (product) probabilities of the
|
||||
// characters along the path. The character probabilities are computed using
|
||||
// the character classifier member of the RecoContext
|
||||
// The BeamSearch class itself holds the state of the last search it performed
|
||||
// using its "Search" method. Subsequent class to the Search method erase the
|
||||
// states of previously done searches
|
||||
|
||||
#ifndef BEAM_SEARCH_H
|
||||
#define BEAM_SEARCH_H
|
||||
|
||||
#include "search_column.h"
|
||||
#include "word_altlist.h"
|
||||
#include "search_object.h"
|
||||
#include "lang_model.h"
|
||||
#include "cube_utils.h"
|
||||
#include "cube_reco_context.h"
|
||||
#include "allheaders.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class BeamSearch {
|
||||
public:
|
||||
explicit BeamSearch(CubeRecoContext *cntxt, bool word_mode = true);
|
||||
~BeamSearch();
|
||||
// Performs a beam search in the specified search using the specified
|
||||
// language model; returns an alternate list of possible words as a result.
|
||||
WordAltList *Search(SearchObject *srch_obj, LangModel *lang_mod = NULL);
|
||||
// Returns the best node in the last column of last performed search.
|
||||
SearchNode *BestNode() const;
|
||||
// Returns the string corresponding to the specified alt.
|
||||
char_32 *Alt(int alt) const;
|
||||
// Backtracks from the specified lattice node and returns the corresponding
|
||||
// character-mapped segments, character count, char_32 result string, and
|
||||
// character bounding boxes (if char_boxes is not NULL). If the segments
|
||||
// cannot be constructed, returns NULL, and all result arguments
|
||||
// will be NULL.
|
||||
CharSamp **BackTrack(SearchObject *srch_obj, int node_index,
|
||||
int *char_cnt, char_32 **str32, Boxa **char_boxes) const;
|
||||
// Same as above, except it takes a pointer to a search node object
|
||||
// instead of node index.
|
||||
CharSamp **BackTrack(SearchObject *srch_obj, SearchNode *node,
|
||||
int *char_cnt, char_32 **str32, Boxa **char_boxes) const;
|
||||
// Returns the size cost of a specified string of a lattice
|
||||
// path that ends at the specified lattice node.
|
||||
int SizeCost(SearchObject *srch_obj, SearchNode *node,
|
||||
char_32 **str32 = NULL) const;
|
||||
// Returns the word unigram cost of the given string, possibly
|
||||
// stripping out a single trailing punctuation character.
|
||||
int WordUnigramCost(char_32 *str32, WordUnigrams* word_unigrams) const;
|
||||
|
||||
// Supplementary functions needed for visualization
|
||||
// Return column count of the lattice.
|
||||
inline int ColCnt() const { return col_cnt_; }
|
||||
// Returns the lattice column corresponding to the specified column index.
|
||||
SearchColumn *Column(int col_idx) const;
|
||||
// Return the index of the best node in the last column of the
|
||||
// best-cost path before the alternates list is sorted.
|
||||
inline int BestPresortedNodeIndex() const {
|
||||
return best_presorted_node_idx_;
|
||||
};
|
||||
|
||||
private:
|
||||
// Maximum reasonable segmentation point count
|
||||
static const int kMaxSegPointCnt = 128;
|
||||
// Recognition context object; the context holds the character classifier
|
||||
// and the tuning parameters object
|
||||
CubeRecoContext *cntxt_;
|
||||
// Count of segmentation pts
|
||||
int seg_pt_cnt_;
|
||||
// Lattice column count; currently redundant with respect to seg_pt_cnt_
|
||||
// but that might change in the future
|
||||
int col_cnt_;
|
||||
// Array of lattice columns
|
||||
SearchColumn **col_;
|
||||
// Run in word or phrase mode
|
||||
bool word_mode_;
|
||||
// Node index of best-cost node, before alternates are merged and sorted
|
||||
int best_presorted_node_idx_;
|
||||
// Cleans up beam search state
|
||||
void Cleanup();
|
||||
// Creates a Word alternate list from the results in the lattice.
|
||||
// This function computes a cost for each node in the final column
|
||||
// of the lattice, which is a weighted average of several costs:
|
||||
// size cost, character bigram cost, word unigram cost, and
|
||||
// recognition cost from the beam search. The weights are the
|
||||
// CubeTuningParams, which are learned together with the character
|
||||
// classifiers.
|
||||
WordAltList *CreateWordAltList(SearchObject *srch_obj);
|
||||
// Creates a set of children nodes emerging from a parent node based on
|
||||
// the character alternate list and the language model.
|
||||
void CreateChildren(SearchColumn *out_col, LangModel *lang_mod,
|
||||
SearchNode *parent_node, LangModEdge *lm_parent_edge,
|
||||
CharAltList *char_alt_list, int extra_cost);
|
||||
// Backtracks from the given lattice node and returns the corresponding
|
||||
// char mapped segments, character count, and character bounding boxes (if
|
||||
// char_boxes is not NULL). If the segments cannot be constructed,
|
||||
// returns NULL, and all result arguments will be NULL.
|
||||
CharSamp **SplitByNode(SearchObject *srch_obj, SearchNode *srch_node,
|
||||
int* char_cnt, Boxa **char_boxes) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BEAM_SEARCH_H
|
1144
cube/bmp_8.cpp
1144
cube/bmp_8.cpp
File diff suppressed because it is too large
Load Diff
122
cube/bmp_8.h
122
cube/bmp_8.h
@ -1,122 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: bmp_8.h
|
||||
* Description: Declaration of an 8-bit Bitmap class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef BMP8_H
|
||||
#define BMP8_H
|
||||
|
||||
// The Bmp8 class is an 8-bit bitmap that represents images of
|
||||
// words, characters and segments throughout Cube
|
||||
// It is meant to provide fast access to the bitmap bits and provide
|
||||
// fast scaling, cropping, deslanting, connected components detection,
|
||||
// loading and saving functionality
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "con_comp.h"
|
||||
#include "cached_file.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// Non-integral deslanting parameters.
|
||||
static const float kMinDeslantAngle = -30.0f;
|
||||
static const float kMaxDeslantAngle = 30.0f;
|
||||
static const float kDeslantAngleDelta = 0.5f;
|
||||
|
||||
class Bmp8 {
|
||||
public:
|
||||
Bmp8(unsigned short wid, unsigned short hgt);
|
||||
~Bmp8();
|
||||
// Clears the bitmap
|
||||
bool Clear();
|
||||
// accessors to bitmap dimensions
|
||||
inline unsigned short Width() const { return wid_; }
|
||||
inline unsigned short Stride() const { return stride_; }
|
||||
inline unsigned short Height() const { return hgt_; }
|
||||
inline unsigned char *RawData() const {
|
||||
return (line_buff_ == NULL ? NULL : line_buff_[0]);
|
||||
}
|
||||
// creates a scaled version of the specified bitmap
|
||||
// Optionally, scaling can be isotropic (preserving aspect ratio) or not
|
||||
bool ScaleFrom(Bmp8 *bmp, bool isotropic = true);
|
||||
// Deslant the bitmap vertically
|
||||
bool Deslant();
|
||||
// Deslant the bitmap horizontally
|
||||
bool HorizontalDeslant(double *deslant_angle);
|
||||
// Create a bitmap object from a file
|
||||
static Bmp8 *FromCharDumpFile(CachedFile *fp);
|
||||
static Bmp8 *FromCharDumpFile(FILE *fp);
|
||||
// are two bitmaps identical
|
||||
bool IsIdentical(Bmp8 *pBmp) const;
|
||||
// Detect connected components
|
||||
ConComp ** FindConComps(int *concomp_cnt, int min_size) const;
|
||||
// compute the foreground ratio
|
||||
float ForegroundRatio() const;
|
||||
// returns the mean horizontal histogram entropy of the bitmap
|
||||
float MeanHorizontalHistogramEntropy() const;
|
||||
// returns the horizontal histogram of the bitmap
|
||||
int *HorizontalHistogram() const;
|
||||
|
||||
private:
|
||||
// Compute a look up tan table that will be used for fast slant computation
|
||||
static bool ComputeTanTable();
|
||||
// create a bitmap buffer (two flavors char & int) and init contents
|
||||
unsigned char ** CreateBmpBuffer(unsigned char init_val = 0xff);
|
||||
static unsigned int ** CreateBmpBuffer(int wid, int hgt,
|
||||
unsigned char init_val = 0xff);
|
||||
// Free a bitmap buffer
|
||||
static void FreeBmpBuffer(unsigned char **buff);
|
||||
static void FreeBmpBuffer(unsigned int **buff);
|
||||
|
||||
// a static array that holds the tan lookup table
|
||||
static float *tan_table_;
|
||||
// bitmap 32-bit-aligned stride
|
||||
unsigned short stride_;
|
||||
// Bmp8 magic number used to validate saved bitmaps
|
||||
static const unsigned int kMagicNumber = 0xdeadbeef;
|
||||
|
||||
protected:
|
||||
// bitmap dimensions
|
||||
unsigned short wid_;
|
||||
unsigned short hgt_;
|
||||
// bitmap contents
|
||||
unsigned char **line_buff_;
|
||||
// deslanting parameters
|
||||
static const int kConCompAllocChunk = 16;
|
||||
static const int kDeslantAngleCount;
|
||||
|
||||
// Load dimensions & contents of bitmap from file
|
||||
bool LoadFromCharDumpFile(CachedFile *fp);
|
||||
bool LoadFromCharDumpFile(FILE *fp);
|
||||
// Load dimensions & contents of bitmap from raw data
|
||||
bool LoadFromCharDumpFile(unsigned char **raw_data);
|
||||
// Load contents of bitmap from raw data
|
||||
bool LoadFromRawData(unsigned char *data);
|
||||
// save bitmap to a file
|
||||
bool SaveBmp2CharDumpFile(FILE *fp) const;
|
||||
// checks if a row or a column are entirely blank
|
||||
bool IsBlankColumn(int x) const;
|
||||
bool IsBlankRow(int y) const;
|
||||
// crop the bitmap returning new dimensions
|
||||
void Crop(int *xst_src, int *yst_src, int *wid, int *hgt);
|
||||
// copy part of the specified bitmap
|
||||
void Copy(int x, int y, int wid, int hgt, Bmp8 *bmp_dest) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BMP8_H
|
@ -1,150 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: cached_file.pp
|
||||
* Description: Implementation of an Cached File Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <string>
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
#include "cached_file.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
CachedFile::CachedFile(string file_name) {
|
||||
file_name_ = file_name;
|
||||
buff_ = NULL;
|
||||
buff_pos_ = 0;
|
||||
buff_size_ = 0;
|
||||
file_pos_ = 0;
|
||||
file_size_ = 0;
|
||||
fp_ = NULL;
|
||||
}
|
||||
|
||||
CachedFile::~CachedFile() {
|
||||
if (fp_ != NULL) {
|
||||
fclose(fp_);
|
||||
fp_ = NULL;
|
||||
}
|
||||
|
||||
if (buff_ != NULL) {
|
||||
delete []buff_;
|
||||
buff_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// free buffers and init vars
|
||||
bool CachedFile::Open() {
|
||||
if (fp_ != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fp_ = fopen(file_name_.c_str(), "rb");
|
||||
if (fp_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// seek to the end
|
||||
fseek(fp_, 0, SEEK_END);
|
||||
// get file size
|
||||
file_size_ = ftell(fp_);
|
||||
if (file_size_ < 1) {
|
||||
return false;
|
||||
}
|
||||
// rewind again
|
||||
rewind(fp_);
|
||||
// alloc memory for buffer
|
||||
buff_ = new unsigned char[kCacheSize];
|
||||
if (buff_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
// init counters
|
||||
buff_size_ = 0;
|
||||
buff_pos_ = 0;
|
||||
file_pos_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// add a new sample
|
||||
int CachedFile::Read(void *read_buff, int bytes) {
|
||||
int read_bytes = 0;
|
||||
unsigned char *buff = (unsigned char *)read_buff;
|
||||
|
||||
// do we need to read beyond the buffer
|
||||
if ((buff_pos_ + bytes) > buff_size_) {
|
||||
// copy as much bytes from the current buffer if any
|
||||
int copy_bytes = buff_size_ - buff_pos_;
|
||||
|
||||
if (copy_bytes > 0) {
|
||||
memcpy(buff, buff_ + buff_pos_, copy_bytes);
|
||||
buff += copy_bytes;
|
||||
bytes -= copy_bytes;
|
||||
read_bytes += copy_bytes;
|
||||
}
|
||||
|
||||
// determine how much to read
|
||||
buff_size_ = kCacheSize;
|
||||
|
||||
if ((file_pos_ + buff_size_) > file_size_) {
|
||||
buff_size_ = static_cast<int>(file_size_ - file_pos_);
|
||||
}
|
||||
|
||||
// EOF ?
|
||||
if (buff_size_ <= 0 || bytes > buff_size_) {
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
// read the first chunck
|
||||
if (fread(buff_, 1, buff_size_, fp_) != buff_size_) {
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
buff_pos_ = 0;
|
||||
file_pos_ += buff_size_;
|
||||
}
|
||||
|
||||
memcpy(buff, buff_ + buff_pos_, bytes);
|
||||
read_bytes += bytes;
|
||||
buff_pos_ += bytes;
|
||||
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
long CachedFile::Size() {
|
||||
if (fp_ == NULL && Open() == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file_size_;
|
||||
}
|
||||
|
||||
long CachedFile::Tell() {
|
||||
if (fp_ == NULL && Open() == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file_pos_ - buff_size_ + buff_pos_;
|
||||
}
|
||||
|
||||
bool CachedFile::eof() {
|
||||
if (fp_ == NULL && Open() == false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (file_pos_ - buff_size_ + buff_pos_) >= file_size_;
|
||||
}
|
||||
|
||||
} // namespace tesseract
|
@ -1,69 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: cached_file.h
|
||||
* Description: Declaration of a Cached File class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef CACHED_FILE_H
|
||||
#define CACHED_FILE_H
|
||||
|
||||
// The CachedFile class provides a large-cache read access to a file
|
||||
// It is mainly designed for loading large word dump files
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#ifdef USE_STD_NAMESPACE
|
||||
using std::string;
|
||||
#endif
|
||||
|
||||
namespace tesseract {
|
||||
class CachedFile {
|
||||
public:
|
||||
explicit CachedFile(string file_name);
|
||||
~CachedFile();
|
||||
|
||||
// reads a specified number of bytes to the specified buffer and
|
||||
// returns the actual number of bytes read
|
||||
int Read(void *read_buff, int bytes);
|
||||
// Returns the file size
|
||||
long Size();
|
||||
// returns the current position in the file
|
||||
long Tell();
|
||||
// End of file flag
|
||||
bool eof();
|
||||
|
||||
private:
|
||||
static const unsigned int kCacheSize = 0x8000000;
|
||||
// file name
|
||||
string file_name_;
|
||||
// internal file buffer
|
||||
unsigned char *buff_;
|
||||
// file position
|
||||
long file_pos_;
|
||||
// file size
|
||||
long file_size_;
|
||||
// position of file within buffer
|
||||
int buff_pos_;
|
||||
// buffer size
|
||||
int buff_size_;
|
||||
// file handle
|
||||
FILE *fp_;
|
||||
// Opens the file
|
||||
bool Open();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CACHED_FILE_H
|
@ -1,115 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_altlist.cpp
|
||||
* Description: Implementation of a Character Alternate List Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 "char_altlist.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// The CharSet is not class owned and must exist for
|
||||
// the life time of this class
|
||||
CharAltList::CharAltList(const CharSet *char_set, int max_alt)
|
||||
: AltList(max_alt) {
|
||||
char_set_ = char_set;
|
||||
max_alt_ = max_alt;
|
||||
class_id_alt_ = NULL;
|
||||
class_id_cost_ = NULL;
|
||||
}
|
||||
|
||||
CharAltList::~CharAltList() {
|
||||
if (class_id_alt_ != NULL) {
|
||||
delete []class_id_alt_;
|
||||
class_id_alt_ = NULL;
|
||||
}
|
||||
|
||||
if (class_id_cost_ != NULL) {
|
||||
delete []class_id_cost_;
|
||||
class_id_cost_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert a new char alternate
|
||||
bool CharAltList::Insert(int class_id, int cost, void *tag) {
|
||||
// validate class ID
|
||||
if (class_id < 0 || class_id >= char_set_->ClassCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// allocate buffers if nedded
|
||||
if (class_id_alt_ == NULL || alt_cost_ == NULL) {
|
||||
class_id_alt_ = new int[max_alt_];
|
||||
alt_cost_ = new int[max_alt_];
|
||||
alt_tag_ = new void *[max_alt_];
|
||||
|
||||
if (class_id_alt_ == NULL || alt_cost_ == NULL || alt_tag_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(alt_tag_, 0, max_alt_ * sizeof(*alt_tag_));
|
||||
}
|
||||
|
||||
if (class_id_cost_ == NULL) {
|
||||
int class_cnt = char_set_->ClassCount();
|
||||
|
||||
class_id_cost_ = new int[class_cnt];
|
||||
if (class_id_cost_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int ich = 0; ich < class_cnt; ich++) {
|
||||
class_id_cost_[ich] = WORST_COST;
|
||||
}
|
||||
}
|
||||
|
||||
if (class_id < 0 || class_id >= char_set_->ClassCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// insert the alternate
|
||||
class_id_alt_[alt_cnt_] = class_id;
|
||||
alt_cost_[alt_cnt_] = cost;
|
||||
alt_tag_[alt_cnt_] = tag;
|
||||
|
||||
alt_cnt_++;
|
||||
|
||||
class_id_cost_[class_id] = cost;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// sort the alternate Desc. based on prob
|
||||
void CharAltList::Sort() {
|
||||
for (int alt_idx = 0; alt_idx < alt_cnt_; alt_idx++) {
|
||||
for (int alt = alt_idx + 1; alt < alt_cnt_; alt++) {
|
||||
if (alt_cost_[alt_idx] > alt_cost_[alt]) {
|
||||
int temp = class_id_alt_[alt_idx];
|
||||
class_id_alt_[alt_idx] = class_id_alt_[alt];
|
||||
class_id_alt_[alt] = temp;
|
||||
|
||||
temp = alt_cost_[alt_idx];
|
||||
alt_cost_[alt_idx] = alt_cost_[alt];
|
||||
alt_cost_[alt] = temp;
|
||||
|
||||
void *tag = alt_tag_[alt_idx];
|
||||
alt_tag_[alt_idx] = alt_tag_[alt];
|
||||
alt_tag_[alt] = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_altlist.h
|
||||
* Description: Declaration of a Character Alternate List Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef CHAR_ALT_LIST_H
|
||||
#define CHAR_ALT_LIST_H
|
||||
|
||||
// The CharAltList class holds the list of class alternates returned from
|
||||
// a character classifier. Each alternate represents a class ID.
|
||||
// It inherits from the AltList class.
|
||||
// The CharAltList owns a CharSet object that maps a class-id to a string.
|
||||
|
||||
#include "altlist.h"
|
||||
#include "char_set.h"
|
||||
|
||||
namespace tesseract {
|
||||
class CharAltList : public AltList {
|
||||
public:
|
||||
CharAltList(const CharSet *char_set, int max_alt = kMaxCharAlt);
|
||||
~CharAltList();
|
||||
|
||||
// Sort the alternate list based on cost
|
||||
void Sort();
|
||||
// insert a new alternate with the specified class-id, cost and tag
|
||||
bool Insert(int class_id, int cost, void *tag = NULL);
|
||||
// returns the cost of a specific class ID
|
||||
inline int ClassCost(int class_id) const {
|
||||
if (class_id_cost_ == NULL ||
|
||||
class_id < 0 ||
|
||||
class_id >= char_set_->ClassCount()) {
|
||||
return WORST_COST;
|
||||
}
|
||||
return class_id_cost_[class_id];
|
||||
}
|
||||
// returns the alternate class-id corresponding to an alternate index
|
||||
inline int Alt(int alt_idx) const { return class_id_alt_[alt_idx]; }
|
||||
// set the cost of a certain alternate
|
||||
void SetAltCost(int alt_idx, int cost) {
|
||||
alt_cost_[alt_idx] = cost;
|
||||
class_id_cost_[class_id_alt_[alt_idx]] = cost;
|
||||
}
|
||||
|
||||
private:
|
||||
// character set object. Passed at construction time
|
||||
const CharSet *char_set_;
|
||||
// array of alternate class-ids
|
||||
int *class_id_alt_;
|
||||
// array of alternate costs
|
||||
int *class_id_cost_;
|
||||
// default max count of alternates
|
||||
static const int kMaxCharAlt = 256;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CHAR_ALT_LIST_H
|
@ -1,207 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_bigrams.cpp
|
||||
* Description: Implementation of a Character Bigrams Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <algorithm>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "char_bigrams.h"
|
||||
#include "cube_utils.h"
|
||||
#include "ndminx.h"
|
||||
#include "cube_const.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
CharBigrams::CharBigrams() {
|
||||
memset(&bigram_table_, 0, sizeof(bigram_table_));
|
||||
}
|
||||
|
||||
CharBigrams::~CharBigrams() {
|
||||
if (bigram_table_.char_bigram != NULL) {
|
||||
for (int ch1 = 0; ch1 <= bigram_table_.max_char; ch1++) {
|
||||
CharBigram *char_bigram = bigram_table_.char_bigram + ch1;
|
||||
|
||||
if (char_bigram->bigram != NULL) {
|
||||
delete []char_bigram->bigram;
|
||||
}
|
||||
}
|
||||
delete []bigram_table_.char_bigram;
|
||||
}
|
||||
}
|
||||
|
||||
CharBigrams *CharBigrams::Create(const string &data_file_path,
|
||||
const string &lang) {
|
||||
string file_name;
|
||||
string str;
|
||||
|
||||
file_name = data_file_path + lang;
|
||||
file_name += ".cube.bigrams";
|
||||
|
||||
// load the string into memory
|
||||
if (!CubeUtils::ReadFileToString(file_name, &str)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// construct a new object
|
||||
CharBigrams *char_bigrams_obj = new CharBigrams();
|
||||
if (char_bigrams_obj == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharBigrams::Create): could not create "
|
||||
"character bigrams object.\n");
|
||||
return NULL;
|
||||
}
|
||||
CharBigramTable *table = &char_bigrams_obj->bigram_table_;
|
||||
|
||||
table->total_cnt = 0;
|
||||
table->max_char = -1;
|
||||
table->char_bigram = NULL;
|
||||
|
||||
// split into lines
|
||||
vector<string> str_vec;
|
||||
CubeUtils::SplitStringUsing(str, "\r\n", &str_vec);
|
||||
|
||||
for (int big = 0; big < str_vec.size(); big++) {
|
||||
char_32 ch1;
|
||||
char_32 ch2;
|
||||
int cnt;
|
||||
if (sscanf(str_vec[big].c_str(), "%d %x %x", &cnt, &ch1, &ch2) != 3) {
|
||||
fprintf(stderr, "Cube ERROR (CharBigrams::Create): invalid format "
|
||||
"reading line: %s\n", str_vec[big].c_str());
|
||||
delete char_bigrams_obj;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// expand the bigram table
|
||||
if (ch1 > table->max_char) {
|
||||
CharBigram *char_bigram = new CharBigram[ch1 + 1];
|
||||
if (char_bigram == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharBigrams::Create): error allocating "
|
||||
"additional memory for character bigram table.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (table->char_bigram != NULL && table->max_char >= 0) {
|
||||
memcpy(char_bigram, table->char_bigram,
|
||||
(table->max_char + 1) * sizeof(*char_bigram));
|
||||
|
||||
delete []table->char_bigram;
|
||||
}
|
||||
table->char_bigram = char_bigram;
|
||||
|
||||
// init
|
||||
for (int new_big = table->max_char + 1; new_big <= ch1; new_big++) {
|
||||
table->char_bigram[new_big].total_cnt = 0;
|
||||
table->char_bigram[new_big].max_char = -1;
|
||||
table->char_bigram[new_big].bigram = NULL;
|
||||
}
|
||||
table->max_char = ch1;
|
||||
}
|
||||
|
||||
if (ch2 > table->char_bigram[ch1].max_char) {
|
||||
Bigram *bigram = new Bigram[ch2 + 1];
|
||||
if (bigram == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharBigrams::Create): error allocating "
|
||||
"memory for bigram.\n");
|
||||
delete char_bigrams_obj;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (table->char_bigram[ch1].bigram != NULL &&
|
||||
table->char_bigram[ch1].max_char >= 0) {
|
||||
memcpy(bigram, table->char_bigram[ch1].bigram,
|
||||
(table->char_bigram[ch1].max_char + 1) * sizeof(*bigram));
|
||||
delete []table->char_bigram[ch1].bigram;
|
||||
}
|
||||
table->char_bigram[ch1].bigram = bigram;
|
||||
|
||||
// init
|
||||
for (int new_big = table->char_bigram[ch1].max_char + 1;
|
||||
new_big <= ch2; new_big++) {
|
||||
table->char_bigram[ch1].bigram[new_big].cnt = 0;
|
||||
}
|
||||
table->char_bigram[ch1].max_char = ch2;
|
||||
}
|
||||
|
||||
table->char_bigram[ch1].bigram[ch2].cnt = cnt;
|
||||
table->char_bigram[ch1].total_cnt += cnt;
|
||||
table->total_cnt += cnt;
|
||||
}
|
||||
|
||||
// compute costs (-log probs)
|
||||
table->worst_cost = static_cast<int>(
|
||||
-PROB2COST_SCALE * log(0.5 / table->total_cnt));
|
||||
for (char_32 ch1 = 0; ch1 <= table->max_char; ch1++) {
|
||||
for (char_32 ch2 = 0; ch2 <= table->char_bigram[ch1].max_char; ch2++) {
|
||||
int cnt = table->char_bigram[ch1].bigram[ch2].cnt;
|
||||
table->char_bigram[ch1].bigram[ch2].cost =
|
||||
static_cast<int>(-PROB2COST_SCALE *
|
||||
log(MAX(0.5, static_cast<double>(cnt)) /
|
||||
table->total_cnt));
|
||||
}
|
||||
}
|
||||
return char_bigrams_obj;
|
||||
}
|
||||
|
||||
int CharBigrams::PairCost(char_32 ch1, char_32 ch2) const {
|
||||
if (ch1 > bigram_table_.max_char) {
|
||||
return bigram_table_.worst_cost;
|
||||
}
|
||||
if (ch2 > bigram_table_.char_bigram[ch1].max_char) {
|
||||
return bigram_table_.worst_cost;
|
||||
}
|
||||
return bigram_table_.char_bigram[ch1].bigram[ch2].cost;
|
||||
}
|
||||
|
||||
int CharBigrams::Cost(const char_32 *char_32_ptr, CharSet *char_set) const {
|
||||
if (!char_32_ptr || char_32_ptr[0] == 0) {
|
||||
return bigram_table_.worst_cost;
|
||||
}
|
||||
int cost = MeanCostWithSpaces(char_32_ptr);
|
||||
if (CubeUtils::StrLen(char_32_ptr) >= kMinLengthCaseInvariant &&
|
||||
CubeUtils::IsCaseInvariant(char_32_ptr, char_set)) {
|
||||
char_32 *lower_32 = CubeUtils::ToLower(char_32_ptr, char_set);
|
||||
if (lower_32 && lower_32[0] != 0) {
|
||||
int cost_lower = MeanCostWithSpaces(lower_32);
|
||||
cost = MIN(cost, cost_lower);
|
||||
delete [] lower_32;
|
||||
}
|
||||
char_32 *upper_32 = CubeUtils::ToUpper(char_32_ptr, char_set);
|
||||
if (upper_32 && upper_32[0] != 0) {
|
||||
int cost_upper = MeanCostWithSpaces(upper_32);
|
||||
cost = MIN(cost, cost_upper);
|
||||
delete [] upper_32;
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
int CharBigrams::MeanCostWithSpaces(const char_32 *char_32_ptr) const {
|
||||
if (!char_32_ptr)
|
||||
return bigram_table_.worst_cost;
|
||||
int len = CubeUtils::StrLen(char_32_ptr);
|
||||
int cost = 0;
|
||||
int c = 0;
|
||||
cost = PairCost(' ', char_32_ptr[0]);
|
||||
for (c = 1; c < len; c++) {
|
||||
cost += PairCost(char_32_ptr[c - 1], char_32_ptr[c]);
|
||||
}
|
||||
cost += PairCost(char_32_ptr[len - 1], ' ');
|
||||
return static_cast<int>(cost / static_cast<double>(len + 1));
|
||||
}
|
||||
} // namespace tesseract
|
@ -1,89 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_bigrams.h
|
||||
* Description: Declaration of a Character Bigrams Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CharBigram class represents the interface to the character bigram
|
||||
// table used by Cube
|
||||
// A CharBigram object can be constructed from the Char Bigrams file
|
||||
// Given a sequence of characters, the "Cost" method returns the Char Bigram
|
||||
// cost of the string according to the table
|
||||
|
||||
#ifndef CHAR_BIGRAMS_H
|
||||
#define CHAR_BIGRAMS_H
|
||||
|
||||
#include <string>
|
||||
#include "char_set.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// structure representing a single bigram value
|
||||
struct Bigram {
|
||||
int cnt;
|
||||
int cost;
|
||||
};
|
||||
|
||||
// structure representing the char bigram array of characters
|
||||
// following a specific character
|
||||
struct CharBigram {
|
||||
int total_cnt;
|
||||
char_32 max_char;
|
||||
Bigram *bigram;
|
||||
};
|
||||
|
||||
// structure representing the whole bigram table
|
||||
struct CharBigramTable {
|
||||
int total_cnt;
|
||||
int worst_cost;
|
||||
char_32 max_char;
|
||||
CharBigram *char_bigram;
|
||||
};
|
||||
|
||||
class CharBigrams {
|
||||
public:
|
||||
CharBigrams();
|
||||
~CharBigrams();
|
||||
// Construct the CharBigrams class from a file
|
||||
static CharBigrams *Create(const string &data_file_path,
|
||||
const string &lang);
|
||||
// Top-level function to return the mean character bigram cost of a
|
||||
// sequence of characters. If char_set is not NULL, use
|
||||
// tesseract functions to return a case-invariant cost.
|
||||
// This avoids unnecessarily penalizing all-one-case words or
|
||||
// capitalized words (first-letter upper-case and remaining letters
|
||||
// lower-case).
|
||||
int Cost(const char_32 *str, CharSet *char_set) const;
|
||||
|
||||
protected:
|
||||
// Returns the character bigram cost of two characters.
|
||||
int PairCost(char_32 ch1, char_32 ch2) const;
|
||||
// Returns the mean character bigram cost of a sequence of
|
||||
// characters. Adds a space at the beginning and end to account for
|
||||
// cost of starting and ending characters.
|
||||
int MeanCostWithSpaces(const char_32 *char_32_ptr) const;
|
||||
|
||||
private:
|
||||
// Only words this length or greater qualify for case-invariant character
|
||||
// bigram cost.
|
||||
static const int kMinLengthCaseInvariant = 4;
|
||||
|
||||
|
||||
CharBigramTable bigram_table_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CHAR_BIGRAMS_H
|
@ -1,669 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_samp.cpp
|
||||
* Description: Implementation of a Character Bitmap Sample Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <string.h>
|
||||
#include <string>
|
||||
#include "char_samp.h"
|
||||
#include "cube_utils.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
#define MAX_LINE_LEN 1024
|
||||
|
||||
CharSamp::CharSamp()
|
||||
: Bmp8(0, 0) {
|
||||
left_ = 0;
|
||||
top_ = 0;
|
||||
label32_ = NULL;
|
||||
page_ = -1;
|
||||
}
|
||||
|
||||
CharSamp::CharSamp(int wid, int hgt)
|
||||
: Bmp8(wid, hgt) {
|
||||
left_ = 0;
|
||||
top_ = 0;
|
||||
label32_ = NULL;
|
||||
page_ = -1;
|
||||
}
|
||||
|
||||
CharSamp::CharSamp(int left, int top, int wid, int hgt)
|
||||
: Bmp8(wid, hgt)
|
||||
, left_(left)
|
||||
, top_(top) {
|
||||
label32_ = NULL;
|
||||
page_ = -1;
|
||||
}
|
||||
|
||||
CharSamp::~CharSamp() {
|
||||
if (label32_ != NULL) {
|
||||
delete []label32_;
|
||||
label32_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// returns a UTF-8 version of the string label
|
||||
string CharSamp::stringLabel() const {
|
||||
string str = "";
|
||||
if (label32_ != NULL) {
|
||||
string_32 str32(label32_);
|
||||
CubeUtils::UTF32ToUTF8(str32.c_str(), &str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// set a the string label using a UTF encoded string
|
||||
void CharSamp::SetLabel(string str) {
|
||||
if (label32_ != NULL) {
|
||||
delete []label32_;
|
||||
label32_ = NULL;
|
||||
}
|
||||
string_32 str32;
|
||||
CubeUtils::UTF8ToUTF32(str.c_str(), &str32);
|
||||
SetLabel(reinterpret_cast<const char_32 *>(str32.c_str()));
|
||||
}
|
||||
|
||||
// creates a CharSamp object from file
|
||||
CharSamp *CharSamp::FromCharDumpFile(CachedFile *fp) {
|
||||
unsigned short left;
|
||||
unsigned short top;
|
||||
unsigned short page;
|
||||
unsigned short first_char;
|
||||
unsigned short last_char;
|
||||
unsigned short norm_top;
|
||||
unsigned short norm_bottom;
|
||||
unsigned short norm_aspect_ratio;
|
||||
unsigned int val32;
|
||||
|
||||
char_32 *label32;
|
||||
|
||||
// read and check 32 bit marker
|
||||
if (fp->Read(&val32, sizeof(val32)) != sizeof(val32)) {
|
||||
return NULL;
|
||||
}
|
||||
if (val32 != 0xabd0fefe) {
|
||||
return NULL;
|
||||
}
|
||||
// read label length,
|
||||
if (fp->Read(&val32, sizeof(val32)) != sizeof(val32)) {
|
||||
return NULL;
|
||||
}
|
||||
// the label is not null terminated in the file
|
||||
if (val32 > 0 && val32 < MAX_UINT32) {
|
||||
label32 = new char_32[val32 + 1];
|
||||
if (label32 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// read label
|
||||
if (fp->Read(label32, val32 * sizeof(*label32)) !=
|
||||
(val32 * sizeof(*label32))) {
|
||||
return NULL;
|
||||
}
|
||||
// null terminate
|
||||
label32[val32] = 0;
|
||||
} else {
|
||||
label32 = NULL;
|
||||
}
|
||||
// read coordinates
|
||||
if (fp->Read(&page, sizeof(page)) != sizeof(page)) {
|
||||
return NULL;
|
||||
}
|
||||
if (fp->Read(&left, sizeof(left)) != sizeof(left)) {
|
||||
return NULL;
|
||||
}
|
||||
if (fp->Read(&top, sizeof(top)) != sizeof(top)) {
|
||||
return NULL;
|
||||
}
|
||||
if (fp->Read(&first_char, sizeof(first_char)) != sizeof(first_char)) {
|
||||
return NULL;
|
||||
}
|
||||
if (fp->Read(&last_char, sizeof(last_char)) != sizeof(last_char)) {
|
||||
return NULL;
|
||||
}
|
||||
if (fp->Read(&norm_top, sizeof(norm_top)) != sizeof(norm_top)) {
|
||||
return NULL;
|
||||
}
|
||||
if (fp->Read(&norm_bottom, sizeof(norm_bottom)) != sizeof(norm_bottom)) {
|
||||
return NULL;
|
||||
}
|
||||
if (fp->Read(&norm_aspect_ratio, sizeof(norm_aspect_ratio)) !=
|
||||
sizeof(norm_aspect_ratio)) {
|
||||
return NULL;
|
||||
}
|
||||
// create the object
|
||||
CharSamp *char_samp = new CharSamp();
|
||||
if (char_samp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// init
|
||||
char_samp->label32_ = label32;
|
||||
char_samp->page_ = page;
|
||||
char_samp->left_ = left;
|
||||
char_samp->top_ = top;
|
||||
char_samp->first_char_ = first_char;
|
||||
char_samp->last_char_ = last_char;
|
||||
char_samp->norm_top_ = norm_top;
|
||||
char_samp->norm_bottom_ = norm_bottom;
|
||||
char_samp->norm_aspect_ratio_ = norm_aspect_ratio;
|
||||
// load the Bmp8 part
|
||||
if (char_samp->LoadFromCharDumpFile(fp) == false) {
|
||||
delete char_samp;
|
||||
return NULL;
|
||||
}
|
||||
return char_samp;
|
||||
}
|
||||
|
||||
// Load a Char Samp from a dump file
|
||||
CharSamp *CharSamp::FromCharDumpFile(FILE *fp) {
|
||||
unsigned short left;
|
||||
unsigned short top;
|
||||
unsigned short page;
|
||||
unsigned short first_char;
|
||||
unsigned short last_char;
|
||||
unsigned short norm_top;
|
||||
unsigned short norm_bottom;
|
||||
unsigned short norm_aspect_ratio;
|
||||
unsigned int val32;
|
||||
char_32 *label32;
|
||||
|
||||
// read and check 32 bit marker
|
||||
if (fread(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
|
||||
return NULL;
|
||||
}
|
||||
if (val32 != 0xabd0fefe) {
|
||||
return NULL;
|
||||
}
|
||||
// read label length,
|
||||
if (fread(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
|
||||
return NULL;
|
||||
}
|
||||
// the label is not null terminated in the file
|
||||
if (val32 > 0 && val32 < MAX_UINT32) {
|
||||
label32 = new char_32[val32 + 1];
|
||||
if (label32 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// read label
|
||||
if (fread(label32, 1, val32 * sizeof(*label32), fp) !=
|
||||
(val32 * sizeof(*label32))) {
|
||||
delete [] label32;
|
||||
return NULL;
|
||||
}
|
||||
// null terminate
|
||||
label32[val32] = 0;
|
||||
} else {
|
||||
label32 = NULL;
|
||||
}
|
||||
// read coordinates
|
||||
if (fread(&page, 1, sizeof(page), fp) != sizeof(page) ||
|
||||
fread(&left, 1, sizeof(left), fp) != sizeof(left) ||
|
||||
fread(&top, 1, sizeof(top), fp) != sizeof(top) ||
|
||||
fread(&first_char, 1, sizeof(first_char), fp) != sizeof(first_char) ||
|
||||
fread(&last_char, 1, sizeof(last_char), fp) != sizeof(last_char) ||
|
||||
fread(&norm_top, 1, sizeof(norm_top), fp) != sizeof(norm_top) ||
|
||||
fread(&norm_bottom, 1, sizeof(norm_bottom), fp) != sizeof(norm_bottom) ||
|
||||
fread(&norm_aspect_ratio, 1, sizeof(norm_aspect_ratio), fp) !=
|
||||
sizeof(norm_aspect_ratio)) {
|
||||
delete [] label32;
|
||||
return NULL;
|
||||
}
|
||||
// create the object
|
||||
CharSamp *char_samp = new CharSamp();
|
||||
if (char_samp == NULL) {
|
||||
delete [] label32;
|
||||
return NULL;
|
||||
}
|
||||
// init
|
||||
char_samp->label32_ = label32;
|
||||
char_samp->page_ = page;
|
||||
char_samp->left_ = left;
|
||||
char_samp->top_ = top;
|
||||
char_samp->first_char_ = first_char;
|
||||
char_samp->last_char_ = last_char;
|
||||
char_samp->norm_top_ = norm_top;
|
||||
char_samp->norm_bottom_ = norm_bottom;
|
||||
char_samp->norm_aspect_ratio_ = norm_aspect_ratio;
|
||||
// load the Bmp8 part
|
||||
if (char_samp->LoadFromCharDumpFile(fp) == false) {
|
||||
delete char_samp; // It owns label32.
|
||||
return NULL;
|
||||
}
|
||||
return char_samp;
|
||||
}
|
||||
|
||||
// returns a copy of the charsamp that is scaled to the
|
||||
// specified width and height
|
||||
CharSamp *CharSamp::Scale(int wid, int hgt, bool isotropic) {
|
||||
CharSamp *scaled_samp = new CharSamp(wid, hgt);
|
||||
if (scaled_samp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (scaled_samp->ScaleFrom(this, isotropic) == false) {
|
||||
delete scaled_samp;
|
||||
return NULL;
|
||||
}
|
||||
scaled_samp->left_ = left_;
|
||||
scaled_samp->top_ = top_;
|
||||
scaled_samp->page_ = page_;
|
||||
scaled_samp->SetLabel(label32_);
|
||||
scaled_samp->first_char_ = first_char_;
|
||||
scaled_samp->last_char_ = last_char_;
|
||||
scaled_samp->norm_top_ = norm_top_;
|
||||
scaled_samp->norm_bottom_ = norm_bottom_;
|
||||
scaled_samp->norm_aspect_ratio_ = norm_aspect_ratio_;
|
||||
return scaled_samp;
|
||||
}
|
||||
|
||||
// Load a Char Samp from a dump file
|
||||
CharSamp *CharSamp::FromRawData(int left, int top, int wid, int hgt,
|
||||
unsigned char *data) {
|
||||
// create the object
|
||||
CharSamp *char_samp = new CharSamp(left, top, wid, hgt);
|
||||
if (char_samp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (char_samp->LoadFromRawData(data) == false) {
|
||||
delete char_samp;
|
||||
return NULL;
|
||||
}
|
||||
return char_samp;
|
||||
}
|
||||
|
||||
// Saves the charsamp to a dump file
|
||||
bool CharSamp::Save2CharDumpFile(FILE *fp) const {
|
||||
unsigned int val32;
|
||||
// write and check 32 bit marker
|
||||
val32 = 0xabd0fefe;
|
||||
if (fwrite(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
|
||||
return false;
|
||||
}
|
||||
// write label length
|
||||
val32 = (label32_ == NULL) ? 0 : LabelLen(label32_);
|
||||
if (fwrite(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
|
||||
return false;
|
||||
}
|
||||
// write label
|
||||
if (label32_ != NULL) {
|
||||
if (fwrite(label32_, 1, val32 * sizeof(*label32_), fp) !=
|
||||
(val32 * sizeof(*label32_))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// write coordinates
|
||||
if (fwrite(&page_, 1, sizeof(page_), fp) != sizeof(page_)) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(&left_, 1, sizeof(left_), fp) != sizeof(left_)) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(&top_, 1, sizeof(top_), fp) != sizeof(top_)) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(&first_char_, 1, sizeof(first_char_), fp) !=
|
||||
sizeof(first_char_)) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(&last_char_, 1, sizeof(last_char_), fp) != sizeof(last_char_)) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(&norm_top_, 1, sizeof(norm_top_), fp) != sizeof(norm_top_)) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(&norm_bottom_, 1, sizeof(norm_bottom_), fp) !=
|
||||
sizeof(norm_bottom_)) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(&norm_aspect_ratio_, 1, sizeof(norm_aspect_ratio_), fp) !=
|
||||
sizeof(norm_aspect_ratio_)) {
|
||||
return false;
|
||||
}
|
||||
if (SaveBmp2CharDumpFile(fp) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Crop the char samp such that there are no white spaces on any side.
|
||||
// The norm_top_ and norm_bottom_ fields are the character top/bottom
|
||||
// with respect to whatever context the character is being recognized
|
||||
// in (e.g. word bounding box) normalized to a standard size of
|
||||
// 255. Here they default to 0 and 255 (word box boundaries), but
|
||||
// since they are context dependent, they may need to be reset by the
|
||||
// calling function.
|
||||
CharSamp *CharSamp::Crop() {
|
||||
// get the dimesions of the cropped img
|
||||
int cropped_left = 0;
|
||||
int cropped_top = 0;
|
||||
int cropped_wid = wid_;
|
||||
int cropped_hgt = hgt_;
|
||||
Bmp8::Crop(&cropped_left, &cropped_top,
|
||||
&cropped_wid, &cropped_hgt);
|
||||
|
||||
if (cropped_wid == 0 || cropped_hgt == 0) {
|
||||
return NULL;
|
||||
}
|
||||
// create the cropped char samp
|
||||
CharSamp *cropped_samp = new CharSamp(left_ + cropped_left,
|
||||
top_ + cropped_top,
|
||||
cropped_wid, cropped_hgt);
|
||||
cropped_samp->SetLabel(label32_);
|
||||
cropped_samp->SetFirstChar(first_char_);
|
||||
cropped_samp->SetLastChar(last_char_);
|
||||
// the following 3 fields may/should be reset by the calling function
|
||||
// using context information, i.e., location of character box
|
||||
// w.r.t. the word bounding box
|
||||
cropped_samp->SetNormAspectRatio(255 *
|
||||
cropped_wid / (cropped_wid + cropped_hgt));
|
||||
cropped_samp->SetNormTop(0);
|
||||
cropped_samp->SetNormBottom(255);
|
||||
|
||||
// copy the bitmap to the cropped img
|
||||
Copy(cropped_left, cropped_top, cropped_wid, cropped_hgt, cropped_samp);
|
||||
return cropped_samp;
|
||||
}
|
||||
|
||||
// segment the char samp to connected components
|
||||
// based on contiguity and vertical pixel density histogram
|
||||
ConComp **CharSamp::Segment(int *segment_cnt, bool right_2_left,
|
||||
int max_hist_wnd, int min_con_comp_size) const {
|
||||
// init
|
||||
(*segment_cnt) = 0;
|
||||
int concomp_cnt = 0;
|
||||
int seg_cnt = 0;
|
||||
// find the concomps of the image
|
||||
ConComp **concomp_array = FindConComps(&concomp_cnt, min_con_comp_size);
|
||||
if (concomp_cnt <= 0 || !concomp_array) {
|
||||
if (concomp_array)
|
||||
delete []concomp_array;
|
||||
return NULL;
|
||||
}
|
||||
ConComp **seg_array = NULL;
|
||||
// segment each concomp further using vertical histogram
|
||||
for (int concomp = 0; concomp < concomp_cnt; concomp++) {
|
||||
int concomp_seg_cnt = 0;
|
||||
// segment the concomp
|
||||
ConComp **concomp_seg_array = NULL;
|
||||
ConComp **concomp_alloc_seg =
|
||||
concomp_array[concomp]->Segment(max_hist_wnd, &concomp_seg_cnt);
|
||||
// no segments, add the whole concomp
|
||||
if (concomp_alloc_seg == NULL) {
|
||||
concomp_seg_cnt = 1;
|
||||
concomp_seg_array = concomp_array + concomp;
|
||||
} else {
|
||||
// delete the original concomp, we no longer need it
|
||||
concomp_seg_array = concomp_alloc_seg;
|
||||
delete concomp_array[concomp];
|
||||
}
|
||||
// add the resulting segments
|
||||
for (int seg_idx = 0; seg_idx < concomp_seg_cnt; seg_idx++) {
|
||||
// too small of a segment: ignore
|
||||
if (concomp_seg_array[seg_idx]->Width() < 2 &&
|
||||
concomp_seg_array[seg_idx]->Height() < 2) {
|
||||
delete concomp_seg_array[seg_idx];
|
||||
} else {
|
||||
// add the new segment
|
||||
// extend the segment array
|
||||
if ((seg_cnt % kConCompAllocChunk) == 0) {
|
||||
ConComp **temp_segm_array =
|
||||
new ConComp *[seg_cnt + kConCompAllocChunk];
|
||||
if (temp_segm_array == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharSamp::Segment): could not "
|
||||
"allocate additional connected components\n");
|
||||
delete []concomp_seg_array;
|
||||
delete []concomp_array;
|
||||
delete []seg_array;
|
||||
return NULL;
|
||||
}
|
||||
if (seg_cnt > 0) {
|
||||
memcpy(temp_segm_array, seg_array, seg_cnt * sizeof(*seg_array));
|
||||
delete []seg_array;
|
||||
}
|
||||
seg_array = temp_segm_array;
|
||||
}
|
||||
seg_array[seg_cnt++] = concomp_seg_array[seg_idx];
|
||||
}
|
||||
} // segment
|
||||
if (concomp_alloc_seg != NULL) {
|
||||
delete []concomp_alloc_seg;
|
||||
}
|
||||
} // concomp
|
||||
delete []concomp_array;
|
||||
|
||||
// sort the concomps from Left2Right or Right2Left, based on the reading order
|
||||
if (seg_cnt > 0 && seg_array != NULL) {
|
||||
qsort(seg_array, seg_cnt, sizeof(*seg_array), right_2_left ?
|
||||
ConComp::Right2LeftComparer : ConComp::Left2RightComparer);
|
||||
}
|
||||
(*segment_cnt) = seg_cnt;
|
||||
return seg_array;
|
||||
}
|
||||
|
||||
// builds a char samp from a set of connected components
|
||||
CharSamp *CharSamp::FromConComps(ConComp **concomp_array, int strt_concomp,
|
||||
int seg_flags_size, int *seg_flags,
|
||||
bool *left_most, bool *right_most,
|
||||
int word_hgt) {
|
||||
int concomp;
|
||||
int end_concomp;
|
||||
int concomp_cnt = 0;
|
||||
end_concomp = strt_concomp + seg_flags_size;
|
||||
// determine ID range
|
||||
bool once = false;
|
||||
int min_id = -1;
|
||||
int max_id = -1;
|
||||
for (concomp = strt_concomp; concomp < end_concomp; concomp++) {
|
||||
if (!seg_flags || seg_flags[concomp - strt_concomp] != 0) {
|
||||
if (!once) {
|
||||
min_id = concomp_array[concomp]->ID();
|
||||
max_id = concomp_array[concomp]->ID();
|
||||
once = true;
|
||||
} else {
|
||||
UpdateRange(concomp_array[concomp]->ID(), &min_id, &max_id);
|
||||
}
|
||||
concomp_cnt++;
|
||||
}
|
||||
}
|
||||
if (concomp_cnt < 1 || !once || min_id == -1 || max_id == -1) {
|
||||
return NULL;
|
||||
}
|
||||
// alloc memo for computing leftmost and right most attributes
|
||||
int id_cnt = max_id - min_id + 1;
|
||||
bool *id_exist = new bool[id_cnt];
|
||||
bool *left_most_exist = new bool[id_cnt];
|
||||
bool *right_most_exist = new bool[id_cnt];
|
||||
if (!id_exist || !left_most_exist || !right_most_exist)
|
||||
return NULL;
|
||||
memset(id_exist, 0, id_cnt * sizeof(*id_exist));
|
||||
memset(left_most_exist, 0, id_cnt * sizeof(*left_most_exist));
|
||||
memset(right_most_exist, 0, id_cnt * sizeof(*right_most_exist));
|
||||
// find the dimensions of the charsamp
|
||||
once = false;
|
||||
int left = -1;
|
||||
int right = -1;
|
||||
int top = -1;
|
||||
int bottom = -1;
|
||||
int unq_ids = 0;
|
||||
int unq_left_most = 0;
|
||||
int unq_right_most = 0;
|
||||
for (concomp = strt_concomp; concomp < end_concomp; concomp++) {
|
||||
if (!seg_flags || seg_flags[concomp - strt_concomp] != 0) {
|
||||
if (!once) {
|
||||
left = concomp_array[concomp]->Left();
|
||||
right = concomp_array[concomp]->Right();
|
||||
top = concomp_array[concomp]->Top();
|
||||
bottom = concomp_array[concomp]->Bottom();
|
||||
once = true;
|
||||
} else {
|
||||
UpdateRange(concomp_array[concomp]->Left(),
|
||||
concomp_array[concomp]->Right(), &left, &right);
|
||||
UpdateRange(concomp_array[concomp]->Top(),
|
||||
concomp_array[concomp]->Bottom(), &top, &bottom);
|
||||
}
|
||||
// count unq ids, unq left most and right mosts ids
|
||||
int concomp_id = concomp_array[concomp]->ID() - min_id;
|
||||
if (!id_exist[concomp_id]) {
|
||||
id_exist[concomp_id] = true;
|
||||
unq_ids++;
|
||||
}
|
||||
if (concomp_array[concomp]->LeftMost()) {
|
||||
if (left_most_exist[concomp_id] == false) {
|
||||
left_most_exist[concomp_id] = true;
|
||||
unq_left_most++;
|
||||
}
|
||||
}
|
||||
if (concomp_array[concomp]->RightMost()) {
|
||||
if (right_most_exist[concomp_id] == false) {
|
||||
right_most_exist[concomp_id] = true;
|
||||
unq_right_most++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete []id_exist;
|
||||
delete []left_most_exist;
|
||||
delete []right_most_exist;
|
||||
if (!once || left == -1 || top == -1 || right == -1 || bottom == -1) {
|
||||
return NULL;
|
||||
}
|
||||
(*left_most) = (unq_left_most >= unq_ids);
|
||||
(*right_most) = (unq_right_most >= unq_ids);
|
||||
// create the char sample object
|
||||
CharSamp *samp = new CharSamp(left, top, right - left + 1, bottom - top + 1);
|
||||
if (!samp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// set the foreground pixels
|
||||
for (concomp = strt_concomp; concomp < end_concomp; concomp++) {
|
||||
if (!seg_flags || seg_flags[concomp - strt_concomp] != 0) {
|
||||
ConCompPt *pt_ptr = concomp_array[concomp]->Head();
|
||||
while (pt_ptr) {
|
||||
samp->line_buff_[pt_ptr->y() - top][pt_ptr->x() - left] = 0;
|
||||
pt_ptr = pt_ptr->Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
return samp;
|
||||
}
|
||||
|
||||
// clones the object
|
||||
CharSamp *CharSamp::Clone() const {
|
||||
// create the cropped char samp
|
||||
CharSamp *samp = new CharSamp(left_, top_, wid_, hgt_);
|
||||
samp->SetLabel(label32_);
|
||||
samp->SetFirstChar(first_char_);
|
||||
samp->SetLastChar(last_char_);
|
||||
samp->SetNormTop(norm_top_);
|
||||
samp->SetNormBottom(norm_bottom_);
|
||||
samp->SetNormAspectRatio(norm_aspect_ratio_);
|
||||
// copy the bitmap to the cropped img
|
||||
Copy(0, 0, wid_, hgt_, samp);
|
||||
return samp;
|
||||
}
|
||||
|
||||
// Load a Char Samp from a dump file
|
||||
CharSamp *CharSamp::FromCharDumpFile(unsigned char **raw_data_ptr) {
|
||||
unsigned int val32;
|
||||
char_32 *label32;
|
||||
unsigned char *raw_data = *raw_data_ptr;
|
||||
|
||||
// read and check 32 bit marker
|
||||
memcpy(&val32, raw_data, sizeof(val32));
|
||||
raw_data += sizeof(val32);
|
||||
if (val32 != 0xabd0fefe) {
|
||||
return NULL;
|
||||
}
|
||||
// read label length,
|
||||
memcpy(&val32, raw_data, sizeof(val32));
|
||||
raw_data += sizeof(val32);
|
||||
// the label is not null terminated in the file
|
||||
if (val32 > 0 && val32 < MAX_UINT32) {
|
||||
label32 = new char_32[val32 + 1];
|
||||
if (label32 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// read label
|
||||
memcpy(label32, raw_data, val32 * sizeof(*label32));
|
||||
raw_data += (val32 * sizeof(*label32));
|
||||
// null terminate
|
||||
label32[val32] = 0;
|
||||
} else {
|
||||
label32 = NULL;
|
||||
}
|
||||
|
||||
// create the object
|
||||
CharSamp *char_samp = new CharSamp();
|
||||
if (char_samp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read coordinates
|
||||
char_samp->label32_ = label32;
|
||||
memcpy(&char_samp->page_, raw_data, sizeof(char_samp->page_));
|
||||
raw_data += sizeof(char_samp->page_);
|
||||
memcpy(&char_samp->left_, raw_data, sizeof(char_samp->left_));
|
||||
raw_data += sizeof(char_samp->left_);
|
||||
memcpy(&char_samp->top_, raw_data, sizeof(char_samp->top_));
|
||||
raw_data += sizeof(char_samp->top_);
|
||||
memcpy(&char_samp->first_char_, raw_data, sizeof(char_samp->first_char_));
|
||||
raw_data += sizeof(char_samp->first_char_);
|
||||
memcpy(&char_samp->last_char_, raw_data, sizeof(char_samp->last_char_));
|
||||
raw_data += sizeof(char_samp->last_char_);
|
||||
memcpy(&char_samp->norm_top_, raw_data, sizeof(char_samp->norm_top_));
|
||||
raw_data += sizeof(char_samp->norm_top_);
|
||||
memcpy(&char_samp->norm_bottom_, raw_data, sizeof(char_samp->norm_bottom_));
|
||||
raw_data += sizeof(char_samp->norm_bottom_);
|
||||
memcpy(&char_samp->norm_aspect_ratio_, raw_data,
|
||||
sizeof(char_samp->norm_aspect_ratio_));
|
||||
raw_data += sizeof(char_samp->norm_aspect_ratio_);
|
||||
|
||||
// load the Bmp8 part
|
||||
if (char_samp->LoadFromCharDumpFile(&raw_data) == false) {
|
||||
delete char_samp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*raw_data_ptr) = raw_data;
|
||||
return char_samp;
|
||||
}
|
||||
|
||||
// computes the features corresponding to the char sample
|
||||
bool CharSamp::ComputeFeatures(int conv_grid_size, float *features) {
|
||||
// Create a scaled BMP
|
||||
CharSamp *scaled_bmp = Scale(conv_grid_size, conv_grid_size);
|
||||
if (!scaled_bmp) {
|
||||
return false;
|
||||
}
|
||||
// prepare input
|
||||
unsigned char *buff = scaled_bmp->RawData();
|
||||
// bitmap features
|
||||
int input;
|
||||
int bmp_size = conv_grid_size * conv_grid_size;
|
||||
for (input = 0; input < bmp_size; input++) {
|
||||
features[input] = 255.0f - (1.0f * buff[input]);
|
||||
}
|
||||
// word context features
|
||||
features[input++] = FirstChar();
|
||||
features[input++] = LastChar();
|
||||
features[input++] = NormTop();
|
||||
features[input++] = NormBottom();
|
||||
features[input++] = NormAspectRatio();
|
||||
delete scaled_bmp;
|
||||
return true;
|
||||
}
|
||||
} // namespace tesseract
|
166
cube/char_samp.h
166
cube/char_samp.h
@ -1,166 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_samp.h
|
||||
* Description: Declaration of a Character Bitmap Sample Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CharSamp inherits the Bmp8 class that represents images of
|
||||
// words, characters and segments throughout Cube
|
||||
// CharSamp adds more data members to hold the physical location of the image
|
||||
// in a page, page number in a book if available.
|
||||
// It also holds the label (GT) of the image that might correspond to a single
|
||||
// character or a word
|
||||
// It also provides methods for segmenting, scaling and cropping of the sample
|
||||
|
||||
#ifndef CHAR_SAMP_H
|
||||
#define CHAR_SAMP_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "bmp_8.h"
|
||||
#include "string_32.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class CharSamp : public Bmp8 {
|
||||
public:
|
||||
CharSamp();
|
||||
CharSamp(int wid, int hgt);
|
||||
CharSamp(int left, int top, int wid, int hgt);
|
||||
~CharSamp();
|
||||
// accessor methods
|
||||
unsigned short Left() const { return left_; }
|
||||
unsigned short Right() const { return left_ + wid_; }
|
||||
unsigned short Top() const { return top_; }
|
||||
unsigned short Bottom() const { return top_ + hgt_; }
|
||||
unsigned short Page() const { return page_; }
|
||||
unsigned short NormTop() const { return norm_top_; }
|
||||
unsigned short NormBottom() const { return norm_bottom_; }
|
||||
unsigned short NormAspectRatio() const { return norm_aspect_ratio_; }
|
||||
unsigned short FirstChar() const { return first_char_; }
|
||||
unsigned short LastChar() const { return last_char_; }
|
||||
char_32 Label() const {
|
||||
if (label32_ == NULL || LabelLen() != 1) {
|
||||
return 0;
|
||||
}
|
||||
return label32_[0];
|
||||
}
|
||||
char_32 * StrLabel() const { return label32_; }
|
||||
string stringLabel() const;
|
||||
|
||||
void SetLeft(unsigned short left) { left_ = left; }
|
||||
void SetTop(unsigned short top) { top_ = top; }
|
||||
void SetPage(unsigned short page) { page_ = page; }
|
||||
void SetLabel(char_32 label) {
|
||||
if (label32_ != NULL) {
|
||||
delete []label32_;
|
||||
}
|
||||
label32_ = new char_32[2];
|
||||
if (label32_ != NULL) {
|
||||
label32_[0] = label;
|
||||
label32_[1] = 0;
|
||||
}
|
||||
}
|
||||
void SetLabel(const char_32 *label32) {
|
||||
if (label32_ != NULL) {
|
||||
delete []label32_;
|
||||
label32_ = NULL;
|
||||
}
|
||||
if (label32 != NULL) {
|
||||
// remove any byte order marks if any
|
||||
if (label32[0] == 0xfeff) {
|
||||
label32++;
|
||||
}
|
||||
int len = LabelLen(label32);
|
||||
label32_ = new char_32[len + 1];
|
||||
if (label32_ != NULL) {
|
||||
memcpy(label32_, label32, len * sizeof(*label32));
|
||||
label32_[len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
void SetLabel(string str);
|
||||
void SetNormTop(unsigned short norm_top) { norm_top_ = norm_top; }
|
||||
void SetNormBottom(unsigned short norm_bottom) {
|
||||
norm_bottom_ = norm_bottom;
|
||||
}
|
||||
void SetNormAspectRatio(unsigned short norm_aspect_ratio) {
|
||||
norm_aspect_ratio_ = norm_aspect_ratio;
|
||||
}
|
||||
void SetFirstChar(unsigned short first_char) {
|
||||
first_char_ = first_char;
|
||||
}
|
||||
void SetLastChar(unsigned short last_char) {
|
||||
last_char_ = last_char;
|
||||
}
|
||||
|
||||
// Saves the charsamp to a dump file
|
||||
bool Save2CharDumpFile(FILE *fp) const;
|
||||
// Crops the underlying image and returns a new CharSamp with the
|
||||
// same character information but new dimensions. Warning: does not
|
||||
// necessarily set the normalized top and bottom correctly since
|
||||
// those depend on its location within the word (or CubeSearchObject).
|
||||
CharSamp *Crop();
|
||||
// Computes the connected components of the char sample
|
||||
ConComp **Segment(int *seg_cnt, bool right_2_left, int max_hist_wnd,
|
||||
int min_con_comp_size) const;
|
||||
// returns a copy of the charsamp that is scaled to the
|
||||
// specified width and height
|
||||
CharSamp *Scale(int wid, int hgt, bool isotropic = true);
|
||||
// returns a Clone of the charsample
|
||||
CharSamp *Clone() const;
|
||||
// computes the features corresponding to the char sample
|
||||
bool ComputeFeatures(int conv_grid_size, float *features);
|
||||
// Load a Char Samp from a dump file
|
||||
static CharSamp *FromCharDumpFile(CachedFile *fp);
|
||||
static CharSamp *FromCharDumpFile(FILE *fp);
|
||||
static CharSamp *FromCharDumpFile(unsigned char **raw_data);
|
||||
static CharSamp *FromRawData(int left, int top, int wid, int hgt,
|
||||
unsigned char *data);
|
||||
static CharSamp *FromConComps(ConComp **concomp_array,
|
||||
int strt_concomp, int seg_flags_size,
|
||||
int *seg_flags, bool *left_most,
|
||||
bool *right_most, int word_hgt);
|
||||
static int AuxFeatureCnt() { return (5); }
|
||||
// Return the length of the label string
|
||||
int LabelLen() const { return LabelLen(label32_); }
|
||||
static int LabelLen(const char_32 *label32) {
|
||||
if (label32 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int len = 0;
|
||||
while (label32[++len] != 0);
|
||||
return len;
|
||||
}
|
||||
private:
|
||||
char_32 * label32_;
|
||||
unsigned short page_;
|
||||
unsigned short left_;
|
||||
unsigned short top_;
|
||||
// top of sample normalized to a word height of 255
|
||||
unsigned short norm_top_;
|
||||
// bottom of sample normalized to a word height of 255
|
||||
unsigned short norm_bottom_;
|
||||
// 255 * ratio of character width to (width + height)
|
||||
unsigned short norm_aspect_ratio_;
|
||||
unsigned short first_char_;
|
||||
unsigned short last_char_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CHAR_SAMP_H
|
@ -1,38 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_samp_enum.h
|
||||
* Description: Declaration of a Character Sample Enumerator Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CharSampEnum class provides the base class for CharSamp class
|
||||
// Enumerators. This is typically used to implement dump file readers
|
||||
|
||||
#ifndef CHARSAMP_ENUM_H
|
||||
#define CHARSAMP_ENUM_H
|
||||
|
||||
#include "char_samp.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class CharSampEnum {
|
||||
public:
|
||||
CharSampEnum();
|
||||
virtual ~CharSampEnum();
|
||||
virtual bool EnumCharSamp(CharSamp *char_samp, float progress) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CHARSAMP_ENUM_H
|
@ -1,182 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_samp_enum.cpp
|
||||
* Description: Implementation of a Character Sample Set Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <stdlib.h>
|
||||
#include <string>
|
||||
#include "char_samp_set.h"
|
||||
#include "cached_file.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
CharSampSet::CharSampSet() {
|
||||
cnt_ = 0;
|
||||
samp_buff_ = NULL;
|
||||
own_samples_ = false;
|
||||
}
|
||||
|
||||
CharSampSet::~CharSampSet() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
// free buffers and init vars
|
||||
void CharSampSet::Cleanup() {
|
||||
if (samp_buff_ != NULL) {
|
||||
// only free samples if owned by class
|
||||
if (own_samples_ == true) {
|
||||
for (int samp_idx = 0; samp_idx < cnt_; samp_idx++) {
|
||||
if (samp_buff_[samp_idx] != NULL) {
|
||||
delete samp_buff_[samp_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
delete []samp_buff_;
|
||||
}
|
||||
cnt_ = 0;
|
||||
samp_buff_ = NULL;
|
||||
}
|
||||
|
||||
// add a new sample
|
||||
bool CharSampSet::Add(CharSamp *char_samp) {
|
||||
if ((cnt_ % SAMP_ALLOC_BLOCK) == 0) {
|
||||
// create an extended buffer
|
||||
CharSamp **new_samp_buff =
|
||||
reinterpret_cast<CharSamp **>(new CharSamp *[cnt_ + SAMP_ALLOC_BLOCK]);
|
||||
if (new_samp_buff == NULL) {
|
||||
return false;
|
||||
}
|
||||
// copy old contents
|
||||
if (cnt_ > 0) {
|
||||
memcpy(new_samp_buff, samp_buff_, cnt_ * sizeof(*samp_buff_));
|
||||
delete []samp_buff_;
|
||||
}
|
||||
samp_buff_ = new_samp_buff;
|
||||
}
|
||||
samp_buff_[cnt_++] = char_samp;
|
||||
return true;
|
||||
}
|
||||
|
||||
// load char samples from file
|
||||
bool CharSampSet::LoadCharSamples(FILE *fp) {
|
||||
// free existing
|
||||
Cleanup();
|
||||
// samples are created here and owned by the class
|
||||
own_samples_ = true;
|
||||
// start loading char samples
|
||||
while (feof(fp) == 0) {
|
||||
CharSamp *new_samp = CharSamp::FromCharDumpFile(fp);
|
||||
if (new_samp != NULL) {
|
||||
if (Add(new_samp) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// creates a CharSampSet object from file
|
||||
CharSampSet * CharSampSet::FromCharDumpFile(string file_name) {
|
||||
FILE *fp;
|
||||
unsigned int val32;
|
||||
// open the file
|
||||
fp = fopen(file_name.c_str(), "rb");
|
||||
if (fp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// read and verify marker
|
||||
if (fread(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
if (val32 != 0xfefeabd0) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
// create an object
|
||||
CharSampSet *samp_set = new CharSampSet();
|
||||
if (samp_set == NULL) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
if (samp_set->LoadCharSamples(fp) == false) {
|
||||
delete samp_set;
|
||||
samp_set = NULL;
|
||||
}
|
||||
fclose(fp);
|
||||
return samp_set;
|
||||
}
|
||||
|
||||
// Create a new Char Dump file
|
||||
FILE *CharSampSet::CreateCharDumpFile(string file_name) {
|
||||
FILE *fp;
|
||||
unsigned int val32;
|
||||
// create the file
|
||||
fp = fopen(file_name.c_str(), "wb");
|
||||
if (!fp) {
|
||||
return NULL;
|
||||
}
|
||||
// read and verify marker
|
||||
val32 = 0xfefeabd0;
|
||||
if (fwrite(&val32, 1, sizeof(val32), fp) != sizeof(val32)) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
// Enumerate the Samples in the set one-by-one calling the enumertor's
|
||||
// EnumCharSamp method for each sample
|
||||
bool CharSampSet::EnumSamples(string file_name, CharSampEnum *enum_obj) {
|
||||
CachedFile *fp_in;
|
||||
unsigned int val32;
|
||||
long i64_size,
|
||||
i64_pos;
|
||||
// open the file
|
||||
fp_in = new CachedFile(file_name);
|
||||
if (fp_in == NULL) {
|
||||
return false;
|
||||
}
|
||||
i64_size = fp_in->Size();
|
||||
if (i64_size < 1) {
|
||||
return false;
|
||||
}
|
||||
// read and verify marker
|
||||
if (fp_in->Read(&val32, sizeof(val32)) != sizeof(val32)) {
|
||||
return false;
|
||||
}
|
||||
if (val32 != 0xfefeabd0) {
|
||||
return false;
|
||||
}
|
||||
// start loading char samples
|
||||
while (fp_in->eof() == false) {
|
||||
CharSamp *new_samp = CharSamp::FromCharDumpFile(fp_in);
|
||||
i64_pos = fp_in->Tell();
|
||||
if (new_samp != NULL) {
|
||||
bool ret_flag = (enum_obj)->EnumCharSamp(new_samp,
|
||||
(100.0f * i64_pos / i64_size));
|
||||
delete new_samp;
|
||||
if (ret_flag == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete fp_in;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ocrlib
|
@ -1,73 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_samp_set.h
|
||||
* Description: Declaration of a Character Sample Set Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CharSampSet set encapsulates a set of CharSet objects typically
|
||||
// but not necessarily loaded from a file
|
||||
// It provides methods to load samples from File, Create a new file and
|
||||
// Add new char samples to the set
|
||||
|
||||
#ifndef CHAR_SAMP_SET_H
|
||||
#define CHAR_SAMP_SET_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "char_samp.h"
|
||||
#include "char_samp_enum.h"
|
||||
#include "char_set.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// chunks of samp pointers to allocate
|
||||
#define SAMP_ALLOC_BLOCK 10000
|
||||
|
||||
class CharSampSet {
|
||||
public:
|
||||
CharSampSet();
|
||||
~CharSampSet();
|
||||
// return sample count
|
||||
int SampleCount() const { return cnt_; }
|
||||
// returns samples buffer
|
||||
CharSamp ** Samples() const { return samp_buff_; }
|
||||
// Create a CharSampSet set object from a file
|
||||
static CharSampSet *FromCharDumpFile(string file_name);
|
||||
// Enumerate the Samples in the set one-by-one calling the enumertor's
|
||||
// EnumCharSamp method for each sample
|
||||
static bool EnumSamples(string file_name, CharSampEnum *enumerator);
|
||||
// Create a new Char Dump file
|
||||
static FILE *CreateCharDumpFile(string file_name);
|
||||
// Add a new sample to the set
|
||||
bool Add(CharSamp *char_samp);
|
||||
|
||||
private:
|
||||
// sample count
|
||||
int cnt_;
|
||||
// the char samp array
|
||||
CharSamp **samp_buff_;
|
||||
// Are the samples owned by the set or not.
|
||||
// Determines whether we should cleanup in the end
|
||||
bool own_samples_;
|
||||
// Cleanup
|
||||
void Cleanup();
|
||||
// Load character samples from a file
|
||||
bool LoadCharSamples(FILE *fp);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CHAR_SAMP_SET_H
|
@ -1,186 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_samp_enum.cpp
|
||||
* Description: Implementation of a Character Set Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <string>
|
||||
|
||||
#include "char_set.h"
|
||||
#include "cube_utils.h"
|
||||
#include "tessdatamanager.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
CharSet::CharSet() {
|
||||
class_cnt_ = 0;
|
||||
class_strings_ = NULL;
|
||||
unicharset_map_ = NULL;
|
||||
init_ = false;
|
||||
|
||||
// init hash table
|
||||
memset(hash_bin_size_, 0, sizeof(hash_bin_size_));
|
||||
}
|
||||
|
||||
CharSet::~CharSet() {
|
||||
if (class_strings_ != NULL) {
|
||||
for (int cls = 0; cls < class_cnt_; cls++) {
|
||||
if (class_strings_[cls] != NULL) {
|
||||
delete class_strings_[cls];
|
||||
}
|
||||
}
|
||||
delete []class_strings_;
|
||||
class_strings_ = NULL;
|
||||
}
|
||||
delete []unicharset_map_;
|
||||
}
|
||||
|
||||
// Creates CharSet object by reading the unicharset from the
|
||||
// TessDatamanager, and mapping Cube's unicharset to Tesseract's if
|
||||
// they differ.
|
||||
CharSet *CharSet::Create(TessdataManager *tessdata_manager,
|
||||
UNICHARSET *tess_unicharset) {
|
||||
CharSet *char_set = new CharSet();
|
||||
if (char_set == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// First look for Cube's unicharset; if not there, use tesseract's
|
||||
bool cube_unicharset_exists;
|
||||
if (!(cube_unicharset_exists =
|
||||
tessdata_manager->SeekToStart(TESSDATA_CUBE_UNICHARSET)) &&
|
||||
!tessdata_manager->SeekToStart(TESSDATA_UNICHARSET)) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::Create): could not find "
|
||||
"either cube or tesseract unicharset\n");
|
||||
return NULL;
|
||||
}
|
||||
FILE *charset_fp = tessdata_manager->GetDataFilePtr();
|
||||
if (!charset_fp) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::Create): could not load "
|
||||
"a unicharset\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If we found a cube unicharset separate from tesseract's, load it and
|
||||
// map its unichars to tesseract's; if only one unicharset exists,
|
||||
// just load it.
|
||||
bool loaded;
|
||||
if (cube_unicharset_exists) {
|
||||
char_set->cube_unicharset_.load_from_file(charset_fp);
|
||||
loaded = tessdata_manager->SeekToStart(TESSDATA_CUBE_UNICHARSET);
|
||||
loaded = loaded && char_set->LoadSupportedCharList(
|
||||
tessdata_manager->GetDataFilePtr(), tess_unicharset);
|
||||
char_set->unicharset_ = &char_set->cube_unicharset_;
|
||||
} else {
|
||||
loaded = char_set->LoadSupportedCharList(charset_fp, NULL);
|
||||
char_set->unicharset_ = tess_unicharset;
|
||||
}
|
||||
if (!loaded) {
|
||||
delete char_set;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char_set->init_ = true;
|
||||
return char_set;
|
||||
}
|
||||
|
||||
// Load the list of supported chars from the given data file pointer.
|
||||
bool CharSet::LoadSupportedCharList(FILE *fp, UNICHARSET *tess_unicharset) {
|
||||
if (init_)
|
||||
return true;
|
||||
|
||||
char str_line[256];
|
||||
// init hash table
|
||||
memset(hash_bin_size_, 0, sizeof(hash_bin_size_));
|
||||
// read the char count
|
||||
if (fgets(str_line, sizeof(str_line), fp) == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::InitMemory): could not "
|
||||
"read char count.\n");
|
||||
return false;
|
||||
}
|
||||
class_cnt_ = atoi(str_line);
|
||||
if (class_cnt_ < 2) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::InitMemory): invalid "
|
||||
"class count: %d\n", class_cnt_);
|
||||
return false;
|
||||
}
|
||||
// memory for class strings
|
||||
class_strings_ = new string_32*[class_cnt_];
|
||||
if (class_strings_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::InitMemory): could not "
|
||||
"allocate memory for class strings.\n");
|
||||
return false;
|
||||
}
|
||||
// memory for unicharset map
|
||||
if (tess_unicharset) {
|
||||
unicharset_map_ = new int[class_cnt_];
|
||||
if (unicharset_map_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::InitMemory): could not "
|
||||
"allocate memory for unicharset map.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Read in character strings and add to hash table
|
||||
for (int class_id = 0; class_id < class_cnt_; class_id++) {
|
||||
// Read the class string
|
||||
if (fgets(str_line, sizeof(str_line), fp) == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::ReadAndHashStrings): "
|
||||
"could not read class string with class_id=%d.\n", class_id);
|
||||
return false;
|
||||
}
|
||||
// Terminate at space if any
|
||||
char *p = strchr(str_line, ' ');
|
||||
if (p != NULL)
|
||||
*p = '\0';
|
||||
// Convert to UTF32 and store
|
||||
string_32 str32;
|
||||
// Convert NULL to a space
|
||||
if (strcmp(str_line, "NULL") == 0) {
|
||||
strcpy(str_line, " ");
|
||||
}
|
||||
CubeUtils::UTF8ToUTF32(str_line, &str32);
|
||||
class_strings_[class_id] = new string_32(str32);
|
||||
if (class_strings_[class_id] == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::ReadAndHashStrings): could not "
|
||||
"allocate memory for class string with class_id=%d.\n", class_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add to hash-table
|
||||
int hash_val = Hash(reinterpret_cast<const char_32 *>(str32.c_str()));
|
||||
if (hash_bin_size_[hash_val] >= kMaxHashSize) {
|
||||
fprintf(stderr, "Cube ERROR (CharSet::LoadSupportedCharList): hash "
|
||||
"table is full.\n");
|
||||
return false;
|
||||
}
|
||||
hash_bins_[hash_val][hash_bin_size_[hash_val]++] = class_id;
|
||||
|
||||
if (tess_unicharset != NULL) {
|
||||
// Add class id to unicharset map
|
||||
UNICHAR_ID tess_id = tess_unicharset->unichar_to_id(str_line);
|
||||
if (tess_id == INVALID_UNICHAR_ID) {
|
||||
tess_unicharset->unichar_insert(str_line);
|
||||
tess_id = tess_unicharset->unichar_to_id(str_line);
|
||||
}
|
||||
ASSERT_HOST(tess_id != INVALID_UNICHAR_ID);
|
||||
unicharset_map_[class_id] = tess_id;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // tesseract
|
174
cube/char_set.h
174
cube/char_set.h
@ -1,174 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: char_samp_enum.h
|
||||
* Description: Declaration of a Character Set Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CharSet class encapsulates the list of 32-bit strings/characters that
|
||||
// Cube supports for a specific language. The char set is loaded from the
|
||||
// .unicharset file corresponding to a specific language
|
||||
// Each string has a corresponding int class-id that gets used throughout Cube
|
||||
// The class provides pass back and forth conversion between the class-id
|
||||
// and its corresponding 32-bit string. This is done using a hash table that
|
||||
// maps the string to the class id.
|
||||
|
||||
#ifndef CHAR_SET_H
|
||||
#define CHAR_SET_H
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "string_32.h"
|
||||
#include "tessdatamanager.h"
|
||||
#include "unicharset.h"
|
||||
#include "cube_const.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class CharSet {
|
||||
public:
|
||||
CharSet();
|
||||
~CharSet();
|
||||
|
||||
// Returns true if Cube is sharing Tesseract's unicharset.
|
||||
inline bool SharedUnicharset() { return (unicharset_map_ == NULL); }
|
||||
|
||||
// Returns the class id corresponding to a 32-bit string. Returns -1
|
||||
// if the string is not supported. This is done by hashing the
|
||||
// string and then looking up the string in the hash-bin if there
|
||||
// are collisions.
|
||||
inline int ClassID(const char_32 *str) const {
|
||||
int hash_val = Hash(str);
|
||||
if (hash_bin_size_[hash_val] == 0)
|
||||
return -1;
|
||||
for (int bin = 0; bin < hash_bin_size_[hash_val]; bin++) {
|
||||
if (class_strings_[hash_bins_[hash_val][bin]]->compare(str) == 0)
|
||||
return hash_bins_[hash_val][bin];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
// Same as above but using a 32-bit char instead of a string
|
||||
inline int ClassID(char_32 ch) const {
|
||||
int hash_val = Hash(ch);
|
||||
if (hash_bin_size_[hash_val] == 0)
|
||||
return -1;
|
||||
for (int bin = 0; bin < hash_bin_size_[hash_val]; bin++) {
|
||||
if ((*class_strings_[hash_bins_[hash_val][bin]])[0] == ch &&
|
||||
class_strings_[hash_bins_[hash_val][bin]]->length() == 1) {
|
||||
return hash_bins_[hash_val][bin];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
// Retrieve the unicharid in Tesseract's unicharset corresponding
|
||||
// to a 32-bit string. When Tesseract and Cube share the same
|
||||
// unicharset, this will just be the class id.
|
||||
inline int UnicharID(const char_32 *str) const {
|
||||
int class_id = ClassID(str);
|
||||
if (class_id == INVALID_UNICHAR_ID)
|
||||
return INVALID_UNICHAR_ID;
|
||||
int unichar_id;
|
||||
if (unicharset_map_)
|
||||
unichar_id = unicharset_map_[class_id];
|
||||
else
|
||||
unichar_id = class_id;
|
||||
return unichar_id;
|
||||
}
|
||||
// Same as above but using a 32-bit char instead of a string
|
||||
inline int UnicharID(char_32 ch) const {
|
||||
int class_id = ClassID(ch);
|
||||
if (class_id == INVALID_UNICHAR_ID)
|
||||
return INVALID_UNICHAR_ID;
|
||||
int unichar_id;
|
||||
if (unicharset_map_)
|
||||
unichar_id = unicharset_map_[class_id];
|
||||
else
|
||||
unichar_id = class_id;
|
||||
return unichar_id;
|
||||
}
|
||||
// Returns the 32-bit string corresponding to a class id
|
||||
inline const char_32 * ClassString(int class_id) const {
|
||||
if (class_id < 0 || class_id >= class_cnt_) {
|
||||
return NULL;
|
||||
}
|
||||
return reinterpret_cast<const char_32 *>(class_strings_[class_id]->c_str());
|
||||
}
|
||||
// Returns the count of supported strings
|
||||
inline int ClassCount() const { return class_cnt_; }
|
||||
|
||||
// Creates CharSet object by reading the unicharset from the
|
||||
// TessDatamanager, and mapping Cube's unicharset to Tesseract's if
|
||||
// they differ.
|
||||
static CharSet *Create(TessdataManager *tessdata_manager,
|
||||
UNICHARSET *tess_unicharset);
|
||||
|
||||
// Return the UNICHARSET cube is using for recognition internally --
|
||||
// ClassId() returns unichar_id's in this unicharset.
|
||||
UNICHARSET *InternalUnicharset() { return unicharset_; }
|
||||
|
||||
private:
|
||||
// Hash table configuration params. Determined emperically on
|
||||
// the supported languages so far (Eng, Ara, Hin). Might need to be
|
||||
// tuned for speed when more languages are supported
|
||||
static const int kHashBins = 3001;
|
||||
static const int kMaxHashSize = 16;
|
||||
|
||||
// Using djb2 hashing function to hash a 32-bit string
|
||||
// introduced in http://www.cse.yorku.ca/~oz/hash.html
|
||||
static inline int Hash(const char_32 *str) {
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
while ((c = *str++))
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
return (hash%kHashBins);
|
||||
}
|
||||
// Same as above but for a single char
|
||||
static inline int Hash(char_32 ch) {
|
||||
char_32 b[2];
|
||||
b[0] = ch;
|
||||
b[1] = 0;
|
||||
return Hash(b);
|
||||
}
|
||||
|
||||
// Load the list of supported chars from the given data file
|
||||
// pointer. If tess_unicharset is non-NULL, mapping each Cube class
|
||||
// id to a tesseract unicharid.
|
||||
bool LoadSupportedCharList(FILE *fp, UNICHARSET *tess_unicharset);
|
||||
|
||||
// class count
|
||||
int class_cnt_;
|
||||
// hash-bin sizes array
|
||||
int hash_bin_size_[kHashBins];
|
||||
// hash bins
|
||||
int hash_bins_[kHashBins][kMaxHashSize];
|
||||
// supported strings array
|
||||
string_32 **class_strings_;
|
||||
// map from class id to secondary (tesseract's) unicharset's ids
|
||||
int *unicharset_map_;
|
||||
// A unicharset which is filled in with a Tesseract-style UNICHARSET for
|
||||
// cube's data if our unicharset is different from tesseract's.
|
||||
UNICHARSET cube_unicharset_;
|
||||
// This points to either the tess_unicharset we're passed or cube_unicharset_,
|
||||
// depending upon whether we just have one unicharset or one for each
|
||||
// tesseract and cube, respectively.
|
||||
UNICHARSET *unicharset_;
|
||||
// has the char set been initialized flag
|
||||
bool init_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CHAR_SET_H
|
@ -1,100 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: classifier_base.h
|
||||
* Description: Declaration of the Base Character Classifier
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CharClassifier class is the abstract class for any character/grapheme
|
||||
// classifier.
|
||||
|
||||
#ifndef CHAR_CLASSIFIER_BASE_H
|
||||
#define CHAR_CLASSIFIER_BASE_H
|
||||
|
||||
#include <string>
|
||||
#include "char_samp.h"
|
||||
#include "char_altlist.h"
|
||||
#include "char_set.h"
|
||||
#include "feature_base.h"
|
||||
#include "lang_model.h"
|
||||
#include "tuning_params.h"
|
||||
|
||||
namespace tesseract {
|
||||
class CharClassifier {
|
||||
public:
|
||||
CharClassifier(CharSet *char_set, TuningParams *params,
|
||||
FeatureBase *feat_extract) {
|
||||
char_set_ = char_set;
|
||||
params_ = params;
|
||||
feat_extract_ = feat_extract;
|
||||
fold_sets_ = NULL;
|
||||
fold_set_cnt_ = 0;
|
||||
fold_set_len_ = NULL;
|
||||
init_ = false;
|
||||
case_sensitive_ = true;
|
||||
}
|
||||
|
||||
virtual ~CharClassifier() {
|
||||
if (fold_sets_ != NULL) {
|
||||
for (int fold_set = 0; fold_set < fold_set_cnt_; fold_set++) {
|
||||
if (fold_sets_[fold_set] != NULL) {
|
||||
delete []fold_sets_[fold_set];
|
||||
}
|
||||
}
|
||||
delete []fold_sets_;
|
||||
fold_sets_ = NULL;
|
||||
}
|
||||
if (fold_set_len_ != NULL) {
|
||||
delete []fold_set_len_;
|
||||
fold_set_len_ = NULL;
|
||||
}
|
||||
if (feat_extract_ != NULL) {
|
||||
delete feat_extract_;
|
||||
feat_extract_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// pure virtual functions that need to be implemented by any inheriting class
|
||||
virtual CharAltList * Classify(CharSamp *char_samp) = 0;
|
||||
virtual int CharCost(CharSamp *char_samp) = 0;
|
||||
virtual bool Train(CharSamp *char_samp, int ClassID) = 0;
|
||||
virtual bool SetLearnParam(char *var_name, float val) = 0;
|
||||
virtual bool Init(const string &data_file_path, const string &lang,
|
||||
LangModel *lang_mod) = 0;
|
||||
|
||||
// accessors
|
||||
FeatureBase *FeatureExtractor() {return feat_extract_;}
|
||||
inline bool CaseSensitive() const { return case_sensitive_; }
|
||||
inline void SetCaseSensitive(bool case_sensitive) {
|
||||
case_sensitive_ = case_sensitive;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Fold() = 0;
|
||||
virtual bool LoadFoldingSets(const string &data_file_path,
|
||||
const string &lang,
|
||||
LangModel *lang_mod) = 0;
|
||||
FeatureBase *feat_extract_;
|
||||
CharSet *char_set_;
|
||||
TuningParams *params_;
|
||||
int **fold_sets_;
|
||||
int *fold_set_len_;
|
||||
int fold_set_cnt_;
|
||||
bool init_;
|
||||
bool case_sensitive_;
|
||||
};
|
||||
} // tesseract
|
||||
|
||||
#endif // CHAR_CLASSIFIER_BASE_H
|
@ -1,97 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: classifier_factory.cpp
|
||||
* Description: Implementation of the Base Character Classifier
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include "classifier_factory.h"
|
||||
#include "conv_net_classifier.h"
|
||||
#include "feature_base.h"
|
||||
#include "feature_bmp.h"
|
||||
#include "feature_chebyshev.h"
|
||||
#include "feature_hybrid.h"
|
||||
#include "hybrid_neural_net_classifier.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// Creates a CharClassifier object of the appropriate type depending on the
|
||||
// classifier type in the settings file
|
||||
CharClassifier *CharClassifierFactory::Create(const string &data_file_path,
|
||||
const string &lang,
|
||||
LangModel *lang_mod,
|
||||
CharSet *char_set,
|
||||
TuningParams *params) {
|
||||
// create the feature extraction object
|
||||
FeatureBase *feat_extract;
|
||||
|
||||
switch (params->TypeFeature()) {
|
||||
case TuningParams::BMP:
|
||||
feat_extract = new FeatureBmp(params);
|
||||
break;
|
||||
case TuningParams::CHEBYSHEV:
|
||||
feat_extract = new FeatureChebyshev(params);
|
||||
break;
|
||||
case TuningParams::HYBRID:
|
||||
feat_extract = new FeatureHybrid(params);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Cube ERROR (CharClassifierFactory::Create): invalid "
|
||||
"feature type.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (feat_extract == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharClassifierFactory::Create): unable "
|
||||
"to instantiate feature extraction object.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create the classifier object
|
||||
CharClassifier *classifier_obj;
|
||||
switch (params->TypeClassifier()) {
|
||||
case TuningParams::NN:
|
||||
classifier_obj = new ConvNetCharClassifier(char_set, params,
|
||||
feat_extract);
|
||||
break;
|
||||
case TuningParams::HYBRID_NN:
|
||||
classifier_obj = new HybridNeuralNetCharClassifier(char_set, params,
|
||||
feat_extract);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Cube ERROR (CharClassifierFactory::Create): invalid "
|
||||
"classifier type.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (classifier_obj == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (CharClassifierFactory::Create): error "
|
||||
"allocating memory for character classifier object.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Init the classifier
|
||||
if (!classifier_obj->Init(data_file_path, lang, lang_mod)) {
|
||||
delete classifier_obj;
|
||||
fprintf(stderr, "Cube ERROR (CharClassifierFactory::Create): unable "
|
||||
"to Init() character classifier object.\n");
|
||||
return NULL;
|
||||
}
|
||||
return classifier_obj;
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: classifier_factory.h
|
||||
* Description: Declaration of the Base Character Classifier
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CharClassifierFactory provides a single static method to create an
|
||||
// instance of the desired classifier
|
||||
|
||||
#ifndef CHAR_CLASSIFIER_FACTORY_H
|
||||
#define CHAR_CLASSIFIER_FACTORY_H
|
||||
|
||||
#include <string>
|
||||
#include "classifier_base.h"
|
||||
#include "lang_model.h"
|
||||
|
||||
namespace tesseract {
|
||||
class CharClassifierFactory {
|
||||
public:
|
||||
// Creates a CharClassifier object of the appropriate type depending on the
|
||||
// classifier type in the settings file
|
||||
static CharClassifier *Create(const string &data_file_path,
|
||||
const string &lang,
|
||||
LangModel *lang_mod,
|
||||
CharSet *char_set,
|
||||
TuningParams *params);
|
||||
};
|
||||
} // tesseract
|
||||
|
||||
#endif // CHAR_CLASSIFIER_FACTORY_H
|
@ -1,286 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: con_comp.cpp
|
||||
* Description: Implementation of a Connected Component class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "con_comp.h"
|
||||
#include "cube_const.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
ConComp::ConComp() {
|
||||
head_ = NULL;
|
||||
tail_ = NULL;
|
||||
left_ = 0;
|
||||
top_ = 0;
|
||||
right_ = 0;
|
||||
bottom_ = 0;
|
||||
left_most_ = false;
|
||||
right_most_ = false;
|
||||
id_ = -1;
|
||||
pt_cnt_ = 0;
|
||||
}
|
||||
|
||||
ConComp::~ConComp() {
|
||||
if (head_ != NULL) {
|
||||
ConCompPt *pt_ptr = head_;
|
||||
while (pt_ptr != NULL) {
|
||||
ConCompPt *pptNext = pt_ptr->Next();
|
||||
delete pt_ptr;
|
||||
pt_ptr = pptNext;
|
||||
}
|
||||
head_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// adds a pt to the conn comp and updates its boundaries
|
||||
bool ConComp::Add(int x, int y) {
|
||||
ConCompPt *pt_ptr = new ConCompPt(x, y);
|
||||
if (pt_ptr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (head_ == NULL) {
|
||||
left_ = x;
|
||||
right_ = x;
|
||||
top_ = y;
|
||||
bottom_ = y;
|
||||
|
||||
head_ = pt_ptr;
|
||||
} else {
|
||||
left_ = left_ <= x ? left_ : x;
|
||||
top_ = top_ <= y ? top_ : y;
|
||||
right_ = right_ >= x ? right_ : x;
|
||||
bottom_ = bottom_ >= y ? bottom_ : y;
|
||||
}
|
||||
|
||||
if (tail_ != NULL) {
|
||||
tail_->SetNext(pt_ptr);
|
||||
}
|
||||
|
||||
tail_ = pt_ptr;
|
||||
pt_cnt_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// merges two connected components
|
||||
bool ConComp::Merge(ConComp *concomp) {
|
||||
if (head_ == NULL || tail_ == NULL ||
|
||||
concomp->head_ == NULL || concomp->tail_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tail_->SetNext(concomp->head_);
|
||||
tail_ = concomp->tail_;
|
||||
left_ = left_ <= concomp->left_ ? left_ : concomp->left_;
|
||||
top_ = top_ <= concomp->top_ ? top_ : concomp->top_;
|
||||
right_ = right_ >= concomp->right_ ? right_ : concomp->right_;
|
||||
bottom_ = bottom_ >= concomp->bottom_ ? bottom_ : concomp->bottom_;
|
||||
pt_cnt_ += concomp->pt_cnt_;
|
||||
|
||||
concomp->head_ = NULL;
|
||||
concomp->tail_ = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates the x-coord density histogram after spreading
|
||||
// each x-coord position by the HIST_WND_RATIO fraction of the
|
||||
// height of the ConComp, but limited to max_hist_wnd
|
||||
int *ConComp::CreateHistogram(int max_hist_wnd) {
|
||||
int wid = right_ - left_ + 1,
|
||||
hgt = bottom_ - top_ + 1,
|
||||
hist_wnd = static_cast<int>(hgt * HIST_WND_RATIO);
|
||||
|
||||
if (hist_wnd > max_hist_wnd) {
|
||||
hist_wnd = max_hist_wnd;
|
||||
}
|
||||
|
||||
// alloc memo for histogram
|
||||
int *hist_array = new int[wid];
|
||||
if (hist_array == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(hist_array, 0, wid * sizeof(*hist_array));
|
||||
|
||||
// compute windowed histogram
|
||||
ConCompPt *pt_ptr = head_;
|
||||
|
||||
while (pt_ptr != NULL) {
|
||||
int x = pt_ptr->x() - left_,
|
||||
xw = x - hist_wnd;
|
||||
|
||||
for (int xdel = -hist_wnd; xdel <= hist_wnd; xdel++, xw++) {
|
||||
if (xw >= 0 && xw < wid) {
|
||||
hist_array[xw]++;
|
||||
}
|
||||
}
|
||||
|
||||
pt_ptr = pt_ptr->Next();
|
||||
}
|
||||
|
||||
return hist_array;
|
||||
}
|
||||
|
||||
// find out the seg pts by looking for local minima in the histogram
|
||||
int *ConComp::SegmentHistogram(int *hist_array, int *seg_pt_cnt) {
|
||||
// init
|
||||
(*seg_pt_cnt) = 0;
|
||||
|
||||
int wid = right_ - left_ + 1,
|
||||
hgt = bottom_ - top_ + 1;
|
||||
|
||||
int *x_seg_pt = new int[wid];
|
||||
if (x_seg_pt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int seg_pt_wnd = static_cast<int>(hgt * SEG_PT_WND_RATIO);
|
||||
|
||||
if (seg_pt_wnd > 1) {
|
||||
seg_pt_wnd = 1;
|
||||
}
|
||||
|
||||
for (int x = 2; x < (wid - 2); x++) {
|
||||
if (hist_array[x] < hist_array[x - 1] &&
|
||||
hist_array[x] < hist_array[x - 2] &&
|
||||
hist_array[x] <= hist_array[x + 1] &&
|
||||
hist_array[x] <= hist_array[x + 2]) {
|
||||
x_seg_pt[(*seg_pt_cnt)++] = x;
|
||||
x += seg_pt_wnd;
|
||||
} else if (hist_array[x] <= hist_array[x - 1] &&
|
||||
hist_array[x] <= hist_array[x - 2] &&
|
||||
hist_array[x] < hist_array[x + 1] &&
|
||||
hist_array[x] < hist_array[x + 2]) {
|
||||
x_seg_pt[(*seg_pt_cnt)++] = x;
|
||||
x += seg_pt_wnd;
|
||||
}
|
||||
}
|
||||
|
||||
// no segments, nothing to do
|
||||
if ((*seg_pt_cnt) == 0) {
|
||||
delete []x_seg_pt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return x_seg_pt;
|
||||
}
|
||||
|
||||
// segments a concomp based on pixel density histogram local minima
|
||||
// if there were none found, it returns NULL
|
||||
// this is more useful than creating a clone of itself
|
||||
ConComp **ConComp::Segment(int max_hist_wnd, int *concomp_cnt) {
|
||||
// init
|
||||
(*concomp_cnt) = 0;
|
||||
|
||||
// No pts
|
||||
if (head_ == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int seg_pt_cnt = 0;
|
||||
|
||||
// create the histogram
|
||||
int *hist_array = CreateHistogram(max_hist_wnd);
|
||||
if (hist_array == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int *x_seg_pt = SegmentHistogram(hist_array, &seg_pt_cnt);
|
||||
|
||||
// free histogram
|
||||
delete []hist_array;
|
||||
|
||||
// no segments, nothing to do
|
||||
if (seg_pt_cnt == 0) {
|
||||
delete []x_seg_pt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create concomp array
|
||||
ConComp **concomp_array = new ConComp *[seg_pt_cnt + 1];
|
||||
if (concomp_array == NULL) {
|
||||
delete []x_seg_pt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int concomp = 0; concomp <= seg_pt_cnt; concomp++) {
|
||||
concomp_array[concomp] = new ConComp();
|
||||
if (concomp_array[concomp] == NULL) {
|
||||
delete []x_seg_pt;
|
||||
delete []concomp_array;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// split concomps inherit the ID this concomp
|
||||
concomp_array[concomp]->SetID(id_);
|
||||
}
|
||||
|
||||
// set the left and right most attributes of the
|
||||
// appropriate concomps
|
||||
concomp_array[0]->left_most_ = true;
|
||||
concomp_array[seg_pt_cnt]->right_most_ = true;
|
||||
|
||||
// assign pts to concomps
|
||||
ConCompPt *pt_ptr = head_;
|
||||
while (pt_ptr != NULL) {
|
||||
int seg_pt;
|
||||
|
||||
// find the first seg-pt that exceeds the x value
|
||||
// of the pt
|
||||
for (seg_pt = 0; seg_pt < seg_pt_cnt; seg_pt++) {
|
||||
if ((x_seg_pt[seg_pt] + left_) > pt_ptr->x()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add the pt to the proper concomp
|
||||
if (concomp_array[seg_pt]->Add(pt_ptr->x(), pt_ptr->y()) == false) {
|
||||
delete []x_seg_pt;
|
||||
delete []concomp_array;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pt_ptr = pt_ptr->Next();
|
||||
}
|
||||
|
||||
delete []x_seg_pt;
|
||||
|
||||
(*concomp_cnt) = (seg_pt_cnt + 1);
|
||||
|
||||
return concomp_array;
|
||||
}
|
||||
|
||||
// Shifts the co-ordinates of all points by the specified x & y deltas
|
||||
void ConComp::Shift(int dx, int dy) {
|
||||
ConCompPt *pt_ptr = head_;
|
||||
|
||||
while (pt_ptr != NULL) {
|
||||
pt_ptr->Shift(dx, dy);
|
||||
pt_ptr = pt_ptr->Next();
|
||||
}
|
||||
|
||||
left_ += dx;
|
||||
right_ += dx;
|
||||
top_ += dy;
|
||||
bottom_ += dy;
|
||||
}
|
||||
|
||||
} // namespace tesseract
|
124
cube/con_comp.h
124
cube/con_comp.h
@ -1,124 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: con_comp.h
|
||||
* Description: Declaration of a Connected Component class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef CONCOMP_H
|
||||
#define CONCOMP_H
|
||||
|
||||
// The ConComp class implements the functionality needed for a
|
||||
// Connected Component object and Connected Component (ConComp) points.
|
||||
// The points consituting a connected component are kept in a linked-list
|
||||
// The Concomp class provided methods to:
|
||||
// 1- Compare components in L2R and R2L reading orders.
|
||||
// 2- Merge ConComps
|
||||
// 3- Compute the windowed vertical pixel density histogram for a specific
|
||||
// windows size
|
||||
// 4- Segment a ConComp based on the local windowed vertical pixel
|
||||
// density histogram local minima
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// Implments a ConComp point in a linked list of points
|
||||
class ConCompPt {
|
||||
public:
|
||||
ConCompPt(int x, int y) {
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
next_pt_ = NULL;
|
||||
}
|
||||
inline int x() { return x_; }
|
||||
inline int y() { return y_; }
|
||||
inline void Shift(int dx, int dy) {
|
||||
x_ += dx;
|
||||
y_ += dy;
|
||||
}
|
||||
inline ConCompPt * Next() { return next_pt_; }
|
||||
inline void SetNext(ConCompPt *pt) { next_pt_ = pt; }
|
||||
|
||||
private:
|
||||
int x_;
|
||||
int y_;
|
||||
ConCompPt *next_pt_;
|
||||
};
|
||||
|
||||
class ConComp {
|
||||
public:
|
||||
ConComp();
|
||||
virtual ~ConComp();
|
||||
// accessors
|
||||
inline ConCompPt *Head() { return head_; }
|
||||
inline int Left() const { return left_; }
|
||||
inline int Top() const { return top_; }
|
||||
inline int Right() const { return right_; }
|
||||
inline int Bottom() const { return bottom_; }
|
||||
inline int Width() const { return right_ - left_ + 1; }
|
||||
inline int Height() const { return bottom_ - top_ + 1; }
|
||||
|
||||
// Comparer used for sorting L2R reading order
|
||||
inline static int Left2RightComparer(const void *comp1,
|
||||
const void *comp2) {
|
||||
return (*(reinterpret_cast<ConComp * const *>(comp1)))->left_ +
|
||||
(*(reinterpret_cast<ConComp * const *>(comp1)))->right_ -
|
||||
(*(reinterpret_cast<ConComp * const *>(comp2)))->left_ -
|
||||
(*(reinterpret_cast<ConComp * const *>(comp2)))->right_;
|
||||
}
|
||||
|
||||
// Comparer used for sorting R2L reading order
|
||||
inline static int Right2LeftComparer(const void *comp1,
|
||||
const void *comp2) {
|
||||
return (*(reinterpret_cast<ConComp * const *>(comp2)))->right_ -
|
||||
(*(reinterpret_cast<ConComp * const *>(comp1)))->right_;
|
||||
}
|
||||
|
||||
// accessors for attribues of a ConComp
|
||||
inline bool LeftMost() const { return left_most_; }
|
||||
inline bool RightMost() const { return right_most_; }
|
||||
inline void SetLeftMost(bool left_most) { left_most_ = left_most; }
|
||||
inline void SetRightMost(bool right_most) { right_most_ = right_most;
|
||||
}
|
||||
inline int ID () const { return id_; }
|
||||
inline void SetID(int id) { id_ = id; }
|
||||
inline int PtCnt () const { return pt_cnt_; }
|
||||
// Add a new pt
|
||||
bool Add(int x, int y);
|
||||
// Merge two connected components in-place
|
||||
bool Merge(ConComp *con_comp);
|
||||
// Shifts the co-ordinates of all points by the specified x & y deltas
|
||||
void Shift(int dx, int dy);
|
||||
// segments a concomp based on pixel density histogram local minima
|
||||
ConComp **Segment(int max_hist_wnd, int *concomp_cnt);
|
||||
// creates the vertical pixel density histogram of the concomp
|
||||
int *CreateHistogram(int max_hist_wnd);
|
||||
// find out the seg pts by looking for local minima in the histogram
|
||||
int *SegmentHistogram(int *hist_array, int *seg_pt_cnt);
|
||||
|
||||
private:
|
||||
int id_;
|
||||
bool left_most_;
|
||||
bool right_most_;
|
||||
int left_;
|
||||
int top_;
|
||||
int right_;
|
||||
int bottom_;
|
||||
ConCompPt *head_;
|
||||
ConCompPt *tail_;
|
||||
int pt_cnt_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CONCOMP_H
|
@ -1,390 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: charclassifier.cpp
|
||||
* Description: Implementation of Convolutional-NeuralNet Character Classifier
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wctype.h>
|
||||
|
||||
#include "char_set.h"
|
||||
#include "classifier_base.h"
|
||||
#include "const.h"
|
||||
#include "conv_net_classifier.h"
|
||||
#include "cube_utils.h"
|
||||
#include "feature_base.h"
|
||||
#include "feature_bmp.h"
|
||||
#include "tess_lang_model.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
ConvNetCharClassifier::ConvNetCharClassifier(CharSet *char_set,
|
||||
TuningParams *params,
|
||||
FeatureBase *feat_extract)
|
||||
: CharClassifier(char_set, params, feat_extract) {
|
||||
char_net_ = NULL;
|
||||
net_input_ = NULL;
|
||||
net_output_ = NULL;
|
||||
}
|
||||
|
||||
ConvNetCharClassifier::~ConvNetCharClassifier() {
|
||||
if (char_net_ != NULL) {
|
||||
delete char_net_;
|
||||
char_net_ = NULL;
|
||||
}
|
||||
|
||||
if (net_input_ != NULL) {
|
||||
delete []net_input_;
|
||||
net_input_ = NULL;
|
||||
}
|
||||
|
||||
if (net_output_ != NULL) {
|
||||
delete []net_output_;
|
||||
net_output_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main training function. Given a sample and a class ID the classifier
|
||||
* updates its parameters according to its learning algorithm. This function
|
||||
* is currently not implemented. TODO(ahmadab): implement end-2-end training
|
||||
*/
|
||||
bool ConvNetCharClassifier::Train(CharSamp *char_samp, int ClassID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A secondary function needed for training. Allows the trainer to set the
|
||||
* value of any train-time parameter. This function is currently not
|
||||
* implemented. TODO(ahmadab): implement end-2-end training
|
||||
*/
|
||||
bool ConvNetCharClassifier::SetLearnParam(char *var_name, float val) {
|
||||
// TODO(ahmadab): implementation of parameter initializing.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Folds the output of the NeuralNet using the loaded folding sets
|
||||
*/
|
||||
void ConvNetCharClassifier::Fold() {
|
||||
// in case insensitive mode
|
||||
if (case_sensitive_ == false) {
|
||||
int class_cnt = char_set_->ClassCount();
|
||||
// fold case
|
||||
for (int class_id = 0; class_id < class_cnt; class_id++) {
|
||||
// get class string
|
||||
const char_32 *str32 = char_set_->ClassString(class_id);
|
||||
// get the upper case form of the string
|
||||
string_32 upper_form32 = str32;
|
||||
for (int ch = 0; ch < upper_form32.length(); ch++) {
|
||||
if (iswalpha(static_cast<int>(upper_form32[ch])) != 0) {
|
||||
upper_form32[ch] = towupper(upper_form32[ch]);
|
||||
}
|
||||
}
|
||||
|
||||
// find out the upperform class-id if any
|
||||
int upper_class_id =
|
||||
char_set_->ClassID(reinterpret_cast<const char_32 *>(
|
||||
upper_form32.c_str()));
|
||||
if (upper_class_id != -1 && class_id != upper_class_id) {
|
||||
float max_out = MAX(net_output_[class_id], net_output_[upper_class_id]);
|
||||
net_output_[class_id] = max_out;
|
||||
net_output_[upper_class_id] = max_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The folding sets specify how groups of classes should be folded
|
||||
// Folding involved assigning a min-activation to all the members
|
||||
// of the folding set. The min-activation is a fraction of the max-activation
|
||||
// of the members of the folding set
|
||||
for (int fold_set = 0; fold_set < fold_set_cnt_; fold_set++) {
|
||||
if (fold_set_len_[fold_set] == 0)
|
||||
continue;
|
||||
float max_prob = net_output_[fold_sets_[fold_set][0]];
|
||||
for (int ch = 1; ch < fold_set_len_[fold_set]; ch++) {
|
||||
if (net_output_[fold_sets_[fold_set][ch]] > max_prob) {
|
||||
max_prob = net_output_[fold_sets_[fold_set][ch]];
|
||||
}
|
||||
}
|
||||
for (int ch = 0; ch < fold_set_len_[fold_set]; ch++) {
|
||||
net_output_[fold_sets_[fold_set][ch]] = MAX(max_prob * kFoldingRatio,
|
||||
net_output_[fold_sets_[fold_set][ch]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the features of specified charsamp and feedforward the
|
||||
* specified nets
|
||||
*/
|
||||
bool ConvNetCharClassifier::RunNets(CharSamp *char_samp) {
|
||||
if (char_net_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::RunNets): "
|
||||
"NeuralNet is NULL\n");
|
||||
return false;
|
||||
}
|
||||
int feat_cnt = char_net_->in_cnt();
|
||||
int class_cnt = char_set_->ClassCount();
|
||||
|
||||
// allocate i/p and o/p buffers if needed
|
||||
if (net_input_ == NULL) {
|
||||
net_input_ = new float[feat_cnt];
|
||||
if (net_input_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::RunNets): "
|
||||
"unable to allocate memory for input nodes\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
net_output_ = new float[class_cnt];
|
||||
if (net_output_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::RunNets): "
|
||||
"unable to allocate memory for output nodes\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// compute input features
|
||||
if (feat_extract_->ComputeFeatures(char_samp, net_input_) == false) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::RunNets): "
|
||||
"unable to compute features\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (char_net_ != NULL) {
|
||||
if (char_net_->FeedForward(net_input_, net_output_) == false) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::RunNets): "
|
||||
"unable to run feed-forward\n");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
Fold();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the cost of being a char
|
||||
*/
|
||||
int ConvNetCharClassifier::CharCost(CharSamp *char_samp) {
|
||||
if (RunNets(char_samp) == false) {
|
||||
return 0;
|
||||
}
|
||||
return CubeUtils::Prob2Cost(1.0f - net_output_[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* classifies a charsamp and returns an alternate list
|
||||
* of chars sorted by char costs
|
||||
*/
|
||||
CharAltList *ConvNetCharClassifier::Classify(CharSamp *char_samp) {
|
||||
// run the needed nets
|
||||
if (RunNets(char_samp) == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int class_cnt = char_set_->ClassCount();
|
||||
|
||||
// create an altlist
|
||||
CharAltList *alt_list = new CharAltList(char_set_, class_cnt);
|
||||
if (alt_list == NULL) {
|
||||
fprintf(stderr, "Cube WARNING (ConvNetCharClassifier::Classify): "
|
||||
"returning emtpy CharAltList\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int out = 1; out < class_cnt; out++) {
|
||||
int cost = CubeUtils::Prob2Cost(net_output_[out]);
|
||||
alt_list->Insert(out, cost);
|
||||
}
|
||||
|
||||
return alt_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an external net (for training purposes)
|
||||
*/
|
||||
void ConvNetCharClassifier::SetNet(tesseract::NeuralNet *char_net) {
|
||||
if (char_net_ != NULL) {
|
||||
delete char_net_;
|
||||
char_net_ = NULL;
|
||||
}
|
||||
char_net_ = char_net;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return true if the file does not exist.
|
||||
* But will fail if the it did not pass the sanity checks
|
||||
*/
|
||||
bool ConvNetCharClassifier::LoadFoldingSets(const string &data_file_path,
|
||||
const string &lang,
|
||||
LangModel *lang_mod) {
|
||||
fold_set_cnt_ = 0;
|
||||
string fold_file_name;
|
||||
fold_file_name = data_file_path + lang;
|
||||
fold_file_name += ".cube.fold";
|
||||
|
||||
// folding sets are optional
|
||||
FILE *fp = fopen(fold_file_name.c_str(), "rb");
|
||||
if (fp == NULL) {
|
||||
return true;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
string fold_sets_str;
|
||||
if (!CubeUtils::ReadFileToString(fold_file_name,
|
||||
&fold_sets_str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// split into lines
|
||||
vector<string> str_vec;
|
||||
CubeUtils::SplitStringUsing(fold_sets_str, "\r\n", &str_vec);
|
||||
fold_set_cnt_ = str_vec.size();
|
||||
|
||||
fold_sets_ = new int *[fold_set_cnt_];
|
||||
if (fold_sets_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
fold_set_len_ = new int[fold_set_cnt_];
|
||||
if (fold_set_len_ == NULL) {
|
||||
fold_set_cnt_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int fold_set = 0; fold_set < fold_set_cnt_; fold_set++) {
|
||||
reinterpret_cast<TessLangModel *>(lang_mod)->RemoveInvalidCharacters(
|
||||
&str_vec[fold_set]);
|
||||
|
||||
// if all or all but one character are invalid, invalidate this set
|
||||
if (str_vec[fold_set].length() <= 1) {
|
||||
fprintf(stderr, "Cube WARNING (ConvNetCharClassifier::LoadFoldingSets): "
|
||||
"invalidating folding set %d\n", fold_set);
|
||||
fold_set_len_[fold_set] = 0;
|
||||
fold_sets_[fold_set] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
string_32 str32;
|
||||
CubeUtils::UTF8ToUTF32(str_vec[fold_set].c_str(), &str32);
|
||||
fold_set_len_[fold_set] = str32.length();
|
||||
fold_sets_[fold_set] = new int[fold_set_len_[fold_set]];
|
||||
if (fold_sets_[fold_set] == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::LoadFoldingSets): "
|
||||
"could not allocate folding set\n");
|
||||
fold_set_cnt_ = fold_set;
|
||||
return false;
|
||||
}
|
||||
for (int ch = 0; ch < fold_set_len_[fold_set]; ch++) {
|
||||
fold_sets_[fold_set][ch] = char_set_->ClassID(str32[ch]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the classifier provided a data-path and a language string
|
||||
*/
|
||||
bool ConvNetCharClassifier::Init(const string &data_file_path,
|
||||
const string &lang,
|
||||
LangModel *lang_mod) {
|
||||
if (init_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// load the nets if any. This function will return true if the net file
|
||||
// does not exist. But will fail if the net did not pass the sanity checks
|
||||
if (!LoadNets(data_file_path, lang)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// load the folding sets if any. This function will return true if the
|
||||
// file does not exist. But will fail if the it did not pass the sanity checks
|
||||
if (!LoadFoldingSets(data_file_path, lang, lang_mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
init_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the classifier's Neural Nets
|
||||
* This function will return true if the net file does not exist.
|
||||
* But will fail if the net did not pass the sanity checks
|
||||
*/
|
||||
bool ConvNetCharClassifier::LoadNets(const string &data_file_path,
|
||||
const string &lang) {
|
||||
string char_net_file;
|
||||
|
||||
// add the lang identifier
|
||||
char_net_file = data_file_path + lang;
|
||||
char_net_file += ".cube.nn";
|
||||
|
||||
// neural network is optional
|
||||
FILE *fp = fopen(char_net_file.c_str(), "rb");
|
||||
if (fp == NULL) {
|
||||
return true;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
// load main net
|
||||
char_net_ = tesseract::NeuralNet::FromFile(char_net_file);
|
||||
if (char_net_ == NULL) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::LoadNets): "
|
||||
"could not load %s\n", char_net_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate net
|
||||
if (char_net_->in_cnt()!= feat_extract_->FeatureCnt()) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::LoadNets): "
|
||||
"could not validate net %s\n", char_net_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// alloc net i/o buffers
|
||||
int feat_cnt = char_net_->in_cnt();
|
||||
int class_cnt = char_set_->ClassCount();
|
||||
|
||||
if (char_net_->out_cnt() != class_cnt) {
|
||||
fprintf(stderr, "Cube ERROR (ConvNetCharClassifier::LoadNets): "
|
||||
"output count (%d) and class count (%d) are not equal\n",
|
||||
char_net_->out_cnt(), class_cnt);
|
||||
return false;
|
||||
}
|
||||
|
||||
// allocate i/p and o/p buffers if needed
|
||||
if (net_input_ == NULL) {
|
||||
net_input_ = new float[feat_cnt];
|
||||
if (net_input_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
net_output_ = new float[class_cnt];
|
||||
if (net_output_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // tesseract
|
@ -1,94 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: conv_net_classifier.h
|
||||
* Description: Declaration of Convolutional-NeuralNet Character Classifier
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The ConvNetCharClassifier inherits from the base classifier class:
|
||||
// "CharClassifierBase". It implements a Convolutional Neural Net classifier
|
||||
// instance of the base classifier. It uses the Tesseract Neural Net library
|
||||
// The Neural Net takes a scaled version of a bitmap and feeds it to a
|
||||
// Convolutional Neural Net as input and performs a FeedForward. Each output
|
||||
// of the net corresponds to class_id in the CharSet passed at construction
|
||||
// time.
|
||||
// Afterwards, the outputs of the Net are "folded" using the folding set
|
||||
// (if any)
|
||||
#ifndef CONV_NET_CLASSIFIER_H
|
||||
#define CONV_NET_CLASSIFIER_H
|
||||
|
||||
#include <string>
|
||||
#include "char_samp.h"
|
||||
#include "char_altlist.h"
|
||||
#include "char_set.h"
|
||||
#include "feature_base.h"
|
||||
#include "classifier_base.h"
|
||||
#include "neural_net.h"
|
||||
#include "lang_model.h"
|
||||
#include "tuning_params.h"
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
// Folding Ratio is the ratio of the max-activation of members of a folding
|
||||
// set that is used to compute the min-activation of the rest of the set
|
||||
static const float kFoldingRatio = 0.75;
|
||||
|
||||
class ConvNetCharClassifier : public CharClassifier {
|
||||
public:
|
||||
ConvNetCharClassifier(CharSet *char_set, TuningParams *params,
|
||||
FeatureBase *feat_extract);
|
||||
virtual ~ConvNetCharClassifier();
|
||||
// The main training function. Given a sample and a class ID the classifier
|
||||
// updates its parameters according to its learning algorithm. This function
|
||||
// is currently not implemented. TODO(ahmadab): implement end-2-end training
|
||||
virtual bool Train(CharSamp *char_samp, int ClassID);
|
||||
// A secondary function needed for training. Allows the trainer to set the
|
||||
// value of any train-time parameter. This function is currently not
|
||||
// implemented. TODO(ahmadab): implement end-2-end training
|
||||
virtual bool SetLearnParam(char *var_name, float val);
|
||||
// Externally sets the Neural Net used by the classifier. Used for training
|
||||
void SetNet(tesseract::NeuralNet *net);
|
||||
|
||||
// Classifies an input charsamp and return a CharAltList object containing
|
||||
// the possible candidates and corresponding scores
|
||||
virtual CharAltList * Classify(CharSamp *char_samp);
|
||||
// Computes the cost of a specific charsamp being a character (versus a
|
||||
// non-character: part-of-a-character OR more-than-one-character)
|
||||
virtual int CharCost(CharSamp *char_samp);
|
||||
|
||||
|
||||
private:
|
||||
// Neural Net object used for classification
|
||||
tesseract::NeuralNet *char_net_;
|
||||
// data buffers used to hold Neural Net inputs and outputs
|
||||
float *net_input_;
|
||||
float *net_output_;
|
||||
|
||||
// Init the classifier provided a data-path and a language string
|
||||
virtual bool Init(const string &data_file_path, const string &lang,
|
||||
LangModel *lang_mod);
|
||||
// Loads the NeuralNets needed for the classifier
|
||||
bool LoadNets(const string &data_file_path, const string &lang);
|
||||
// Loads the folding sets provided a data-path and a language string
|
||||
virtual bool LoadFoldingSets(const string &data_file_path,
|
||||
const string &lang,
|
||||
LangModel *lang_mod);
|
||||
// Folds the output of the NeuralNet using the loaded folding sets
|
||||
virtual void Fold();
|
||||
// Scales the input char_samp and feeds it to the NeuralNet as input
|
||||
bool RunNets(CharSamp *char_samp);
|
||||
};
|
||||
}
|
||||
#endif // CONV_NET_CLASSIFIER_H
|
@ -1,41 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: const.h
|
||||
* Description: Defintions of constants used by Cube
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef CUBE_CONST_H
|
||||
#define CUBE_CONST_H
|
||||
|
||||
// Scale used to normalize a log-prob to a cost
|
||||
#define PROB2COST_SCALE 4096.0
|
||||
// Maximum possible cost (-log prob of MIN_PROB)
|
||||
#define MIN_PROB_COST 65536
|
||||
// Probability corresponding to the max cost MIN_PROB_COST
|
||||
#define MIN_PROB 0.000000113
|
||||
// Worst possible cost (returned on failure)
|
||||
#define WORST_COST 0x40000
|
||||
// Oversegmentation hysteresis thresholds
|
||||
#define HIST_WND_RATIO 0.1f
|
||||
#define SEG_PT_WND_RATIO 0.1f
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef __GNUC__
|
||||
#include <climits>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // CUBE_CONST_H
|
@ -1,255 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: cube_line_object.cpp
|
||||
* Description: Implementation of the Cube Line Object Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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 <algorithm>
|
||||
#include "cube_line_object.h"
|
||||
|
||||
namespace tesseract {
|
||||
CubeLineObject::CubeLineObject(CubeRecoContext *cntxt, Pix *pix) {
|
||||
line_pix_ = pix;
|
||||
own_pix_ = false;
|
||||
processed_ = false;
|
||||
cntxt_ = cntxt;
|
||||
phrase_cnt_ = 0;
|
||||
phrases_ = NULL;
|
||||
}
|
||||
|
||||
CubeLineObject::~CubeLineObject() {
|
||||
if (line_pix_ != NULL && own_pix_ == true) {
|
||||
pixDestroy(&line_pix_);
|
||||
line_pix_ = NULL;
|
||||
}
|
||||
|
||||
if (phrases_ != NULL) {
|
||||
for (int phrase_idx = 0; phrase_idx < phrase_cnt_; phrase_idx++) {
|
||||
if (phrases_[phrase_idx] != NULL) {
|
||||
delete phrases_[phrase_idx];
|
||||
}
|
||||
}
|
||||
|
||||
delete []phrases_;
|
||||
phrases_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Recognize the specified pix as one line returning the recognized
|
||||
bool CubeLineObject::Process() {
|
||||
// do nothing if pix had already been processed
|
||||
if (processed_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// validate data
|
||||
if (line_pix_ == NULL || cntxt_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// create a CharSamp
|
||||
CharSamp *char_samp = CubeUtils::CharSampleFromPix(line_pix_, 0, 0,
|
||||
line_pix_->w,
|
||||
line_pix_->h);
|
||||
if (char_samp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute connected components.
|
||||
int con_comp_cnt = 0;
|
||||
ConComp **con_comps = char_samp->FindConComps(&con_comp_cnt,
|
||||
cntxt_->Params()->MinConCompSize());
|
||||
// no longer need char_samp, delete it
|
||||
delete char_samp;
|
||||
// no connected components, bail out
|
||||
if (con_comp_cnt <= 0 || con_comps == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sort connected components based on reading order
|
||||
bool rtl = (cntxt_->ReadingOrder() == tesseract::CubeRecoContext::R2L);
|
||||
qsort(con_comps, con_comp_cnt, sizeof(*con_comps), rtl ?
|
||||
ConComp::Right2LeftComparer : ConComp::Left2RightComparer);
|
||||
|
||||
// compute work breaking threshold as a ratio of line height
|
||||
bool ret_val = false;
|
||||
int word_break_threshold = ComputeWordBreakThreshold(con_comp_cnt, con_comps,
|
||||
rtl);
|
||||
if (word_break_threshold > 0) {
|
||||
// over-allocate phrases object buffer
|
||||
phrases_ = new CubeObject *[con_comp_cnt];
|
||||
if (phrases_ != NULL) {
|
||||
// create a phrase if the horizontal distance between two consecutive
|
||||
// concomps is higher than threshold
|
||||
int start_con_idx = 0;
|
||||
int current_phrase_limit = rtl ? con_comps[0]->Left() :
|
||||
con_comps[0]->Right();
|
||||
|
||||
for (int con_idx = 1; con_idx <= con_comp_cnt; con_idx++) {
|
||||
bool create_new_phrase = true;
|
||||
// if not at the end, compute the distance between two consecutive
|
||||
// concomps
|
||||
if (con_idx < con_comp_cnt) {
|
||||
int dist = 0;
|
||||
if (cntxt_->ReadingOrder() == tesseract::CubeRecoContext::R2L) {
|
||||
dist = current_phrase_limit - con_comps[con_idx]->Right();
|
||||
} else {
|
||||
dist = con_comps[con_idx]->Left() - current_phrase_limit;
|
||||
}
|
||||
create_new_phrase = (dist > word_break_threshold);
|
||||
}
|
||||
|
||||
// create a new phrase
|
||||
if (create_new_phrase) {
|
||||
// create a phrase corresponding to a range on components
|
||||
bool left_most;
|
||||
bool right_most;
|
||||
CharSamp *phrase_char_samp =
|
||||
CharSamp::FromConComps(con_comps, start_con_idx,
|
||||
con_idx - start_con_idx, NULL,
|
||||
&left_most, &right_most,
|
||||
line_pix_->h);
|
||||
if (phrase_char_samp == NULL) {
|
||||
break;
|
||||
}
|
||||
phrases_[phrase_cnt_] = new CubeObject(cntxt_, phrase_char_samp);
|
||||
if (phrases_[phrase_cnt_] == NULL) {
|
||||
delete phrase_char_samp;
|
||||
break;
|
||||
}
|
||||
// set the ownership of the charsamp to the cube object
|
||||
phrases_[phrase_cnt_]->SetCharSampOwnership(true);
|
||||
phrase_cnt_++;
|
||||
// advance the starting index to the current index
|
||||
start_con_idx = con_idx;
|
||||
// set the limit of the newly starting phrase (if any)
|
||||
if (con_idx < con_comp_cnt) {
|
||||
current_phrase_limit = rtl ? con_comps[con_idx]->Left() :
|
||||
con_comps[con_idx]->Right();
|
||||
}
|
||||
} else {
|
||||
// update the limit of the current phrase
|
||||
if (cntxt_->ReadingOrder() == tesseract::CubeRecoContext::R2L) {
|
||||
current_phrase_limit = MIN(current_phrase_limit,
|
||||
con_comps[con_idx]->Left());
|
||||
} else {
|
||||
current_phrase_limit = MAX(current_phrase_limit,
|
||||
con_comps[con_idx]->Right());
|
||||
}
|
||||
}
|
||||
}
|
||||
ret_val = true;
|
||||
}
|
||||
}
|
||||
|
||||
// clean-up connected comps
|
||||
for (int con_idx = 0; con_idx < con_comp_cnt; con_idx++) {
|
||||
delete con_comps[con_idx];
|
||||
}
|
||||
delete []con_comps;
|
||||
|
||||
// success
|
||||
processed_ = true;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// Compute the least word breaking threshold that is required to produce a
|
||||
// valid set of phrases. Phrases are validated using the Aspect ratio
|
||||
// constraints specified in the language specific Params object
|
||||
int CubeLineObject::ComputeWordBreakThreshold(int con_comp_cnt,
|
||||
ConComp **con_comps, bool rtl) {
|
||||
// initial estimate of word breaking threshold
|
||||
int word_break_threshold =
|
||||
static_cast<int>(line_pix_->h * cntxt_->Params()->MaxSpaceHeightRatio());
|
||||
bool valid = false;
|
||||
|
||||
// compute the resulting words and validate each's aspect ratio
|
||||
do {
|
||||
// group connected components into words based on breaking threshold
|
||||
int start_con_idx = 0;
|
||||
int current_phrase_limit = (rtl ? con_comps[0]->Left() :
|
||||
con_comps[0]->Right());
|
||||
int min_x = con_comps[0]->Left();
|
||||
int max_x = con_comps[0]->Right();
|
||||
int min_y = con_comps[0]->Top();
|
||||
int max_y = con_comps[0]->Bottom();
|
||||
valid = true;
|
||||
for (int con_idx = 1; con_idx <= con_comp_cnt; con_idx++) {
|
||||
bool create_new_phrase = true;
|
||||
// if not at the end, compute the distance between two consecutive
|
||||
// concomps
|
||||
if (con_idx < con_comp_cnt) {
|
||||
int dist = 0;
|
||||
if (rtl) {
|
||||
dist = current_phrase_limit - con_comps[con_idx]->Right();
|
||||
} else {
|
||||
dist = con_comps[con_idx]->Left() - current_phrase_limit;
|
||||
}
|
||||
create_new_phrase = (dist > word_break_threshold);
|
||||
}
|
||||
|
||||
// create a new phrase
|
||||
if (create_new_phrase) {
|
||||
// check aspect ratio. Break if invalid
|
||||
if ((max_x - min_x + 1) >
|
||||
(cntxt_->Params()->MaxWordAspectRatio() * (max_y - min_y + 1))) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
// advance the starting index to the current index
|
||||
start_con_idx = con_idx;
|
||||
// set the limit of the newly starting phrase (if any)
|
||||
if (con_idx < con_comp_cnt) {
|
||||
current_phrase_limit = rtl ? con_comps[con_idx]->Left() :
|
||||
con_comps[con_idx]->Right();
|
||||
// re-init bounding box
|
||||
min_x = con_comps[con_idx]->Left();
|
||||
max_x = con_comps[con_idx]->Right();
|
||||
min_y = con_comps[con_idx]->Top();
|
||||
max_y = con_comps[con_idx]->Bottom();
|
||||
}
|
||||
} else {
|
||||
// update the limit of the current phrase
|
||||
if (rtl) {
|
||||
current_phrase_limit = MIN(current_phrase_limit,
|
||||
con_comps[con_idx]->Left());
|
||||
} else {
|
||||
current_phrase_limit = MAX(current_phrase_limit,
|
||||
con_comps[con_idx]->Right());
|
||||
}
|
||||
// update bounding box
|
||||
UpdateRange(con_comps[con_idx]->Left(),
|
||||
con_comps[con_idx]->Right(), &min_x, &max_x);
|
||||
UpdateRange(con_comps[con_idx]->Top(),
|
||||
con_comps[con_idx]->Bottom(), &min_y, &max_y);
|
||||
}
|
||||
}
|
||||
|
||||
// return the breaking threshold if all broken word dimensions are valid
|
||||
if (valid) {
|
||||
return word_break_threshold;
|
||||
}
|
||||
|
||||
// decrease the threshold and try again
|
||||
word_break_threshold--;
|
||||
} while (!valid && word_break_threshold > 0);
|
||||
|
||||
// failed to find a threshold that achieves the target aspect ratio.
|
||||
// Just use the default threshold
|
||||
return static_cast<int>(line_pix_->h *
|
||||
cntxt_->Params()->MaxSpaceHeightRatio());
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/**********************************************************************
|
||||
* File: cube_line_object.h
|
||||
* Description: Declaration of the Cube Line Object Class
|
||||
* Author: Ahmad Abdulkader
|
||||
* Created: 2007
|
||||
*
|
||||
* (C) Copyright 2008, 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.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// The CubeLineObject implements an objects that holds a line of text
|
||||
// Each line is broken into phrases. Phrases are blocks within the line that
|
||||
// are unambiguously separate collections of words
|
||||
|
||||
#ifndef CUBE_LINE_OBJECT_H
|
||||
#define CUBE_LINE_OBJECT_H
|
||||
|
||||
#include "cube_reco_context.h"
|
||||
#include "cube_object.h"
|
||||
#include "allheaders.h"
|
||||
|
||||
namespace tesseract {
|
||||
class CubeLineObject {
|
||||
public:
|
||||
CubeLineObject(CubeRecoContext *cntxt, Pix *pix);
|
||||
~CubeLineObject();
|
||||
|
||||
// accessors
|
||||
inline int PhraseCount() {
|
||||
if (!processed_ && !Process()) {
|
||||
return 0;
|
||||
}
|
||||
return phrase_cnt_;
|
||||
}
|
||||
inline CubeObject **Phrases() {
|
||||
if (!processed_ && !Process()) {
|
||||
return NULL;
|
||||
}
|
||||
return phrases_;
|
||||
}
|
||||
|
||||
private:
|
||||
CubeRecoContext *cntxt_;
|
||||
bool own_pix_;
|
||||
bool processed_;
|
||||
Pix *line_pix_;
|
||||
CubeObject **phrases_;
|
||||
int phrase_cnt_;
|
||||
bool Process();
|
||||
// Compute the least word breaking threshold that is required to produce a
|
||||
// valid set of phrases. Phrases are validated using the Aspect ratio
|
||||
// constraints specified in the language specific Params object
|
||||
int ComputeWordBreakThreshold(int con_comp_cnt, ConComp **con_comps,
|
||||
bool rtl);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CUBE_LINE_OBJECT_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user