mirror of
https://github.com/qurator-spk/eynollah.git
synced 2026-08-19 01:02:23 +02:00
Compare commits
No commits in common. "main" and "v0.3.1" have entirely different histories.
211 changed files with 7979 additions and 25388 deletions
|
|
@ -1,10 +0,0 @@
|
|||
tests
|
||||
dist
|
||||
build
|
||||
env*
|
||||
venv*
|
||||
*.egg-info
|
||||
models_eynollah*
|
||||
reloaded
|
||||
*.h5
|
||||
config_files*
|
||||
44
.github/workflows/build-docker.yml
vendored
44
.github/workflows/build-docker.yml
vendored
|
|
@ -1,44 +0,0 @@
|
|||
name: CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
workflow_dispatch: # run manually
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# we need tags for docker version tagging
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
- # Activate cache export feature to reduce build time of images
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERIO_USERNAME }}
|
||||
password: ${{ secrets.DOCKERIO_PASSWORD }}
|
||||
- name: Build the Docker image
|
||||
# build both tags at the same time
|
||||
run: make docker DOCKER_TAG="docker.io/ocrd/eynollah ghcr.io/qurator-spk/eynollah"
|
||||
- name: Test the Docker image
|
||||
run: docker run --rm ocrd/eynollah ocrd-eynollah-segment -h
|
||||
- name: Push to Dockerhub
|
||||
run: docker push docker.io/ocrd/eynollah
|
||||
- name: Push to Github Container Registry
|
||||
run: docker push ghcr.io/qurator-spk/eynollah
|
||||
24
.github/workflows/pypi.yml
vendored
24
.github/workflows/pypi.yml
vendored
|
|
@ -1,24 +0,0 @@
|
|||
name: PyPI CD
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pypi-publish:
|
||||
name: upload release to PyPI
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# IMPORTANT: this permission is mandatory for Trusted Publishing
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
- name: Build package
|
||||
run: make build
|
||||
- name: Publish package distributions to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
verbose: true
|
||||
83
.github/workflows/test-eynollah.yml
vendored
83
.github/workflows/test-eynollah.yml
vendored
|
|
@ -14,90 +14,23 @@ jobs:
|
|||
python-version: ['3.8', '3.9', '3.10', '3.11']
|
||||
|
||||
steps:
|
||||
- name: clean up
|
||||
run: |
|
||||
df -h
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
df -h
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# - name: Lint with ruff
|
||||
# uses: astral-sh/ruff-action@v3
|
||||
# with:
|
||||
# src: "./src"
|
||||
|
||||
- name: Try to restore models_eynollah
|
||||
uses: actions/cache/restore@v4
|
||||
id: all_model_cache
|
||||
- uses: actions/cache@v4
|
||||
id: model_cache
|
||||
with:
|
||||
path: models_eynollah
|
||||
key: models_eynollah-${{ hashFiles('src/eynollah/model_zoo/default_specs.py') }}
|
||||
|
||||
key: ${{ runner.os }}-models
|
||||
- name: Download models
|
||||
if: steps.all_model_cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
make models
|
||||
ls -la models_eynollah
|
||||
|
||||
- uses: actions/cache/save@v4
|
||||
if: steps.all_model_cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: models_eynollah
|
||||
key: models_eynollah-${{ hashFiles('src/eynollah/model_zoo/default_specs.py') }}
|
||||
|
||||
if: steps.model_cache.outputs.cache-hit != 'true'
|
||||
run: make models
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
# - uses: actions/cache@v4
|
||||
# with:
|
||||
# path: |
|
||||
# path/to/dependencies
|
||||
# some/other/dependencies
|
||||
# key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
# preempt CUDA dependencies (which need core's recipe)
|
||||
pip install onnxruntime tensorflow tf-keras "torch<2.11"
|
||||
sed -i '/onnxruntime-gpu/d;/tensorrt/d;/torch/d;/tensorflow/d' requirements*.txt
|
||||
make install-dev EXTRAS=OCR,plotting
|
||||
make deps-test EXTRAS=OCR,plotting
|
||||
|
||||
pip install .
|
||||
pip install -r requirements-test.txt
|
||||
- name: Test with pytest
|
||||
run: make coverage PYTEST_ARGS="-vv --junitxml=pytest.xml"
|
||||
|
||||
- name: Get coverage results
|
||||
run: |
|
||||
coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
|
||||
coverage html
|
||||
coverage json
|
||||
coverage xml
|
||||
|
||||
- name: Store coverage results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-report_${{ matrix.python-version }}
|
||||
path: |
|
||||
htmlcov
|
||||
pytest.xml
|
||||
coverage.xml
|
||||
coverage.json
|
||||
|
||||
- name: Upload coverage results
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: coverage.xml
|
||||
fail_ci_if_error: false
|
||||
|
||||
- name: Test standalone CLI
|
||||
run: make smoke-test
|
||||
|
||||
- name: Test OCR-D CLI
|
||||
run: make ocrd-test
|
||||
run: make test
|
||||
|
|
|
|||
13
.gitignore
vendored
13
.gitignore
vendored
|
|
@ -1,18 +1,7 @@
|
|||
*.egg-info
|
||||
__pycache__
|
||||
sbb_newspapers_org_image/pylint.log
|
||||
default-2021-03-09
|
||||
models_eynollah*
|
||||
output.html
|
||||
/build
|
||||
*.tif
|
||||
*.sw?
|
||||
TAGS
|
||||
uv.lock
|
||||
/dist
|
||||
/ignore
|
||||
*.log
|
||||
.env
|
||||
models/reloaded
|
||||
models/packages
|
||||
models/models_eynollah
|
||||
models/pretrained_model
|
||||
|
|
|
|||
326
CHANGELOG.md
326
CHANGELOG.md
|
|
@ -5,322 +5,6 @@ Versioned according to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
## Unreleased
|
||||
|
||||
## [0.9.2] - 2026-07-28
|
||||
|
||||
Fixed:
|
||||
|
||||
* `return_deskew_slop`: typo caused silent exit for landscape pages, #223, #224, ht @lazyants @SAY-5
|
||||
|
||||
## [0.9.1] - 2026-07-20
|
||||
|
||||
Fixed:
|
||||
|
||||
- Base image version must be >= core 3.13.2 for ONNX base image, OCR-D/core#1365
|
||||
|
||||
## [0.9.0] - 2026-07-20
|
||||
|
||||
Fixed:
|
||||
|
||||
- CLIs for `reorder` and OCR: make work again
|
||||
- more robust predictor/model shutdown
|
||||
- :fire: `do_order_of_regions`: rm overcautious assertion
|
||||
- :fire: correctly order textlines again
|
||||
- make `utils.contours.make_valid()` even more robust
|
||||
- :fire: region-wise deskewing w/o `-cl`: typo when only single usable textline
|
||||
- Keras OCR (`cnn-rnn-ocr`):
|
||||
* `training.models`: correct config names for height and width
|
||||
* `utils_ocr`: rare errors
|
||||
* `run_single()` w/o `overwrite`: skip instead of return
|
||||
- OCR-D layout processor:
|
||||
* :fire: resolve filesystem paths for `models` resource names again
|
||||
* :fire: avoid writing secondary `.xml` into workspace
|
||||
|
||||
Changed:
|
||||
|
||||
- CLIs: remove redundant negative options, add `-h` everywhere, show defaults
|
||||
- move `--device` option to group level, apply to all model types (including Torch/ONNX)
|
||||
- load models w/ `memory_limit` instead of `memory_growth` strategy (faster and less VRAM)
|
||||
- show full stacktrace in case predictor fails (not just exception name)
|
||||
- :fire: default to ONNX inference w/ TensorRT instead of TF (much **faster**, but requires **warmup** phase w/ persistent cache directory `$XDG_CONFIG_HOME`)
|
||||
- :fire: published **new** set of **models**, both for training (TF/Keras) and inference (ONNX) – rebuilt from code changes (see below), *not* retrained
|
||||
- :fire: Docker image now based on `ocrd/core-cuda-onnx` for layout only, no `[OCR]` in Docker ATM
|
||||
- OCR: run pages in **parallel** (as for layout) via forking, add `--halt-fail` and `--num-jobs`, too
|
||||
- improve layout:
|
||||
* for heuristic reading order, do not try to elongate horizontal separators
|
||||
* when column classifier is confident enough, do maximally enlarge the image (for 6 columns or more)
|
||||
- improve TrOCR:
|
||||
* refactor, simplify
|
||||
* batch over entire page (faster)
|
||||
* extract confidence, too
|
||||
* use beam search instead of greedy decoder
|
||||
* load model and preprocessor/tokenizer into one object (no need for distinct models)
|
||||
* no need to resize images in advance
|
||||
* if set, apply `-nmtc` here, too
|
||||
* skip lines lower than `-min_conf` instead of setting empty string
|
||||
- improve Keras OCR:
|
||||
* refactor, simplify
|
||||
* batch over entire page (faster)
|
||||
* use correct confidence estimation
|
||||
* run binarization ad-hoc (if not provided)
|
||||
* adapt to all-in-one inference model
|
||||
* get image size from model (instead of fixed)
|
||||
* apply `-min_conf` here, too
|
||||
* skip lines lower than `-min_conf` instead of setting empty string
|
||||
* separate off `.png` files if `dir_in_bin==dir_in`
|
||||
* batch flipped line candidates together with normal lines
|
||||
- training/setup:
|
||||
* refactor imports from `.models` (single auto-configured `get_model()` call, no `custom_objects` loading)
|
||||
* drop new setting `reload_weights` in favour of `--rebuild` option for new CLI `eynollah-training convert`
|
||||
* new CLI for model conversion between Keras (formats HDF5 / native Keras, TF SavedModel), TF-Serving (i.e. `model.export()`) and ONNX
|
||||
* extract `MusicRegion` from PAGE GT, too
|
||||
- training/models:
|
||||
* ViT models: use Keras `Reshape` layer instead of ad-hoc `tf.reshape`
|
||||
* ViT models: use `tf.map_fn` to iterate over batch in `tf.image.extract_patches` for attention (faster, less VRAM, makes ONNX conversion work)
|
||||
* Keras (CNN-RNN) OCR backend: replace `Conv1D(channels_first)` (not fully supported by TF/CUDNN on CPU) by `Conv1D(channels_last)` w/ `Permute` layers
|
||||
* Keras (CNN-RNN) OCR training→inference conversion: encapsulate CTC decoder and inverse string lookup by model itself (no need for extra models and files, all on GPU), always ensemble RGB and binarized input
|
||||
|
||||
Added:
|
||||
|
||||
- inference backends for TF-Serving and ONNX/TensorRT, differentiate by loaded model type
|
||||
- integrate training for TrOCR (still untested!)
|
||||
- integrate weight ensembling for TrOCR
|
||||
- integrate standalone inference for TrOCR
|
||||
- OCR-D processor: pass on more parameters:
|
||||
- `device` selection
|
||||
- `model_overrides`
|
||||
- `skip_layout_and_reading_order`
|
||||
- `num_col_upper`
|
||||
- `num_col_lower`
|
||||
- `binarize` (for `input_binary`)
|
||||
|
||||
|
||||
## [0.8.0] - 2026-05-11
|
||||
|
||||
* Optimize model performance
|
||||
* `multiprocessing.SpawnProcess` predictor wrapper for models to have commmunication with Tensorflow in a separate subprocess in a task queue with parallel jobs configurable via `--num-jobs` and maximum number of failed jobs via `--halt-fail`
|
||||
* Keep batch size low enough for processing fitting into common 8GB GPU (with model-dependent batch resizing prepared but not yet active)
|
||||
* GPU device can be selected manually with `--device`
|
||||
* Handle image resizing and tiling in GPU as much as possible to avoid overhead of switching between GPU and CPU
|
||||
* jit-compile and precompile models where possible (non-autosized, non-patched Keras models)
|
||||
* Fix bugs and homogenize internal labels related to differing labels for early layout and different stages of full layout detection
|
||||
* Replace `Lambda` layers with `ZeroPadding2D`, improving size and optimizability of models for `eynollah layout`
|
||||
* Improved training
|
||||
* Use connected components for loss function
|
||||
* Integrate with Tensorboard to observe model training progress, including plots and visualizing intermediate evaluation results
|
||||
* Simplified model usage
|
||||
* Models can be overridden individually, so any model trained with `eynollah-training` can replace any model in the [distributions on zenodo](https://zenodo.org/records/17727267)
|
||||
* `--model` is a CLI option of the `eynollah` root CLI now and should point to the same directory for all subcommands
|
||||
* Improved reading order detection heuristics
|
||||
* Improved drop capital, marginalia and column detection
|
||||
* Fixing bugs in polygon handling and image operations
|
||||
* No more self-intersecting polygons
|
||||
* Correct rotation implementation, enlarging/shrinking canvas as necessary
|
||||
* Use actual area of a polygon instead of length of polygon path or first candidate for comparisons
|
||||
* Improved PAGE-XML serialization
|
||||
* Annotate column classifier result in `/PcGts/Page/@custom` (Transkribus convention) and `/PcGts/Metadata/Comment` (QURATOR convention)
|
||||
* Annotate page skew in `/PcGts/Page/@orientation`
|
||||
* Calculate and annotate confidences as `Coords/@conf` for regions, lines, images and tables
|
||||
* Massive refactoring and code quality improvement
|
||||
* deduplication, idiomatic python, clean parallel processing, class reuse, consistent and meaningful naming
|
||||
|
||||
|
||||
**NOTE** We are aware of a possible issue with regards to the cropping of images. It appears that we have not consistenly cropped images for training. This can lead to suboptimal results for cropped images. If you experience quality issues with the `eynollah layout`, try setting the `-ipe/--ignore_page_extraction` option to skip the builtin cropping. We will rectify this in the next trainings.
|
||||
|
||||
## [0.7.0] - 2026-01-30
|
||||
|
||||
Added:
|
||||
|
||||
* "Model zoo", central place to describe and load models, #207
|
||||
* Training code for the CNN/RNN OCR model
|
||||
|
||||
Changed:
|
||||
|
||||
* Lint training code, #204
|
||||
* Update documentation: README, pyproject.toml metadata, guides in `docs/`, #209
|
||||
|
||||
|
||||
## [0.6.0] - 2025-10-17
|
||||
|
||||
Added:
|
||||
|
||||
* `eynollah-training` CLI and docs for training the models, #187, #193, https://github.com/qurator-spk/sbb_pixelwise_segmentation/tree/unifying-training-models
|
||||
|
||||
Fixed:
|
||||
|
||||
* `join_polygons` always returning Polygon, not MultiPolygon, #203
|
||||
|
||||
## [0.6.0rc2] - 2025-10-14
|
||||
|
||||
Fixed:
|
||||
|
||||
* Prevent OOM GPU error by avoiding loading the `region_fl` model, #199
|
||||
* XML output: encoding should be `utf-8`, not `utf8`, #196, #197
|
||||
|
||||
## [0.6.0rc1] - 2025-10-10
|
||||
|
||||
Fixed:
|
||||
|
||||
* continue processing when no columns detected but text regions exist
|
||||
* convert marginalia to main text if no main text is present
|
||||
* reset deskewing angle to 0° when text covers <30% image area and detected angle >45°
|
||||
* :fire: polygons: avoid invalid paths (use `Polygon.buffer()` instead of dilation etc.)
|
||||
* `return_boxes_of_images_by_order_of_reading_new`: avoid Numpy.dtype mismatch, simplify
|
||||
* `return_boxes_of_images_by_order_of_reading_new`: log any exceptions instead of ignoring
|
||||
* `filter_contours_without_textline_inside`: avoid removing from duplicate lists twice
|
||||
* `get_marginals`: exit early if no peaks found to avoid spurious overlap mask
|
||||
* `get_smallest_skew`: after shifting search range of rotation angle, use overall best result
|
||||
* Dockerfile: fix CUDA installation (cuDNN contested between Torch and TF due to extra OCR)
|
||||
* OCR: re-instate missing methods and fix `utils_ocr` function calls
|
||||
* mbreorder/enhancement CLIs: missing imports
|
||||
* :fire: writer: `SeparatorRegion` needs `SeparatorRegionType` (not `ImageRegionType`), f458e3e
|
||||
* tests: switch from `pytest-subtests` to `parametrize` so we can use `pytest-isolate`
|
||||
(so CUDA memory gets freed between tests if running on GPU)
|
||||
|
||||
Added:
|
||||
* :fire: `layout` CLI: new option `--model_version` to override default choices
|
||||
* test coverage for OCR options in `layout`
|
||||
* test coverage for table detection in `layout`
|
||||
* CI linting with ruff
|
||||
|
||||
Changed:
|
||||
|
||||
* polygons: slightly widen for regions and lines, increase for separators
|
||||
* various refactorings, some code style and identifier improvements
|
||||
* deskewing/multiprocessing: switch back to ProcessPoolExecutor (faster),
|
||||
but use shared memory if necessary, and switch back from `loky` to stdlib,
|
||||
and shutdown in `del()` instead of `atexit`
|
||||
* :fire: OCR: switch CNN-RNN model to `20250930` version compatible with TF 2.12 on CPU, too
|
||||
* OCR: allow running `-tr` without `-fl`, too
|
||||
* :fire: writer: use `@type='heading'` instead of `'header'` for headings
|
||||
* :fire: performance gains via refactoring (simplification, less copy-code, vectorization,
|
||||
avoiding unused calculations, avoiding unnecessary 3-channel image operations)
|
||||
* :fire: heuristic reading order detection: many improvements
|
||||
- contour vs splitter box matching:
|
||||
* contour must be contained in box exactly instead of heuristics
|
||||
* make fallback center matching, center must be contained in box
|
||||
- original vs deskewed contour matching:
|
||||
* same min-area filter on both sides
|
||||
* similar area score in addition to center proximity
|
||||
* avoid duplicate and missing mappings by allowing N:M
|
||||
matches and splitting+joining where necessary
|
||||
* CI: update+improve model caching
|
||||
|
||||
|
||||
## [0.5.0] - 2025-09-26
|
||||
|
||||
Fixed:
|
||||
|
||||
* restoring the contour in the original image caused an error due to an empty tuple, #154
|
||||
* removed NumPy warnings calculating sigma, mean, (fixed issue #158)
|
||||
* fixed bug in `separate_lines.py`, #124
|
||||
* Drop capitals are now handled separately from their corresponding textline
|
||||
* Marginals are now divided into left and right. Their reading order is written first for left marginals, then for right marginals, and within each side from top to bottom
|
||||
* Added a new page extraction model. Instead of bounding boxes, it outputs page contours in the XML file, improving results for skewed pages
|
||||
* Improved reading order for cases where a textline is segmented into multiple smaller textlines
|
||||
|
||||
Changed
|
||||
|
||||
* CLIs: read only allowed filename suffixes (image or XML) with `--dir_in`
|
||||
* CLIs: make all output option required, and `-i` / `-di` required but mutually exclusive
|
||||
* ocr CLI: drop redundant `-brb` in favour of just `-dib`
|
||||
* APIs: move all input/output path options from class (kwarg and attribute) ro `run` kwarg
|
||||
* layout textlines: polygonal also without `-cl`
|
||||
|
||||
Added:
|
||||
|
||||
* `eynollah machine-based-reading-order` CLI to run reading order detection, #175
|
||||
* `eynollah enhancement` CLI to run image enhancement, #175
|
||||
* Improved models for page extraction and reading order detection, #175
|
||||
* For the lightweight version (layout and textline detection), thresholds are now assigned to the artificial class. Users can apply these thresholds to improve detection of isolated textlines and regions. To counteract the drawback of thresholding, the skeleton of the artificial class is used to keep lines as thin as possible (resolved issues #163 and #161)
|
||||
* Added and integrated a trained CNN-RNN OCR models
|
||||
* Added and integrated a trained TrOCR model
|
||||
* Improved OCR detection to support vertical and curved textlines
|
||||
* Introduced a new machine-based reading order model with rotation augmentation
|
||||
* Optimized reading order speed by clustering text regions that belong to the same block, maintaining top-to-bottom order
|
||||
* Implemented text merging across textlines based on hyphenation when a line ends with a hyphen
|
||||
* Integrated image enhancement as a separate use case
|
||||
* Added reading order functionality on the layout level as a separate use case
|
||||
* CNN-RNN OCR models provide confidence scores for predictions
|
||||
* Added OCR visualization: predicted OCR can be overlaid on an image of the same size as the input
|
||||
* Introduced a threshold value for CNN-RNN OCR models, allowing users to filter out low-confidence textline predictions
|
||||
* For OCR, users can specify a single model by name instead of always using the default model
|
||||
* Under the OCR use case, if Ground Truth XMLs and images are available, textline image and corresponding text extraction can now be performed
|
||||
|
||||
Merged PRs:
|
||||
|
||||
* better machine based reading order + layout and textline + ocr by @vahidrezanezhad in https://github.com/qurator-spk/eynollah/pull/175
|
||||
* CI: pypi by @kba in https://github.com/qurator-spk/eynollah/pull/154
|
||||
* CI: Use most recent actions/setup-python@v5 by @kba in https://github.com/qurator-spk/eynollah/pull/157
|
||||
* update docker by @bertsky in https://github.com/qurator-spk/eynollah/pull/159
|
||||
* Ocrd fixes by @kba in https://github.com/qurator-spk/eynollah/pull/167
|
||||
* Updating readme for eynollah use cases cli by @kba in https://github.com/qurator-spk/eynollah/pull/166
|
||||
* OCR-D processor: expose reading_order_machine_based by @bertsky in https://github.com/qurator-spk/eynollah/pull/171
|
||||
* prepare release v0.5.0: fix logging by @bertsky in https://github.com/qurator-spk/eynollah/pull/180
|
||||
* mb_ro_on_layout: remove copy-pasta code not actually used by @kba in https://github.com/qurator-spk/eynollah/pull/181
|
||||
* prepare release v0.5.0: improve CLI docstring, refactor I/O path options from class to run kwargs, increase test coverage @bertsky in #182
|
||||
* prepare release v0.5.0: fix for OCR doit subtest by @bertsky in https://github.com/qurator-spk/eynollah/pull/183
|
||||
* Prepare release v0.5.0 by @kba in https://github.com/qurator-spk/eynollah/pull/178
|
||||
* updating eynollah README, how to use it for use cases by @vahidrezanezhad in https://github.com/qurator-spk/eynollah/pull/156
|
||||
* add feedback to command line interface by @michalbubula in https://github.com/qurator-spk/eynollah/pull/170
|
||||
|
||||
## [0.4.0] - 2025-04-07
|
||||
|
||||
Fixed:
|
||||
|
||||
* allow empty imports for optional dependencies
|
||||
* avoid Numpy warnings (empty slices etc.)
|
||||
* remove deprecated Numpy types
|
||||
* binarization CLI: make `dir_in` usable again
|
||||
|
||||
Added:
|
||||
|
||||
* Continuous Deployment via Dockerhub and GHCR
|
||||
* CI: also test CLIs and OCR-D
|
||||
* CI: measure code coverage, annotate+upload reports
|
||||
* smoke-test: also check results
|
||||
* smoke-test: also test sbb-binarize
|
||||
* ocrd-test: analog for OCR-D CLI (segment and binarize)
|
||||
* pytest: add asserts, extend coverage, use subtests for various options
|
||||
* pytest: also add binarization
|
||||
* pytest: add `dir_in` mode (segment and binarize)
|
||||
* make install: control optional dependencies via `EXTRAS` variable
|
||||
* OCR-D: expose and describe recently added parameters:
|
||||
- `ignore_page_extraction`
|
||||
- `allow_enhancement`
|
||||
- `textline_light`
|
||||
- `right_to_left`
|
||||
* OCR-D: :fire: integrate ocrd-sbb-binarize
|
||||
* add detection confidence in `TextRegion/Coords/@conf`
|
||||
(but only in light version and not for marginalia)
|
||||
|
||||
Changed:
|
||||
|
||||
* Docker build: simplify, w/ `OCR`, conform to OCR-D spec
|
||||
* OCR-D: :fire: migrate to core v3
|
||||
- initialize+setup only once
|
||||
- restrict number of parallel page workers to 1
|
||||
(conflicts with existing multiprocessing; TF parts not mp-compatible)
|
||||
- do query maximally annotated page image
|
||||
(but filtering existing binarization/cropping/deskewing),
|
||||
rebase (as new `@imageFilename`) if necessary
|
||||
- add behavioural docstring
|
||||
|
||||
* :fire: refactor `Eynollah` API:
|
||||
- no more data (kw)args at init,
|
||||
but kwargs `dir_in` / `image_filename` for `run()`
|
||||
- no more data attributes, but function kwargs
|
||||
(`pcgts`, `image_filename`, `image_pil`, `dir_in`, `override_dpi`)
|
||||
- remove redundant TF session/model loaders
|
||||
(only load once during init)
|
||||
- factor `run_single()` out of `run()` (loop body),
|
||||
expose for independent calls (like OCR-D)
|
||||
- expose `cache_images()`, add `dpi` kwarg, set `self._imgs`
|
||||
- single-image mode writes PAGE file result
|
||||
(just as directory mode does)
|
||||
|
||||
* CLI: assertions (instead of print+exit) for options checks
|
||||
* light mode: fine-tune ratio to better detect a region as header
|
||||
|
||||
## [0.3.1] - 2024-08-27
|
||||
|
||||
Fixed:
|
||||
|
|
@ -441,16 +125,6 @@ Fixed:
|
|||
Initial release
|
||||
|
||||
<!-- link-labels -->
|
||||
[0.9.2]: ../../compare/v0.9.2...v0.9.1
|
||||
[0.9.1]: ../../compare/v0.9.1...v0.9.0
|
||||
[0.9.0]: ../../compare/v0.9.0...v0.8.0
|
||||
[0.8.0]: ../../compare/v0.8.0...v0.7.0
|
||||
[0.7.0]: ../../compare/v0.7.0...v0.6.0
|
||||
[0.6.0]: ../../compare/v0.6.0...v0.6.0rc2
|
||||
[0.6.0rc2]: ../../compare/v0.6.0rc2...v0.6.0rc1
|
||||
[0.6.0rc1]: ../../compare/v0.6.0rc1...v0.5.0
|
||||
[0.5.0]: ../../compare/v0.5.0...v0.4.0
|
||||
[0.4.0]: ../../compare/v0.4.0...v0.3.1
|
||||
[0.3.1]: ../../compare/v0.3.1...v0.3.0
|
||||
[0.3.0]: ../../compare/v0.3.0...v0.2.0
|
||||
[0.2.0]: ../../compare/v0.2.0...v0.1.0
|
||||
|
|
|
|||
50
Dockerfile
50
Dockerfile
|
|
@ -1,50 +0,0 @@
|
|||
ARG DOCKER_BASE_IMAGE
|
||||
FROM $DOCKER_BASE_IMAGE
|
||||
|
||||
ARG VCS_REF
|
||||
ARG BUILD_DATE
|
||||
LABEL \
|
||||
maintainer="https://ocr-d.de/en/contact" \
|
||||
org.label-schema.vcs-ref=$VCS_REF \
|
||||
org.label-schema.vcs-url="https://github.com/qurator-spk/eynollah" \
|
||||
org.label-schema.build-date=$BUILD_DATE \
|
||||
org.opencontainers.image.vendor="DFG-Funded Initiative for Optical Character Recognition Development" \
|
||||
org.opencontainers.image.title="Eynollah" \
|
||||
org.opencontainers.image.description="" \
|
||||
org.opencontainers.image.source="https://github.com/qurator-spk/eynollah" \
|
||||
org.opencontainers.image.documentation="https://github.com/qurator-spk/eynollah/blob/${VCS_REF}/README.md" \
|
||||
org.opencontainers.image.revision=$VCS_REF \
|
||||
org.opencontainers.image.created=$BUILD_DATE \
|
||||
org.opencontainers.image.base.name=ocrd/core-cuda-onnx
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
# set proper locales
|
||||
ENV PYTHONIOENCODING=utf8
|
||||
ENV LANG=C.UTF-8
|
||||
ENV LC_ALL=C.UTF-8
|
||||
|
||||
# avoid HOME/.local/share (hard to predict USER here)
|
||||
# so let XDG_DATA_HOME coincide with fixed system location
|
||||
# (can still be overridden by derived stages)
|
||||
ENV XDG_DATA_HOME /usr/local/share
|
||||
# avoid the need for an extra volume for persistent resource user db
|
||||
# (i.e. XDG_CONFIG_HOME/ocrd/resources.yml)
|
||||
ENV XDG_CONFIG_HOME /usr/local/share/ocrd-resources
|
||||
|
||||
WORKDIR /build/eynollah
|
||||
COPY . .
|
||||
COPY ocrd-tool.json .
|
||||
# prepackage ocrd-tool.json as ocrd-all-tool.json
|
||||
RUN ocrd ocrd-tool ocrd-tool.json dump-tools > $(dirname $(ocrd bashlib filename))/ocrd-all-tool.json
|
||||
# prepackage ocrd-all-module-dir.json
|
||||
RUN ocrd ocrd-tool ocrd-tool.json dump-module-dirs > $(dirname $(ocrd bashlib filename))/ocrd-all-module-dir.json
|
||||
# install everything and reduce image size
|
||||
# FIXME: EXTRAS=OCR (should become extra Dockerfile based on ocrd/core-cuda-tf2 and ocrd/core-cuda-torch)
|
||||
RUN make install && rm -rf /build/eynollah
|
||||
# fixup for broken cuDNN installation (Torch may pull in version which is incompatible with Tensorflow)
|
||||
RUN pip install "nvidia-cudnn-cu12<9.10.2.21"
|
||||
# smoke test
|
||||
RUN eynollah --help
|
||||
|
||||
WORKDIR /data
|
||||
VOLUME /data
|
||||
132
Makefile
132
Makefile
|
|
@ -1,24 +1,5 @@
|
|||
PYTHON ?= python3
|
||||
PIP ?= pip3
|
||||
EXTRAS ?=
|
||||
|
||||
DOCKER_BASE_IMAGE ?= docker.io/ocrd/core-cuda-onnx:v3.13.2
|
||||
DOCKER_TAG ?= ocrd/eynollah
|
||||
DOCKER ?= docker
|
||||
WGET = wget -O
|
||||
|
||||
#SEG_MODEL := https://qurator-data.de/eynollah/2021-04-25/models_eynollah.tar.gz
|
||||
#SEG_MODEL := https://qurator-data.de/eynollah/2022-04-05/models_eynollah_renamed.tar.gz
|
||||
# SEG_MODEL := https://qurator-data.de/eynollah/2022-04-05/models_eynollah.tar.gz
|
||||
#SEG_MODEL := https://github.com/qurator-spk/eynollah/releases/download/v0.3.0/models_eynollah.tar.gz
|
||||
#SEG_MODEL := https://github.com/qurator-spk/eynollah/releases/download/v0.3.1/models_eynollah.tar.gz
|
||||
#SEG_MODEL := https://zenodo.org/records/17194824/files/models_layout_v0_5_0.tar.gz?download=1
|
||||
# EYNOLLAH_MODELS_URL := https://zenodo.org/records/21362927/files/models_inference_all_v0_9_0.zip
|
||||
EYNOLLAH_MODELS_URL := https://zenodo.org/records/21381102/files/models_inference_all_v0_9_1.zip
|
||||
EYNOLLAH_MODELS_ZIP = $(notdir $(EYNOLLAH_MODELS_URL))
|
||||
EYNOLLAH_MODELS_DIR = $(EYNOLLAH_MODELS_ZIP:%.zip=%)
|
||||
|
||||
PYTEST_ARGS ?= -vv --isolate
|
||||
EYNOLLAH_MODELS ?= $(PWD)/models_eynollah
|
||||
export EYNOLLAH_MODELS
|
||||
|
||||
# BEGIN-EVAL makefile-parser --make-help Makefile
|
||||
|
||||
|
|
@ -26,113 +7,44 @@ help:
|
|||
@echo ""
|
||||
@echo " Targets"
|
||||
@echo ""
|
||||
@echo " docker Build Docker image"
|
||||
@echo " build Build Python source and binary distribution"
|
||||
@echo " install Install package with pip"
|
||||
@echo " models Download and extract models to $(PWD)/models_eynollah"
|
||||
@echo " install Install with pip"
|
||||
@echo " install-dev Install editable with pip"
|
||||
@echo " deps-test Install test dependencies with pip"
|
||||
@echo " models Download and extract models to $(CURDIR):"
|
||||
@echo " $(EYNOLLAH_MODELS_DIR)"
|
||||
@echo " smoke-test Run simple CLI check"
|
||||
@echo " ocrd-test Run OCR-D CLI check"
|
||||
@echo " test Run unit tests"
|
||||
@echo ""
|
||||
@echo " Variables"
|
||||
@echo " EXTRAS comma-separated list of features (like 'OCR,plotting') for 'install' [$(EXTRAS)]"
|
||||
@echo " DOCKER_TAG Docker image tag for 'docker' [$(DOCKER_TAG)]"
|
||||
@echo " PYTEST_ARGS pytest args for 'test' (Set to '-s' to see log output during test execution, '-vv' to see individual tests. [$(PYTEST_ARGS)]"
|
||||
@echo " ALL_MODELS URL of archive of all models [$(ALL_MODELS)]"
|
||||
@echo ""
|
||||
|
||||
# END-EVAL
|
||||
|
||||
# Download and extract models to $(PWD)/models_layout_v0_6_0
|
||||
models: $(EYNOLLAH_MODELS_DIR)
|
||||
|
||||
# do not download these files if we already have the directories
|
||||
.INTERMEDIATE: $(EYNOLLAH_MODELS_ZIP)
|
||||
# Download and extract models to $(PWD)/models_eynollah
|
||||
models: models_eynollah
|
||||
|
||||
$(EYNOLLAH_MODELS_ZIP):
|
||||
$(WGET) $@ $(EYNOLLAH_MODELS_URL)
|
||||
models_eynollah: models_eynollah.tar.gz
|
||||
# tar xf models_eynollah_renamed.tar.gz --transform 's/models_eynollah_renamed/models_eynollah/'
|
||||
# tar xf models_eynollah_renamed.tar.gz
|
||||
# tar xf models_eynollah_renamed_savedmodel.tar.gz --transform 's/models_eynollah_renamed_savedmodel/models_eynollah/'
|
||||
tar xf models_eynollah.tar.gz
|
||||
|
||||
$(EYNOLLAH_MODELS_DIR): $(EYNOLLAH_MODELS_ZIP)
|
||||
unzip $<
|
||||
|
||||
build:
|
||||
$(PIP) install build
|
||||
$(PYTHON) -m build .
|
||||
models_eynollah.tar.gz:
|
||||
# wget 'https://qurator-data.de/eynollah/2021-04-25/models_eynollah.tar.gz'
|
||||
# wget 'https://qurator-data.de/eynollah/2022-04-05/models_eynollah_renamed.tar.gz'
|
||||
# wget 'https://ocr-d.kba.cloud/2022-04-05.SavedModel.tar.gz'
|
||||
# wget 'https://qurator-data.de/eynollah/2022-04-05/models_eynollah_renamed_savedmodel.tar.gz'
|
||||
wget https://github.com/qurator-spk/eynollah/releases/download/v0.3.0/models_eynollah.tar.gz
|
||||
|
||||
# Install with pip
|
||||
install:
|
||||
$(PIP) install .$(and $(EXTRAS),[$(EXTRAS)])
|
||||
pip install .
|
||||
|
||||
# Install editable with pip
|
||||
install-dev:
|
||||
$(PIP) install -e .$(and $(EXTRAS),[$(EXTRAS)])
|
||||
pip install -e .
|
||||
|
||||
deps-test:
|
||||
$(PIP) install -r requirements-test.txt
|
||||
|
||||
smoke-test: TMPDIR != mktemp -d
|
||||
smoke-test: tests/resources/2files/kant_aufklaerung_1784_0020.tif
|
||||
# layout analysis:
|
||||
eynollah -m $(CURDIR) layout -i $< -o $(TMPDIR)
|
||||
fgrep -q http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15 $(TMPDIR)/$(basename $(<F)).xml
|
||||
fgrep -c -e TextRegion -e ImageRegion -e SeparatorRegion $(TMPDIR)/$(basename $(<F)).xml
|
||||
# layout, directory mode (skip one, add one):
|
||||
eynollah -m $(CURDIR) layout -di $(<D) -o $(TMPDIR)
|
||||
test -s $(TMPDIR)/euler_rechenkunst01_1738_0025.xml
|
||||
# mbreorder, directory mode (overwrite):
|
||||
eynollah -m $(CURDIR) machine-based-reading-order -di $(<D) -o $(TMPDIR)
|
||||
fgrep -q http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15 $(TMPDIR)/$(basename $(<F)).xml
|
||||
fgrep -c -e RegionRefIndexed $(TMPDIR)/$(basename $(<F)).xml
|
||||
# binarize:
|
||||
eynollah -m $(CURDIR) binarization -i $< -o $(TMPDIR)/$(<F)
|
||||
test -s $(TMPDIR)/$(<F)
|
||||
@set -x; test "$$(identify -format '%w %h' $<)" = "$$(identify -format '%w %h' $(TMPDIR)/$(<F))"
|
||||
# enhance:
|
||||
eynollah -m $(CURDIR) enhancement -sos -i $< -o $(TMPDIR) -O
|
||||
test -s $(TMPDIR)/$(<F)
|
||||
@set -x; test "$$(identify -format '%w %h' $<)" = "$$(identify -format '%w %h' $(TMPDIR)/$(<F))"
|
||||
$(RM) -r $(TMPDIR)
|
||||
|
||||
ocrd-test: export OCRD_MISSING_OUTPUT := ABORT
|
||||
ocrd-test: TMPDIR != mktemp -d
|
||||
ocrd-test: tests/resources/2files/kant_aufklaerung_1784_0020.tif
|
||||
cp $< $(TMPDIR)
|
||||
ocrd workspace -d $(TMPDIR) init
|
||||
ocrd workspace -d $(TMPDIR) add -G OCR-D-IMG -g PHYS_0020 -i OCR-D-IMG_0020 $(<F)
|
||||
ocrd-eynollah-segment -w $(TMPDIR) -I OCR-D-IMG -O OCR-D-SEG -P models $(CURDIR)
|
||||
result=$$(ocrd workspace -d $(TMPDIR) find -G OCR-D-SEG); \
|
||||
fgrep -q http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15 $(TMPDIR)/$$result && \
|
||||
fgrep -c -e TextRegion -e ImageRegion -e SeparatorRegion $(TMPDIR)/$$result
|
||||
ocrd-sbb-binarize -w $(TMPDIR) -I OCR-D-IMG -O OCR-D-BIN -P model $(CURDIR)
|
||||
ocrd-sbb-binarize -w $(TMPDIR) -I OCR-D-SEG -O OCR-D-SEG-BIN -P model $(CURDIR) -P operation_level region
|
||||
$(RM) -r $(TMPDIR)
|
||||
smoke-test:
|
||||
eynollah -i tests/resources/kant_aufklaerung_1784_0020.tif -o . -m $(PWD)/models_eynollah
|
||||
|
||||
# Run unit tests
|
||||
test: export EYNOLLAH_MODELS_DIR := $(CURDIR)
|
||||
test:
|
||||
$(PYTHON) -m pytest tests --durations=0 --continue-on-collection-errors $(PYTEST_ARGS)
|
||||
|
||||
coverage:
|
||||
coverage erase
|
||||
$(MAKE) test PYTHON="coverage run"
|
||||
coverage report -m
|
||||
|
||||
# Concatenate docker image names with either the git tag describing current commit or 'latest' and
|
||||
# merge list with "-t"
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
GIT_TAG := $(strip $(shell git describe --tags | grep -x "v[0-9]\+\.[0-9]\+\.[0-9]\+"))
|
||||
DOCKER_TAGS = $(subst $(space),$(space)-t$(space),$(DOCKER_TAG:%=$(if $(GIT_TAG),%:$(GIT_TAG),%:latest)))
|
||||
|
||||
# Build docker image
|
||||
docker:
|
||||
$(DOCKER) build \
|
||||
--build-arg DOCKER_BASE_IMAGE=$(DOCKER_BASE_IMAGE) \
|
||||
--build-arg VCS_REF=$$(git rev-parse --short HEAD) \
|
||||
--build-arg BUILD_DATE=$$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
|
||||
-t $(DOCKER_TAGS) .
|
||||
|
||||
.PHONY: models build install install-dev test smoke-test ocrd-test coverage docker help
|
||||
pytest tests
|
||||
|
|
|
|||
226
README.md
226
README.md
|
|
@ -1,36 +1,29 @@
|
|||
# Eynollah
|
||||
> Document Layout Analysis with Deep Learning and Heuristics
|
||||
|
||||
> Document Layout Analysis, Binarization and OCR with Deep Learning and Heuristics
|
||||
|
||||
[](https://pypi.python.org/pypi/eynollah)
|
||||
[](https://pypi.org/project/eynollah/)
|
||||
[](https://github.com/qurator-spk/eynollah/actions/workflows/test-eynollah.yml)
|
||||
[](https://github.com/qurator-spk/eynollah/actions/workflows/build-docker.yml)
|
||||
[](https://opensource.org/license/apache-2-0/)
|
||||
[](https://opensource.org/license/apache-2-0/)
|
||||
[](https://doi.org/10.1145/3604951.3605513)
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
* Document layout analysis using pixelwise segmentation models with support for 10 segmentation classes:
|
||||
* Support for up to 10 segmentation classes:
|
||||
* background, [page border](https://ocr-d.de/en/gt-guidelines/trans/lyRand.html), [text region](https://ocr-d.de/en/gt-guidelines/trans/lytextregion.html#textregionen__textregion_), [text line](https://ocr-d.de/en/gt-guidelines/pagexml/pagecontent_xsd_Complex_Type_pc_TextLineType.html), [header](https://ocr-d.de/en/gt-guidelines/trans/lyUeberschrift.html), [image](https://ocr-d.de/en/gt-guidelines/trans/lyBildbereiche.html), [separator](https://ocr-d.de/en/gt-guidelines/trans/lySeparatoren.html), [marginalia](https://ocr-d.de/en/gt-guidelines/trans/lyMarginalie.html), [initial](https://ocr-d.de/en/gt-guidelines/trans/lyInitiale.html), [table](https://ocr-d.de/en/gt-guidelines/trans/lyTabellen.html)
|
||||
* Textline segmentation to bounding boxes or polygons (contours) including for curved lines and vertical text
|
||||
* Document image binarization with pixelwise segmentation or hybrid CNN-Transformer models
|
||||
* Text recognition (OCR) with CNN-RNN or TrOCR models
|
||||
* Detection of reading order (left-to-right or right-to-left) using heuristics or trainable models
|
||||
* Support for various image optimization operations:
|
||||
* cropping (border detection), binarization, deskewing, dewarping, scaling, enhancing, resizing
|
||||
* Text line segmentation to bounding boxes or polygons (contours) including for curved lines and vertical text
|
||||
* Detection of reading order (left-to-right or right-to-left)
|
||||
* Output in [PAGE-XML](https://github.com/PRImA-Research-Lab/PAGE-XML)
|
||||
* [OCR-D](https://github.com/qurator-spk/eynollah#use-as-ocr-d-processor) interface
|
||||
|
||||
:warning: Development is focused on achieving the best quality of results for a wide variety of historical
|
||||
documents using a combination of multiple deep learning models and heuristics; therefore processing can be slow.
|
||||
:warning: Development is currently focused on achieving the best possible quality of results for a wide variety of historical documents and therefore processing can be very slow. We aim to improve this, but contributions are welcome.
|
||||
|
||||
## Installation
|
||||
Python `3.8-3.11` with Tensorflow `2.12-2.15` on Linux are currently supported.
|
||||
|
||||
Python `3.8-3.11` with ONNX Runtime on Linux are currently supported.
|
||||
|
||||
For GPU support, NVidia drivers supporting CUDA 12 must be installed.
|
||||
The runtime dependencies will pull in ONNX, TensorRT and CUDA runtime
|
||||
libraries (including cuDNN) from PyPI.
|
||||
For (limited) GPU support the CUDA toolkit needs to be installed.
|
||||
|
||||
You can either install from PyPI
|
||||
|
||||
|
|
@ -47,192 +40,71 @@ cd eynollah; pip install -e .
|
|||
|
||||
Alternatively, you can run `make install` or `make install-dev` for editable installation.
|
||||
|
||||
To also install the dependencies for the OCR engines:
|
||||
|
||||
```
|
||||
pip install "eynollah[OCR]"
|
||||
# or
|
||||
make install EXTRAS=OCR
|
||||
```
|
||||
|
||||
> **Note**: Requirements for OCR are more involved,
|
||||
> as they may need Tensorflow (with tf-keras) and/or
|
||||
> Torch (with transformers). Those two frameworks may
|
||||
> also have conflicting CUDA dependencies. An ONNX
|
||||
> conversion for these models may be achieved soon.
|
||||
> :construction:
|
||||
|
||||
### Docker
|
||||
|
||||
Use
|
||||
|
||||
```
|
||||
docker pull ghcr.io/qurator-spk/eynollah:latest
|
||||
```
|
||||
|
||||
When using Eynollah with Docker, see [`docker.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/docker.md).
|
||||
|
||||
## Models
|
||||
Pre-trained models can be downloaded from [qurator-data.de](https://qurator-data.de/eynollah/) or [huggingface](https://huggingface.co/SBB?search_models=eynollah).
|
||||
|
||||
Pretrained models can be downloaded from [Zenodo](https://doi.org/10.5281/zenodo.17194823) or [Hugging Face](https://huggingface.co/SBB?search_models=eynollah).
|
||||
|
||||
For fast runtime inference, download the ONNX models distributed as `models_inference_...zip`.
|
||||
|
||||
For finetuning training, download the original (Tensorflow / Torch) models distributed as `models_training...zip`
|
||||
(and install the `[training]` extra).
|
||||
|
||||
For model documentation and model cards, see [`models.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/models.md).
|
||||
|
||||
## Training
|
||||
|
||||
To train your own model with Eynollah, see [`train.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/train.md) and use the tools in the [`train`](https://github.com/qurator-spk/eynollah/tree/main/train) folder.
|
||||
## Train
|
||||
🚧 **Work in progress**
|
||||
|
||||
In case you want to train your own model, have a look at [`sbb_pixelwise_segmentation`](https://github.com/qurator-spk/sbb_pixelwise_segmentation).
|
||||
|
||||
## Usage
|
||||
|
||||
Eynollah supports five use cases:
|
||||
1. [layout analysis (segmentation)](#layout-analysis),
|
||||
2. [binarization](#binarization),
|
||||
3. [image enhancement](#image-enhancement),
|
||||
4. [text recognition (OCR)](#ocr), and
|
||||
5. [reading order detection](#reading-order-detection).
|
||||
|
||||
Some example outputs can be found in [`examples.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/examples.md).
|
||||
|
||||
The **generic options** shared by all subcommands are:
|
||||
```sh
|
||||
-m <directory containing model files>
|
||||
-mv <model category> <model variant> <model path>
|
||||
-D <device specifier>
|
||||
-l <log level>
|
||||
```
|
||||
|
||||
### Layout Analysis
|
||||
|
||||
Detects layout elements, i.e. regions of various types and text lines,
|
||||
and determines their reading order using either heuristic methods or a
|
||||
[pretrained model](https://github.com/qurator-spk/eynollah#machine-based-reading-order).
|
||||
|
||||
The command-line interface for layout analysis can be called like this:
|
||||
The command-line interface can be called like this:
|
||||
|
||||
```sh
|
||||
eynollah [GENERIC_OPTIONS] layout \
|
||||
eynollah \
|
||||
-i <single image file> | -di <directory containing image files> \
|
||||
-o <output directory> \
|
||||
-m <directory containing model files> \
|
||||
[OPTIONS]
|
||||
```
|
||||
|
||||
The following options can be used to further configure the processing:
|
||||
|
||||
| option | description |
|
||||
|-------------------|:--------------------------------------------------------------------------------------------|
|
||||
| `-fl` | full layout analysis including all steps and segmentation classes (recommended) |
|
||||
| `-tab` | apply table detection |
|
||||
| `-ae` | apply enhancement (the resulting image is saved to the output directory) |
|
||||
| `-as` | apply scaling |
|
||||
| `-cl` | apply contour detection for curved text lines, deskewing all regions independently |
|
||||
| `-ib` | apply binarization (the resulting image is saved to the output directory) |
|
||||
| `-ep` | enable plotting (MUST always be used with `-sl`, `-sd`, `-sa`, `-si` or `-ae`) |
|
||||
| `-ho` | ignore headers for reading order dectection |
|
||||
| `-si <directory>` | save image regions detected to this directory |
|
||||
| `-sd <directory>` | save deskewed image to this directory |
|
||||
| `-sl <directory>` | save layout prediction as plot to this directory |
|
||||
| `-sp <directory>` | save cropped page image to this directory |
|
||||
| `-sa <directory>` | save all (plot, enhanced/binary image, layout) to this directory |
|
||||
| `-thart` | confidence threshold of artifical boundary class during textline detection |
|
||||
| `-tharl` | confidence threshold of artifical boundary class during region detection |
|
||||
| `-ncu` | upper limit of columns in document image |
|
||||
| `-ncl` | lower limit of columns in document image |
|
||||
| `-slro` | skip layout detection and reading order |
|
||||
| `-romb` | apply machine based reading order detection |
|
||||
| `-ipe` | ignore page extraction |
|
||||
| `-j` | number of CPU jobs to run parallel (useful with -di) |
|
||||
| `-H` | when to halt when some jobs fail |
|
||||
| option | description |
|
||||
|-------------------|:-------------------------------------------------------------------------------|
|
||||
| `-fl` | full layout analysis including all steps and segmentation classes |
|
||||
| `-light` | lighter and faster but simpler method for main region detection and deskewing |
|
||||
| `-tab` | apply table detection |
|
||||
| `-ae` | apply enhancement (the resulting image is saved to the output directory) |
|
||||
| `-as` | apply scaling |
|
||||
| `-cl` | apply contour detection for curved text lines instead of bounding boxes |
|
||||
| `-ib` | apply binarization (the resulting image is saved to the output directory) |
|
||||
| `-ep` | enable plotting (MUST always be used with `-sl`, `-sd`, `-sa`, `-si` or `-ae`) |
|
||||
| `-ho` | ignore headers for reading order dectection |
|
||||
| `-si <directory>` | save image regions detected to this directory |
|
||||
| `-sd <directory>` | save deskewed image to this directory |
|
||||
| `-sl <directory>` | save layout prediction as plot to this directory |
|
||||
| `-sp <directory>` | save cropped page image to this directory |
|
||||
| `-sa <directory>` | save all (plot, enhanced/binary image, layout) to this directory |
|
||||
|
||||
The default is to only perform layout detection of main regions
|
||||
(background, text, images, separators and marginals).
|
||||
If no option is set, the tool performs layout detection of main regions (background, text, images, separators and marginals).
|
||||
The best output quality is produced when RGB images are used as input rather than greyscale or binarized images.
|
||||
|
||||
The best output quality is achieved when RGB images are used as input
|
||||
rather than greyscale or binarized images.
|
||||
#### Use as OCR-D processor
|
||||
🚧 **Work in progress**
|
||||
|
||||
Additional documentation can be found in
|
||||
[`usage.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/usage.md).
|
||||
Eynollah ships with a CLI interface to be used as [OCR-D](https://ocr-d.de) processor.
|
||||
|
||||
### Binarization
|
||||
In this case, the source image file group with (preferably) RGB images should be used as input like this:
|
||||
|
||||
Performs document image binarization (thresholding)
|
||||
using pretrained pixelwise segmentation models.
|
||||
|
||||
The command-line interface for binarization can be called like this:
|
||||
|
||||
```sh
|
||||
eynollah [GENERIC_OPTIONS] binarization \
|
||||
-i <single image file> | -di <directory containing image files> \
|
||||
-o <output directory> \
|
||||
[OPTIONS]
|
||||
```
|
||||
|
||||
### Image Enhancement
|
||||
|
||||
This enlarges and enhances images. Useful in case the scan quality is low.
|
||||
|
||||
```sh
|
||||
eynollah [GENERIC_OPTIONS] enhancement \
|
||||
-i <single image file> | -di <directory containing image files> \
|
||||
-o <output directory> \
|
||||
[OPTIONS]
|
||||
ocrd-eynollah-segment -I OCR-D-IMG -O SEG-LINE -P models
|
||||
```
|
||||
|
||||
Any image referenced by `@imageFilename` in PAGE-XML is passed on directly to Eynollah as a processor, so that e.g.
|
||||
|
||||
| option | description |
|
||||
|-------------------|:--------------------------------------------------------------------------------------------|
|
||||
| `-sos` | save the enhanced image in original image size |
|
||||
| `-ncu` | upper limit of columns in document image |
|
||||
| `-ncl` | lower limit of columns in document image |
|
||||
|
||||
### OCR
|
||||
|
||||
Performs text recognition using either a CNN-RNN model or a Transformer model.
|
||||
Needs a PAGE-XML input file.
|
||||
|
||||
The command-line interface for OCR can be called like this:
|
||||
|
||||
```sh
|
||||
eynollah [GENERIC_OPTIONS] ocr \
|
||||
-i <single image file> | -di <directory containing image files> \
|
||||
-dx <directory of xmls> \
|
||||
-o <output directory> \
|
||||
```
|
||||
|
||||
The following options can be used to further configure the ocr processing:
|
||||
|
||||
| option | description |
|
||||
|-------------------|:-------------------------------------------------------------------------------------------|
|
||||
| `-trocr` | use transformer OCR model instead of CNN-RNN model |
|
||||
| `-dib` | directory of binarized images (file type must be '.png'), prediction with both RGB and bin |
|
||||
| `-doit` | directory for output images rendered with the predicted text |
|
||||
| `-nmtc` | cropped textline images will not be masked with textline contour |
|
||||
| `-bs` | ocr inference batch size. Default batch size is 2 for trocr and 8 for cnn_rnn models |
|
||||
| `-min_conf` | minimum OCR confidence value. OCR with textline conf lower than this will be ignored |
|
||||
|
||||
|
||||
### Reading Order Detection
|
||||
|
||||
Reading order can be detected either during layout analysis,
|
||||
or as a separate module, which requires a PAGE-XML input file.
|
||||
|
||||
The command-line interface for machine based reading order can be called like this:
|
||||
|
||||
```sh
|
||||
eynollah [GENERIC_OPTIONS] machine-based-reading-order \
|
||||
-i <single image file> | -di <directory containing image files> \
|
||||
-xml <xml file name> | -dx <directory containing xml files> \
|
||||
-o <output directory>
|
||||
ocrd-eynollah-segment -I OCR-D-IMG-BIN -O SEG-LINE -P models
|
||||
```
|
||||
|
||||
uses the original (RGB) image despite any binarization that may have occured in previous OCR-D processing steps
|
||||
|
||||
## Use as OCR-D processor
|
||||
|
||||
See [`ocrd.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/ocrd.md).
|
||||
#### Additional documentation
|
||||
Please check the [wiki](https://github.com/qurator-spk/eynollah/wiki).
|
||||
|
||||
## How to cite
|
||||
If you find this tool useful in your work, please consider citing our paper:
|
||||
|
||||
```bibtex
|
||||
@inproceedings{hip23rezanezhad,
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
## Inference with Docker
|
||||
|
||||
docker pull ghcr.io/qurator-spk/eynollah:latest
|
||||
|
||||
### 1. ocrd resource manager
|
||||
(just once, to get the models and install them into a named volume for later re-use)
|
||||
|
||||
vol_models=ocrd-resources:/usr/local/share/ocrd-resources
|
||||
docker run --rm -v $vol_models ocrd/eynollah ocrd resmgr download ocrd-eynollah-segment default
|
||||
|
||||
Now, each time you want to use Eynollah, pass the same resources volume again.
|
||||
Also, bind-mount some data directory, e.g. current working directory $PWD (/data is default working directory in the container).
|
||||
|
||||
Either use standalone CLI (2) or OCR-D CLI (3):
|
||||
|
||||
### 2. standalone CLI
|
||||
(follow self-help, cf. readme)
|
||||
|
||||
docker run --rm -v $vol_models -v $PWD:/data ocrd/eynollah eynollah binarization --help
|
||||
docker run --rm -v $vol_models -v $PWD:/data ocrd/eynollah eynollah layout --help
|
||||
docker run --rm -v $vol_models -v $PWD:/data ocrd/eynollah eynollah ocr --help
|
||||
|
||||
### 3. OCR-D CLI
|
||||
(follow self-help, cf. readme and https://ocr-d.de/en/spec/cli)
|
||||
|
||||
docker run --rm -v $vol_models -v $PWD:/data ocrd/eynollah ocrd-eynollah-segment -h
|
||||
docker run --rm -v $vol_models -v $PWD:/data ocrd/eynollah ocrd-sbb-binarize -h
|
||||
|
||||
Alternatively, just "log in" to the container once and use the commands there:
|
||||
|
||||
docker run --rm -v $vol_models -v $PWD:/data -it ocrd/eynollah bash
|
||||
|
||||
## Training with Docker
|
||||
|
||||
Build the Docker training image
|
||||
|
||||
cd train
|
||||
docker build -t model-training .
|
||||
|
||||
Run the Docker training image
|
||||
|
||||
cd train
|
||||
docker run --gpus all -v $PWD:/entry_point_dir model-training
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# Examples
|
||||
|
||||
Example outputs of various Eynollah models
|
||||
|
||||
# Binarisation
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/952378/63592437-e433e400-c5b1-11e9-9c2d-889c6e93d748.jpg" width="45%"><img src="https://user-images.githubusercontent.com/952378/63592435-e433e400-c5b1-11e9-88e4-3e441b61fa67.jpg" width="45%">
|
||||
<img src="https://user-images.githubusercontent.com/952378/63592440-e4cc7a80-c5b1-11e9-8964-2cd1b22c87be.jpg" width="45%"><img src="https://user-images.githubusercontent.com/952378/63592438-e4cc7a80-c5b1-11e9-86dc-a9e9f8555422.jpg" width="45%">
|
||||
|
||||
# Reading Order Detection
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/42df2582-4579-415e-92f1-54858a02c830" alt="Input Image" width="45%">
|
||||
<img src="https://github.com/user-attachments/assets/77fc819e-6302-4fc9-967c-ee11d10d863e" alt="Output Image" width="45%">
|
||||
|
||||
# OCR
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/71054636-51c6-4117-b3cf-361c5cda3528" alt="Input Image" width="45%"><img src="https://github.com/user-attachments/assets/cfb3ce38-007a-4037-b547-21324a7d56dd" alt="Output Image" width="45%">
|
||||
<img src="https://github.com/user-attachments/assets/343b2ed8-d818-4d4a-b301-f304cbbebfcd" alt="Input Image" width="45%"><img src="https://github.com/user-attachments/assets/accb5ba7-e37f-477e-84aa-92eafa0d136e" alt="Output Image" width="45%">
|
||||
226
docs/models.md
226
docs/models.md
|
|
@ -1,226 +0,0 @@
|
|||
# Models documentation
|
||||
|
||||
This suite of 15 models presents a document layout analysis (DLA) system for historical documents implemented by
|
||||
pixel-wise segmentation using a combination of a ResNet50 encoder with various U-Net decoders. In addition, heuristic
|
||||
methods are applied to detect marginals and to determine the reading order of text regions.
|
||||
|
||||
The detection and classification of multiple classes of layout elements such as headings, images, tables etc. as part of
|
||||
DLA is required in order to extract and process them in subsequent steps. Altogether, the combination of image
|
||||
detection, classification and segmentation on the wide variety that can be found in over 400 years of printed cultural
|
||||
heritage makes this a very challenging task. Deep learning models are complemented with heuristics for the detection of
|
||||
text lines, marginals, and reading order. Furthermore, an optional image enhancement step was added in case of documents
|
||||
that either have insufficient pixel density and/or require scaling. Also, a column classifier for the analysis of
|
||||
multi-column documents was added. With these additions, DLA performance was improved, and a high accuracy in the
|
||||
prediction of the reading order is accomplished.
|
||||
|
||||
Two Arabic/Persian terms form the name of the model suite: عين الله, which can be transcribed as "ain'allah" or
|
||||
"eynollah"; it translates into English as "God's Eye" -- it sees (nearly) everything on the document image.
|
||||
|
||||
See the flowchart below for the different stages and how they interact:
|
||||
|
||||
<img width="810" height="691" alt="eynollah_flowchart" src="https://github.com/user-attachments/assets/42dd55bc-7b85-4b46-9afe-15ff712607f0" />
|
||||
|
||||
|
||||
|
||||
## Models
|
||||
|
||||
### Image enhancement
|
||||
|
||||
Model card: [Image Enhancement](https://huggingface.co/SBB/eynollah-enhancement)
|
||||
|
||||
This model addresses image resolution, specifically targeting documents with suboptimal resolution. In instances where
|
||||
the detection of document layout exhibits inadequate performance, the proposed enhancement aims to significantly improve
|
||||
the quality and clarity of the images, thus facilitating enhanced visual interpretation and analysis.
|
||||
|
||||
### Page extraction / border detection
|
||||
|
||||
Model card: [Page Extraction/Border Detection](https://huggingface.co/SBB/eynollah-page-extraction)
|
||||
|
||||
A problem that can negatively affect OCR are black margins around a page caused by document scanning. A deep learning
|
||||
model helps to crop to the page borders by using a pixel-wise segmentation method.
|
||||
|
||||
### Column classification
|
||||
|
||||
Model card: [Column Classification](https://huggingface.co/SBB/eynollah-column-classifier)
|
||||
|
||||
This model is a trained classifier that recognizes the number of columns in a document by use of a training set with
|
||||
manual classification of all documents into six classes with either one, two, three, four, five, or six and more columns
|
||||
respectively.
|
||||
|
||||
### Binarization
|
||||
|
||||
Model card: [Binarization](https://huggingface.co/SBB/eynollah-binarization)
|
||||
|
||||
This model is designed to tackle the intricate task of document image binarization, which involves segmentation of the
|
||||
image into white and black pixels. This process significantly contributes to the overall performance of the layout
|
||||
models, particularly in scenarios where the documents are degraded or exhibit subpar quality. The robust binarization
|
||||
capability of the model enables improved accuracy and reliability in subsequent layout analysis, thereby facilitating
|
||||
enhanced document understanding and interpretation.
|
||||
|
||||
### Main region detection
|
||||
|
||||
Model card: [Main Region Detection](https://huggingface.co/SBB/eynollah-main-regions)
|
||||
|
||||
This model has employed a different set of labels, including an artificial class specifically designed to encompass the
|
||||
text regions. The inclusion of this artificial class facilitates easier isolation of text regions by the model. This
|
||||
approach grants the advantage of training the model using downscaled images, which in turn leads to faster predictions
|
||||
during the inference phase. By incorporating this methodology, improved efficiency is achieved without compromising the
|
||||
model's ability to accurately identify and classify text regions within documents.
|
||||
|
||||
### Main region detection (with scaling augmentation)
|
||||
|
||||
Model card: [Main Region Detection (with scaling augmentation)](https://huggingface.co/SBB/eynollah-main-regions-aug-scaling)
|
||||
|
||||
Utilizing scaling augmentation, this model leverages the capability to effectively segment elements of extremely high or
|
||||
low scales within documents. By harnessing this technique, the tool gains a significant advantage in accurately
|
||||
categorizing and isolating such elements, thereby enhancing its overall performance and enabling precise analysis of
|
||||
documents with varying scale characteristics.
|
||||
|
||||
### Main region detection (with rotation augmentation)
|
||||
|
||||
Model card: [Main Region Detection (with rotation augmentation)](https://huggingface.co/SBB/eynollah-main-regions-aug-rotation)
|
||||
|
||||
This model takes advantage of rotation augmentation. This helps the tool to segment the vertical text regions in a
|
||||
robust way.
|
||||
|
||||
### Main region detection (ensembled)
|
||||
|
||||
Model card: [Main Region Detection (ensembled)](https://huggingface.co/SBB/eynollah-main-regions-ensembled)
|
||||
|
||||
The robustness of this model is attained through an ensembling technique that combines the weights from various epochs.
|
||||
By employing this approach, the model achieves a high level of resilience and stability, effectively leveraging the
|
||||
strengths of multiple epochs to enhance its overall performance and deliver consistent and reliable results.
|
||||
|
||||
### Full region detection (1,2-column documents)
|
||||
|
||||
Model card: [Full Region Detection (1,2-column documents)](https://huggingface.co/SBB/eynollah-full-regions-1column)
|
||||
|
||||
This model deals with documents comprising of one and two columns.
|
||||
|
||||
### Full region detection (3,n-column documents)
|
||||
|
||||
Model card: [Full Region Detection (3,n-column documents)](https://huggingface.co/SBB/eynollah-full-regions-3pluscolumn)
|
||||
|
||||
This model is responsible for detecting headers and drop capitals in documents with three or more columns.
|
||||
|
||||
### Textline detection
|
||||
|
||||
Model card: [Textline Detection](https://huggingface.co/SBB/eynollah-textline)
|
||||
|
||||
The method for textline detection combines deep learning and heuristics. In the deep learning part, an image-to-image
|
||||
model performs binary segmentation of the document into the classes textline vs. background. In the heuristics part,
|
||||
bounding boxes or contours are derived from binary segmentation.
|
||||
|
||||
Skewed documents can heavily affect textline detection accuracy, so robust deskewing is needed. But detecting textlines
|
||||
with rectangle bounding boxes cannot deal with partially curved textlines. To address this, a functionality
|
||||
specifically for documents with curved textlines was included. After finding the contour of a text region and its
|
||||
corresponding textline segmentation, the text region is cut into smaller vertical straps. For each strap, its textline
|
||||
segmentation is first deskewed and then the textlines are separated with the same heuristic method as for finding
|
||||
textline bounding boxes. Later, the strap is rotated back into its original orientation.
|
||||
|
||||
### Textline detection (light)
|
||||
|
||||
Model card: [Textline Detection Light (simpler but faster method)](https://huggingface.co/SBB/eynollah-textline_light)
|
||||
|
||||
The method for textline detection combines deep learning and heuristics. In the deep learning part, an image-to-image
|
||||
model performs binary segmentation of the document into the classes textline vs. background. In the heuristics part,
|
||||
bounding boxes or contours are derived from binary segmentation.
|
||||
|
||||
In the context of this textline model, a distinct labeling approach has been employed to ensure accurate predictions.
|
||||
Specifically, an artificial bounding class has been incorporated alongside the textline classes. This strategic
|
||||
inclusion effectively prevents any spurious connections between adjacent textlines during the prediction phase, thereby
|
||||
enhancing the model's ability to accurately identify and delineate individual textlines within documents. This model
|
||||
eliminates the need for additional heuristics in extracting textline contours.
|
||||
|
||||
### Table detection
|
||||
|
||||
Model card: [Table Detection](https://huggingface.co/SBB/eynollah-tables)
|
||||
|
||||
The objective of this model is to perform table segmentation in historical document images. Due to the pixel-wise
|
||||
segmentation approach employed and the presence of traditional tables predominantly composed of text, the detection of
|
||||
tables required the incorporation of heuristics to achieve reasonable performance. These heuristics were necessary to
|
||||
effectively identify and delineate tables within the historical document images, ensuring accurate segmentation and
|
||||
enabling subsequent analysis and interpretation.
|
||||
|
||||
### Image detection
|
||||
|
||||
Model card: [Image Detection](https://huggingface.co/SBB/eynollah-image-extraction)
|
||||
|
||||
This model is used for the task of illustration detection only.
|
||||
|
||||
### Reading order detection
|
||||
|
||||
Model card: [Reading Order Detection]()
|
||||
|
||||
The model extracts the reading order of text regions from the layout by classifying pairwise relationships between them. A sorting algorithm then determines the overall reading sequence.
|
||||
|
||||
### OCR
|
||||
|
||||
We have trained three OCR models: two CNN-RNN–based models and one transformer-based TrOCR model. The CNN-RNN models are generally faster and provide better results in most cases, though their performance decreases with heavily degraded images. The TrOCR model, on the other hand, is computationally expensive and slower during inference, but it can possibly produce better results on strongly degraded images.
|
||||
|
||||
#### CNN-RNN model: model_eynollah_ocr_cnnrnn_20250805
|
||||
|
||||
This model is trained on data where most of the samples are in Fraktur german script.
|
||||
|
||||
| Dataset | Input | CER | WER |
|
||||
|-----------------------|:-------|:-----------|:----------|
|
||||
| OCR-D-GT-Archiveform | BIN | 0.02147 | 0.05685 |
|
||||
| OCR-D-GT-Archiveform | RGB | 0.01636 | 0.06285 |
|
||||
|
||||
#### CNN-RNN model: model_eynollah_ocr_cnnrnn_20250904 (Default)
|
||||
|
||||
Compared to the model_eynollah_ocr_cnnrnn_20250805 model, this model is trained on a larger proportion of Antiqua data and achieves superior performance.
|
||||
|
||||
| Dataset | Input | CER | WER |
|
||||
|-----------------------|:------------|:-----------|:----------|
|
||||
| OCR-D-GT-Archiveform | BIN | 0.01635 | 0.05410 |
|
||||
| OCR-D-GT-Archiveform | RGB | 0.01471 | 0.05813 |
|
||||
| BLN600 | RGB | 0.04409 | 0.08879 |
|
||||
| BLN600 | Enhanced | 0.03599 | 0.06244 |
|
||||
|
||||
|
||||
#### Transformer OCR model: model_eynollah_ocr_trocr_20250919
|
||||
|
||||
This transformer OCR model is trained on the same data as model_eynollah_ocr_trocr_20250919.
|
||||
|
||||
| Dataset | Input | CER | WER |
|
||||
|-----------------------|:------------|:-----------|:----------|
|
||||
| OCR-D-GT-Archiveform | BIN | 0.01841 | 0.05589 |
|
||||
| OCR-D-GT-Archiveform | RGB | 0.01552 | 0.06177 |
|
||||
| BLN600 | RGB | 0.06347 | 0.13853 |
|
||||
|
||||
##### Qualitative evaluation of the models
|
||||
|
||||
| <img width="1600" src="https://github.com/user-attachments/assets/120fec0c-c370-46a6-b132-b0af800607cf"> | <img width="1000" src="https://github.com/user-attachments/assets/d84e6819-0a2a-4b3a-bb7d-ceac941babc4"> | <img width="1000" src="https://github.com/user-attachments/assets/bdd27cdb-bbec-4223-9a86-de7a27c6d018"> | <img width="1000" src="https://github.com/user-attachments/assets/1a507c75-75de-4da3-9545-af3746b9a207"> |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| Image | cnnrnn_20250805 | cnnrnn_20250904 | trocr_20250919 |
|
||||
|
||||
|
||||
|
||||
| <img width="2000" src="https://github.com/user-attachments/assets/9bc13d48-2a92-45fc-88db-c07ffadba067"> | <img width="1000" src="https://github.com/user-attachments/assets/2b294aeb-1362-4d6e-b70f-8aeffd94c5e7"> | <img width="1000" src="https://github.com/user-attachments/assets/9911317e-632e-4e6a-8839-1fb7e783da11"> | <img width="1000" src="https://github.com/user-attachments/assets/2c5626d9-0d23-49d3-80f5-a95f629c9c76"> |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| Image | cnnrnn_20250805 | cnnrnn_20250904 | trocr_20250919 |
|
||||
|
||||
|
||||
| <img width="2000" src="https://github.com/user-attachments/assets/d54d8510-5c6a-4ab0-9ba7-f6ec4ad452c6"> | <img width="1000" src="https://github.com/user-attachments/assets/a418b25b-00dc-493a-b3a3-b325b9b0cb85"> | <img width="1000" src="https://github.com/user-attachments/assets/df6e2b9e-a821-4b4c-8868-0c765700c341"> | <img width="1000" src="https://github.com/user-attachments/assets/b90277f5-40f4-4c99-80a2-da400f7d3640"> |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| Image | cnnrnn_20250805 | cnnrnn_20250904 | trocr_20250919 |
|
||||
|
||||
|
||||
| <img width="2000" src="https://github.com/user-attachments/assets/7ec49211-099f-4c21-9e60-47bfdf21f1b6"> | <img width="1000" src="https://github.com/user-attachments/assets/00ef9785-8885-41b3-bf6e-21eab743df71"> | <img width="1000" src="https://github.com/user-attachments/assets/13eb9f62-4d5a-46dc-befc-b02eb4f31fc1"> | <img width="1000" src="https://github.com/user-attachments/assets/a5c078d1-6d15-4d12-9040-526d7063d459"> |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| Image | cnnrnn_20250805 | cnnrnn_20250904 | trocr_20250919 |
|
||||
|
||||
|
||||
|
||||
## Heuristic methods
|
||||
|
||||
Additionally, some heuristic methods are employed to further improve the model predictions:
|
||||
|
||||
* After border detection, the largest contour is determined by a bounding box, and the image cropped to these coordinates.
|
||||
* Unlike the non-light version, where the image is scaled up to help the model better detect the background spaces between text regions, the light version uses down-scaled images. In this case, introducing an artificial class along the boundaries of text regions and text lines has helped to isolate and separate the text regions more effectively.
|
||||
* A minimum area is defined for text regions in relation to the overall image dimensions, so that very small regions that are noise can be filtered out.
|
||||
* In the non-light version, deskewing is applied at the text-region level (since regions may have different degrees of skew) to improve text-line segmentation results. In contrast, the light version performs deskewing only at the page level to enhance margin detection and heuristic reading-order estimation.
|
||||
* After deskewing, a calculation of the pixel distribution on the X-axis allows the separation of textlines (foreground) and background pixels (only in non-light version).
|
||||
* Finally, using the derived coordinates, bounding boxes are determined for each textline (only in non-light version).
|
||||
* As mentioned above, the reading order can be determined using a model; however, this approach is computationally expensive, time-consuming, and less accurate due to the limited amount of ground-truth data available for training. Therefore, our tool uses a heuristic reading-order detection method as the default. The heuristic approach relies on headers and separators to determine the reading order of text regions.
|
||||
26
docs/ocrd.md
26
docs/ocrd.md
|
|
@ -1,26 +0,0 @@
|
|||
## Use as OCR-D processor
|
||||
|
||||
Eynollah ships with a CLI interface to be used as [OCR-D](https://ocr-d.de) [processor](https://ocr-d.de/en/spec/cli),
|
||||
formally described in [`ocrd-tool.json`](https://github.com/qurator-spk/eynollah/tree/main/src/eynollah/ocrd-tool.json).
|
||||
|
||||
When using Eynollah in OCR-D, the source image file group with (preferably) RGB images should be used as input like this:
|
||||
|
||||
ocrd-eynollah-segment -I OCR-D-IMG -O OCR-D-SEG -P models eynollah_layout_v0_9_0
|
||||
|
||||
If the input file group is PAGE-XML (from a previous OCR-D workflow step), Eynollah behaves as follows:
|
||||
- existing regions are kept and ignored (i.e. in effect they might overlap segments from Eynollah results)
|
||||
- existing annotation (and respective `AlternativeImage`s) are partially _ignored_:
|
||||
- previous page frame detection (`cropped` images)
|
||||
- previous derotation (`deskewed` images)
|
||||
- previous thresholding (`binarized` images)
|
||||
- if the page-level image nevertheless deviates from the original (`@imageFilename`)
|
||||
(because some other preprocessing step was in effect like `denoised`), then
|
||||
the output PAGE-XML will be based on that as new top-level (`@imageFilename`)
|
||||
|
||||
ocrd-eynollah-segment -I OCR-D-XYZ -O OCR-D-SEG -P models eynollah_layout_v0_9_0
|
||||
|
||||
In general, it makes more sense to add other workflow steps **after** Eynollah.
|
||||
|
||||
There is also an OCR-D processor for binarization:
|
||||
|
||||
ocrd-sbb-binarize -I OCR-D-IMG -O OCR-D-BIN -P models default-2021-03-09
|
||||
804
docs/train.md
804
docs/train.md
|
|
@ -1,804 +0,0 @@
|
|||
# Prerequisistes
|
||||
|
||||
## 1. Install Eynollah with training dependencies
|
||||
|
||||
Clone the repository and install eynollah along with the dependencies necessary for training:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/qurator-spk/eynollah
|
||||
cd eynollah
|
||||
pip install '.[training]'
|
||||
```
|
||||
|
||||
## 2. Pretrained encoder
|
||||
|
||||
Download our pretrained weights and add them to a `train/pretrained_model` folder:
|
||||
|
||||
```sh
|
||||
cd train
|
||||
wget -O pretrained_model.tar.gz https://zenodo.org/records/17243320/files/pretrained_model_v0_5_1.tar.gz?download=1
|
||||
tar xf pretrained_model.tar.gz
|
||||
```
|
||||
|
||||
## 3. Example data
|
||||
|
||||
### Binarization
|
||||
A small sample of training data for binarization experiment can be found on [Zenodo](https://zenodo.org/records/17243320/files/training_data_sample_binarization_v0_5_1.tar.gz?download=1),
|
||||
which contains `images` and `labels` folders.
|
||||
|
||||
## 4. Helpful tools
|
||||
|
||||
* [`pagexml2img`](https://github.com/qurator-spk/page2img)
|
||||
> Tool to extract 2-D or 3-D RGB images from PAGE-XML data. In the former case, the output will be 1 2-D image array which each class has filled with a pixel value. In the case of a 3-D RGB image,
|
||||
each class will be defined with a RGB value and beside images, a text file of classes will also be produced.
|
||||
* [`cocoSegmentationToPng`](https://github.com/nightrome/cocostuffapi/blob/17acf33aef3c6cc2d6aca46dcf084266c2778cf0/PythonAPI/pycocotools/cocostuffhelper.py#L130)
|
||||
> Convert COCO GT or results for a single image to a segmentation map and write it to disk.
|
||||
* [`ocrd-segment-extract-pages`](https://github.com/OCR-D/ocrd_segment/blob/master/ocrd_segment/extract_pages.py)
|
||||
> Extract region classes and their colours in mask (pseg) images. Allows the color map as free dict parameter, and comes with a default that mimics PageViewer's coloring for quick debugging; it also warns when regions do overlap.
|
||||
|
||||
# Training documentation
|
||||
|
||||
This document aims to assist users in preparing training datasets, training models, and
|
||||
performing inference with trained models. We cover various use cases including
|
||||
pixel-wise segmentation, image classification, image enhancement, and
|
||||
machine-based reading order detection. For each use case, we provide guidance
|
||||
on how to generate the corresponding training dataset.
|
||||
|
||||
The following three tasks can all be accomplished using the code in the
|
||||
[`train`](https://github.com/qurator-spk/eynollah/tree/main/train) directory:
|
||||
|
||||
* [Generate training dataset](#generate-training-dataset)
|
||||
* [Train a model](#train-a-model)
|
||||
* [Inference with the trained model](#inference-with-the-trained-model)
|
||||
|
||||
## Training, evaluation and output
|
||||
|
||||
The train and evaluation folders should contain subfolders of `images` and `labels`.
|
||||
|
||||
The output folder should be an empty folder where the output model will be written to.
|
||||
|
||||
## Generate training dataset
|
||||
|
||||
The script `generate_gt_for_training.py` is used for generating training datasets. As the results of the following
|
||||
command demonstrates, the dataset generator provides several subcommands:
|
||||
|
||||
```sh
|
||||
eynollah-training generate-gt --help
|
||||
```
|
||||
|
||||
The three most important subcommands are:
|
||||
|
||||
* image-enhancement
|
||||
* machine-based-reading-order
|
||||
* pagexml2label
|
||||
|
||||
### image-enhancement
|
||||
|
||||
Generating a training dataset for image enhancement is quite straightforward. All that is needed is a set of
|
||||
high-resolution images. The training dataset can then be generated using the following command:
|
||||
|
||||
```sh
|
||||
eynollah-training image-enhancement \
|
||||
-dis "dir of high resolution images" \
|
||||
-dois "dir where degraded images will be written" \
|
||||
-dols "dir where the corresponding high resolution image will be written as label" \
|
||||
-scs "degrading scales json file"
|
||||
```
|
||||
|
||||
The scales JSON file is a dictionary with a key named `scales` and values representing scales smaller than 1. Images are
|
||||
downscaled based on these scales and then upscaled again to their original size. This process causes the images to lose
|
||||
resolution at different scales. The degraded images are used as input images, and the original high-resolution images
|
||||
serve as labels. The enhancement model can be trained with this generated dataset. The scales JSON file looks like this:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"scales": [0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9]
|
||||
}
|
||||
```
|
||||
|
||||
### machine-based-reading-order
|
||||
|
||||
For machine-based reading order, we aim to determine the reading priority between two sets of text regions. The model's
|
||||
input is a three-channel image: the first and last channels contain information about each of the two text regions,
|
||||
while the middle channel encodes prominent layout elements necessary for reading order, such as separators and headers.
|
||||
To generate the training dataset, our script requires a PAGE XML file that specifies the image layout with the correct
|
||||
reading order.
|
||||
|
||||
For output images, it is necessary to specify the width and height. Additionally, a minimum text region size can be set
|
||||
to filter out regions smaller than this minimum size. This minimum size is defined as the ratio of the text region area
|
||||
to the image area, with a default value of zero. To run the dataset generator, use the following command:
|
||||
|
||||
```shell
|
||||
eynollah-training generate-gt machine-based-reading-order \
|
||||
-dx "dir of GT xml files" \
|
||||
-domi "dir where output images will be written" \
|
||||
"" -docl "dir where the labels will be written" \
|
||||
-ih "height" \
|
||||
-iw "width" \
|
||||
-min "min area ratio"
|
||||
```
|
||||
|
||||
### pagexml2label
|
||||
|
||||
`pagexml2label` is designed to generate labels from PAGE XML GT files for various pixel-wise segmentation use cases,
|
||||
including:
|
||||
- `printspace` (i.e. page frame),
|
||||
- `layout` (i.e. regions),
|
||||
- `textline`,
|
||||
- `word`, and
|
||||
- `glyph`.
|
||||
|
||||
To train a pixel-wise segmentation model, we require images along with their corresponding labels. Our training script
|
||||
expects a PNG image where each pixel corresponds to a label, represented by an integer. The background is always labeled
|
||||
as zero, while other elements are assigned different integers. For instance, if we have ground truth data with four
|
||||
elements including the background, the classes would be labeled as 0, 1, 2, and 3 respectively.
|
||||
|
||||
In binary segmentation scenarios such as textline or page extraction, the background is encoded as 0, and the desired
|
||||
element is automatically encoded as 1 in the PNG label.
|
||||
|
||||
To specify the desired use case and the elements to be extracted in the PNG labels, a custom JSON file can be passed.
|
||||
For example, in the case of textline detection, the JSON contents could be this:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"use_case": "textline"
|
||||
}
|
||||
```
|
||||
|
||||
In the case of layout segmentation, the config JSON file might look like this:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"use_case": "layout",
|
||||
"textregions": {"rest_as_paragraph": 1, "drop-capital": 1, "header": 2, "heading": 2, "marginalia": 3},
|
||||
"imageregion": 4,
|
||||
"separatorregion": 5,
|
||||
"graphicregions": {"rest_as_decoration": 6, "stamp": 7}
|
||||
}
|
||||
```
|
||||
|
||||
The same example if `PrintSpace` (or `Border`) should be represented as a unique class:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"use_case": "layout",
|
||||
"textregions": {"rest_as_paragraph": 1, "drop-capital": 1, "header": 2, "heading": 2, "marginalia": 3},
|
||||
"imageregion": 4,
|
||||
"separatorregion": 5,
|
||||
"graphicregions": {"rest_as_decoration": 6, "stamp": 7}
|
||||
"printspace_as_class_in_layout": 8
|
||||
}
|
||||
```
|
||||
|
||||
In the `layout` use-case, it is beneficial to first understand the structure of the PAGE XML file and its elements.
|
||||
For a given page image, the visible segments are annotated in XML with their polygon coordinates and types.
|
||||
On the region level, available segment types include `TextRegion`, `SeparatorRegion`, `ImageRegion`, `GraphicRegion`,
|
||||
`NoiseRegion` and `TableRegion`.
|
||||
|
||||
Moreover, text regions and graphic regions in particular are subdivided via `@type`:
|
||||
- The allowed subtypes for text regions are `paragraph`, `heading`, `marginalia`, `drop-capital`, `header`, `footnote`,
|
||||
`footnote-continued`, `signature-mark`, `page-number` and `catch-word`.
|
||||
- The known subtypes for graphic regions are `handwritten-annotation`, `decoration`, `stamp` and `signature`.
|
||||
|
||||
These types and subtypes must be mapped to classes for the segmentation model. However, sometimes these fine-grained
|
||||
distinctions are not useful or the existing annotations are not very usable (too scarce or too unreliable).
|
||||
In that case, instead of these subtypes with a specific mapping, they can be pooled together by using the two special
|
||||
types:
|
||||
- `rest_as_paragraph` (mapping missing TextRegion subtypes and `paragraph`)
|
||||
- `rest_as_decoration` (mapping missing GraphicRegion subtypes and `decoration`)
|
||||
|
||||
(That way, users can extract all known types from the labels and be confident that no subtypes are overlooked.)
|
||||
|
||||
In the custom JSON example shown above, `header` and `heading` are extracted as the same class,
|
||||
while `marginalia` is modelled as a different class. All other text region types, including `drop-capital`,
|
||||
are grouped into the same class. For graphic regions, `stamp` has its own class, while all other types
|
||||
are classified together. `ImageRegion` and `SeparatorRegion` will also represented with a class label in the
|
||||
training data. However, other regions like `NoiseRegion` or `TableRegion` will not be included in the PNG files,
|
||||
even if they were present in the PAGE XML.
|
||||
|
||||
The tool expects various command-line options:
|
||||
|
||||
```sh
|
||||
eynollah-training generate-gt pagexml2label \
|
||||
-dx "dir of input PAGE XML files" \
|
||||
-do "dir of output label PNG files" \
|
||||
-cfg "custom config JSON file" \
|
||||
-to "output type (2d or 3d)"
|
||||
```
|
||||
|
||||
As output type, use
|
||||
- `2d` for training,
|
||||
- `3d` to just visualise the labels.
|
||||
|
||||
We have also defined an artificial class that can be added to (rendered around) the boundary
|
||||
of text region types or text lines in order to make separation of neighbouring segments more
|
||||
reliable. The key is called `artificial_class_on_boundary`, and it takes a list of text region
|
||||
types to be applied to.
|
||||
|
||||
Our example JSON config file could then look like this:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"use_case": "layout",
|
||||
"textregions": {
|
||||
"paragraph": 1,
|
||||
"drop-capital": 1,
|
||||
"header": 2,
|
||||
"heading": 2,
|
||||
"marginalia": 3
|
||||
},
|
||||
"imageregion": 4,
|
||||
"separatorregion": 5,
|
||||
"graphicregions": {
|
||||
"rest_as_decoration": 6
|
||||
},
|
||||
"artificial_class_on_boundary": ["paragraph", "header", "heading", "marginalia"],
|
||||
"artificial_class_label": 7
|
||||
}
|
||||
```
|
||||
|
||||
This implies that the artificial class label (denoted by 7) will be present in the generated PNG files
|
||||
and will only be added around segments labeled `paragraph`, `header`, `heading` or `marginalia`. (This
|
||||
class will be handled specially during decoding at inference, and not show up in final results.)
|
||||
|
||||
For `printspace`, `textline`, `word`, and `glyph` segmentation use-cases, there is no `artificial_class_on_boundary` key,
|
||||
but `artificial_class_label` is available. If specified in the config file, then its value should be set at 2, because
|
||||
these elements represent binary classification problems (with background represented as 0, and segments as 1, respectively).
|
||||
|
||||
For example, the JSON config for textline detection could look as follows:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"use_case": "textline",
|
||||
"artificial_class_label": 2
|
||||
}
|
||||
```
|
||||
|
||||
If the coordinates of `PrintSpace` (or `Border`) are present in the PAGE XML ground truth files,
|
||||
and one wishes to crop images to only cover the print space bounding box, this can be achieved
|
||||
by passing the `-ps` option. Note that in this scenario, the directory of the original images
|
||||
must also be provided, to ensure that the images are cropped in sync with the labels. The command
|
||||
line would then resemble this:
|
||||
|
||||
```sh
|
||||
eynollah-training generate-gt pagexml2label \
|
||||
-dx "dir of input PAGE XML files" \
|
||||
-do "dir of output label PNG files" \
|
||||
-cfg "custom config JSON file" \
|
||||
-to "output type (2d or 3d)" \
|
||||
-ps \
|
||||
-di "dir of input original images" \
|
||||
-doi "dir of output cropped images"
|
||||
```
|
||||
|
||||
Also, note that it can be detrimental to layout training if there are visible segments which
|
||||
the annotation does not account for (and thus the model must learn to ignore). So if the images
|
||||
are not cropped, the `-ps` _should_ be used. If a PAGE XML file is missing `PrintSpace` (or `Border`)
|
||||
annotations, use `-mps` to either `skip` these or `project` (i.e. crop from existing segments).
|
||||
|
||||
## Train a model
|
||||
|
||||
### classification
|
||||
|
||||
For the image classification use-case, we have not provided a ground truth generator, as it is unnecessary.
|
||||
All we require is a training directory with subdirectories, each containing images of its respective classes. We need
|
||||
separate directories for training and evaluation, and the class names (subdirectories) must be consistent across both
|
||||
directories. Additionally, the class names should be specified in the config JSON file, as shown in the following
|
||||
example. If, for instance, we aim to classify "apple" and "orange," with a total of 2 classes, the
|
||||
`classification_classes_name` key in the config file should appear as follows:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"backbone_type" : "nontransformer",
|
||||
"task": "classification",
|
||||
"n_classes" : 2,
|
||||
"n_epochs" : 10,
|
||||
"input_height" : 448,
|
||||
"input_width" : 448,
|
||||
"weight_decay" : 1e-6,
|
||||
"n_batch" : 4,
|
||||
"learning_rate": 1e-4,
|
||||
"f1_threshold_classification": 0.8,
|
||||
"pretraining" : true,
|
||||
"classification_classes_name" : {"0":"apple", "1":"orange"},
|
||||
"dir_train": "./train",
|
||||
"dir_eval": "./eval",
|
||||
"dir_output": "./output"
|
||||
}
|
||||
```
|
||||
|
||||
Then `dir_train` should be like this:
|
||||
|
||||
```
|
||||
.
|
||||
└── train # train directory
|
||||
├── apple # directory of images for apple class
|
||||
└── orange # directory of images for orange class
|
||||
```
|
||||
|
||||
And `dir_eval` analogously:
|
||||
|
||||
```
|
||||
.
|
||||
└── eval # evaluation directory
|
||||
├── apple # directory of images for apple class
|
||||
└── orange # directory of images for orange class
|
||||
|
||||
```
|
||||
|
||||
The classification model can be trained using the following command line:
|
||||
|
||||
```sh
|
||||
eynollah-training train with config_classification.json
|
||||
```
|
||||
|
||||
As evident in the example JSON file above, for classification, we utilize a "f1_threshold_classification" parameter.
|
||||
This parameter is employed to gather all models with an evaluation f1 score surpassing this threshold. Subsequently,
|
||||
an ensemble of these model weights is executed, and a model is saved in the output directory as "model_ens_avg".
|
||||
Additionally, the weight of the best model based on the evaluation f1 score is saved as "model_best".
|
||||
|
||||
### reading order
|
||||
An example config json file for machine based reading order should be like this:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"backbone_type" : "nontransformer",
|
||||
"task": "reading_order",
|
||||
"n_classes" : 1,
|
||||
"n_epochs" : 5,
|
||||
"input_height" : 672,
|
||||
"input_width" : 448,
|
||||
"weight_decay" : 1e-6,
|
||||
"n_batch" : 4,
|
||||
"learning_rate": 1e-4,
|
||||
"pretraining" : true,
|
||||
"dir_train": "./train",
|
||||
"dir_eval": "./eval",
|
||||
"dir_output": "./output"
|
||||
}
|
||||
```
|
||||
|
||||
The "dir_train" should be like this:
|
||||
|
||||
```
|
||||
.
|
||||
└── train # train directory
|
||||
├── images # directory of images
|
||||
└── labels # directory of labels
|
||||
```
|
||||
|
||||
And the "dir_eval" the same structure as train directory:
|
||||
|
||||
```
|
||||
.
|
||||
└── eval # evaluation directory
|
||||
├── images # directory of images
|
||||
└── labels # directory of labels
|
||||
```
|
||||
|
||||
The reading-order model can be trained like the classification case command line.
|
||||
|
||||
### Segmentation (Textline, Binarization, Page extraction and layout) and enhancement
|
||||
|
||||
#### Parameter configuration for segmentation or enhancement usecases
|
||||
|
||||
The following parameter configuration can be applied to all segmentation use cases and enhancements. The augmentation,
|
||||
its sub-parameters, and continued training are defined only for segmentation use cases and enhancements, not for
|
||||
classification and machine-based reading order, as you can see in their example config files.
|
||||
|
||||
* `task`: The task parameter must be one of the following values:
|
||||
- `binarization`,
|
||||
- `enhancement`,
|
||||
- `segmentation`,
|
||||
- `classification`,
|
||||
- `reading_order`.
|
||||
* `backbone_type`: For the tasks `segmentation` (such as text line, and region layout detection),
|
||||
`binarization` and `enhancement`, we offer two backbone options:
|
||||
- `nontransformer` (only a CNN ResNet-50).
|
||||
- `transformer` (first apply a CNN, followed by a transformer)
|
||||
* `transformer_cnn_first`: Whether to apply the CNN first (followed by the transformer) when using `transformer` backbone.
|
||||
* `transformer_num_patches_xy`: Number of patches for vision transformer in x and y direction respectively.
|
||||
* `transformer_patchsize_x`: Patch size of vision transformer patches in x direction.
|
||||
* `transformer_patchsize_y`: Patch size of vision transformer patches in y direction.
|
||||
* `transformer_projection_dim`: Transformer projection dimension. Default value is 64.
|
||||
* `transformer_mlp_head_units`: Transformer Multilayer Perceptron (MLP) head units. Default value is [128, 64].
|
||||
* `transformer_layers`: transformer layers. Default value is 8.
|
||||
* `transformer_num_heads`: Transformer number of heads. Default value is 4.
|
||||
* `patches`: Whether to break up (tile) input images into smaller patches (input size of the model).
|
||||
If `false`, the model will see the image once (resized to the input size of the model).
|
||||
Should be set to `false` for cases like page extraction.
|
||||
* `n_batch`: Number of batches at each iteration.
|
||||
* `n_classes`: Number of classes. In the case of binary classification this should be 2. In the case of reading_order it
|
||||
should set to 1. And for the case of layout detection just the unique number of classes should be given.
|
||||
* `n_epochs`: Number of epochs (iterations over the data) to train.
|
||||
* `input_height`: the image height for the model's input.
|
||||
* `input_width`: the image width for the model's input.
|
||||
* `weight_decay`: Weight decay of l2 regularization of model layers.
|
||||
* `weighted_loss`: If `true`, this means that you want to apply weighted categorical crossentropy as loss function.
|
||||
(Mutually exclusive with `is_loss_soft_dice`, and only applies for `segmentation` and `binarization` tasks.)
|
||||
* `pretraining`: Set to `true` to (download and) initialise pretrained weights of ResNet50 encoder.
|
||||
* `dir_train`: Path to directory of raw training data (as extracted via `pagexml2labels`, i.e. with subdirectories
|
||||
`images` and `labels` for input images and output labels.
|
||||
(These are not prepared for training the model, yet. Upon first run, the raw data will be transformed to suitable size
|
||||
needed for the model, and written in `dir_output` under `train` and `eval` subdirectories. See `data_is_provided`.)
|
||||
* `dir_eval`: Ditto for raw evaluation data.
|
||||
* `dir_output`: Directory to write model checkpoints, logs (for Tensorboard) and precomputed images to.
|
||||
* `data_is_provided`: If you have already trained at least one complete epoch (using the same data settings) before,
|
||||
you can set this to `true` to avoid computing the resized / patched / augmented image files again.
|
||||
Be sure that there are subdirectories `train` and `eval` data are in `dir_output` (each with subdirectories `images`
|
||||
and `labels`, respectively).
|
||||
* `continue_training`: If `true`, continue training a model checkpoint from a previous run.
|
||||
This requires providing the directory of the model checkpoint to load via `dir_of_start_model`
|
||||
and setting `index_start` counter for naming new checkpoints.
|
||||
For example if you have already trained for 3 epochs, then your last index is 2, so if you want
|
||||
to continue with `model_04`, `model_05` etc., set `index_start=3`.
|
||||
* `index_start`: Starting index for saving models in the case that `continue_training` is `true`.
|
||||
(Existing checkpoints above this will be overwritten.)
|
||||
* `dir_of_start_model`: Directory containing existing model checkpoint to initialise model weights from when `continue_training=true`.
|
||||
(Can be an epoch-interval checkpoint, or batch-interval checkpoint from `save_interval`.)
|
||||
* `augmentation`: If you want to apply any kind of augmentation this parameter should first set to `true`.
|
||||
The remaining settings pertain to that...
|
||||
* `flip_aug`: If `true`, different types of flipping over the image arrays. Requires `flip_index` parameter.
|
||||
* `flip_index`: List of flip codes (as in `cv2.flip`, i.e. 0 for vertical, positive for horizontal shift, negative for vertical and horizontal shift).
|
||||
* `blur_aug`: If `true`, different types of blurring will be applied on image. Requires `blur_k` parameter.
|
||||
* `blur_k`: Method of blurring (`gauss`, `median` or `blur`).
|
||||
* `scaling`: If `true`, scaling will be applied on image. Requires `scales` parameter.
|
||||
* `scales`: List of scale factors for scaling.
|
||||
* `scaling_bluring`: If `true`, combination of scaling and blurring will be applied on image.
|
||||
* `scaling_binarization`: If `true`, combination of scaling and binarization will be applied on image.
|
||||
* `scaling_flip`: If `true`, combination of scaling and flip will be applied on image.
|
||||
* `degrading`: If `true`, degrading will be applied to the image. Requires `degrade_scales` parameter.
|
||||
* `degrade_scales`: List of intensity factors for degrading.
|
||||
* `brightening`: If `true`, brightening will be applied to the image. Requires `brightness` parameter.
|
||||
* `brightness`: List of intensity factors for brightening.
|
||||
* `binarization`: If `true`, Otsu thresholding will be applied to augment the input data with binarized images.
|
||||
* `dir_img_bin`: With `binarization`, use this directory to read precomputed binarized images instead of ad-hoc Otsu.
|
||||
(Base names should correspond to the files in `dir_train/images`.)
|
||||
* `rotation`: If `true`, 90° rotation will be applied on images.
|
||||
* `rotation_not_90`: If `true`, random rotation (other than 90°) will be applied on image. Requires `thetha` parameter.
|
||||
* `thetha`: List of rotation angles (in degrees).
|
||||
|
||||
In case of segmentation and enhancement the train and evaluation data should be organised as follows.
|
||||
|
||||
The "dir_train" directory should be like this:
|
||||
|
||||
```
|
||||
.
|
||||
└── train # train directory
|
||||
├── images # directory of images
|
||||
└── labels # directory of labels
|
||||
```
|
||||
|
||||
And the "dir_eval" the same structure as train directory:
|
||||
|
||||
```
|
||||
.
|
||||
└── eval # evaluation directory
|
||||
├── images # directory of images
|
||||
└── labels # directory of labels
|
||||
```
|
||||
|
||||
After configuring the JSON file for segmentation or enhancement,
|
||||
training can be initiated by running the following command line,
|
||||
similar to classification and reading-order model training:
|
||||
|
||||
```sh
|
||||
eynollah-training train with config_classification.json
|
||||
```
|
||||
|
||||
#### Binarization
|
||||
|
||||
### Ground truth format
|
||||
|
||||
Lables for each pixel are identified by a number. So if you have a
|
||||
binary case, ``n_classes`` should be set to ``2`` and labels should
|
||||
be ``0`` and ``1`` for each class and pixel.
|
||||
|
||||
In the case of multiclass, just set ``n_classes`` to the number of classes
|
||||
you have and the try to produce the labels by pixels set from ``0 , 1 ,2 .., n_classes-1``.
|
||||
The labels format should be png.
|
||||
Our lables are 3 channel png images but only information of first channel is used.
|
||||
If you have an image label with height and width of 10, for a binary case the first channel should look like this:
|
||||
|
||||
Label: [ [1, 0, 0, 1, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
...,
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ]
|
||||
|
||||
This means that you have an image by `10*10*3` and `pixel[0,0]` belongs
|
||||
to class `1` and `pixel[0,1]` belongs to class `0`.
|
||||
|
||||
A small sample of training data for binarization experiment can be found here, [Training data sample](https://qurator-data.de/~vahid.rezanezhad/binarization_training_data_sample/), which contains images and lables folders.
|
||||
|
||||
|
||||
An example config json file for binarization can be like this:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"backbone_type" : "transformer",
|
||||
"task": "binarization",
|
||||
"n_classes" : 2,
|
||||
"n_epochs" : 4,
|
||||
"input_height" : 224,
|
||||
"input_width" : 672,
|
||||
"weight_decay" : 1e-6,
|
||||
"n_batch" : 1,
|
||||
"learning_rate": 1e-4,
|
||||
"patches" : true,
|
||||
"pretraining" : true,
|
||||
"augmentation" : true,
|
||||
"flip_aug" : false,
|
||||
"blur_aug" : false,
|
||||
"scaling" : true,
|
||||
"degrading": false,
|
||||
"brightening": false,
|
||||
"binarization" : false,
|
||||
"scaling_bluring" : false,
|
||||
"scaling_binarization" : false,
|
||||
"scaling_flip" : false,
|
||||
"rotation": false,
|
||||
"rotation_not_90": false,
|
||||
"transformer_num_patches_xy": [7, 7],
|
||||
"transformer_patchsize_x": 3,
|
||||
"transformer_patchsize_y": 1,
|
||||
"transformer_projection_dim": 192,
|
||||
"transformer_mlp_head_units": [128, 64],
|
||||
"transformer_layers": 8,
|
||||
"transformer_num_heads": 4,
|
||||
"transformer_cnn_first": true,
|
||||
"blur_k" : ["blur","guass","median"],
|
||||
"scales" : [0.6, 0.7, 0.8, 0.9, 1.1, 1.2, 1.4],
|
||||
"brightness" : [1.3, 1.5, 1.7, 2],
|
||||
"degrade_scales" : [0.2, 0.4],
|
||||
"flip_index" : [0, 1, -1],
|
||||
"thetha" : [10, -10],
|
||||
"continue_training": false,
|
||||
"index_start" : 0,
|
||||
"dir_of_start_model" : " ",
|
||||
"weighted_loss": false,
|
||||
"is_loss_soft_dice": false,
|
||||
"data_is_provided": false,
|
||||
"dir_train": "./train",
|
||||
"dir_eval": "./eval",
|
||||
"dir_output": "./output"
|
||||
}
|
||||
```
|
||||
|
||||
#### Textline
|
||||
|
||||
```yaml
|
||||
{
|
||||
"backbone_type" : "nontransformer",
|
||||
"task": "segmentation",
|
||||
"n_classes" : 2,
|
||||
"n_epochs" : 4,
|
||||
"input_height" : 448,
|
||||
"input_width" : 224,
|
||||
"weight_decay" : 1e-6,
|
||||
"n_batch" : 1,
|
||||
"learning_rate": 1e-4,
|
||||
"patches" : true,
|
||||
"pretraining" : true,
|
||||
"augmentation" : true,
|
||||
"flip_aug" : false,
|
||||
"blur_aug" : false,
|
||||
"scaling" : true,
|
||||
"degrading": false,
|
||||
"brightening": false,
|
||||
"binarization" : false,
|
||||
"scaling_bluring" : false,
|
||||
"scaling_binarization" : false,
|
||||
"scaling_flip" : false,
|
||||
"rotation": false,
|
||||
"rotation_not_90": false,
|
||||
"blur_k" : ["blur","guass","median"],
|
||||
"scales" : [0.6, 0.7, 0.8, 0.9, 1.1, 1.2, 1.4],
|
||||
"brightness" : [1.3, 1.5, 1.7, 2],
|
||||
"degrade_scales" : [0.2, 0.4],
|
||||
"flip_index" : [0, 1, -1],
|
||||
"thetha" : [10, -10],
|
||||
"continue_training": false,
|
||||
"index_start" : 0,
|
||||
"dir_of_start_model" : " ",
|
||||
"weighted_loss": false,
|
||||
"is_loss_soft_dice": false,
|
||||
"data_is_provided": false,
|
||||
"dir_train": "./train",
|
||||
"dir_eval": "./eval",
|
||||
"dir_output": "./output"
|
||||
}
|
||||
```
|
||||
|
||||
#### Enhancement
|
||||
|
||||
```yaml
|
||||
{
|
||||
"backbone_type" : "nontransformer",
|
||||
"task": "enhancement",
|
||||
"n_classes" : 3,
|
||||
"n_epochs" : 4,
|
||||
"input_height" : 448,
|
||||
"input_width" : 224,
|
||||
"weight_decay" : 1e-6,
|
||||
"n_batch" : 4,
|
||||
"learning_rate": 1e-4,
|
||||
"patches" : true,
|
||||
"pretraining" : true,
|
||||
"augmentation" : true,
|
||||
"flip_aug" : false,
|
||||
"blur_aug" : false,
|
||||
"scaling" : true,
|
||||
"degrading": false,
|
||||
"brightening": false,
|
||||
"binarization" : false,
|
||||
"scaling_bluring" : false,
|
||||
"scaling_binarization" : false,
|
||||
"scaling_flip" : false,
|
||||
"rotation": false,
|
||||
"rotation_not_90": false,
|
||||
"blur_k" : ["blur","guass","median"],
|
||||
"scales" : [0.6, 0.7, 0.8, 0.9, 1.1, 1.2, 1.4],
|
||||
"brightness" : [1.3, 1.5, 1.7, 2],
|
||||
"degrade_scales" : [0.2, 0.4],
|
||||
"flip_index" : [0, 1, -1],
|
||||
"thetha" : [10, -10],
|
||||
"continue_training": false,
|
||||
"index_start" : 0,
|
||||
"dir_of_start_model" : " ",
|
||||
"weighted_loss": false,
|
||||
"is_loss_soft_dice": false,
|
||||
"data_is_provided": false,
|
||||
"dir_train": "./train",
|
||||
"dir_eval": "./eval",
|
||||
"dir_output": "./output"
|
||||
}
|
||||
```
|
||||
|
||||
It's important to mention that the value of n_classes for enhancement should be 3, as the model's output is a 3-channel
|
||||
image.
|
||||
|
||||
#### Page extraction
|
||||
|
||||
```yaml
|
||||
{
|
||||
"backbone_type" : "nontransformer",
|
||||
"task": "segmentation",
|
||||
"n_classes" : 2,
|
||||
"n_epochs" : 4,
|
||||
"input_height" : 448,
|
||||
"input_width" : 224,
|
||||
"weight_decay" : 1e-6,
|
||||
"n_batch" : 1,
|
||||
"learning_rate": 1e-4,
|
||||
"patches" : false,
|
||||
"pretraining" : true,
|
||||
"augmentation" : false,
|
||||
"flip_aug" : false,
|
||||
"blur_aug" : false,
|
||||
"scaling" : true,
|
||||
"degrading": false,
|
||||
"brightening": false,
|
||||
"binarization" : false,
|
||||
"scaling_bluring" : false,
|
||||
"scaling_binarization" : false,
|
||||
"scaling_flip" : false,
|
||||
"rotation": false,
|
||||
"rotation_not_90": false,
|
||||
"blur_k" : ["blur","guass","median"],
|
||||
"scales" : [0.6, 0.7, 0.8, 0.9, 1.1, 1.2, 1.4],
|
||||
"brightness" : [1.3, 1.5, 1.7, 2],
|
||||
"degrade_scales" : [0.2, 0.4],
|
||||
"flip_index" : [0, 1, -1],
|
||||
"thetha" : [10, -10],
|
||||
"continue_training": false,
|
||||
"index_start" : 0,
|
||||
"dir_of_start_model" : " ",
|
||||
"weighted_loss": false,
|
||||
"is_loss_soft_dice": false,
|
||||
"data_is_provided": false,
|
||||
"dir_train": "./train",
|
||||
"dir_eval": "./eval",
|
||||
"dir_output": "./output"
|
||||
}
|
||||
```
|
||||
|
||||
For page segmentation (or print space or border segmentation), the model needs to view the input image in its
|
||||
entirety,hence the patches parameter should be set to false.
|
||||
|
||||
#### layout segmentation
|
||||
|
||||
An example config json file for layout segmentation with 5 classes (including background) can be like this:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"backbone_type" : "transformer",
|
||||
"task": "segmentation",
|
||||
"n_classes" : 5,
|
||||
"n_epochs" : 4,
|
||||
"input_height" : 448,
|
||||
"input_width" : 224,
|
||||
"weight_decay" : 1e-6,
|
||||
"n_batch" : 1,
|
||||
"learning_rate": 1e-4,
|
||||
"patches" : true,
|
||||
"pretraining" : true,
|
||||
"augmentation" : true,
|
||||
"flip_aug" : false,
|
||||
"blur_aug" : false,
|
||||
"scaling" : true,
|
||||
"degrading": false,
|
||||
"brightening": false,
|
||||
"binarization" : false,
|
||||
"scaling_bluring" : false,
|
||||
"scaling_binarization" : false,
|
||||
"scaling_flip" : false,
|
||||
"rotation": false,
|
||||
"rotation_not_90": false,
|
||||
"transformer_num_patches_xy": [7, 14],
|
||||
"transformer_patchsize_x": 1,
|
||||
"transformer_patchsize_y": 1,
|
||||
"transformer_projection_dim": 64,
|
||||
"transformer_mlp_head_units": [128, 64],
|
||||
"transformer_layers": 8,
|
||||
"transformer_num_heads": 4,
|
||||
"transformer_cnn_first": true,
|
||||
"blur_k" : ["blur","guass","median"],
|
||||
"scales" : [0.6, 0.7, 0.8, 0.9, 1.1, 1.2, 1.4],
|
||||
"brightness" : [1.3, 1.5, 1.7, 2],
|
||||
"degrade_scales" : [0.2, 0.4],
|
||||
"flip_index" : [0, 1, -1],
|
||||
"thetha" : [10, -10],
|
||||
"continue_training": false,
|
||||
"index_start" : 0,
|
||||
"dir_of_start_model" : " ",
|
||||
"weighted_loss": false,
|
||||
"is_loss_soft_dice": false,
|
||||
"data_is_provided": false,
|
||||
"dir_train": "./train",
|
||||
"dir_eval": "./eval",
|
||||
"dir_output": "./output"
|
||||
}
|
||||
```
|
||||
## Inference with the trained model
|
||||
|
||||
### classification
|
||||
|
||||
For conducting inference with a trained model, you simply need to execute the following command line, specifying the
|
||||
directory of the model and the image on which to perform inference:
|
||||
|
||||
```sh
|
||||
eynollah-training inference -m "model dir" -i "image"
|
||||
```
|
||||
|
||||
This will straightforwardly return the class of the image.
|
||||
|
||||
### machine based reading order
|
||||
|
||||
To infer the reading order using a reading order model, we need a PAGE XML file containing layout information but
|
||||
without the reading order. We simply need to provide the model directory, the XML file, and the output directory. The
|
||||
new XML file with the added reading order will be written to the output directory with the same name. We need to run:
|
||||
|
||||
```sh
|
||||
eynollah-training inference \
|
||||
-m "model dir" \
|
||||
-xml "page xml file" \
|
||||
-o "output dir to write new xml with reading order"
|
||||
```
|
||||
|
||||
### Segmentation (Textline, Binarization, Page extraction and layout) and enhancement
|
||||
|
||||
For conducting inference with a trained model for segmentation and enhancement you need to run the following command line:
|
||||
|
||||
```sh
|
||||
eynollah-training inference \
|
||||
-m "model dir" \
|
||||
-i "image" \
|
||||
-p \
|
||||
-s "output image"
|
||||
```
|
||||
|
||||
Note that in the case of page extraction the -p flag is not needed.
|
||||
|
||||
For segmentation or binarization tasks, if a ground truth (GT) label is available, the IoU evaluation metric can be
|
||||
calculated for the output. To do this, you need to provide the GT label using the argument -gt.
|
||||
112
docs/usage.md
112
docs/usage.md
|
|
@ -1,112 +0,0 @@
|
|||
# Usage documentation
|
||||
The command-line interface can be called like this:
|
||||
|
||||
```sh
|
||||
eynollah \
|
||||
[GENERIC_OPTIONS] \
|
||||
layout \
|
||||
-i <single image file> | -di <directory containing image files> \
|
||||
-o <output directory> \
|
||||
[LAYOUT_OPTIONS]
|
||||
```
|
||||
|
||||
## Generic options
|
||||
Pass any of the following options:
|
||||
|
||||
| **option** | **description** |
|
||||
|---------------------------------------------------|:----------------------------------------------------------------|
|
||||
| -m <directory containing model files> | override default directory `$PWD/models_eynollah` |
|
||||
| -mv <model category> <model variant> <model path> | override specific models, e.g. `region_1_2 '' /path/to/my.onnx` |
|
||||
| -D <device specifier> | allocate models to GPUs, e.g. `col*:CPU,page:GPU1,*:GPU0` |
|
||||
| -l <log level> | override default `INFO` log level e.g. `DEBUG` |
|
||||
|
||||
## Processing options
|
||||
The following options can be used to further control layout analysis:
|
||||
|
||||
| **option** | **description** |
|
||||
|-------------------|:-------------------------------------------------------------------------------|
|
||||
| `-fl` | full layout analysis including all steps and segmentation classes (recommended)|
|
||||
| `-tab` | apply table detection |
|
||||
| `-ae` | apply enhancement (the resulting image is saved to the output directory) |
|
||||
| `-as` | apply scaling |
|
||||
| `-cl` | apply contour detection for curved text lines, deskewing regions independently |
|
||||
| `-ib` | apply binarization (the resulting image is saved to the output directory) |
|
||||
| `-ep` | enable plotting (MUST always be used with `-sl`, `-sd`, `-sa`, `-si` or `-ae`) |
|
||||
| `-ho` | ignore headers for reading order dectection |
|
||||
| `-si <directory>` | save image regions detected to this directory |
|
||||
| `-sd <directory>` | save deskewed image to this directory |
|
||||
| `-sl <directory>` | save layout prediction as plot to this directory |
|
||||
| `-sp <directory>` | save cropped page image to this directory |
|
||||
| `-sa <directory>` | save all (plot, enhanced/binary image, layout) to this directory |
|
||||
| `-thart` | confidence threshold of artifical boundary class during textline detection |
|
||||
| `-tharl` | confidence threshold of artifical boundary class during region detection |
|
||||
| `-ncu` | upper limit of columns in document image |
|
||||
| `-ncl` | lower limit of columns in document image |
|
||||
| `-slro` | skip layout detection and reading order |
|
||||
| `-romb` | apply machine based reading order detection |
|
||||
| `-ipe` | ignore page extraction |
|
||||
| `-j` | number of CPU jobs to run parallel (useful with -di) |
|
||||
| `-H` | when to halt if some jobs fail, e.g. `0.1` for 10% or `3` for 3 pages |
|
||||
|
||||
If no option is set, the tool performs detection of main regions (background, text, images, separators and marginals).
|
||||
|
||||
### `--full-layout` vs shallow
|
||||
|
||||
Here are the differences in segment types detected:
|
||||
|
||||
| | `-fl` | without |
|
||||
|--------------------------|-------|---------|
|
||||
| reading order | x | x |
|
||||
| header regions | x | - |
|
||||
| text regions | x | x |
|
||||
| text regions / textlines | x | x |
|
||||
| drop-capitals | x | - |
|
||||
| marginals | x | x |
|
||||
| marginals / textlines | x | x |
|
||||
| image regions | x | x |
|
||||
|
||||
(Note: No marginals are detected for pages with 3 columns or more.)
|
||||
|
||||
## Use as OCR-D processor
|
||||
Eynollah ships with a CLI interface to be used as [OCR-D](https://ocr-d.de) processor that is described in
|
||||
[`ocrd-tool.json`](https://github.com/qurator-spk/eynollah/tree/main/src/eynollah/ocrd-tool.json).
|
||||
|
||||
The source image file group with (preferably) RGB images should be used as input for Eynollah like this:
|
||||
|
||||
```
|
||||
ocrd-eynollah-segment -I OCR-D-IMG -O SEG-LINE -P full_layout true
|
||||
```
|
||||
|
||||
Any image referenced by `@imageFilename` in PAGE-XML is passed on directly to Eynollah as a processor, so that e.g.
|
||||
|
||||
```
|
||||
ocrd-eynollah-segment -I OCR-D-IMG-BIN -O SEG-LINE -P full_layout true
|
||||
```
|
||||
|
||||
uses the original (RGB) image despite any binarization that may have occured in previous OCR-D processing steps.
|
||||
|
||||
## Use with Docker
|
||||
TODO
|
||||
|
||||
## Hints
|
||||
* The best output quality is produced when RGB images are used as input rather than greyscale or binarized images.
|
||||
* If none of the parameters is set to `true`, the tool will perform a layout detection of main regions (background,
|
||||
text, images, separators and marginals). An advantage of this tool is that it tries to extract main text regions
|
||||
separately as much as possible.
|
||||
* If you set `-ae` (**a**llow image **e**nhancement) parameter to `true`, the tool will first check the ppi
|
||||
(pixel-per-inch) of the image and when it is less than 300, the tool will resize it and only then image enhancement will
|
||||
occur. Image enhancement can also take place without this option, but by setting this option to `true`, the layout xml
|
||||
data (e.g. coordinates) will be based on the resized and enhanced image instead of the original image.
|
||||
* For some documents, while the quality is good, their scale is very large, and the performance of tool decreases. In
|
||||
such cases you can set `-as` (**a**llow **s**caling) to `true`. With this option enabled, the tool will try to rescale
|
||||
the image and only then the layout detection process will begin.
|
||||
* If you care about drop capitals (initials) and headings, you can set `-fl` (**f**ull **l**ayout) to `true`. With this
|
||||
setting, the tool can currently distinguish 7 document layout classes/elements.
|
||||
* In cases where the document includes curved headers or curved lines, rectangular bounding boxes for textlines will not
|
||||
be a great option. In such cases it is strongly recommended setting the flag `-cl` (**c**urved **l**ines) to `true` to
|
||||
find contours of curved lines instead of rectangular bounding boxes. Be advised that enabling this option increases the
|
||||
processing time of the tool.
|
||||
* To crop and save image regions inside the document, set the parameter `-si` (**s**ave **i**mages) to true and provide
|
||||
a directory path to store the extracted images.
|
||||
* To extract only images from a document, set the parameter `-eoi` (**e**xtract **o**nly **i**mages). Choosing this
|
||||
option disables any other processing. To save the cropped images add `-ep` and `-si`.
|
||||
142
models/Makefile
142
models/Makefile
|
|
@ -1,142 +0,0 @@
|
|||
SHELL = bash -e
|
||||
|
||||
VERSION = v0_9_1
|
||||
MODELS_SRC = models_eynollah
|
||||
MODELS_DST = reloaded/models_eynollah
|
||||
|
||||
|
||||
# eynollah-main-regions-aug-rotation_20210425
|
||||
# eynollah-main-regions-aug-scaling_20210425
|
||||
# eynollah-main-regions-ensembled_20210425
|
||||
# eynollah-main-regions_20220314
|
||||
# eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18
|
||||
# eynollah-tables_20210319
|
||||
|
||||
CURRENT_MODELS :=
|
||||
CURRENT_MODELS += eynollah-main-regions-aug-rotation_20210425
|
||||
CURRENT_MODELS += eynollah-main-regions-aug-scaling_20210425
|
||||
CURRENT_MODELS += eynollah-main-regions-ensembled_20210425
|
||||
CURRENT_MODELS += eynollah-main-regions_20220314
|
||||
CURRENT_MODELS += eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18
|
||||
CURRENT_MODELS += eynollah-tables_20210319
|
||||
CURRENT_MODELS += eynollah-main-regions_20220314
|
||||
CURRENT_MODELS += model_eynollah_page_extraction_20250915
|
||||
CURRENT_MODELS += model_eynollah_reading_order_20250824
|
||||
CURRENT_MODELS += modelens_e_l_all_sp_0_1_2_3_4_171024
|
||||
CURRENT_MODELS += modelens_full_lay_1__4_3_091124
|
||||
CURRENT_MODELS += modelens_table_0t4_201124
|
||||
CURRENT_MODELS += modelens_textline_0_1__2_4_16092024
|
||||
CURRENT_MODELS += model_eynollah_ocr_cnnrnn_20250930
|
||||
CURRENT_MODELS += eynollah-binarization_20210425
|
||||
CURRENT_MODELS += eynollah-column-classifier_20210425
|
||||
CURRENT_MODELS += eynollah-enhancement_20210425
|
||||
|
||||
help:
|
||||
@echo "Targets:"
|
||||
@echo ""
|
||||
@echo "Model conversion:"
|
||||
@echo " all Convert all current models to TensorFlow SavedModel (default)"
|
||||
@echo " tf[-serving] Convert all current models to TensorFlow SavedModel"
|
||||
@echo " keras Convert all current models to Keras format (.keras)"
|
||||
@echo " hdf5 Convert all current models to HDF5 format (.h5)"
|
||||
@echo " onnx Convert all eligible current models to ONNX (.onnx)"
|
||||
@echo " reload Reload selected pre-v0.8 models without Lambda layers"
|
||||
@echo ""
|
||||
@echo "Model reloading:"
|
||||
@echo " compare Compare original and v0.8 reloaded models"
|
||||
@echo ""
|
||||
@echo "Packaging:"
|
||||
@echo " packages Build all Zenodo distribution archives"
|
||||
@echo " upload Upload all distribution archives to Zenodo"
|
||||
@echo ""
|
||||
@echo "Cleanup:"
|
||||
@echo " clean Remove all generated files"
|
||||
@echo " clean-reload Remove reloaded model directories"
|
||||
@echo " clean-packages Remove generated package archives"
|
||||
@echo ""
|
||||
@echo "Variables:"
|
||||
@echo " VERSION=$(VERSION)"
|
||||
|
||||
|
||||
# tf (SavedModel format) for training
|
||||
# onnx conversion for fast inference
|
||||
all: tf onnx
|
||||
|
||||
tf-serving: $(CURRENT_MODELS:%=$(MODELS_DST)/%)
|
||||
tf: $(CURRENT_MODELS:%=$(MODELS_DST)/%)
|
||||
keras: $(CURRENT_MODELS:%=$(MODELS_DST)/%.keras)
|
||||
hdf5: $(CURRENT_MODELS:%=$(MODELS_DST)/%.h5)
|
||||
onnx: $(CURRENT_MODELS:%=$(MODELS_DST)/%.onnx)
|
||||
|
||||
# distinguish tf from tf-serving: target pattern is the same,
|
||||
# so check if either is current goal, otherwise assumg tf
|
||||
$(MODELS_DST)/%: FORMAT = $(or $(filter tf-serving,$(MAKECMDGOALS)), tf)
|
||||
$(MODELS_DST)/%: $(MODELS_SRC)/%
|
||||
$(if $(and $(filter tf-serving,$(FORMAT)),$(findstring _ocr,$@)),$(warning skipping $@: OCR CTC decoder fails in TF-Serving) : )\
|
||||
eynollah-training convert \
|
||||
$(and $(wildcard $</config.json),--rebuild) \
|
||||
--in $< \
|
||||
--format $(FORMAT) \
|
||||
--out $@ \
|
||||
> $(notdir $<).$(FORMAT).log 2>&1 || { cat $(notdir $<).$(FORMAT).log; false; }
|
||||
|
||||
$(MODELS_DST)/%.keras: $(MODELS_SRC)/%
|
||||
eynollah-training convert \
|
||||
$(and $(wildcard $</config.json),--rebuild) \
|
||||
--in $< \
|
||||
--format keras \
|
||||
--out $@ \
|
||||
> $(notdir $<).keras.log 2>&1 || { cat $(notdir $<).keras.log; false; }
|
||||
|
||||
$(MODELS_DST)/%.h5: $(MODELS_SRC)/%
|
||||
eynollah-training convert \
|
||||
$(and $(wildcard $</config.json),--rebuild) \
|
||||
--in $< \
|
||||
--format hdf5 \
|
||||
--out $@ \
|
||||
> $(notdir $<).hdf5.log 2>&1 || { cat $(notdir $<).hdf5.log; false; }
|
||||
|
||||
$(MODELS_DST)/%.onnx: $(MODELS_SRC)/%
|
||||
$(if $(findstring _ocr,$@),$(warning skipping $@: OCR CTC decoder is buggy in ONNX) : )\
|
||||
eynollah-training convert \
|
||||
$(and $(wildcard $</config.json),--rebuild) \
|
||||
--in $< \
|
||||
--format onnx \
|
||||
--out $@ \
|
||||
> $(notdir $<).onnx.log 2>&1 || { cat $(notdir $<).onnx.log; false; }
|
||||
|
||||
compare:
|
||||
for i in `find $(MODELS_DST) -mindepth 2`;do \
|
||||
n=$(MODELS_SRC)$${i#$(MODELS_DST)}; \
|
||||
du -bs $$n $$i ; \
|
||||
done
|
||||
|
||||
clean: clean-reload clean-packages
|
||||
|
||||
clean-reload:
|
||||
rm -rf $(RELOADABLE_MODELS)
|
||||
|
||||
clean-packages:
|
||||
rm -rf $(PACKAGES_DIR)
|
||||
|
||||
# NB: this works using symlinks
|
||||
PACKAGES_DIR = packages
|
||||
BUNDLES = inference training
|
||||
CATEGORIES = layout ocr extra all
|
||||
|
||||
packages: $(foreach B,$(BUNDLES),$(foreach C,$(CATEGORIES),$(PACKAGES_DIR)/models_$(B)_$(C)_$(VERSION).zip))
|
||||
|
||||
$(PACKAGES_DIR)/models_%.zip:
|
||||
@mkdir -p $(PACKAGES_DIR) ;\
|
||||
bundle=$(word 1,$(subst _, ,$*)); \
|
||||
category=$(word 2,$(subst _, ,$*)); \
|
||||
echo "Packaging $$bundle/$$category to $(notdir $@)" ;\
|
||||
cd "dist/$$bundle/$$category" && \
|
||||
zip -vqr "$$OLDPWD/$@" models_eynollah
|
||||
|
||||
|
||||
upload: $(foreach B,$(BUNDLES),$(foreach C,$(CATEGORIES),upload/$(B)_$(C)))
|
||||
|
||||
upload/%:
|
||||
@source .env ;\
|
||||
bash scripts/zenodo_upload.sh $$ZENODO_ID $(PACKAGES_DIR)/models_$*_$(VERSION).zip --verbose
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/characters_org.txt
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-binarization_20210309
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-binarization_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-column-classifier_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-enhancement_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-rotation_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-scaling_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions-ensembled_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions_20220314.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-tables_20210319.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/model_eynollah_ocr_cnnrnn_20250930
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_cnnrnn__degraded_20250805
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_trocr_20250919
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/model_eynollah_page_extraction_20250915.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/model_eynollah_reading_order_20250824.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_full_lay_1__4_3_091124.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_table_0t4_201124.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_textline_0_1__2_4_16092024.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-binarization_20210309
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-binarization_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-scaling_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-tables_20210319.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_textline_0_1__2_4_16092024.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-binarization_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-column-classifier_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-enhancement_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-rotation_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-scaling_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions-ensembled_20210425.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions_20220314.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/model_eynollah_page_extraction_20250915.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/model_eynollah_reading_order_20250824.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_full_lay_1__4_3_091124.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_table_0t4_201124.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/modelens_textline_0_1__2_4_16092024.onnx
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/characters_org.txt
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/model_eynollah_ocr_cnnrnn_20250930
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_cnnrnn__degraded_20250805
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_trocr_20250919
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/characters_org.txt
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-binarization-hybrid_20230504
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-binarization_20210309
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-binarization_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-column-classifier_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-enhancement_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions-aug-rotation_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions-aug-scaling_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions-ensembled_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions_20220314
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-tables_20210319
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_cnnrnn_20250930
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_cnnrnn__degraded_20250805
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_trocr_20250919
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_page_extraction_20250915
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_reading_order_20250824
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_full_lay_1__4_3_091124
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_table_0t4_201124
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_textline_0_1__2_4_16092024
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-binarization_20210309
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-binarization_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions-aug-scaling_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-tables_20210319
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_textline_0_1__2_4_16092024
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-column-classifier_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-enhancement_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions-aug-rotation_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions-aug-scaling_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions-ensembled_20210425
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions_20220314
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../reloaded/models_eynollah/model_eynollah_page_extraction_20250915
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_reading_order_20250824
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_full_lay_1__4_3_091124
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_table_0t4_201124
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/modelens_textline_0_1__2_4_16092024
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/characters_org.txt
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../../models_eynollah/model_eynollah_ocr_cnnrnn_20250930
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue