Compare commits

...

934 commits
v0.4.0 ... main

Author SHA1 Message Date
kba
15ddb7750e 📦 v0.9.2 2026-07-28 15:40:46 +02:00
kba
027d6aaa26 📝 changelog 2026-07-28 13:59:53 +02:00
Sai Asish Y
42d383920d return_deskew_slop: pass refined angles, not sigma_des, on landscape main page
Signed-off-by: Sai Asish Y <say.apm35@gmail.com>
2026-07-26 18:29:07 -07:00
kba
88ca39dedb 📦 v0.9.1 2026-07-20 20:08:51 +02:00
kba
b10fb9927d 📝 changelog 2026-07-20 20:07:41 +02:00
kba
17028a2193 require core v3.13.2 for ONNX base image 2026-07-20 19:57:56 +02:00
kba
c94ff96057 📦 v0.9.0 2026-07-20 19:15:54 +02:00
Robert Sachunsky
b0b77ce2c7 📝 changelog 2026-07-20 19:14:42 +02:00
kba
21abde833d Merge branch 'fix-0.8-modelzoo-and-predictor' 2026-07-20 19:12:44 +02:00
Robert Sachunsky
5e3fde31d9 calculate_width_height_by_columns: do allow highest enlargement when confident 2026-07-19 03:22:56 +02:00
Robert Sachunsky
d0a55a1fcb reading order: drop hsep/head elongation mechanism (too many FP) 2026-07-19 03:21:38 +02:00
Robert Sachunsky
4f7c5675fc ocr: ensure forked logging handlers also work under pytest 2026-07-18 18:02:40 +02:00
Robert Sachunsky
79a9bb0128 cnn-rnn-ocr: increase default batch size and VRAM limit 2026-07-18 00:59:57 +02:00
Robert Sachunsky
be8b161607 cnn-rnn-ocr: batch flipped line candidates together with rest 2026-07-18 00:37:19 +02:00
Robert Sachunsky
7e776612a4 cnn-rnn-ocr: if dir_in_bin==dir_in, then split PNG and rest…
(supports common case that binarized images have same stem,
 but different file name extension)
2026-07-18 00:35:50 +02:00
Robert Sachunsky
6840b67961 ocr: run dir_in mode in parallel (like layout), too…
- add CLI options `--num-jobs` and `--halt-fail`
- separate `Eynollah_ocr.run_single()` to be scheduled
- use ProcessPoolExecutor w/ forking and QueueListener
- also skip if input XML file is missing
- log processing times per job and overall
2026-07-18 00:24:08 +02:00
Robert Sachunsky
1c8ac38d31 OCR w/o overwrite: skip one file, not the entire run 2026-07-17 19:19:20 +02:00
Robert Sachunsky
aace571368 cnn-rnn-ocr: fix 2026-07-17 19:15:54 +02:00
Robert Sachunsky
5d129dc8c1 cnn-rnn-ocr: fix typo causing rare failures 2026-07-17 19:02:42 +02:00
Robert Sachunsky
4b9fa543ae processor: fix typo (empty model_overrides) 2026-07-17 16:23:03 +02:00
Robert Sachunsky
5939845d1d utils.contour.make_valid: be more robust (avoiding MultiPolygon) 2026-07-17 15:43:47 +02:00
Robert Sachunsky
c1b276fea1 processor: pass on more Eynollah parameters…
- `device` selection
- `model_overrides` (as dict; including relative path resolution), e.g.
```JSON
{
  "binarization": {
    "":
      "models_inference_layout_v0_9_1/models_eynollah/eynollah-binarization_20210425.onnx"
  }
}
```
- `skip_layout_and_reading_order`
- `num_col_upper`
- `num_col_lower`
- `binarize` (for `input_binary`, which is a misnomer)
2026-07-17 15:37:39 +02:00
Robert Sachunsky
f579d12866 processor: resolve models path as processor resource 2026-07-17 12:56:19 +02:00
Robert Sachunsky
0a9b3097f1 processor: avoid writing XML twice (once by writer, once by OCR-D) 2026-07-17 12:53:13 +02:00
kba
d2755d1e93 update references to new v0_9_1 model release 2026-07-15 20:05:36 +02:00
kba
1440d454cc models: bump version 2026-07-15 17:18:33 +02:00
kba
32c5e9ae76 add missing models, remove microsoft 2026-07-15 17:03:04 +02:00
kba
03915b24a5 models: symlinks for the model packages for zenodo upload 2026-07-15 16:02:49 +02:00
kba
909ccfd38b Merge branch 'fix-0.8-modelzoo-and-predictor' of https://github.com/bertsky/eynollah into fix-0.8-modelzoo-and-predictor 2026-07-15 15:37:11 +02:00
Robert Sachunsky
9804d736ac CI: avoid CUDA dependencies here 2026-07-15 13:59:43 +02:00
Robert Sachunsky
4d97e3bf7f training: fix typos found by ruff 2026-07-15 12:46:33 +02:00
Robert Sachunsky
0ab6e19f33 configure ruff search path 2026-07-15 12:46:13 +02:00
Robert Sachunsky
b89e1b4296 ocrd-tool.json: differentiate inference-all and inference-layout 2026-07-15 04:24:33 +02:00
Robert Sachunsky
25865372d0 dependencies for [OCR]: add TF, avoid newer Torch (pulling CUDA 13) 2026-07-15 04:11:29 +02:00
Robert Sachunsky
efe4aa8b0c mbreorder: fix init (wrong way to load model) 2026-07-15 04:10:47 +02:00
Robert Sachunsky
839d7b9a7e ModelZoo: avoid Azure EP (displacing CPU) 2026-07-15 04:09:33 +02:00
kba
c5713e010e deps: OCR requires explicit dep on tensorflow/keras now 2026-07-14 21:04:06 +02:00
kba
b4165114ea update zenodo links to v0_9_0 models 2026-07-14 21:00:09 +02:00
kba
c43e219858 model packaging/uploading 2026-07-14 20:51:46 +02:00
Robert Sachunsky
83fca95914
Merge pull request #9 from qurator-spk/integrating_trocr_and_torch_ensembling_and_updating_characters_list-refactor
Integrating trocr and torch ensembling and updating characters list refactor
2026-07-14 16:23:12 +02:00
Robert Sachunsky
1591d2091c update docs 2026-07-14 16:22:47 +02:00
Robert Sachunsky
5dc9a3456c Dockerfile: do not install OCR (as Torch and ONNX clash over CUDA) 2026-07-14 15:58:00 +02:00
Robert Sachunsky
12be983487 cnn-rnn-ocr inference: switch back to beam search, only run in TF…
- training.models.CTCDecoder: prefer beam search over greedy
  (because it is more accurate)
- training reload makefile: skip ONNX and TF-Serving conversion
  for cnn-rnn-ocr models (because these would not work)
- training reload makefile: default to onnx and tf conversions
  for all models (tf for training and onnx for inference)
  instead of tf-serving export
2026-07-12 03:49:41 +02:00
Robert Sachunsky
c680dae2d1 ModelZoo for ONNX backend: allow setting execution providers via env 2026-07-10 17:22:50 +02:00
kba
39e054e718 train: remove tf-specifics and weird __getitem__ def from transformer-ocr setup 2026-07-09 19:23:21 +02:00
kba
affddd6c85 train: make preprocess_imgs_ocr work for transformer-ocr 2026-07-09 19:12:09 +02:00
kba
b2f3a8f2d8 Merge branch 'fix-0.8-modelzoo-and-predictor-kba0709' into integrating_trocr_and_torch_ensembling_and_updating_characters_list-refactor
# Conflicts:
#	train/requirements.txt
2026-07-09 17:32:23 +02:00
kba
b1f2f43051 upgrade tf2onnx fork dep, remove spurious tf-data dep 2026-07-09 17:30:48 +02:00
kba
492fcbacb7 switch to fork of tf2onnx 2026-07-09 15:17:11 +02:00
kba
b9ba43b444 training: require tf2onnx and pin ml_dtypes >= 0.5 2026-07-09 14:37:51 +02:00
Robert Sachunsky
c9c14ed83d Docker: update to ONNX base image (in Makefile, too) 2026-07-08 14:04:19 +02:00
Robert Sachunsky
98e28ca9f4 Docker: fixup cuDNN installation after OCR extra 2026-07-08 03:05:07 +02:00
Robert Sachunsky
5354583913 update readme 2026-07-08 02:56:11 +02:00
Robert Sachunsky
8cc8c28471 ModelZoo for ONNX backend: configure TRT cache path from XDG env 2026-07-08 02:55:25 +02:00
Robert Sachunsky
32568a590f Docker: update to ONNX base image 2026-07-08 02:54:34 +02:00
Robert Sachunsky
171a8a3161 move TF+Keras dependencies to training extra, replace by ONNX+TRT 2026-07-07 22:56:36 +02:00
Robert Sachunsky
1567df1379 remove numba dependency (previously used to free CUDA memory) 2026-07-07 22:09:46 +02:00
Robert Sachunsky
16943f70b4 models (ViT backbone) iterate extract_patches over batch dim…
`Patches.call`: use `tf.map_fn` instead of running
entire batch through `tf.image.extract_patches`
(faster, less VRAM, allows ONNX conversion to work)
2026-07-02 20:58:22 +02:00
Robert Sachunsky
1b27c7390f training.convert/ONNX: run strict shape inference and check model 2026-07-02 20:56:55 +02:00
Robert Sachunsky
5e531ab006 get_textlines_of_textregion_sorted: fix be61875 2026-07-01 18:27:46 +02:00
Robert Sachunsky
01e69a0e22 predictor for OCR models: work around ONNX bug …
(ONNX converted models already return `np.dtype=object`
 arrays of `np.str_` instead of `np.bytes_`; so undo this)
2026-06-26 02:42:51 +02:00
Robert Sachunsky
948d841a7d training.models for cnn-rnn-ocr: make ONNX convertible…
- `training.models.CTCDecoder`: switch back
  from `tf.nn.ctc_beam_search_decoder()`
  to `tf.nn.ctc_greedy_decoder()`
  (because ONNX only implements `CTCGreedyDecoder`)
- `training.models.cnn_rnn_ocr_model(inference=True)` and
  `training.models.cnn_rnn_ocr_model4inference`:
  drop layer `tf.io.decode_raw()`
  (because ONNX does not implement `DecodePaddedRaw`)
- `Eynollah_ocr.run_cnn()`: expect bytes arrays from predictor
  instead of uint8
- `predictor`: to prevent segfaults when sending `tf.string` results
  via `shared_memory`, convert `np.object` to `np.bytes_` directly
2026-06-26 02:21:47 +02:00
Robert Sachunsky
45168178dc ModelZoo ONNX backend: log configured top provider (backend) 2026-06-26 02:13:39 +02:00
Robert Sachunsky
ef47f0ef09 training convert: only add characters_org.txt if it exists 2026-06-26 02:11:59 +02:00
Robert Sachunsky
42a3751e63 ModelZoo ONNX: avoid verbose logging 2026-06-19 22:01:39 +02:00
Robert Sachunsky
0bfbbfdc80 training.metrics: allow module init without TFA 2026-06-19 22:01:02 +02:00
Robert Sachunsky
eb4cae9dee training.models for cnn-rnn-ocr: avoid Conv1D(..channels_first..) 2026-06-16 17:28:10 +02:00
Robert Sachunsky
dfa651ef8a predictor: show full stacktrace before passing the exception over 2026-06-12 22:21:06 +02:00
vahidrezanezhad
89ce9de6fa musicregion is added to pagexml to label 2026-06-12 18:00:03 +02:00
vahidrezanezhad
303bdfe0e7 Amiri font which works for both arabic and latin 2026-06-12 18:00:03 +02:00
vahidrezanezhad
d2123a2746 FIXME: get label for decoration without type attribute 2026-06-12 18:00:03 +02:00
vahidrezanezhad
499e3d0715 trocr inference is integrated - works on CPU cause seg fault on GPU 2026-06-12 18:00:03 +02:00
vahidrezanezhad
a11c833fc1 bug fix: layout visualization 2026-06-12 18:00:03 +02:00
vahidrezanezhad
d0b3bb419f extracting ocr textline images and text: vertical lines threshold has changed to 1.4 2026-06-12 17:58:09 +02:00
vahidrezanezhad
4776ea9fc4 torch model ensembling is integrated 2026-06-12 17:58:09 +02:00
vahidrezanezhad
aba0138216 generate or update list of characters in the case of cnn-rnn ocr training 2026-06-12 17:58:09 +02:00
vahidrezanezhad
7f86a55ccb integrating transformer ocr 2026-06-12 17:58:07 +02:00
Robert Sachunsky
e9839a8b54 makefile to reload models: avoid ONNX conversion for cnn-rnn-ocr too 2026-06-12 15:00:36 +02:00
Robert Sachunsky
19504cb932 makefile to reload models: add target for SavedModel Keras format 2026-06-12 14:59:38 +02:00
Robert Sachunsky
60c9f4786c ModelZoo device selection: warn if model category still unmatched…
(and try GPU)
2026-06-12 14:58:32 +02:00
Robert Sachunsky
94082bc64a ModelZoo TF-Serving backend: deal with buggy .inputs signature…
work around TF bug that adds captured/unknown inputs to function signature
2026-06-12 14:56:44 +02:00
Robert Sachunsky
45c92eada2 models w/ multiple inputs yield a tuple for .input_shape 2026-06-12 14:55:46 +02:00
Robert Sachunsky
08946067ac ModelZoo ONNX backend: handle multiple inputs, too 2026-06-12 14:54:51 +02:00
Robert Sachunsky
9d2412080f training.models for cnn-rnn-ocr: fix config names for height/width…
- rename `image_height` → `input_height`
- rename `image_width` → `input_width`
2026-06-12 14:52:23 +02:00
Robert Sachunsky
4181e03bc9 training convert --rebuild for cnn-rnn-ocr: override charset file…
when rebuilding the inference model for cnn-rnn-ocr,
- open the old `characters_org.txt` file for the charset
- use it to pass the actual `n_classes` (overriding the config)
- use its path to pass the `characters_txt_file` (overriding the config)
2026-06-12 14:48:47 +02:00
Robert Sachunsky
348ac95ad3 Eynollah_ocr: drop fixed input sizes…
- tr-ocr: no need to resize images in advance (done by model, anyway)
- cnn-rnn-ocr: get model size from model's input shape
2026-06-03 20:59:00 +02:00
Robert Sachunsky
24c7d4c277 update trocr smoke test, add cnnrnn ocr smoke test 2026-06-03 20:58:05 +02:00
Robert Sachunsky
27ca9733db ModelZoo ONNX backend for inference: support multi-input or -output 2026-06-03 20:57:02 +02:00
Robert Sachunsky
38fe4d33ad Predictor for multi-input models: present as list instead of tuple…
(because TF-Serving expects that and cannot cast)
2026-06-03 20:56:00 +02:00
Robert Sachunsky
4e7e1c06b9 trocr viarant for Predictor runtime: no model size for input_shape…
Because transformers v4 and v5 API for image preprocessor differs,
and the model-internal image input sizes are actually irrelevant,
because the preprocessor will resize them anyway, and there is no
batch dimension (because the input images will have different shapes),
do not advertise this information in `.input_shape`.
2026-06-03 20:51:56 +02:00
Robert Sachunsky
f447a9f248 trocr: move preprocessor and decoder into model object, too…
- ModelZoo: drop `trocr_processor` model type
- `ModelZoo.load_models()`: use Predictor for `ocr_tr` models, too
- `ModelZoo.load_model()`: for `ocr_tr`, load processor and model,
  then define a function object as stand-in for the common model
  interface based on Keras (w/ `.predict_on_batch()`)
- Predictor: allow multi-input without actual batch dimension
  for `ocr_tr` models (because the model takes a list of original
  image arrays and resizes them to model shape internally)
- Eynollah_ocr: adapt (replacing preprocessing, prediction and
  decoding steps by a single `.predict()` call)
2026-06-03 03:41:44 +02:00
Robert Sachunsky
d2f2a1e06b Eynollah_ocr: correctly handle min_conf, improve writer…
- `min_conf_value_of_textline_text`: apply by skipping
  lines below threshold (instead of writing empty text),
  and delete their TextEquiv (if existing)
- `write_ocr()`: simplify, and ensure consistency between
  line and region level text correctly
2026-06-03 00:43:46 +02:00
Robert Sachunsky
8ffc4ed8d3 Eynollah_ocr: adapt to inference model, improve and simplify…
- drop `end_character` mechanics and `characters` model type
  for decoding output probability (not needed)
- drop `decode_batch_predictions()` and `num_to_char` model type
  (part of inference model)
- drop roughshot confidence estimation calculation
  (returned precisely by inference model)
- adapt model prediction to inference model: just omit zeros,
  map to bytes, filter OOV tokens and decode UTF-8 to str
- if no binarization input was provided, then compute it on the fly
  using `binarization` model
- also apply `min_conf_value_of_textline_text` (as for TrOCR)
- batching over entire page instead of region-wise
  (which underfilled batches)
- simplify and avoid copied redundant code
- rename `extracted_conf_value_merged` → `extracted_confs_merged`
- move `batched()` from `utils.utils_ocr` to `utils`
- drop `utils_ocr.distortion_free_resize()` (not needed)
- simplify `utils_ocr.break_curved_line_into_small_pieces_and_then_merge()`
- drop `utils_ocr.return_textline_contour_with_added_box_coordinate()`
  and `utils_ocr.return_rnn_cnn_ocr_of_given_textlines()` (not needed)
2026-06-02 21:20:06 +02:00
Robert Sachunsky
a391ee24e6 Predictor: handle multi-input and/or multi-output cases 2026-06-02 21:18:22 +02:00
Robert Sachunsky
c79b73dcc8 cnn-rnn-ocr: move CTC decoder and string decoder to inference model…
- ModelZoo: drop `num_to_char` and `characters` model types,
  also drop `_load_characters()` and `_load_num_to_char()` loaders
- `ModelZoo.load_models()`: use Predictor for `ocr` models, too
- `ModelZoo.load_model()`: delegate runtime/inference conversion of
  OCR models to `eynollah.training.models.cnn_rnn_ocr_model4inference`
- `training.models`: add (purely functional) Keras layer `CTCDecoder`
  for inference on top of softmax output, but using TF backend
  function instead of (broken) `Keras.backend.ctc_decode()`, while
  switching to beam search (instead of greedy) and also returning
  decoded path probability
- `training.models.cnn_rnn_ocr_model()` w/ `inference=True`:
  * add kwarg `characters_txt_file` for file path of character set
  * configure secondary tensor path on OCR graph for binarized input
    (additional input `image_bin`, averaging softmax outputs)
  * use new `CTCDecoder` layer and inverse `StringLookup` layer to
    decode from softmax output to tf.string; so inference models
    now have 2 inputs (RGB, binarized) and 2 outputs (text, prob)
  * since `np.dtype=object` cannot be handled by SharedMemory (as
    needed by Predictor queues), also replace tf.string by tf.uint8
    arrays
  * use this for `training convert` for OCR models w/ `--rebuild`
- `training.models.cnn_rnn_ocr_model4inference`:
  * new function which does the same but loads an existing OCR model
    in training configuration (i.e. without prior `inference=True`)
  * use this for `training convert` for OCR models w/o `--rebuild`
2026-06-02 20:26:42 +02:00
Robert Sachunsky
13f2f81c45 ModelZoo: support inference with ONNX/TensorRT…
- comment out ad-hoc conversion/loading of autosized models
- refactor predictor backends for model types into separate functions
- only attempt inference conversion of cnn-rnn-ocr model
  if applicable (`ctc_loss` layer still present)
- apply VRAM limits across model types
  (Keras, TF-Serving, ONNX)
- apply TF device selection across model types
  (Keras, TF-Serving)
- implement predictor backend for ONNX models:
  - using onnxruntime
  - covering CUDA and TensorRT providers
  - trying to support manual device selection
  - hiding session management details
  - converting float32 to float16
2026-05-28 18:08:08 +02:00
Robert Sachunsky
f833a516e7 training: add CLI command convert
- move `train_cli` from cli.py to train.py,
  add docstring
- add `convert_cli`:
  - load any (supported) model format
    (i.e. not exported TF-Serving or ONNX)
  - if SavedModel format with `config.json` present,
    and `--rebuild` is requested, create new model
    from `models.get_model()` for this configuration,
    and load weights
  - if model type is `cnn-rnn-ocr` and configuration
    is still for training (`ctc_loss`), then extract
    inference model
  - apply requested `--format` conversion:
    HDF5, Keras native, Keras SavedModel, TF-Serving SavedModel
    or ONNX
  - if output format is directory (i.e. SavedModel),
    then copy over `config.json`, too
- reload-models-v0.8.mk:
  - adapt recipe for converter CLI (i.e. `--format tf-serving`
    w/ `--rebuild` if possible)
  - add targets for other useful data formats
  - extend list of model names to all current models
    (as all benefit from TF-Serving export)
  - cancel ONNX conversion for vision transformer models
    (as these do not work, yet)
2026-05-28 17:48:21 +02:00
Robert Sachunsky
62b55a3809 train params: drop reload_weights, re-use dir_of_start_model
- drop ad-hoc configuration parameter `reload_weights`
  (used for conversion/export of models for inference,
   to be replaced by extra CLI)
- re-interprete `dir_of_start_model` to also load weights
  if not `continue_training`
2026-05-28 17:42:55 +02:00
Robert Sachunsky
093030f503 train/models: move all model builders to models.get_model()
- models: add new `get_model()`, passing in Sacred config
  to capture builder function arguments
- train: fewer imports
- train: no need to pass `custom_objects` if loading with
  `compile=False` (and we custom-compile later, anyway)
2026-05-28 17:37:45 +02:00
Robert Sachunsky
faef1967f8 models.cnn_rnn_ocr_model: add inference option, drop model name 2026-05-28 17:33:57 +02:00
Clemens Neudecker
2e3f45c300
Merge pull request #220 from dokempf/remove-vim-swap-file
Remove accidentally committed vim swap file
2026-05-28 11:41:21 +02:00
Dominic Kempf
e17712eacd Remove accidentally committed vim swap file 2026-05-28 11:27:41 +02:00
Robert Sachunsky
c4a7eec5b3 models: cosmetics
- using `Reshape`, do not pass `target_shape` as kwarg
- add a default `name` for `Patches` and `PatchEncoder`
2026-05-27 01:58:21 +02:00
Robert Sachunsky
9801129aa6 estimate_skew_contours: ensure retval is always float 2026-05-22 12:37:07 +02:00
Robert Sachunsky
26afc5ddab ModelZoo: ensure exported TensorShape is converted to plain tuple 2026-05-22 12:35:44 +02:00
Robert Sachunsky
0836230c6b utils_ocr: avoid module-level import of TF 2026-05-21 22:50:53 +02:00
Robert Sachunsky
f3a93983c0 ModelZoo: add ocr key for memory_limit 2026-05-21 22:50:13 +02:00
Robert Sachunsky
ea41dcae1d trocr: use beam search instead of greedy decoding 2026-05-21 17:52:27 +02:00
Robert Sachunsky
074753a98e ModelZoo: fix Torch device selection 2026-05-21 17:25:53 +02:00
Robert Sachunsky
000e4ac8d8 trocr: extract confidence, too 2026-05-21 17:25:39 +02:00
Robert Sachunsky
f3649adbf2 trocr: apply do_not_mask_with_textline_contour here, too 2026-05-21 17:23:11 +02:00
Robert Sachunsky
1d67e65f11 trocr: simplify, batch over entire page…
- batching over entire page instead of region-wise
  (underfilling batches)
- avoid copied redundant code
2026-05-21 15:48:21 +02:00
Robert Sachunsky
d50bd7c650 trocr: avoid warnings by passing clean_up_tokenization_spaces=False 2026-05-21 14:20:51 +02:00
Robert Sachunsky
f9f9130dbb do_order_of_regions: remove redundant+overcautious assertion 2026-05-21 03:21:36 +02:00
Robert Sachunsky
bf7ec0233d ModelZoo.load_model: use memory_limit instead of memory_growth
- growth strategy is more flexible, but uses much more VRAM
- limit strategy needs to be calibrated to models (currently fixed),
  and batch size, but needs much less VRAM and is faster
2026-05-21 02:43:34 +02:00
Robert Sachunsky
94a5e9da14 ModelZoo.load_model: avoid attempting to load exported models as Keras
models (which causes a warning), but switch to TF-Serving import right away
2026-05-21 02:41:19 +02:00
Robert Sachunsky
7f2bf715df ModelZoo.load_model: fix loading exported vs saved models 2026-05-21 02:39:59 +02:00
Robert Sachunsky
3de1407d18 drop unnecessary TF / Torch imports 2026-05-21 02:38:20 +02:00
Robert Sachunsky
bdfebd2c70 reload_weights: save()export() w/ serve() inference 2026-05-19 03:40:18 +02:00
Robert Sachunsky
86adaf299a training.models.transformer_block: tf.reshape → Keras Reshape layer 2026-05-19 03:40:16 +02:00
Robert Sachunsky
9efce5e9f2 Predictor.shutdown: use join() instead of terminate() 2026-05-19 03:40:07 +02:00
Robert Sachunsky
ffe5cdc519 ModelZoo.shutdown: drop extra del (already done by shutdown()) 2026-05-19 03:40:05 +02:00
Robert Sachunsky
481c286da9 ModelZoo.load_model: no XLA compilation 2026-05-19 03:40:05 +02:00
Robert Sachunsky
f329e10a80 test_layout: rm ignored --allow_scaling option 2026-05-19 03:40:04 +02:00
Robert Sachunsky
17b311441a model_zoo: also parse comma/colon syntax for device in Torch case 2026-05-19 03:40:03 +02:00
Robert Sachunsky
be4fe8c263 contour: drop unused functions depending on rotation_image_new() 2026-05-19 03:40:02 +02:00
Robert Sachunsky
87cce6c963 CLI tests: add opt-in envvar EYNOLLAH_OPTIONS for device selection,
model directory etc.
2026-05-19 03:40:01 +02:00
Robert Sachunsky
1ed633bc25 test_model_zoo: adapt (load_models instead of load_model) 2026-05-19 03:40:00 +02:00
Robert Sachunsky
21ecb043f7 CLIs: move --device option to group level 2026-05-19 03:39:59 +02:00
Robert Sachunsky
7ed1a1ebac CLIs: allow -h and show defaults uniformly, harmonise help, drop
remaining redundant negative options
2026-05-19 03:39:56 +02:00
Robert Sachunsky
cd62f13872 eynollah_ocr: make work again, re-use Eynollah base class…
- re-use Eynollah base class
- use `ModelZoo.load_models()` instead of `load_model()`
- pass in `device` init kwarg, delegate to `ModelZoo.load_models()`
- `device`: return Torch device at loaded model tensors
  instead of ad-hoc selection
- make numeric init kwargs non-optional (only numeric)
2026-05-19 03:39:55 +02:00
Robert Sachunsky
ded668a256 model_zoo: fix clash between Predictor and direct (OCR) use-cases…
- `load_models()`: uniformly handle arg types
- `load_model()`: move handling of non-model categories
  to `load_models()`
- `load_model()`: move SavedModel preference over HDF5 to `model_path()`
- `_load_ocr_model()`: add user-selected device handling and reporting
  for Torch (as for TF)
- `_load_ocr_model()`: move (TF-based) CNN-RNN case to `load_model()`
  (including Keras layer mapping)
- `shutdown()`: only apply `shutdown()` to Predictor model types
2026-05-19 03:39:53 +02:00
Robert Sachunsky
98e6fbbcbb mbreorder: make work again, re-use Eynollah base class 2026-05-19 03:39:52 +02:00
Robert Sachunsky
7e8b9311d3 Revert "test_model_zoo: fix calls"
This reverts commit 5a98f55be3.
2026-05-19 03:32:37 +02:00
Robert Sachunsky
a1449da1d1 Revert "fix model loading in mb_ro and ocr"
This reverts commit 218a95e6a0.
2026-05-19 03:32:19 +02:00
kba
1df32eba87 CD: base docker image: typo {,v}3.13.0 2026-05-11 13:41:30 +02:00
kba
d7337a3080 CD: base docker image on versioned ocrd/core-cuda-tf2:v3.13.0 2026-05-11 13:38:36 +02:00
kba
e612db2bb1 📦 v0.8.0 2026-05-11 13:16:30 +02:00
kba
6cfbd93ac7 📝 changelog 2026-05-11 13:14:56 +02:00
kba
c7104c2852 Merge branch 'prepare-release-v0.8.0' 2026-05-11 13:12:19 +02:00
kba
5a98f55be3 test_model_zoo: fix calls 2026-05-11 12:22:24 +02:00
kba
218a95e6a0 fix model loading in mb_ro and ocr 2026-05-11 12:19:20 +02:00
kba
2035b07b55 Merge remote-tracking branch 'bertsky/ro-fixes-final' into prepare-release-v0.8.0
# Conflicts:
#	requirements-ocr.txt
2026-05-11 09:46:17 +02:00
Robert Sachunsky
db87aa995d reqs for OCR: relax ad5f2272 (depending on Python version) 2026-05-11 03:15:54 +02:00
Robert Sachunsky
e183937c5d separate_lines_new2: fix coord overflow by clipping, simplify…
- found positive and negative peaks, and even more so their
  relative offsets, may overflow in the cropped image,
  causing fake textlines; avoid that by clipping to the valid
  y coordinates
- calculation for number of tiles: sometimes one less
  tile is needed by making the previous last tile
  half-full on the right side
- add some (commented) plotting
- simplify (a lot, but only partially)
2026-05-11 03:09:02 +02:00
Robert Sachunsky
130f0aee42 do_work_of_slopes_curved: improve on d257869d
- relative images now need larger relative min_area
  (i.e. compensation factors)
- do not attempt (even) single-line skew estimation
  (via linear regression) if there is no (large enough)
  contour at all
- avoid re-computing `mask_parent`
- add some (commented) plotting
2026-05-11 03:03:04 +02:00
kba
ce5d6bc43c try to accomodate outdaten Python versions unsupported by current transformers 2026-05-09 18:03:40 +02:00
kba
03f3f9af17 update model zoo and docs to link to v0_8_0 model release on zenodo 2026-05-09 17:58:59 +02:00
Robert Sachunsky
a61fb09ec5 CI: drop py3.8 (u/a for new req transformers >= 5) 2026-05-09 04:14:49 +02:00
Robert Sachunsky
4406a0299e update CLI test for binarization…
- update expected log messages
2026-05-09 04:12:19 +02:00
Robert Sachunsky
4cd398bd0d standalone binarization: update, simplify…
- re-use Eynollah base class, drop copied code
- simplify `run()` and `run_single()`
- delegate to `do_prediction()`
  instead of custom (old) tiling loop
- drop `predict()`
- add `--device` option to CLI as well
2026-05-09 04:12:02 +02:00
Robert Sachunsky
29abae0144 update CLI test for enhancer…
- update expected log messages
- force `-ncu 3`, because otherwise
  the example images would not be deemed
  in need of enhancement
2026-05-09 02:59:52 +02:00
Robert Sachunsky
c1b6a61301 standalone enhancer: make this work (at all)…
- re-use Eynollah base class, drop copied code
- write usable `run()` and `run_single()`
- delegate to `resize_image_with_column_classifier()`
  for column classifier, resizing and enhancement,
  instead of `resize_and_enhance_image_with_column_classifier()`
  (which does _not_ actually enhance)
- drop unused `predict_enhancement()`
- add defaults to `num_col` options (always numeric)
- add `--device` option to CLI as well
2026-05-09 02:55:01 +02:00
Robert Sachunsky
d63ce5538c resize_image_with_column_classifier(): apply num_col bounds here too
use rules from `resize_and_enhance_image_with_column_classifier()`
and apply them to `resize_image_with_column_classifier()` as well

(to be used by enhancer CLI)
2026-05-09 02:53:04 +02:00
Robert Sachunsky
6df2144c0f fix 2 typos in previous commits…
- becf031c65
- cefe596f8b
2026-05-09 02:31:22 +02:00
Robert Sachunsky
daf0c90d6e
Merge pull request #8 from bertsky/ro-fixes-training-reload
training: reload models
2026-05-08 18:46:43 +02:00
Robert Sachunsky
395decd6d6
Merge pull request #7 from qurator-spk/ro-fixes-training-reload-additions
Ro fixes training reload additions
2026-05-08 18:45:28 +02:00
Robert Sachunsky
3a9d72d3fc
Merge pull request #6 from qurator-spk/update-cd
Deploy versioned docker images and update transformers
2026-05-08 18:44:49 +02:00
Robert Sachunsky
ea8f985ff1 apply cropping only after textline and early layout…
(because old models seem to fare better that way,
 despite training documentation)
2026-05-08 18:41:47 +02:00
Robert Sachunsky
58afdf5e87 do_prediction*(): ensure always returns dtype=uint8 2026-05-08 17:36:31 +02:00
Robert Sachunsky
68a26a5c3f do_prediction*(): smooth window transitions with sigmoid…
instead of hard cut-offs between overlapping window tiles,
apply sigmoid attenuation to slide from one to the next

(apply all postprocessing in the end)
2026-05-08 05:18:00 +02:00
Robert Sachunsky
cefe596f8b do_prediction*(): avoid unnecessary tiles, simplify…
- calculation for number of tiles: sometimes one less
  tile is needed by making the previous last tile
  half-full on the right side
- calculation of window margins: fix case if dimension
  extends to full image shape
- simplify (identifiers, slicing etc)
2026-05-08 00:55:18 +02:00
kba
a0bf1b51f4 makefile to reload models 2026-05-07 19:30:29 +02:00
kba
34a9d458ce training deps: use sacred fork w/o pkg_resources, pin tf/tf_keras, protobuf packages to work with tensorflow_addons 2026-05-07 18:09:27 +02:00
kba
2747385f89 remove unused deprecating-warning-causing biopyton dependency 2026-05-07 17:15:15 +02:00
Robert Sachunsky
d8c83d6137 make_valid(): avoid oversimplification, improve parameter search 2026-05-05 15:00:16 +02:00
Robert Sachunsky
45868e99cd get_slopes_and_deskew_new_light2: ignore tiny contour areas 2026-05-04 15:55:00 +02:00
Robert Sachunsky
934ac90e92 get_slopes_and_deskew_new_light2: avoid +/- 90° cancellation…
in `estimate_skew_contours()`, distinguish between angle stats
scattering around <45° vs >45°: in the latter case, use modulo
180° for averages - to avoid cancelling out +90° with -90°
2026-05-04 15:52:07 +02:00
Robert Sachunsky
29bb55ceff return_deskew_slop: no >90° search unless for full page, simplify 2026-05-01 00:27:00 +02:00
Robert Sachunsky
d7a3f4cec6 training: add cfg param reload_weights for building but loading…
- introduce `config_params` key `reload_weights`
- add respective section for all model types:
  - build fresh model from code
  - load existing weights from `dir_of_start_model`
  - save to `dir_output` under same basename as existing model
    (but without optimizer and metrics; which does not work currently)
  - exit immediately (i.e. no actual training)
- reorder so reload_weights is after compilation but before data loading
2026-04-30 16:54:26 +02:00
Robert Sachunsky
cbb3be0e01 add diagnostic plotting for prediction masking (commented) 2026-04-30 16:12:00 +02:00
Robert Sachunsky
33c055389d bold run_single refactoring (predict segmentation on cropped img)…
- move `extract_page()` to the start (right after enhancement),
  so early layout and textline model prediction sees cropped
  image
- `extract_page()`: also return page mask
- `get_early_layout()`:
  * use cropped image
  * also run optional table prediction here,
    map table label and confidence already
    (so no need to pass these arrays everywhere)
  * suppress all non-text type regions in textline mask
  * also return text+table mask
    (so no need to reconstruct it everywhere)
- apply page mask to textline mask and early layout result
  (i.e. suppress areas beyond border contour)
- `run_graphics_and_columns()`:
  * rename → `run_columns()`
  * no table prediction here
  * no page extraction here
  * no page cropping+masking here
  * no textline mask suppression here
- `run_graphics_and_columns_without_layout()`: drop
  (not needed anymore)
- `run_marginals()` vs. `get_marginals()`: extract
  `text_mask` internally from early layout
- early page cropping for col-classifier:
  also use cropped image in input binarization mode
- early page cropping for col-classifier:
  get external contours instead of indiscriminate tree
- writer: skip layout mode now also uses cropped coordinates
  (so drop kwarg for it)
2026-04-30 16:12:00 +02:00
Robert Sachunsky
7e7cc6a801 do_order_of_regions(): use region mask instead of textline mask…
for local (within-box) ordering of region contours, use the same
text mask (merely eroded) as for the contour extraction itself:
the text+table+drop mask from early+full layout prediction,
rather than the textline mask, because the latter may be empty
in some boxes and is unlikely to be more useful than the region
mask itself
2026-04-30 16:11:59 +02:00
Robert Sachunsky
63df9be4db find_number_of_columns_in_document(): pass in (reuse) masks 2026-04-30 16:11:59 +02:00
Robert Sachunsky
da9e00cfe5 consistently handle textline mask with respect to drop-capital mask…
- suppress drop-capital in textline mask for textline contours
- elevate drop-capital in textline mask for reading order boxes
2026-04-30 16:11:59 +02:00
Robert Sachunsky
2641171fb1 return_boxes_...order_of_reading...: avoid negative slices…
fix rare bug when horizontal separators are detected
by the very top (of a major vertical part of the page),
causing box intervals to become negative
2026-04-30 16:11:59 +02:00
Robert Sachunsky
6a92f0d49c make get_deskewed_masks() unconditional, call only when needed 2026-04-30 16:11:59 +02:00
Robert Sachunsky
52eb4c9a0a move label definition and deskewing cancellation up 2026-04-30 16:11:59 +02:00
Robert Sachunsky
fa882e1dbe move run_boxes_order() call to RO section of run_single() 2026-04-30 16:11:59 +02:00
Robert Sachunsky
d88bd485ff get_slopes*(): does not need passing boxes separately 2026-04-30 16:11:59 +02:00
Robert Sachunsky
869646cbf5 get_full_layout() does not need the textline mask 2026-04-30 16:11:59 +02:00
Robert Sachunsky
b5bc161a4c extract_page(): get external contours instead of indiscriminate tree 2026-04-30 16:11:59 +02:00
Robert Sachunsky
287bebde0d get_marginals(): fix height factor for mask resizing 2026-04-30 16:11:59 +02:00
Robert Sachunsky
a031d590b8 get_marginals(): do allow both left and right point (f/u 4bdea39)…
(as there are valid cases where both left and right marginalia
 is present) follow-up 4bdea39 by re-allowing left point _and_
right point - but still score-based, and not if very asymmetric
2026-04-30 16:11:59 +02:00
Robert Sachunsky
9571ce3474 get_marginals(): reduce indentation 2026-04-30 16:11:52 +02:00
Robert Sachunsky
c18deb0722 drop relabelling all marginalia to main if no main (now unnecessary) 2026-04-30 16:09:03 +02:00
Robert Sachunsky
1f6db34adf run/get_marginals(): simplify and speed up…
- `get_marginals` modifies region labels in-place anyways,
  so no need for retval
- de/rotate only inside `get_marginals` (for consistency)
- return early if no marginals detected
- `run_marginals`: only useful in 1 or 2 columns, so keep to
  that conditional branch; allows avoiding unnecessary resizing
  of images to and fro
- rename `text_regions_p_1` → `text_regions_p`
2026-04-30 16:09:03 +02:00
Robert Sachunsky
45a43f7e5e get_marginals(): fixup point_right fallback 2026-04-30 16:08:15 +02:00
kba
0b8d8a7330 docker: core to 3.12.3 2026-04-29 17:20:36 +02:00
kba
ad5f22726e 🔥 require transformers >= 5 2026-04-29 17:06:13 +02:00
kba
f58189d5f4 ci: tag eynollah docker image with git tag version if possible, else latest 2026-04-29 16:34:06 +02:00
Robert Sachunsky
68ceeec764 get_marginals(): improve contour assignment…
- use undeskewed mask for contour comparisons
  instead of deskewed mask (less precise)
- rename `text_with_lines` → `text_mask_d`
- rename `mask_marginals` → `main_mask_d`
- rename `text_regions` → `early_layout`
- rename `...textline...` → `...text...`
2026-04-25 03:06:34 +02:00
Robert Sachunsky
6d55d0b87b get_marginals(): improve peak point threshold criterion…
in search of valid peaks (gaps between text columns),
- drop absolute values for minimum gap depth
  (likely crafted for some fixed resolution examples)
- instead, use criterion relative to maximum column depth
  and page height (trying to loosely approximate the prior
  constants, albeit somewhat more permissive)
2026-04-25 02:23:16 +02:00
Robert Sachunsky
4bdea39c98 get_marginals(): improve left/right point selection…
in search of valid (above threshold) peaks:
- do not just pick right-most left and left-most right span;
- instead,
  * if no peaks on the left, then only search right
  * if no peaks on the right, then only search left
  * if peaks on both sides, then only better side
    (so never return marginals on both sides!)
  * use scoring for peaks that reflects their peak
    prominence and peak height (but keep positional
    range constraints for what constitues left and right)
2026-04-25 01:59:48 +02:00
Robert Sachunsky
70bf461c30 get_marginals(): simplify, improve…
- rename `thickness_along_y_percent` →
  `max_textline_thickness_percent`
- rename `marginlas_should_be_main_text` →
  `main_text_should_be_marginals`
- constrain `find_peaks()` by prominence and distance
- simplify (a lot)
- add comments for possible improvements
  and for plotting
2026-04-25 01:52:21 +02:00
Robert Sachunsky
bb092364af get_slopes_and_deskew_new_light2: estimate slopes here, too…
extract slopes from minimal bounding rectangles of textlines,
using heuristics on aspect ratios, lengths and angles
2026-04-24 15:27:29 +02:00
Robert Sachunsky
c478c03db4 avoid deskewed contour matching w/ -romb 2026-04-24 15:27:29 +02:00
Robert Sachunsky
998ee2ecee get_textlines_of_a_textregion_sorted: simplify 2026-04-24 15:27:29 +02:00
Robert Sachunsky
be61875d6e get_textlines_of_a_textregion_sorted: w-h instead of w/h test 2026-04-24 15:27:29 +02:00
Robert Sachunsky
9723dfeb73 writer: also annotate col-classifier result…
both notations:
- in `/PcGts/Page/@custom` (CSS-style)
- in `/PcGts/Metadata/Comment` (qurator-style)
2026-04-24 15:27:29 +02:00
Robert Sachunsky
e3720d6623 writer: also annotate page-level deskewing result 2026-04-24 15:27:29 +02:00
Robert Sachunsky
2da718f76f writer, do_work_of_slopes*: drop passing bboxes around
(needed no more)
2026-04-24 15:27:29 +02:00
Robert Sachunsky
b792324c5b do_work_of_slopes_new_curved (if angle >45°): simplify, improve…
- use new `rotate_image_enlarge` instead of
  custom (insufficient) padding w/ `rotate_image`
- get external contours instead of tree
  (without checking hierarchy afterwards)
- use largest textline contours by area instead of
  longest polygon path
- always use `separate_lines` (but without its incorrect
  angle/offset calculations) instead of `separate_lines_vertical_cont`
- calculate coordinate transformation (shift, angle)
  for all cases (including >45°)
- simplify
2026-04-24 15:27:29 +02:00
Robert Sachunsky
dbdb6d0d53 rotate: rm unused failed variants, add new rotate_image_enlarge
(correct version that enlarges canvas instead of clipping corners,
 using only OpenCV)
2026-04-24 15:27:29 +02:00
Robert Sachunsky
d257869d83 do_work_of_slopes_new_curved (if angle <45°): simplify, improve…
- use relative images, cropped to parent bbox (faster)
- no `scale` parameter (unused)
- use largest textline contours by area instead of first
- simplify
2026-04-24 15:27:29 +02:00
Robert Sachunsky
0dce1f24d2 do_work_of_slopes_new_curved: improve deskewing…
- return early if textline mask is empty
- intersect textline mask with parent mask
  (so neighbouring, truncated textlines
   will not interfere)
- fix bug when resulting angle is small:
  rather, compare with page angle
- if there is more than 1 line in the region,
  * use median instead of mean to estimate y_diff
  * if height dominates over width and x_diff
    over y_diff, then assume 90°: transpose image,
    deskew on that, then add 90° to result
- otherwise instead of just using page angle,
  try to estimate single-line angle by approximating
  slope of linear x-y regression on mask image;
  again, if height dominates over width, then
  assume +90° and use transposed image
- drop unused `scale` param
2026-04-24 15:27:29 +02:00
Robert Sachunsky
97d9b0ea50 small_textlines_to_parent_adherence2: simplify, improve…
- when merging large line with small lines,
  don't use first new contour but largest
- get external contours instead of tree
  (without checking hierarchy afterwards)
- simplify
2026-04-24 15:27:29 +02:00
Robert Sachunsky
0735cb9d2b filter_contours_without_textline_inside: also filter slopes 2026-04-24 15:27:29 +02:00
Robert Sachunsky
fa8340dbb4 -cl: also filter textregions without textlines here 2026-04-24 15:27:29 +02:00
Robert Sachunsky
4a6d3968f9 major run_single refactoring…
- rename `get_regions()` → `get_early_layout()`
- split up `run_boxes_no/full_layout()` into shared
  * `get_full_layout()` (for lapping mapping,
    table decoding and optional full model prediction)
  * `get_deskewed_masks()` (for de-rotation)
  * extraction of various region types (polygons and confidences)
  * `run_boxes_order()` (for column detection and box ordering)
- rename `contours_tables` → `polygons_of_tables`

This further reduces redundant code, avoids splitting up the same
functionality across different places depending on mode etc.
2026-04-24 15:27:29 +02:00
Robert Sachunsky
dfb40f4a49 hsep fusion: avoid zero division if zero overlap 2026-04-24 15:27:29 +02:00
Robert Sachunsky
b63e073121 skip deskewing if no textlines 2026-04-24 15:27:29 +02:00
Robert Sachunsky
7b5aa2a1f6 more run_single refactoring…
- `run_single`: re-use `return_contours_of_interested_region`
  for extraction and filtering of text region contours
- `run_single`: isolate new function `match_deskewed_contours`
- `run_single`: apply dilation afterwards
- rename `contours_only_text_parent_d_ordered` → `polygons_of_textregions_d`
- rename `contours_only_text_parent` → `polygons_of_textregions`
- rename `contours_only_text_parent_h` → `polygons_of_textregions_h`
- `do_work_of_slopes_new_curved` and `get_slopes_and_deskew_new_curved`:
   no need for `mask_texts_only` array arg
- `filter_contours_inside_a_bigger_one`: no need for `image` as array arg,
  simplify
- `split_textregion_main_vs_head`: simplify, re-order arguments
  and return tuple logically
- if no main text regions are found, just convert marginals to main text
  and continue normally instead of stopping early w/ empty marginals (i.e.
  no textlines)
2026-04-24 15:27:29 +02:00
Robert Sachunsky
a2f43b8d69 simplify, add confidence for headings as well 2026-04-23 21:14:39 +02:00
Robert Sachunsky
264b00f8ab predictor: cache models' input shape instead of output shape 2026-04-23 21:14:39 +02:00
Robert Sachunsky
829256df91 do_prediction*: remove autosized variants, simplify 2026-04-23 21:14:39 +02:00
Robert Sachunsky
de65a55a04 mbro: simplify, add drop-caps as well, reduce batch size…
- do_order_of_regions_with_model:
  * add `polygons_of_drop_capitals`, order these indices as well
    (model was not trained for this, but it works)
  * explicit label identifiers instead of number literals
  * map marginals and images correctly
  * simplify (a lot)
  * reduce inference batch size to accomodate 8 GB VRAM GPUs
- return_indexes_of_contours_located_inside_another_list_of_contours:
  simplify
2026-04-23 21:14:39 +02:00
Robert Sachunsky
0dfc9d911f run_boxes_no_full_layout: also map to fl labels here…
(because -mbro assumes the label set from -fl)
2026-04-20 18:20:58 +02:00
Robert Sachunsky
0015f2675b with -slro, also extract and apply page (Border) mask 2026-04-20 18:20:58 +02:00
Robert Sachunsky
569b96d1a9 find_number_of_columns_in_document: pass correct label_seps…
- in fl: 6
- non-fl: 3 (now fixed)
2026-04-20 18:20:58 +02:00
Robert Sachunsky
f28a9c9e0b add confidence for all region types, prepare for textlines…
- pass on probabilities from predicted class everywhere
- rename `confidence_matrix` → `confidence_regions` / `regions_confidence`
- rename `get_textregion_confidences()` → `get_region_confidences()`
- add same for tables, textlines and regionsfl (full layout model)
- aggregate per-region confidence lists for image, table, drop-capital,
  left marginal and right marginal regions
- add in writer
- simplify/re-indent some
- try to replace more number literals with class label identifiers
2026-04-20 18:20:58 +02:00
Robert Sachunsky
1164b97917 extract_text_regions_new: fix heading thresholding…
- re-introduce boosting `heading` thresholding broken
  when refactoring (light version and do_prediction)
- also return confidence for full layout prediction
2026-04-20 18:20:58 +02:00
Robert Sachunsky
20dc5c3188 also cover drop-capital in (heuristic) reading order 2026-04-20 18:20:58 +02:00
Robert Sachunsky
92e94753c7 decoding of dropcaps in -fl: ensure consistency w/ early layout…
1. use connected component analysis to get unique segments
   in early prediction result
2. for each drop-capital segment in full prediction result,
   find matching early segment
3. when they have high overlap, assign drop-capital label
   to the entire early segment
2026-04-20 18:20:58 +02:00
Robert Sachunsky
29b42fdfaa decoding of drop-capitals in full layout: also allow replacing img…
- rename `putt_bb_of_drop_capitals_of_model_in_patches_in_layout`
  → `fill_bb_of_drop_capitals`
- also allow image (besides text) label in early layout prediction
  result when checking if entire bbox can be filled (as opposed to
  just drop-capital | image | background mask)
- simplify
2026-04-16 18:37:27 +02:00
Robert Sachunsky
6e0aed35f4 run_boxes_*: simplify, document class label mappings, start using
identifier constants instead of literals for labels
2026-04-16 18:37:27 +02:00
Robert Sachunsky
f29e876a7c return_boxes_of_images_by_order_of_reading_new: sep label differs w/o -fl…
fix bug where in non-full mode, the wrong class label was assumed
for separator regions (3 in non- vs 6 in full layout mode):

- pass in separator mask instead of full segmentation map
- rename for clarity:
  - `regions_without_separators` → `text_mask` (alread binary)
  - `regions_with_separators` → `sep_mask` (now just binary)
2026-04-16 05:16:23 +02:00
Robert Sachunsky
f5f2435a38 run_marginals: drop unnecessarily passing textline_mask, mask_seps, mask_images 2026-04-16 05:13:06 +02:00
Robert Sachunsky
9309586712 split_textregion_main_vs_header → split_textregion_main_vs_head…
(and simplify)
2026-04-16 05:07:22 +02:00
Robert Sachunsky
0f82b568ba do_prediction_new_concept: aggregate confidence for all classes…
(not just text; will still have to pass that on to the writer...)
2026-04-16 05:02:20 +02:00
Robert Sachunsky
5a27e46b22 keep seps over artificial boundaries to improve col separation…
(thresholding and decoding with artificial boundary class can
 overwrite existing column separators, which in turn can contribute
 to missing column boundaries; this prioritises seps over boundaries,
 which does not impair separation of instances, as seps will separate
 text/image/etc instances just as well as artificial boundaries)
2026-04-16 04:56:38 +02:00
Robert Sachunsky
9d6ff65e1d get_tables_from_model: utilise artificial bound thresholding…
(to improve separation of neighbouring tables, esp. across
 columns; since model's threshold class is particularly weak,
 also use lower threshold here)
2026-04-16 04:49:07 +02:00
Robert Sachunsky
12b1271487 layout cli: add option --halt-fail 2026-04-13 01:19:47 +02:00
Robert Sachunsky
56e6deb02c predictor: jit-compile and precompile (non-autosized) models 2026-04-13 01:17:04 +02:00
Robert Sachunsky
01c54eb2ef reduce inference batch sizes to accommodate 8 GB VRAM
(still pending a solution for flexible batch sizes)
2026-04-13 01:15:25 +02:00
Robert Sachunsky
f44c39667e predictor: disable rebatching (until we have flexible batch sizes) 2026-04-13 01:14:49 +02:00
Robert Sachunsky
219954d15b predictor: use predict_on_batch instead of predict 2026-04-13 01:14:18 +02:00
Robert Sachunsky
0d21b62aee disable autosized prediction entirely (also for _patched)…
When 338c4a0e wrapped all prediction models for automatic
image size adaptation in CUDA,
- tiling (`_patched`) was indeed faster
- whole  (`_resized`) was actually slower

But CUDA-based tiling also increases GPU memory requirements
a lot. And with the new parallel subprocess predictors, Numpy-
based tiling is not necessarily slower anymore.
2026-04-10 18:23:10 +02:00
Robert Sachunsky
ccef63f08b get_regions: always use resized/enhanced image…
(avoid strange image handling short-cut, which uses
 early cropped image used for column classification
 instead of normal image in 1/2-column cases;
 fixes accuracy issues of region_1_2 model on these images)
2026-04-10 18:17:51 +02:00
Robert Sachunsky
04da66ed73 training: plot only ~ 1000 training and ~ 100 validation images 2026-03-30 13:34:05 +02:00
Robert Sachunsky
a8556f5210 run: sort parallel log messages by file name instead of prefixing…
(as follow-up to ec08004f:)

- create log queues and QueueListener separately for each job
- receive job logs sequentially
- drop log filter mechanism (prefixing log messages by file name)
- also count ratio of successful jobs
2026-03-30 13:18:40 +02:00
Robert Sachunsky
1756443605 fixup device sel 2026-03-16 15:35:07 +01:00
Robert Sachunsky
6bbdcc39ef CLI/Eynollah.setup_models/ModelZoo.load_models: add device option/kwarg
allow setting device specifier to load models into

either
- CPU or single GPU0, GPU1 etc
- per-model patterns, e.g. col*:CPU,page:GPU0,*:GPU1

pass through as kwargs until `ModelZoo.load_models()` setup up TF
2026-03-15 04:54:04 +01:00
Robert Sachunsky
67e9f84b54 do_prediction* for "col_classifier": pass array as float16 instead of float64 2026-03-15 03:20:39 +01:00
Robert Sachunsky
f54deff452 model_zoo/predictor: use one subprocess per model…
- Eynollah: instead of one `Predictor` instance as stand-in for
  entire `ModelZoo`, keep the latter but have each model in `_loaded`
  dict become an independent predictor instance
- `ModelZoo.load_models()`: instantiate `Predictor`s for each
  `model_category` and then call `Predictor.load_model()` on them
- `Predictor.load_model()`: set args/kwargs for `ModelZoo.load_model()`,
  then spawn subprocess via `.start()`, which first enters `setup()`...
- `Predictor.setup()`: call `ModelZoo.load_model()` instead of (plural)
 `.load_models()`; save to `self.model` instead of `self.model_zoo`
- `ModelZoo.load_model()`: move _all_ CUDA configuration and
  TF/Keras-specific module initialization here (to be used only by
  predictor subprocess)
- `Predictor`: drop stand-in `SingleModelPredictor` retrieved by `get()`;
  directly provide `predict()` and `output_shape` via `self.call()`
- `Predictor`: drop `model` arg from all queues - now implicit; use
  `self.name` for model name in messages
- `Predictor`: no need for requeuing other tasks (only same model now)
- `Predictor`: reduce rebatching batch sizes due to increased VRAM footprint

- `Eynollah.setup_models()`: set up loading `_patched` / `_resized`
  here instead of during `ModelZoo.load_model()`
- `ModelZoo.load_models()`: for resized/patched models, call
  `Predictor.load_model()` with kwarg instead of resp. model name suffix
- `ModelZoo.load_model()`: expect boolean kwargs `patched/resized`
  for `wrap_layout_model_patched/resized` model wrappers, respectively
2026-03-15 02:53:37 +01:00
Robert Sachunsky
c514bbc661 make switching between autosized and looped tiling easier 2026-03-14 02:16:26 +01:00
Robert Sachunsky
2f3b622cf5 predictor: rebatch tasks to increase CUDA throughput…
- depending on model type (i.e. size), configure target
  batch sizes
- after receiving a prediction task for some model,
  look up target batch size, then try to retrieve arrays
  from follow-up tasks for the same model on the task queue;
  stop when either no tasks are immediately available or
  when the combined batch size (input batch size * number of tasks)
  reaches the target
- push back tasks for other models to the queue
- rebatch: read all shared arrays, concatenate them along axis 0,
  map respective job ids they came from
- predict on new (possibly larger) batch
- split result along axis 0 into number of jobs
- send each result along with its jobid to task queue
2026-03-14 00:52:34 +01:00
Robert Sachunsky
b550725cc5 wrap_layout_model_patched: simplify shape calculation 2026-03-14 00:51:22 +01:00
Robert Sachunsky
d6404dbbc2 do_prediction*: pass arrays as float16 instead of float64 to TF 2026-03-14 00:49:26 +01:00
Robert Sachunsky
135064a48e model_zoo: region model not used at runtime anymore - don't load 2026-03-14 00:48:52 +01:00
Robert Sachunsky
ec08004fb0 run: add QueueListener to pool / QueueHandler to workers…
- set up a Queue and QueueListener along with ProcessPoolExecutor,
  delegating messages from the queue to all handlers
- in forked subprocesses, instead of just inheriting handlers,
  replace them with a single QueueHandler, and make sure
  log messages get prefixes by the respective job id (img_filename)
  so concurrent messages will still be readable
- in the predictor, make sure to pass on the log level to the
  spawned subprocess, too
2026-03-14 00:43:58 +01:00
Robert Sachunsky
b7aa1d24cc CLI: drop redundant negative option forms, add --num-jobs 2026-03-13 18:22:25 +01:00
Robert Sachunsky
576e120ba6 autosized prediction is only faster for _patched, not for _resized…
When 338c4a0e wrapped all prediction models for automatic
image size adaptation in CUDA,
- tiling (`_patched`) was indeed faster
- whole  (`_resized`) was actually slower

So this reverts the latter part.
2026-03-13 18:15:30 +01:00
Robert Sachunsky
6d55f297a5 run: use ProcessPoolExecutor for parallel run_single across pages…
- reintroduce ProcessPoolExecutor
  (previously for parallel deskewing within pages)
- wrap Eynollah instance into global, so (with forking)
  serialization can be avoided – same pattern as in core ocrd.Processor
- move timing/logging into `run_single()`, respectively
2026-03-13 10:15:51 +01:00
Robert Sachunsky
96cfddf92d split_textregion_main_vs_header: avoid zero division 2026-03-13 02:44:08 +01:00
Robert Sachunsky
4e9b062b84 separate_marginals_to_left_and_right...: simplify 2026-03-13 02:44:08 +01:00
Robert Sachunsky
ae0f194241 drop ProcessPoolExecutor for intra-page parallel subprocessing…
(interferes with inter-page parallelism, not as useful)
2026-03-13 02:44:08 +01:00
Robert Sachunsky
becf031c65 refactor to remove data-dependency from all Eynollah methods…
- `cache_images()`: only return an image dict (plus extra keys
  for file name stem and dpi) - don't set any attributes
- `imread()`: just take from passed image dict, also add `binary` key
- `resize_and_enhance_image_with_column_classifier()`:
  * `imread()` from image dict
  * set `img_bin` key for binarization result if `input_binary`
  * instead of `image_page_org_size` / `page_coord` attributes,
    set `img_page` / `coord_page` in image dict
  * instead of retval, set `img_res` in image dict
  * also set `scale_x` and `scale_y` in image dict, resp.
  * simplify
- `resize_image_with_column_classifier()`:
  * `imread()` from image dict
  * (as in `resize_and_enhance_with_column_classifier`:)
    call `calculate_width_height_by_columns_1_2` if `num_col` is
    1 or 2 here
  * instead of retval, set `img_res` in image dict
  * also set `scale_x` and `scale_y` in image dict, resp.
  * simplify
- `calculate_width_height_by_columns*()`: simplify, get confidence of
  num_col instead of entire array
- `extract_page()`: read `img_res` from image dict; simplify
- `early_page_for_num_of_column_classification()`:
  `imread()` from image dict; simplify
- `textline_contours()`: no need for `num_col_classifier` here
- `run_textline()`: no need for `num_col_classifier` here
- `get_regions_light_v()` → `get_regions()`:
  * read `img_res` from image dict
  * get shapes via `img` from image dict instead of `image_org` attr
  * use `img_page` / `coord_page` from image dict instead of attrs
  * avoid unnecessary 3-channel arrays
  * simplify
- `get_tables_from_model()`: no need for `num_col_classifier` here
- `run_graphics_and_columns_light()` → `run_graphics_and_columns()`:
  * pass through image dict instead of `img_bin` (which really was `img_res`)
  * simplify
- `run_graphics_and_columns_without_layout()`:
  * pass through image dict instead of `img_bin` (which really was `img_res`)
  * simplify
- `run_enhancement()`: pass through image dict
- `get_image_and_sclaes*()`: drop
- `run_boxes_full_layout()`:
  * pass `image_page` instead of `img_bin` (which really was `image_page`)
  * simplify
- `run()`:
  * instantiate plotter outside of loop, and independent of img files
  * move writer instantiation and overwrite checks into `run_single()`
  * add try/catch for `run_single()` w/ logging
- `reset_file_name_dir`: drop
- `run_single()`:
  * add some args/kwargs from `run()`
  * call `cache_images()` (reading image dict) here
  * instantiate writer here instead of (reused) attr in `run()`
  * set `scale_x` / `scale_y` in writer from image dict once known
    (i.e. after `run_enhancement()`)
  * don't return anything, but write PAGE result here
- `check_any_text_region_in_model_one_is_main_or_header_light()` →
  `split_textregion_main_vs_header()`
- plotter:
  * pass `name` (file stem) from image dict to all methods
  * for `write_images_into_directory()`: also `scale_x` and `scale_y`
    from image dict
- writer:
  * init with width/height
- ocrd processor:
  * adapt (just `run_single()` call)
  * drop `max_workers=1` restriction (can now run fully parallel)
- `get_textregion_contours_in_org_image_light()` →
  `get_textregion_confidences()`:
  * take shape from confmat directly instead of extra array
  * simplify
2026-03-13 02:44:08 +01:00
Robert Sachunsky
800c55b826 predictor: fix spawn vs fork / parent vs child contexts 2026-03-13 02:44:07 +01:00
Robert Sachunsky
64281768a9 run_graphics_and_columns_light: fix double 1-off error…
When `num_col_classifier` predicted result gets bypassed
by heuristic result from `find_num_col()` (because prediction
had too little confidence or `calculate_width_height_by_columns()`
would have become too large), do not increment `num_col` further
(already 1 more than colseps).
2026-03-12 10:18:14 +01:00
Robert Sachunsky
46c5f52491 CLI: don't append /models_eynollah here (already in default_specs) 2026-03-11 02:40:53 +01:00
Robert Sachunsky
10214dfdda predictor: make sure all shared arrays get freed eventually 2026-03-11 02:40:53 +01:00
Robert Sachunsky
cf5caa1eca predictor: fix termination for pytests…
- rename `terminate` → `stopped`
- call `terminate()` from superclass during shutdown
- del `self.model_zoo` in the parent process after spawn,
  and in the child during shutdown
2026-03-11 02:40:53 +01:00
Robert Sachunsky
bb468bf68f predictor: mp.Value must come from spawn context, too 2026-03-11 02:27:47 +01:00
Robert Sachunsky
9f127a0783 introduce predictor subprocess for exclusive GPU processing…
- new class `Predictor(multiprocessing.Process)` as stand-in
  for EynollahModelZoo:
  * calling `load_models()` starts the subprocess (and has
    `.model_zoo.load_models()` run internally)
  * calling `get()` yields a stand-in that supports `.predict()`,
    which actually communicates with the singleton subprocess
    via task and result queues, sharing Numpy arrays via SHM
  * calling `predict()` with an empty dict (instead of an image)
    merely retrieves the respective model's output shapes (cached)
  * shared memory objects for arrays are cleared as soon as possible
  * log messages are piped through QueueHandler / QueueListener
  * exceptions are passed through the queues, and raised afterwards
- move all TF initialization to the predictor
2026-03-07 03:54:16 +01:00
Robert Sachunsky
6f4ec53f7e wrap_layout_model_resized/patched: compile call instead of predict
(so `predict()` can directly convert back to Numpy)
2026-03-07 03:52:14 +01:00
Robert Sachunsky
338c4a0edf wrap layout models for prediction (image resize or tiling) all in TF
(to avoid back and forth between CPU and GPU memory when looping
 over image patches)

- `patch_encoder`: define `Model` subclasses which take an existing
  (layout segmentation) model in the constructor, and define a new
  `call()` using the existing model in a GPU-only `tf.function`:
  * `wrap_layout_model_resized`: just `tf.image.resize()` from
    input image to model size, then predict, then resize back
  * `wrap_layout_model_patched`: ditto if smaller than model size;
    otherwise use `tf.image.extract_patches` for patching in a
    sliding-window approach, then predict patches one by one, then
    `tf.scatter_nd` to reconstruct to image size
- when compiling `tf.function` graph, make sure to use input signature
  with variable image size, but avoid retracing each new size sample
- in `EynollahModelZoo.load_model` for relevant model types,
  also wrap the loaded model
  * by `wrap_layout_model_resized` under model name + `_resized`
  * by `wrap_layout_model_patched` under model name + `_patched`
- introduce `do_prediction_new_concept_autosize`,
  replacing `do_prediction/_new_concept`,
  but using passed model's `predict` directly without
  resizing or tiling to model size
- instead of `do_prediction/_new_concept(True, ...)`,
  now call `do_prediction_new_concept_autosize`,
  but with `_patched` appended to model name
- instead of `do_prediction/_new_concept(False, ...)`,
  now call `do_prediction_new_concept_autosize`,
  but with `_resized` appended to model name
2026-03-07 03:33:44 +01:00
Robert Sachunsky
f33fd57da8 model_zoo: resolve path names coming in from caller (CLI)
(to make relative paths work)
2026-03-05 00:50:32 +01:00
Robert Sachunsky
41dccb216c use (generalized) do_prediction() instead of predict_enhancement() 2026-03-05 00:50:32 +01:00
Robert Sachunsky
341480e9a0 do_prediction: if img was too small for model, also upscale results
(i.e. resize back to match original size after prediction)
2026-03-05 00:50:32 +01:00
Robert Sachunsky
8ebbe65c17 textline_contours: remove unnecessary resize_image, simplify 2026-03-05 00:50:32 +01:00
Robert Sachunsky
3370a3aa85 do_prediction*: avoid 3-channel results, simplify further…
- `do_prediction/_new_concept`: avoid unnecessary `np.repeat`
  on results, aggregate intermediate artificial class mask and
  confidence data in extra arrays
- callers: avoid unnecessary thresholding the result arrays
- callers: adapt (no need to slice into channels)
- simplify by refactoring thresholding and skeletonization into
  function `seg_mask_label`
- `extract_text_regions*`: drop unused second result array
- `textline_contours`: avoid calculating unused unpatched prediction
2026-03-05 00:50:32 +01:00
Clemens Neudecker
c9f6aa35b2
fix license badge 2026-03-03 09:43:54 +01:00
Robert Sachunsky
ff7dc31a68 do_prediction*: rename identifiers for artificial class thresholding
- `do_prediction_new_concept` w/ patches: remove branches for
  `thresholding_for_artificial_class` (never used, wrong name)
- `do_prediction_new_concept` w/ patches: rename kwarg
  `thresholding_for_some_classes` →
  `thresholding_for_artificial_class`
- `do_prediction_new_concept`: introduce kwarg `artificial_class`
  (for baked constant 4)
- `do_prediction`: introduce kwarg `artificial_class`
  (for baked constant 2)
- `do_prediction/_new_concept`: rename kwargs
  `thresholding_for..._in_light_version` →
  `thresholding_for...`
- `do_prediction`: rename kwarg
  `threshold_art_class_textline` →
  `threshold_art_class`
- `do_prediction_new_concept`: rename kwarg
  `threshold_art_class_layout` →
  `threshold_art_class`
2026-03-02 13:08:11 +01:00
Robert Sachunsky
b9cf68b51a training: fix b6d2440c 2026-03-01 20:00:05 +01:00
Robert Sachunsky
686f1d34aa do_prediction*: simplify (esp. indexing/slicing) 2026-03-01 04:37:20 +01:00
Robert Sachunsky
3b56fa2a5b training: plot GT/prediction and metrics before training (commented) 2026-02-28 20:11:12 +01:00
Robert Sachunsky
e47653f684 training: move nCC metric/loss to .metrics and rename…
- `num_connected_components_regression` → `connected_components_loss`
- move from training.train to training.metrics
2026-02-28 20:11:12 +01:00
Robert Sachunsky
361d40c064 training: improve nCC metric/loss - measure localized congruence…
- instead of just comparing the number of connected components,
  calculate the GT/pred label incidence matrix and retrieve the
  share of singular values (i.e. nearly diagonal under reordering)
  over total counts as similarity score
- also, suppress artificial class in that
2026-02-28 20:11:12 +01:00
Robert Sachunsky
7e06ab2c8c training: add config param add_ncc_loss for layout/binarization…
- add `metrics.metrics_superposition` and `metrics.Superposition`
- if non-zero, mix configured loss with weighted nCC metric
2026-02-28 20:11:12 +01:00
Robert Sachunsky
c6d9dd7945 training: use mixed precision and XLA (commented; does not work, yet) 2026-02-28 20:10:53 +01:00
Robert Sachunsky
c1d8a72edc training: shuffle tf.data pipelines 2026-02-28 20:10:53 +01:00
Robert Sachunsky
1cff937e72 training: make data pipeline in 7888fa5 more efficient 2026-02-28 20:10:53 +01:00
Robert Sachunsky
f8dd5a328c training: make plotting 18607e0f more efficient…
- avoid control dependencies in model path
- store only every 3rd sample
2026-02-28 20:10:53 +01:00
Robert Sachunsky
2d5de8e595 training.models: use bilinear instead of nearest upsampling…
(to benefit from CUDA optimization)
2026-02-27 12:48:28 +01:00
Robert Sachunsky
ba954d6314 training.models: fix daa084c3 2026-02-27 12:47:59 +01:00
Robert Sachunsky
7c3aeda65e training.models: fix 9b66867c 2026-02-27 12:40:56 +01:00
Robert Sachunsky
439ca350dd training: add metric ConfusionMatrix and plot it to TensorBoard 2026-02-26 13:55:37 +01:00
Robert Sachunsky
b6d2440ce1 training.utils.preprocess_imgs: fix polymorphy in 27f43c1
(Functions cannot be both generators and procedures,
 so make this a pure generator and save the image files
 on the caller's side; also avoids passing output
 directories)

Moreover, simplify by moving the `os.listdir` into the function
body (saving lots of extra variable bindings).
2026-02-25 20:39:15 +01:00
Robert Sachunsky
42bab0f935 docs/train: document --missing-printspace=project 2026-02-25 13:18:40 +01:00
Robert Sachunsky
4202a1b2db training.generate-gt.pagexml2label: add --missing-printspace
- keep default (fallback to full page), but warn
- new option `skip`
- new option `project`
2026-02-25 11:16:21 +01:00
Robert Sachunsky
7823ea2c95 training.train: add early stopping for OCR 2026-02-25 00:16:07 +01:00
Robert Sachunsky
36e370aa45 training.train: add validation data for OCR 2026-02-25 00:10:43 +01:00
Robert Sachunsky
b399db3c00 training.models: simplify CTC loss layer 2026-02-24 20:43:50 +01:00
Robert Sachunsky
92fc2bd815 training.train: fix data batching for OCR in 27f43c17 2026-02-24 20:42:08 +01:00
Robert Sachunsky
86b009bc31 training.utils.preprocess_imgs: fix file name stemming 27f43c17 2026-02-24 20:41:08 +01:00
Robert Sachunsky
20a3672be3 training.utils.preprocess_imgs: fix file shuffling in 27f43c17 2026-02-24 20:37:44 +01:00
Robert Sachunsky
658dade0d4 training.config_params: flip_index needed for scaling_flip, too 2026-02-24 20:36:00 +01:00
Robert Sachunsky
abf111de76 training: add metric for (same) number of connected components
(in trying to capture region instance separability)
2026-02-24 17:03:21 +01:00
Robert Sachunsky
18607e0f48 training: plot predictions to TB logs along with training/testing 2026-02-24 17:00:48 +01:00
Robert Sachunsky
56833b3f55 training: fix data representation in 7888fa5
(Eynollah models expet BGR/float instead of RGB/int)
2026-02-24 16:46:19 +01:00
Robert Sachunsky
a9496bbc70 enhancer/mbreorder: use std Keras data loader for classification 2026-02-17 18:39:30 +01:00
Robert Sachunsky
003c88f18a fix double import in 82266f82 2026-02-17 18:23:32 +01:00
Robert Sachunsky
f61effe8ce fix typo in c8240905 2026-02-17 18:20:58 +01:00
Robert Sachunsky
5f71333649 fix missing import in 49261fa9 2026-02-17 18:11:49 +01:00
Robert Sachunsky
67fca82f38 fix missing import in 27f43c17 2026-02-17 18:09:15 +01:00
Robert Sachunsky
6a4163ae56 fix typo in 27f43c17 2026-02-17 18:09:15 +01:00
Robert Sachunsky
c1b5cc92af fix typo in 7562317d 2026-02-17 18:09:15 +01:00
Robert Sachunsky
7bef8fa95a training.train: add verbose=1 consistently 2026-02-17 18:09:15 +01:00
Robert Sachunsky
9b66867c21 training.models: re-use transformer builder code 2026-02-17 18:09:15 +01:00
Robert Sachunsky
daa084c367 training.models: re-use UNet decoder builder code 2026-02-17 18:09:15 +01:00
Robert Sachunsky
fcd10c3956 training.models: re-use RESNET50 builder (+weight init) code 2026-02-17 18:09:15 +01:00
Robert Sachunsky
4414f7b89b training.models.vit_resnet50_unet: re-use IMAGE_ORDERING 2026-02-17 14:18:32 +01:00
Robert Sachunsky
7888fa5968 training: remove data_gen in favor of tf.data pipelines
instead of looping over file pairs indefinitely, yielding
Numpy arrays: re-use `keras.utils.image_dataset_from_directory`
here as well, but with img/label generators zipped together

(thus, everything will already be loaded/prefetched on the GPU)
2026-02-17 12:44:45 +01:00
Robert Sachunsky
83c2408192 training.utils.data_gen: avoid repeated array allocation 2026-02-17 12:44:45 +01:00
Robert Sachunsky
514a897dd5 training.train: assert n_epochs vs. index_start 2026-02-17 12:44:45 +01:00
Robert Sachunsky
37338049af training: use relative imports 2026-02-17 12:44:45 +01:00
Robert Sachunsky
7b7ef041ec training.models: use asymmetric zero padding instead of lambda layer 2026-02-17 12:44:45 +01:00
Robert Sachunsky
ee4bffd81d training.train: simplify transformer cfg checks 2026-02-17 12:44:45 +01:00
Robert Sachunsky
53252a59c6 training.models: fix glitch introduced in 3a73ccca 2026-02-17 12:44:45 +01:00
Robert Sachunsky
ea285124ce fix Patches/PatchEncoder (make configurable again) 2026-02-17 12:44:45 +01:00
Robert Sachunsky
2492c257c6 ocrd-tool.json: re-instante light_version and textline_light dummies for backwards compatibility 2026-02-07 16:52:54 +01:00
Robert Sachunsky
bd282a594d training follow-up:
- use relative imports
- use tf.keras everywhere (and ensure v2)
- `weights_ensembling`:
  * use `Patches` and `PatchEncoder` from .models
  * drop TF1 stuff
  * make function / CLI more flexible (expect list of
    checkpoint dirs instead of single top-level directory)
- train for `classification`: delegate to `weights_ensembling.run_ensembling`
2026-02-07 16:34:55 +01:00
Robert Sachunsky
27f43c175f Merge branch 'main' into ro-fixes and resolve conflicts…
major conflicts resolved manually:

- branches for non-`light` segmentation already removed in main
- Keras/TF setup and no TF1 sessions, esp. in new ModelZoo
- changes to binarizer and its CLI (`mode`, `overwrite`, `run_single()`)
- writer: `build...` w/ kwargs instead of positional
- training for segmentation/binarization/enhancement tasks:
  * drop unused `generate_data_from_folder()`
  * simplify `preprocess_imgs()`: turn `preprocess_img()`, `get_patches()`
    and `get_patches_num_scale_new()` into generators, only writing
    result files in the caller (top-level loop) instead of passing
    output directories and file counter
- training for new OCR task:
  * `train`: put keys into additional `config_params` where they belong,
    resp. (conditioned under existing keys), and w/ better documentation
  * `train`: add new keys as kwargs to `run()` to make usable
  * `utils`: instead of custom data loader `data_gen_ocr()`, re-use
    existing `preprocess_imgs()` (for cfg capture and top-level loop),
    but extended w/ new kwargs and calling new `preprocess_img_ocr()`;
    the latter as single-image generator (also much simplified)
  * `train`: use tf.data loader pipeline from that generator w/ standard
    mechanisms for batching, shuffling, prefetching etc.
  * `utils` and `train`: instead of `vectorize_label`, use `Dataset.padded_batch`
  * add TensorBoard callback and re-use our checkpoint callback
  * also use standard Keras top-level loop for training

still problematic (substantially unresolved):
- `Patches` now only w/ fixed implicit size
  (ignoring training config params)
- `PatchEncoder` now only w/ fixed implicit num patches and projection dim
  (ignoring training config params)
2026-02-07 14:05:56 +01:00
Robert Sachunsky
6944d31617 modify manual RO preference…
in `return_boxes_of_images_by_order_of_reading_new`,
when the next multicol separator ends in the same column,
do not recurse into subspan if the next starts earlier
(but continue with top span to the right first)
2026-02-05 17:58:32 +01:00
Robert Sachunsky
d047327a1f
Merge pull request #5 from bertsky/ro-fixes-update-deps
update deps, refactor training
2026-02-05 17:36:50 +01:00
Robert Sachunsky
0d3a8eacba improve/update docs/train.md 2026-02-05 17:12:48 +01:00
Robert Sachunsky
b1633dfc7c training.generate_gt: for RO, skip files if regionRefs are missing 2026-02-05 17:12:48 +01:00
Robert Sachunsky
5d0c26b629 training.train: use std Keras data loader for classification
(much more efficient, works with std F1 metric)
2026-02-05 17:12:48 +01:00
Robert Sachunsky
f03124f747 training.train: simplify+fix classification data loaders…
- unify `generate_data_from_folder_training` w/ `..._evaluation`
- instead of recreating array after every batch, just zero out
- cast image results to uint8 instead of uint16
- cast categorical results to float instead of int
2026-02-05 17:12:48 +01:00
Robert Sachunsky
82d649061a training.train: fix F1 metric score setup 2026-02-05 17:12:48 +01:00
Robert Sachunsky
5c7801a1d6 training.train: simplify config args for model builder 2026-02-05 17:12:48 +01:00
Robert Sachunsky
4a65ee0c67 training.train: more config dependencies…
- make more config_params keys dependent on each other
- re-order accordingly
- in main, initialise them (as kwarg), so sacred actually
  allows overriding them by named config file
2026-02-05 11:53:19 +01:00
Robert Sachunsky
7562317da5 training: fix+simplify load_model logic for continue_training
- add missing combination `transformer` (w/ patch encoder and
  `weighted_loss`)
- add assertion to prevent wrong loss type being configured
2026-02-04 17:35:38 +01:00
Robert Sachunsky
1581094141 training: extend index_start to tasks classification and RO 2026-02-04 17:35:12 +01:00
Robert Sachunsky
e85003db4a training: re-instate index_start, reflect cfg dependency
- `index_start`: re-introduce cfg key, pass to Keras `Model.fit`
  as `initial_epoch`
- make config keys `index_start` and `dir_of_start_model` dependent
  on `continue_training`
- improve description
2026-02-04 17:32:24 +01:00
kba
586077fbcd 📦 v0.7.0 2026-01-30 16:40:55 +01:00
kba
4ade0f788f 📝 changelog 2026-01-29 17:33:35 +01:00
kba
f13560726e Merge remote-tracking branch 'origin/adding-cnn-rnn-training-script' into 2026-01-29-training
# Conflicts:
#	src/eynollah/training/inference.py
2026-01-29 17:32:08 +01:00
Robert Sachunsky
25153ad307 training: add IoU metric 2026-01-29 12:20:42 +01:00
Robert Sachunsky
d1e8a02fd4 training: fix epoch size calculation 2026-01-29 12:20:42 +01:00
Robert Sachunsky
29a0f19cee training: simplify image preprocessing…
- `utils.provide_patches`: split up loop into
  * `utils.preprocess_img` (single img function)
  * `utils.preprocess_imgs` (top-level loop)
- capture exceptions for all cases (not just some)
  at top level and with informative logging
- avoid repeating / delegating config keys in several
  places: only as kwargs to `preprocess_img()`
- read files into memory only once, then re-use
- improve readability (avoiding long lines, repeated code)
2026-01-29 12:20:42 +01:00
kba
87190f8997 Merge branch 'adding-cnn-rnn-training-script-rfct' into 2026-01-29-training
# Conflicts:
#	src/eynollah/training/models.py
2026-01-29 10:27:36 +01:00
kba
a76de1e182 Merge branch 'adding-cnn-rnn-training-script' into 2026-01-29-training 2026-01-29 10:26:34 +01:00
kba
ef3cf02877 Merge branch 'ruff-training' into 2026-01-29-training 2026-01-29 10:26:14 +01:00
Robert Sachunsky
e69b35b49c training.train.config_params: re-organise to reflect dependencies
- re-order keys belonging together logically
- make keys dependent on each other
2026-01-29 03:01:57 +01:00
Robert Sachunsky
0372fd7a1e training.gt_gen_utils: fix+simplify cropping…
when parsing `PrintSpace` or `Border` from PAGE-XML,
- use `lxml` XPath instead of nested loops
- convert points to polygons directly
  (instead of painting on canvas and retrieving contours)
- pass result bbox in slice notation
  (instead of xywh)
2026-01-29 03:01:57 +01:00
Robert Sachunsky
acda9c84ee training.gt_gen_utils: improve XML→img path mapping…
when matching files in `dir_images` by XML path name stem,
 * use `dict` instead of `list` to assign reliably
 * filter out `.xml` files (so input directories can be mixed)
 * show informative warnings for files which cannot be matched
2026-01-29 03:01:57 +01:00
Robert Sachunsky
eb92760f73 training: download pretrained RESNET weights if missing 2026-01-29 03:01:57 +01:00
Robert Sachunsky
6a81db934e improve docs/train.md 2026-01-29 03:01:57 +01:00
Robert Sachunsky
87d7ffbdd8 training: use proper Keras callbacks and top-level loop 2026-01-29 03:01:57 +01:00
vahidrezanezhad
f9695cd7be Merge branch 'adding-cnn-rnn-training-script' of https://github.com/qurator-spk/eynollah into adding-cnn-rnn-training-script 2026-01-28 11:52:36 +01:00
vahidrezanezhad
3500167870 weights ensembling for tensorflow models is integrated 2026-01-28 11:52:12 +01:00
vahidrezanezhad
33f6a231bc fix: prevent crash when printspace is missing in xmls used for label generation 2026-01-26 17:30:26 +01:00
vahidrezanezhad
6ae244bf9b Fix filename stem extraction using binarization. Restore the CNN-RNN model to its previous version, as setting channels_last alone was insufficient for running on both CPU and GPU. Prevent errors caused by null values in image shape elements. 2026-01-26 15:04:47 +01:00
vahidrezanezhad
30f39e7383 mapregion is added to labels 2026-01-26 13:56:34 +01:00
vahidrezanezhad
c8240905a8 Fix label generation by selecting largest contour when erosion splits shapes 2026-01-26 13:36:24 +01:00
Robert Sachunsky
3c3effcfda drop TF1 vernacular, relax TF/Keras and Torch requirements…
- do not restrict TF version, but depend on tf-keras and
  set `TF_USE_LEGACY_KERAS=1` to avoid Keras 3 behaviour
- relax Numpy version requirement up to v2
- relax Torch version requirement
- drop TF1 session management code
- drop TF1 config in favour of TF2 config code for memory growth
- training.*: also simplify and limit line length
- training.train: always train with TensorBoard callback
2026-01-20 11:34:02 +01:00
Robert Sachunsky
e2754da4f5 adapt to Numpy 1.25 changes…
(esp. `np.array(...)` now not allowed on ragged arrays unless
 `dtype=object`, but then coercing sub-arrays to `object` as well)
2026-01-20 04:04:07 +01:00
kba
9ccc495b4a wip 2025-12-19 14:57:10 +01:00
vahidrezanezhad
49261fa99b CNN–RNN–OCR inference and adaptation of the CNN–RNN–OCR model to support inference on both CPU and GPU 2025-12-17 15:12:39 +01:00
vahidrezanezhad
6ee79c7320 evaluation with a given GT is only possible for segmentation tasks 2025-12-17 13:28:02 +01:00
vahidrezanezhad
4651000191 debuging input shape + enable finetuning a model 2025-12-15 11:36:09 +01:00
vahidrezanezhad
4fc3ff33cb The cnn-rnn ocr model can be trained now 2025-12-09 17:22:12 +01:00
vahidrezanezhad
84a72a128b cnn-rnn model can be called - model input height and width are dynamic now - data generator is also callable 2025-12-09 15:30:19 +01:00
vahidrezanezhad
59e5a73654 adding cnn-rnn training script 2025-12-08 19:30:57 +01:00
vahidrezanezhad
7bf5e077d9 Restore correct execution of export_textline_images_and_text 2025-12-03 15:40:52 +01:00
vahidrezanezhad
6ac37af2f8 Fix eynollah ocr --help so it works again 2025-12-03 14:11:47 +01:00
vahidrezanezhad
d687d862d6 Restored correct functionality of the extract_only_images mode and cleaned up the argument handling 2025-12-03 12:01:42 +01:00
Robert Sachunsky
9fdae72e96 utils_ocr.return_textline_contour: gen cv2-like contours (w/ ndim=3, as in all other places) 2025-12-03 03:04:46 +01:00
Robert Sachunsky
ad8f8167c2 separate_lines/_vertical: gen cv2-like contours (w/ ndim=3, as in all other places) 2025-12-03 00:58:26 +01:00
Robert Sachunsky
43a95842bd writer: also ensure validity after scaling 2025-12-02 16:35:32 +01:00
kba
51abe9617a log to STDERR not STDOUT 2025-12-02 15:00:33 +01:00
Robert Sachunsky
56e73bf72f deskewing: add a 2nd stage for precision
after selecting the optimum angle on the original
search range, narrow down around in the vicinity
with half the range (adding computational costs,
but gaining precision)
2025-11-28 18:27:58 +01:00
Robert Sachunsky
adcea47bc0 return_boxes_of_images_by_order_of_reading_new: always erode
when passing the text region mask, do not apply erosion only
if there are more than 2 columns, but iff `not erosion_hurts`
(consistent with `find_num_col`'s expectations and making
 it as easy to find the column gaps on 1 and 2-column pages
 as on multi-column pages)
2025-11-28 18:23:59 +01:00
Robert Sachunsky
5a3de3b42d column detection: improve, aided by vseps whenever possible
- `find_number_of_columns_in_document`: retain vertical separators
  and pass to `find_num_col` for each vertical split
- `return_boxes_of_images_by_order_of_reading_new`: reconstruct
  the vertical separators from the segmentation mask and the separator
  bboxes; pass it on to `find_num_col` everywhere
- `return_boxes_of_images_by_order_of_reading_new`: no need to
  try-catch `find_num_col` anymore
- `return_boxes_of_images_by_order_of_reading_new`: when a vertical
  split has too few columns,
  * do not raise but lower the threshold `multiplier` responsible for
    allowing gaps as column boundaries
  * do not pass the `num_col_classifier` (i.e. expected number of
    resulting columns) of the entire page to the iterative
    `find_num_col` for each existing column, but only the portion
    of that span
2025-11-28 18:14:24 +01:00
Robert Sachunsky
4dd40c542b find_num_col: add optional criterion - sum of vertical separators
when searching for gaps between text regions, consider the vertical
separator mask (if given): add the vertical sum of vertical separators
to the peak scores (making column detection more robust if still slighly
skewed or partially obscured by multi-column regions, but fg seps are
present)
2025-11-28 18:07:15 +01:00
Robert Sachunsky
84d10962f3 return_boxes_of_images_by_order_of_reading_new: improve
- when searching for multi-col box makers, pick the right-most
  allowable column, not the left-most
2025-11-28 18:04:12 +01:00
Robert Sachunsky
5abf0c1097 return_boxes_of_images_by_order_of_reading_new: improve
- when analysing regions spanning across columns,
  disregard tiny regions (smaller than half the median size)
- if a region spans across columns just by a tiny fraction,
  and therefore is not good enough for a multi-col separator,
  then it should also not be good enough for a multi-col box
  maker
2025-11-28 17:58:44 +01:00
Robert Sachunsky
b71bb80e3a return_boxes_of_images_by_order_of_reading_new: fix 4abc2ff5
(forgot to also flip `regions_with_separators` if right2left)
2025-11-28 17:57:10 +01:00
Robert Sachunsky
a527d7a10d combine_hor_lines_and_delete_cross_points: improve
- avoid unnecessary `fillPoly` (we already have the mask)
- do not merge hseps if vseps interfere
- remove old criterion (based on total length of hseps)
- create new criterion (no x overlap and x close to each other)
- rename identifiers:
  * `sum_dis` → `sum_xspan`
  * `diff_max_min_uniques` → `tot_xspan`
  * np.std / np.mean → `dev_xspan`
- remove rule cutting around the center of crossing seps
  (which is unnecessary and creates small isolated seps
  at the center, unrelated to the actual crossing points)
- create rule cutting hseps by vseps _prior_ to merging
2025-11-28 17:34:11 +01:00
Robert Sachunsky
5c12b6a851 combine_hor_lines_and_delete_cross_points: simplify and rename
- `x_width_smaller_than_acolumn_width` →
  `avg_col_width`
- `len_lines_bigger_than_x_width_smaller_than_acolumn_width` →
  `nseps_wider_than_than_avg_col_width`
- `img_in_hor` → `img_p_in_hor` (analogous to vertical)
2025-11-28 17:27:12 +01:00
Robert Sachunsky
06cb9d1d31 combine_hor_lines_and_delete_cross_points: fix 1-off px bug
when eroding the vertical separator mask (by slicing),
avoid leaving 1px strips
2025-11-28 17:08:39 +01:00
Robert Sachunsky
38d91673b1 combine_hor_lines_and_delete_cross_points: get external contours
instead of tree without looking at the actual hierarchy

(to prevent retrieving holes as separators)
2025-11-28 16:50:08 +01:00
Robert Sachunsky
ee59a6809d contours_in_same_horizon: fix 5d15941b 2025-11-28 16:17:09 +01:00
kba
b161e33854 🔥 refactor eynollah ocr
.
2025-11-28 15:45:21 +01:00
kba
30f9c695dc move line-gt extraction out of ocr to eynollah-training 2025-11-28 15:12:31 +01:00
kba
951bd2fce6 CI: do not upgrade (now-unpineed) torch 2025-11-28 15:12:31 +01:00
kba
9bcfeab057 💀 remove dead code from eynollah.py 2025-11-28 12:52:28 +01:00
kba
5171e09c2d eynollah.py: fix kwargs to writer 2025-11-28 12:52:28 +01:00
kba
c24cf94bce enforce kwargs for writer.build_... 2025-11-28 12:52:28 +01:00
kba
4aa9543a7d remove more branches after textline_light default true 2025-11-27 11:30:00 +01:00
kba
177d555ded factor out extract_only_images as eynollah extract-images 2025-11-26 21:37:00 +01:00
kba
83e8b289da 🔥 drop light_version/textline_light (now default and implied) 2025-11-26 20:48:22 +01:00
kba
ca83cf934d fix imports from src/cli/cli_*/*_cli 2025-11-26 20:48:14 +01:00
kba
095b36c389 models: split into layout, extra and ocr
layout: Everything not OCR or extra
ocr: trocr/cnnrnn models
extra: obsolete or niche models
2025-11-26 19:49:59 +01:00
kba
000af16a47 🔥 remove torch pinning 2025-11-26 19:23:49 +01:00
kba
e503c1a0b7 drop obsolete multi-model binarization 2025-11-26 18:51:41 +01:00
kba
82266f8234 reorganize cli 2025-11-26 18:51:20 +01:00
kba
5a1900e664 🔥 remove OCR option from eynollah layout 2025-11-26 18:12:03 +01:00
kba
0f410c2e7c disable tf/keras logging on first import 2025-11-26 16:37:54 +01:00
kba
9d9d32daed update OCR-D bindings 2025-11-26 16:20:27 +01:00
kba
103c007368 . 2025-11-26 14:37:00 +01:00
kba
0149147e95 . 2025-11-25 13:45:47 +01:00
Robert Sachunsky
e428e7ad78 ensure separators stay within image bounds 2025-11-16 16:35:18 +01:00
Robert Sachunsky
406288b1fe fixup 72d059f3: forgot to update other writer calls 2025-11-16 16:32:45 +01:00
Robert Sachunsky
028ed16921 adapt ocrd-sbb-binarize 2025-11-15 17:17:37 +01:00
Robert Sachunsky
49ab269e08 fix typos found by ruff 2025-11-15 15:49:51 +01:00
Robert Sachunsky
72d059f3c9 reading order: simplify assignment / counting
- `do_order_of_regions`: simplify aggregating per-box orders
  for paragraphs and headings to overall order passed to
  `xml_reading_order`; no need for `order_and_id_of_texts`,
  no need to return `id_of_texts_tot`
- `do_order_of_regions_with_model`: no need to return `region_ids`
- writer: no need to pass `id_of_texts_tot` in `build_pagexml`
2025-11-15 14:34:12 +01:00
Robert Sachunsky
5a778003fd contour matching for deskewed image: ensure matches for both sides 2025-11-15 14:32:22 +01:00
Robert Sachunsky
3c15c4f7d4 back to rotate_image instead of rotation_image_new for deskewing
(because the latter does not preserve coordinates;
 it scales, even when resizing the image;
 this caused coordinate problems when matching deskewed contours)
2025-11-15 14:29:41 +01:00
Robert Sachunsky
4475183f08 improve rules governing column split
- reduce `sigma` for smoothing of input to `find_peaks`
  (so we get deeper gaps between columns)
- allow column boundaries closer to the margins
  (50 instead of 100 or 200 px, 170 instead of 370 px)
- allow column boundaries closer to each other
  (300 instead of 400 px)
- add a secondary `grenze` criterion for depth of gap
  (relative to lowest minimum, if that is smaller than
   the old criterion relative to lowest maximum)
- for calls to `find_num_col` within parts of a page,
  do allow unbalanced column boundaries
2025-11-14 13:15:09 +01:00
Robert Sachunsky
4abc2ff572 rewrite/simplify manual reading order using recursive algorithm
- rename `return_x_start_end_mothers_childs_and_type_of_reading_order`
  → `return_multicol_separators_x_start_end`, and drop all the analysis
  pertaining to mother/child relationships and full-span separators,
  also drop the separator unification rules;
  instead of the latter, try to combine neighbouring separators more
  generally: join column spans iff there is nothing in between
  (which also necessitates passing the region mask), and keep only
  one of every such redundant pair;
  add the top (of each page part) as full-span separator up front,
  and return separators already ordered by y
- `return_boxes_of_images_by_order_of_reading_new`:
  - also pass regions with separators, so they do not have to be
    reconstructed from the separator coordinates, and also contain
    images and other non-text region types, when trying to elongate
    separators to maximize their span (without introducing overlaps)
  - determine connected components of the region mask, i.e. labels
    and their respective bboxes, in order to
    1. gain additional multi-column separators, if possible
    2. avoid cutting through regions which do cross column boundaries
       later on
  - whenever adding a new bbox, first look up the label map to see if
    there are any multi-column regions extending to the right of the
    current column; if there are, then advance not just one column
    to the right, but as many as necessary to avoid cutting through
    these regions
  - new core algorithm: iterate separators sorted by y and then column
    by column, but whenever the next separator ends in the same column
    as the current one or even further left, recurse (i.e. finish that
    span first before continuing with the top iteration)
2025-11-14 13:14:53 +01:00
Robert Sachunsky
95f76081d1 rename some more identifiers:
- `lines` → `seps` (to distinguish from textlines)
- `text_regions_p_1_n` → `text_regions_p_d` (because all other
  deskewed variables are called like this)
- `pixel` → `label`
2025-11-14 13:13:50 +01:00
Robert Sachunsky
1a76ce177d do_order_of_regions: round contour centers
(so we can be sure they do not fall through the
 "pixel cracks": bboxes are delimited by integers,
 and we do not want to assign contours between
 boxes)
2025-11-14 13:08:10 +01:00
kba
67003b837c . 2025-11-13 16:56:04 +01:00
kba
d66549012f . 2025-11-13 14:57:28 +01:00
kba
b9bc8e79c0 github ci: cache models with model_zoo default config as key 2025-11-13 13:58:38 +01:00
kba
b34329dd61 tests: more path fixes 2025-11-13 12:21:48 +01:00
kba
9aeff6d155 tests: typo 2025-11-13 11:49:09 +01:00
kba
a72be69958 tests: fix model download URL 2025-11-13 11:48:23 +01:00
kba
3afbce023d tests: adapt paths 2025-11-13 11:46:31 +01:00
vahidrezanezhad
ed5b5c13dd Add test images; call TrOCR processor from the same directory as the TrOCR model 2025-11-07 12:47:21 +01:00
kba
8732007aaf . 2025-11-06 16:33:39 +01:00
kba
f902756ce1 try importing torch, then shapely, then tensorflow 2025-11-06 13:10:35 +01:00
kba
44037bc05d add layout marginalia test 2025-11-06 12:42:57 +01:00
kba
d224b0f7e8 try with shapely.set_precision(...mode="keep_collpased") 2025-11-06 11:55:40 +01:00
kba
0d84e7da16 Merge remote-tracking branch 'origin/docs_and_minor_fixes' into model-zoo
# Conflicts:
#	README.md
#	train/README.md
2025-11-06 11:37:10 +01:00
kba
53e879e289 make *test: another typo; 2025-11-05 16:19:55 +01:00
kba
e449dbab6d make *test: fix paths 2025-11-05 15:28:41 +01:00
kba
0bef6e297b make models: unzip to the versioned directory 2025-11-05 15:19:16 +01:00
kba
2c211095d7 make deps-test should not depend on the models 2025-11-05 15:02:55 +01:00
kba
b6c7283b4d further debugging 2025-11-05 14:41:18 +01:00
cneud
f90259d6e2 fix docs links 2025-10-30 22:24:54 +01:00
cneud
d5b7089bad Merge branch 'docs_and_minor_fixes' of https://github.com/qurator-spk/eynollah into docs_and_minor_fixes 2025-10-30 22:17:41 +01:00
cneud
9dbac280cc Revert "remove unnecessary backslash"
This reverts commit f212ffa22d.
2025-10-30 22:16:53 +01:00
cneud
2d35a0598d Revert "replace list declaration with list literal (faster)"
This reverts commit 9733d575bf.
2025-10-30 22:16:48 +01:00
cneud
70d8577a15 Revert "remove redundant parentheses"
This reverts commit 20a95365c2.
2025-10-30 22:16:41 +01:00
Clemens Neudecker
c9efbe1871
refactor image layout in examples.md 2025-10-30 16:52:59 +01:00
kba
8782ef17b2 CI: 🔥 upgrade torch for debugging 2025-10-30 12:19:35 +01:00
kba
62d05917c5 test_layout: str(Path) 2025-10-30 12:17:38 +01:00
cneud
b1e191b2ea reformat cli options table 2025-10-29 22:30:58 +01:00
cneud
f6c0f56348 Update README.md 2025-10-29 22:23:56 +01:00
cneud
46a45f6b0e Create examples.md 2025-10-29 22:23:48 +01:00
kba
15e6ecb95d make models: update URL 2025-10-29 21:27:10 +01:00
kba
600ebfeb50 make: fix to use single-archive ZIP 2025-10-29 21:07:49 +01:00
kba
9ab565fa02 model basedir might be a symlink 2025-10-29 21:02:42 +01:00
kba
4772fd17e2 missed changing override mechanism in eynollah_ocr 2025-10-29 20:47:13 +01:00
kba
29c273685f fix merge issues 2025-10-29 20:15:19 +01:00
kba
de76eabc1d Merge branch 'cli-logging' into model-zoo 2025-10-29 19:41:01 +01:00
kba
5e22e9db64 model_zoo: make type str to reduce importing overhead 2025-10-29 19:16:35 +01:00
kba
a913bdf7dc make --model-basedir and --model-overrides top-level CLI options 2025-10-29 18:48:41 +01:00
kba
b6f82c72b9 refactor cli tests 2025-10-29 17:23:21 +01:00
cneud
22d61e8d94 remove newspaper images from main readme 2025-10-28 19:56:23 +01:00
cneud
8822da17cf Merge remote-tracking branch 'origin/updating_docs' into docs_and_minor_fixes 2025-10-28 19:53:12 +01:00
kba
ef999c8f0a Merge branch 'model-zoo' of lx0145.sbb.spk-berlin.de:/data/eynollah into model-zoo 2025-10-27 11:45:20 +01:00
kba
294b6356d3 wip 2025-10-27 11:45:16 +01:00
kba
51d2680d9c wip 2025-10-27 11:44:59 +01:00
Robert Sachunsky
19b2c3fa42 reading order: improve handling of headings and horizontal seps
- drop connected components analysis to test overlaps between
  horizontal separators and (horizontal) neighbours (introduced
  in ab17a927)
- instead of converting headings to topline and baseline during
  `find_number_of_columns_in_document` (introduced in 9f1595d7),
  add them to the matrix unchanged, but mark as extra type
  (besides horizontal and vertical separtors)
- convert headings to toplines and baselines no earlier than in
  `return_boxes_of_images_by_order_of_reading_new`
- for both headings and horizontal separators, if they already
  span multiple columns, check if they would overlap (horizontal)
  neighbours by looking at successively larger (left and right)
  intervals of columns (and pick the largest elongation which
  does not introduce any overlaps)
2025-10-25 13:36:35 +02:00
Robert Sachunsky
3367462d18 return_boxes_of_images_by_order_of_reading_new: change arg order 2025-10-25 13:36:24 +02:00
Robert Sachunsky
a2a9fe5117 delete_separator_around: simplify, eynollah: identifiers
- use array instead of list operations
- rename identifiers:
  - `pixel` → `label`
  - `line` → `sep`
2025-10-25 13:36:17 +02:00
Robert Sachunsky
3ebbc2d693 return_boxes_of_images_by_order_of_reading_new: indent
(by removing unnecessary conditional)
2025-10-25 13:36:06 +02:00
Robert Sachunsky
66a0e55e49 return_boxes_of_images_by_order_of_reading_new: avoid oversplits
when y slice (`top:bot`) is not a significant part of the page,
viz. less than 22% (as in `find_number_of_columns_in_document`),
avoid forcing `find_num_col` to reach `num_col_classifier`

(allows large headers not to be split up and thus better ordered)
2025-10-25 13:35:56 +02:00
Robert Sachunsky
6fbb5f8a12 return_boxes_of_images_by_order_of_reading_new: simplify
- array instead of list operations
- add better plotting (but commented out)
- add more debug printing (but commented out)
- add more inline comments for documentation
- rename identifiers to make more readable:
  - `cy_hor_diff` → `y_max_hor_some` (because the ymax gets passed)
  - `lines` → `seps`
  - `y_type_2` → `y_mid`
  - `y_diff_type_2` → `y_max`
  - `y_lines_by_order` → `y_mid_by_order`
  - `y_lines_without_mother` → `y_mid_without_mother`
  - `y_lines_with_child_without_mother` → `y_mid_with_child_without_mother`
  - `y_column` → `y_mid_column`
  - `y_column_nc` → `y_mid_column_nc`
  - `y_all_between_nm_wc` → `y_mid_between_nm_wc`
  - `lines_so_close_to_top_separator` → `seps_too_close_to_top_separator`
  - `y_in_cols` and `y_down` → `y_mid_next`
- use `pairwise()` `nc_top:nc_bot` instead of `i_c` indexing
2025-10-25 13:35:44 +02:00
Robert Sachunsky
6cc5900943 find_num_col: add better plotting (but commented out) 2025-10-25 13:35:34 +02:00
Robert Sachunsky
5d15941b35 contours_in_same_horizon: simplify
- array instead of list operations
- return array of index pairs instead of list objects
2025-10-25 13:35:26 +02:00
Robert Sachunsky
acee4c1bfe find_number_of_columns_in_document: simplify 2025-10-25 13:35:18 +02:00
Robert Sachunsky
b2a79cc6ed return_x_start_end_mothers_childs_and_type_of_reading_order: fix+1
when calculating `reading_order_type`, upper limit on column range
(`x_end`) needs to be `+1` here as well
2025-10-25 13:35:12 +02:00
Robert Sachunsky
e2dfec75fb return_x_start_end_mothers_childs_and_type_of_reading_order:
simplify and document

- simplify
- rename identifiers to make readable:
  - `y_sep` → `y_mid` (because the cy gets passed)
  - `y_diff` → `y_max` (because the ymax gets passed)
- array instead of list operations
- add docstring and in-line comments
- return (zero-length) numpy array instead of empty list
2025-10-25 13:35:06 +02:00
Robert Sachunsky
0fc4b2535d return_boxes_of_images_by_order_of_reading_new: fix no-mother case
- when handling lines without mother,
  and biggest line already accounts for all columns,
  but some are too close to the top and therefore must be removed,
  avoid invalidating `biggest` index, causing `IndexError`
- remove try-catch (now unnecessary)
- array instead of list operations
2025-10-25 13:34:58 +02:00
Robert Sachunsky
7c3e418588 return_boxes_of_images_by_order_of_reading_new: simplify
- enumeration instead of indexing
- array instead of list operations
- add better plotting (but commented out)
2025-10-25 13:34:52 +02:00
Robert Sachunsky
cd35241e81 find_number_of_columns_in_document: split headings at top+baseline
regarding `splitter_y` result, for headings, instead of cutting right
through them via center line, add their toplines and baselines as if
they were horizontal separators
2025-10-25 13:34:35 +02:00
vahidrezanezhad
6192e5ba5c
qualitative evaluation of ocr models are added to docs 2025-10-23 16:37:24 +02:00
kba
ec1fd93dad wip 2025-10-23 11:58:23 +02:00
vahidrezanezhad
d0ad7a98b7 starting qualitative ocr evaluation 2025-10-22 22:45:22 +02:00
vahidrezanezhad
7b7714af2e completing ocr evaluations metric 2025-10-22 22:42:37 +02:00
vahidrezanezhad
b56bb44284 providing ocr model evaluation metrics 2025-10-22 21:30:06 +02:00
vahidrezanezhad
59eb4fd3be
images with ro are added to readme 2025-10-22 19:04:01 +02:00
vahidrezanezhad
ab9ddd5214
OCR examples are added to README 2025-10-22 18:41:15 +02:00
vahidrezanezhad
2fc723d292 extend README 2025-10-22 18:29:14 +02:00
kba
874cfc247f . 2025-10-22 17:56:18 +02:00
kba
883546a6b8 eynollah models package 2025-10-22 17:05:40 +02:00
kba
04bc4a63d0 reorganize model_zoo 2025-10-22 16:04:48 +02:00
kba
d94285b3ea rewrite model spec data structure 2025-10-22 13:07:35 +02:00
kba
146658f026 eynollah layout: fix trocr_processor model_zoo call 2025-10-22 10:48:26 +02:00
kba
4c8abfe19c eynollah_ocr: actually replace the model calls 2025-10-22 10:48:26 +02:00
kba
1337461d47 adopt image_enhancer to the zoo 2025-10-21 19:24:55 +02:00
kba
f0c86672f8 adopt mb_ro_on_layout to the zoo 2025-10-21 17:55:08 +02:00
kba
bcffa2e503 adopt binarizer to the zoo 2025-10-21 17:53:24 +02:00
kba
de34a15809 Makefile: fix make models for OCR 2025-10-21 17:27:16 +02:00
kba
9d2b18d2af test_run: check log messages starting with eynollah 2025-10-21 13:29:55 +02:00
kba
a53d5fc452 update docs/makefile to point to v0.6.0 models 2025-10-21 13:15:57 +02:00
kba
c6b863b13f typing and asserts 2025-10-21 12:05:27 +02:00
kba
44b75eb36f cli: model -> model_basedir 2025-10-21 11:05:12 +02:00
cneud
7d70835d22 small fixes to main readme 2025-10-20 23:19:10 +02:00
cneud
230e7cc705 integrate ocrd docs 2025-10-20 22:52:54 +02:00
cneud
e5254dc6c5 integrate training docs 2025-10-20 22:39:54 +02:00
cneud
6e3399fe7a combine Docker docs 2025-10-20 22:16:56 +02:00
kba
062f317d2e Introduce model_zoo to Eynollah_ocr 2025-10-20 21:14:52 +02:00
kba
d609a532bf organize imports mostly 2025-10-20 19:46:07 +02:00
kba
48d1198d24 move Eynollah_ocr to separate module 2025-10-20 19:15:31 +02:00
kba
b90cfdfcc4 adapt tests to -l being top-level option now 2025-10-20 18:56:24 +02:00
kba
a850ef39ea factor model loading in Eynollah to EynollahModelZoo 2025-10-20 18:34:44 +02:00
Robert Sachunsky
5a0e4c3b0f find_number_of_columns_in_document: improve splitter rule
extend horizontal separators to full img width if they do not overlap
any other regions

(only as regards to returned `splitter_y` result,
 but without changing returned separators mask)
2025-10-20 17:41:50 +02:00
Robert Sachunsky
542d38ab43 find_number_of_columns_in_document: simplify, rename lineseps 2025-10-20 17:41:49 +02:00
Robert Sachunsky
d3d599b010 order_of_regions: add better plotting (but commented out) 2025-10-20 17:41:47 +02:00
Robert Sachunsky
c43a825d1d order_of_regions: filter out-of-image peaks 2025-10-20 17:41:47 +02:00
Robert Sachunsky
48761c3e12 find_num_col: simplify, add better plotting (but commented out) 2025-10-20 17:41:45 +02:00
Robert Sachunsky
184927fb54 find_num_cols: re-sort peaks when cutting n-best num_col_classifier 2025-10-20 17:41:44 +02:00
Robert Sachunsky
086c1880ac binarization: add option --overwrite, skip existing outputs
(also, simplify `run` and separate `run_single`)
2025-10-20 17:40:52 +02:00
vahidrezanezhad
c8455370a9 updating heuristics and ocr documentation 2025-10-20 15:13:45 +02:00
vahidrezanezhad
3ec5ceb22e
Update flowchart 2025-10-20 14:55:14 +02:00
vahidrezanezhad
9d2dbb8388 updating model based reading orde detection 2025-10-20 14:47:55 +02:00
cneud
496a0e2ca4 readme and documentation updates 2025-10-17 19:19:26 +02:00
cneud
f212ffa22d remove unnecessary backslash 2025-10-17 18:27:18 +02:00
cneud
9733d575bf replace list declaration with list literal (faster) 2025-10-17 18:21:49 +02:00
cneud
20a95365c2 remove redundant parentheses 2025-10-17 18:19:00 +02:00
cneud
2a1f892d72 expand keywords and supported Python versions 2025-10-17 18:17:41 +02:00
kba
6c89888166 Refactor CLI for consistent logging and late imports 2025-10-17 17:47:59 +02:00
kba
557fb227f3 training/gt_gen_utils: fix type errors, comment out dead code 2025-10-17 14:21:05 +02:00
kba
af74890b2e training/inference.py: add typing info, organize imports 2025-10-17 14:07:43 +02:00
kba
3a73ccca2e training/models.py: make imports explicit 2025-10-17 13:45:44 +02:00
kba
38c028c6b5 📦 v0.6.0 2025-10-17 10:36:30 +02:00
kba
ca8edb35e3 📝 changelog 2025-10-17 10:35:13 +02:00
kba
50e8b2c266 Merge branch 'integrate-training-from-sbb_pixelwise_segmentation' 2025-10-17 10:33:04 +02:00
kba
46d25647f7 📝 changelog 2025-10-17 10:32:15 +02:00
Robert Sachunsky
2ac01ecacc join_polygons: try to catch rare case of MultiPolygon 2025-10-17 10:31:51 +02:00
kba
2e0fb64dcb disable ruff check for training code for now 2025-10-16 21:29:37 +02:00
kba
76c13bcfd7 Merge branch 'integrate-training-from-sbb_pixelwise_segmentation' of https://github.com/qurator-spk/eynollah into integrate-training-from-sbb_pixelwise_segmentation 2025-10-16 20:50:24 +02:00
kba
af5abb77fd Merge branch 'main' into integrate-training-from-sbb_pixelwise_segmentation 2025-10-16 20:50:16 +02:00
kba
d2f0a43088 📝 changelog 2025-10-16 20:46:49 +02:00
Konstantin Baierer
3bd3faef68
Merge pull request #193 from qurator-spk/training-installation
Training installation
2025-10-16 20:39:17 +02:00
kba
1e66c85222 Merge branch 'integrate-training-from-sbb_pixelwise_segmentation' into training-installation 2025-10-16 16:18:02 +02:00
kba
bd8c8bfeac training: pin numpy to <1.24 as well 2025-10-16 16:15:31 +02:00
Robert Sachunsky
948c8c3441 join_polygons: try to catch rare case of MultiPolygon 2025-10-15 16:58:17 +02:00
kba
f485dd4181 📦 v0.6.0rc2 2025-10-14 16:10:50 +02:00
kba
c1f0158806 📝 changelog 2025-10-14 14:53:15 +02:00
kba
7daa0a1bd5 Merge branch 'fix-196' into prepare-v0.6.0rc2 2025-10-14 14:52:36 +02:00
kba
2febf53479 📝 changelog 2025-10-14 14:52:31 +02:00
Robert Sachunsky
8299e7009a setup_models: avoid unnecessarily loading region_fl 2025-10-14 14:27:32 +02:00
Robert Sachunsky
e8b7212f36 polygon2contour: avoid uint for coords
(introduced in a433c736 to make consistent with
 `filter_contours_area_of_image`, but actually
 np.uint is prone to create overflows downstream)
2025-10-14 14:27:26 +02:00
kba
745cf3be48 XML encoding should be utf-8 not utf8
... and  should use OCR-D's generateDS PAGE API consistently
2025-10-10 16:39:17 +02:00
kba
2056a8bdb9 📦 v0.6.0rc1 2025-10-10 16:32:47 +02:00
Robert Sachunsky
4e9a1618c3 layout: refactor model setup, allow loading custom versions
- simplify definition of (defaults for) model versions
- unify loading of loadable models (depending on mode)
- use `self.models` dict instead of `self.model_*` attributes
- add `model_versions` kwarg / `--model_version` CLI option
2025-10-10 03:18:09 +02:00
Robert Sachunsky
374818de11 📝 update changelog for 5725e4f 2025-10-09 23:11:05 +02:00
Robert Sachunsky
c4cb16c2a8 simplify
(`skip_layout_and_reading_order` is already an attr)
2025-10-09 23:05:50 +02:00
Robert Sachunsky
ecb53056f2 Merge branch 'main' of https://github.com/qurator-spk/eynollah into loky-with-shm-for-175-rebuilt 2025-10-09 22:54:11 +02:00
Robert Sachunsky
d96af425a7
Merge pull request #4 from bertsky/loky-with-shm-for-175-rebuilt-refactored
refactoring for 192: speedup and improvements
2025-10-09 22:18:53 +02:00
Robert Sachunsky
cab392601e 📝 update changelog 2025-10-09 20:14:11 +02:00
Robert Sachunsky
e1b56d97da CI: lint with ruff 2025-10-09 20:14:11 +02:00
Robert Sachunsky
a144026b27 add rough ruff config 2025-10-09 20:14:11 +02:00
Robert Sachunsky
b3d29bef89 return_contours_of_interested_region*: rm unused variants 2025-10-09 20:14:11 +02:00
Robert Sachunsky
8a2d682e12 fix identifier scope in layout OCR options (w/o full_layout) 2025-10-09 20:14:11 +02:00
Robert Sachunsky
096def1e9d mbreorder/enhancment: fix missing imports
(not sure if these models really need that, though)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
027b87d321 fixup c0137c2 (missing arguments for utils_ocr) 2025-10-09 20:14:11 +02:00
Robert Sachunsky
1d4815b48f utils_ocr: forgot to pass coordinate offsets 2025-10-09 20:14:11 +02:00
Robert Sachunsky
839b7c4d84 make models: avoid re-download 2025-10-09 20:14:11 +02:00
Robert Sachunsky
e5b5264568 CI: add diagnostic message for model symlink 2025-10-09 20:14:11 +02:00
Robert Sachunsky
ca72a095ca tests: cover table detection in various modes 2025-10-09 20:14:11 +02:00
Robert Sachunsky
5e11a68a3e writer/run_single: consistent kwarg naming conf_contours_textregion(s) 2025-10-09 20:14:11 +02:00
Robert Sachunsky
75823f9bed run_single: call writer.build_pagexml_no_full_layout w/ kwargs 2025-10-09 20:14:11 +02:00
Robert Sachunsky
cbbb3248c7 writer: simplify
- `build_pagexml_no_full_layout`: delegate to
  `build_pagexml_full_layout` (removing redundant code)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
e32479765c writer: simplify
- simplify serialization of coordinates
- re-use `serialize_lines_in_region` (drop `*_in_dropcapital` and `*_in_marginal`)
- re-use `calculate_polygon_coords`
2025-10-09 20:14:11 +02:00
Robert Sachunsky
d88ca18eec get/do_work_of_slopes etc.: reduce call/return signatures
- `get_textregion_contours_in_org_image_light`: no more need
  to also return unchanged contours here (see 41cc38c5); therefore
- `txt_con_org`: no more need for this
  (now mere alias to `contours_only_text_parent`); also
- `index_by_text_par_con`: no more need for this (see prev. commit),
  so do not pass/return
- `get_slopes_and_deskew_*`: do not pass `contours_only_text`
  (where not used)
- `get_slopes_and_deskew_*`: do not return unchanged contours, boxes
- `do_work_of_slopes_*`: adapt respectively
2025-10-09 20:14:11 +02:00
Robert Sachunsky
02a347a48a no more need to rm from contours_only_text_parent_d_ordered now 2025-10-09 20:14:11 +02:00
Robert Sachunsky
fd43e78442 filter_contours_without_textline_inside: simplify
- np.delete in index array instead of contour lists
- yield actual resulting indices
2025-10-09 20:14:11 +02:00
Robert Sachunsky
0a80cd5dff avoid unnecessary 3-channel conversions: for tables, too 2025-10-09 20:14:11 +02:00
Robert Sachunsky
dfdc705375 do_work_of_slopes: rm unused old variant 2025-10-09 20:14:11 +02:00
Robert Sachunsky
2e907875c1 get_text_region_boxes_by_given_contours: simplify 2025-10-09 20:14:11 +02:00
Robert Sachunsky
d53f829dfd filter_contours_inside_a_bigger_one: fix edge case in 81827c29 2025-10-09 20:14:11 +02:00
Robert Sachunsky
18bbdb7c48 CI: run deps-test with OCR extra so symlink rule fires 2025-10-09 20:14:11 +02:00
Robert Sachunsky
23535998f7 tests: symlink OCR models into layout model directory
(so layout with OCR options works with our split model packages)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
a1904fa660 tests: cover layout with OCR in various modes 2025-10-09 20:14:11 +02:00
Robert Sachunsky
595ed02743 run_single: simplify; allow running TrOCR in non-fl mode, too
- refactor final `self.full_layout` conditional, removing copied code
- allow running `self.ocr` and `self.tr` branch in both cases (non/fl)
- when running TrOCR, use model / processor / device initialised during init
  (instead of ad-hoc loading)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
6e57ab3741 textline_contours_postprocessing: do not catch arbitrary exceptions 2025-10-09 20:14:11 +02:00
Robert Sachunsky
fe603188f4 avoid unnecessary 3-channel conversions 2025-10-09 20:14:11 +02:00
Robert Sachunsky
155b8f68b8 matching deskewed text region contours with predicted: improve
- avoid duplicate and missing mappings by using a different approach:
  instead of just minimising the center distance for the N contours
  that we expect,
  1. get all N:M distances
  2. iterate over them from small to large
  3. continue adding correspondences until both every original contour
     and every deskewed contour have at least one match
  4. where one original matches multiple deskewed contours,
     join the latter polygons to map as single contour
  5. where one deskewed contour matches multiple originals,
     split the former by intersecting with each of the latter
     (after bringing them into the same coordinate space),
     so ultimately only the respective match gets assigned
2025-10-09 20:14:11 +02:00
Robert Sachunsky
0e00d7868b matching deskewed text region contours with predicted: improve
- apply same min-area filter to deskewed contours as to original ones
2025-10-09 20:14:11 +02:00
Robert Sachunsky
0f33c21eb3 matching deskewed text region contours with predicted: improve
- when matching undeskewed and new contours, do not just
  pick the closest centers, respectively, but also of similar
  size (by making the contour area the 3rd dimension of the
  vector norm in the distance calculation)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
73e5a1def8 matching deskewed text region contours with predicted: simplify
- (no need for argmax if already sorted)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
d774a23daa matching deskewed text region contours with predicted: simplify
- avoid loops in favour of array processing
- improve readability and identifiers
2025-10-09 20:14:11 +02:00
Robert Sachunsky
29b4527bde do_order_of_regions: simplify
- remove duplicate code via inline def for the try-catch
2025-10-09 20:14:11 +02:00
Robert Sachunsky
e674ea08f3 do_order_of_regions: drop redundant no/full_layout
(`_no_full_layout` is the same copied code as `_full_layout`;
 the latter runs just the same if passed an empty list for headings)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
e9bb62bd86 do_order_of_regions: simplify
- avoid loops in favour of array processing
2025-10-09 20:14:11 +02:00
Robert Sachunsky
7387f5a929 do_order_of_regions: improve box matching, simplify
- when searching for boxes matching contour, be more precise:
  - avoid heuristic rules ("xmin + 80 within xrange") in favour
    of exact criteria (contour properly contained in box)
  - for fallback criterion (nearest centers), also require
    proper containment of center in box
- `order_of_regions`: remove (now) unnecessary (and insufficient)
  workaround for missing indexes (if boxes are not covering contours
  exactly)
2025-10-09 20:14:11 +02:00
Robert Sachunsky
4950e6bd78 order_of_regions: simplify
- use new `find_center_of_contours`
- avoid unused calculations
- avoid loops in favour of array processing
2025-10-09 20:14:10 +02:00
Robert Sachunsky
a1c8fd4467 do_order_of_regions / order_of_regions: simplify
- array-convert only once (before returning from `order_of_regions`)
- avoid passing `matrix_of_orders` unnecessarily between
  `order_of_regions` and `order_and_id_of_texts`
2025-10-09 20:14:10 +02:00
Robert Sachunsky
415b2cbad8 eynollah, drop_capitals: simplify
- use new `find_center_of_contours`
2025-10-09 20:14:10 +02:00
Robert Sachunsky
3f3353ec3a do_order_of_regions: simplify
- avoid loops in favour of array processing
2025-10-09 20:14:10 +02:00
Robert Sachunsky
8c3d5eb0eb separate_marginals_to_left_and_right_and_order_from_top_to_down: simplify
- use new `find_center_of_contours`
- avoid loops in favour of array processing
- avoid repeated sorting
2025-10-09 20:14:10 +02:00
kba
8215814a3f Merge branch 'changelog-v0.5.0' 2025-10-09 14:03:45 +02:00
kba
4ffe6190d2 📝 changelog 2025-10-09 14:03:26 +02:00
vahidrezanezhad
8869c20c33 updating CHANGELOG for v0.5.0 2025-10-09 13:54:29 +02:00
Robert Sachunsky
81827c2942 filter_contours_inside_a_bigger_one: simplify
- use new `find_center_of_contours`
- avoid loops in favour of array processing
- use sets instead of `np.unique` and `np.delete` instead of list.pop
2025-10-06 13:32:34 +02:00
Robert Sachunsky
0b9d4901a6 contour features: avoid unused calculations, simplify, add shortcuts
- new function: `find_center_of_contours`
- simplified: `find_(new_)features_of_contours`
2025-10-02 20:51:03 +02:00
kba
8a9b4f8f55 remove commented-out requirement for tf == 2.12.1, rely on same version as in eynollah proper 2025-10-02 12:16:26 +02:00
kba
f60e0543ab training: update docs 2025-10-01 19:16:58 +02:00
kba
1c043c586a eynollah-training: all training CLI into single click group 2025-10-01 19:16:45 +02:00
kba
690d47444c make relative wildcard imports explicit 2025-10-01 18:43:20 +02:00
kba
2baf42e878 organize imports, use relative imports 2025-10-01 18:15:54 +02:00
kba
4f5cdf3140 move training scripts to src/eynollah/training 2025-10-01 18:12:45 +02:00
kba
f0ef2b5db2 remove unused imports 2025-10-01 18:10:13 +02:00
kba
95bb5908bb Merge branch 'integrate-training-from-sbb_pixelwise_segmentation' of https://github.com/qurator-spk/eynollah into integrate-training-from-sbb_pixelwise_segmentation 2025-10-01 18:02:09 +02:00
kba
48266b1ee0 make training dependencies optional-dependencies of eynollah
i.e. `pip install "eynollah[training]"` will install the requirements for training
2025-10-01 18:01:25 +02:00
kba
733af1e9a7 📝 update train/README.md, align with docs/train.md 2025-10-01 17:43:32 +02:00
vahidrezanezhad
5725e4fd1f -Continue processing when num_col is None but textregions exist. -Convert marginal-only to main body if no main body is present. -Reset deskew angle to 0 when text region density (textregion area to page area) < 0.3 and angle > 45°. 2025-10-01 15:58:03 +02:00
cneud
4514d417a7 force GH markdown code block in list 2025-10-01 01:16:25 +02:00
cneud
e027bc038e Update README.md 2025-10-01 01:05:15 +02:00
cneud
91d2a74ac9 remove redundant parentheses 2025-10-01 00:38:01 +02:00
cneud
f2f93e0251 list literal is faster than using list constructor to create a new list 2025-10-01 00:26:27 +02:00
cneud
70af00182b mutable defaults are the source of all evil 2025-10-01 00:20:18 +02:00
cneud
1d0616eb69 comparisons to None should not use the equality operators 2025-10-01 00:15:11 +02:00
cneud
9ce127eb51 remove unnecessary backslash 2025-10-01 00:04:53 +02:00
cneud
558867eb24 fix typo 2025-10-01 00:04:07 +02:00
Robert Sachunsky
3aa7ad04fa 📝 update changelog 2025-09-30 23:14:52 +02:00
Robert Sachunsky
f0de1adabf rm loky dependency 2025-09-30 23:12:18 +02:00
Robert Sachunsky
7daec392b9 Dockerfile: fix up CUDA installation for mixed TF/Torch 2025-09-30 22:10:45 +02:00
Robert Sachunsky
ad129ed46c CI: remove OS from model cache keys 2025-09-30 22:05:53 +02:00
Robert Sachunsky
c86e59f481 CI: update model key, split up cache restore/save 2025-09-30 22:03:46 +02:00
Robert Sachunsky
a3d8197930 makefile: update model URL 2025-09-30 21:50:21 +02:00
Robert Sachunsky
61b20cc83d tests: switch from subtests to parametrize, use --isolate everywhere to free CUDA memory in between 2025-09-30 19:20:35 +02:00
Robert Sachunsky
375e0263d4 CNN-RNN OCR model: switch to 20250930 version (compatible with TF 2.12 on CPU as well) 2025-09-30 19:16:50 +02:00
Robert Sachunsky
b21051db21 ProcessPoolExecutor: shutdown during del() instead of atexit() 2025-09-30 19:16:00 +02:00
Robert Sachunsky
08c8c26028 indent extremely long lines 2025-09-30 03:52:19 +02:00
Robert Sachunsky
f857ee7b51 simplify 2025-09-30 02:26:00 +02:00
Robert Sachunsky
c0137c29ad try to fix the failed outsourcing of utils_ocr 2025-09-30 02:23:43 +02:00
Robert Sachunsky
13f85b0d5c Merge branch 'main' into loky-with-shm-for-175-rebuilt 2025-09-30 02:07:20 +02:00
cneud
070dafca75 remove duplicate LICENSE 2025-09-29 22:17:27 +02:00
cneud
53c1ca11fc Update README.md 2025-09-29 22:15:17 +02:00
Robert Sachunsky
758602403e replace loky with concurrent.futures.ProcessPoolExecutor (faster) 2025-09-29 17:48:22 +02:00
Robert Sachunsky
0366707136 get_smallest_skew: do not pass logger 2025-09-29 17:48:22 +02:00
Robert Sachunsky
b94c96fcbb find_num_col: exit early if empty (avoiding exceptions) 2025-09-29 17:48:22 +02:00
Robert Sachunsky
04c3d7dd1b get_smallest_skew: avoid shm if no ProcessPoolExecutor is passed 2025-09-29 17:48:22 +02:00
Robert Sachunsky
0662ece536 do_work_of_slopes*: use shm also in non-light mode(s) 2025-09-29 17:48:22 +02:00
Robert Sachunsky
31f240c3b8 do_image_rotation, do_work_of_slopes_new_curved: pass arrays via shared memory 2025-09-29 17:48:22 +02:00
Robert Sachunsky
8be2c79771 Revert "deskewing with faster multiprocessing"
This reverts commit 5db3e9fa64.
2025-09-29 17:48:22 +02:00
Robert Sachunsky
abf5c0f845 get_smallest_skew: when shifting search range of rotation angle, compare resulting (maximum) variances instead of blindly assuming the new range is better 2025-09-29 17:48:22 +02:00
Robert Sachunsky
dc0caad512 writer: use @type='heading' instead of 'header' 2025-09-29 17:48:22 +02:00
Robert Sachunsky
f458e3ece0 writer: SeparatorRegion needs SeparatorRegionType (not ImageRegionType) 2025-09-29 17:48:22 +02:00
Robert Sachunsky
4337d62985 contours: rename 'pixel' → 'label' for clarity 2025-09-29 17:48:22 +02:00
Robert Sachunsky
5b16c2fc00 avoid pulling unused 'image_page_rotated' through functions 2025-09-29 17:48:22 +02:00
Robert Sachunsky
5bff2d156a use box2rect instead of crop_image_inside_box when no image needed 2025-09-29 17:48:22 +02:00
Robert Sachunsky
9b5182c1c0 utils: introduce box2rect and box2slice 2025-09-29 17:48:19 +02:00
Robert Sachunsky
bca2ae3d78 get_marginals: exit early if no peaks found to avoid spurious overlap mask 2025-09-29 17:47:51 +02:00
Robert Sachunsky
235539a350 filter_contours_without_textline_inside: avoid removing from identical lists twice 2025-09-29 17:47:51 +02:00
Robert Sachunsky
11e143afee polygon2contour: avoid overflow 2025-09-29 17:47:51 +02:00
Robert Sachunsky
7a9e8256ee increase dilatation: textregions/lines (5→6), seplines (0→1) 2025-09-29 17:47:51 +02:00
Robert Sachunsky
f3faa29528 refactor shapely converisons into contour2polygon / polygon2contour, also handle heterogeneous geometries 2025-09-29 17:47:51 +02:00
Robert Sachunsky
0650274ffa move dilate_*_contours to .utils.contour, rename dilate_textregions_contours_textline_version → dilate_textline_contours 2025-09-29 17:47:47 +02:00
Robert Sachunsky
a433c73628 filter_contours_area_of_image*: also ensure validity here 2025-09-29 17:46:50 +02:00
Robert Sachunsky
17bcf1af71 rename *lines_xml → *seplines for clarity 2025-09-29 17:46:50 +02:00
Robert Sachunsky
e730725da3 check_any_text_region_in_model_one_is_main_or_header_light: return original instead of resampled contours 2025-09-29 17:46:50 +02:00
Robert Sachunsky
7b51fd6624 avoid creating invalid polygons via rounding 2025-09-29 17:46:50 +02:00
Robert Sachunsky
41cc38c51a get_textregion_contours_in_org_image_light: no back rotation, drop slope_first (always 0) 2025-09-29 17:46:48 +02:00
Robert Sachunsky
afba70c920 separate_lines/do_work_of_slopes: skip if crop is empty 2025-09-29 17:44:39 +02:00
Robert Sachunsky
66b2bce8b9 return_boxes_of_images_by_order_of_reading_new: log any exceptions 2025-09-29 17:44:36 +02:00
Robert Sachunsky
b48c41e68f return_boxes_of_images_by_order_of_reading_new: simplify, avoid changing dtype during np.append 2025-09-29 17:42:53 +02:00
Robert Sachunsky
09ece86f0d dilate_textregions_contours: simplify (via shapely's Polygon.buffer()), ensure validity 2025-09-29 17:42:53 +02:00
kba
9d8b858dfc remove docs/eynollah-layout, superseded by docs/model.md and docs/usage.md 2025-09-29 16:01:29 +02:00
kba
2bcd20ebc7 reference the now-merged training tools in README.md 2025-09-29 15:21:42 +02:00
kba
ce02a3553b 🔥 remove obsolete versions of the training document 2025-09-29 15:18:21 +02:00
kba
6d379782ab 📝 align former upstream train.md with wiki train.md syntactically 2025-09-29 15:11:02 +02:00
kba
52a7c93319 add documentation on training eynollah from sbb_pixelwise_segmentation wiki 2025-09-29 15:05:05 +02:00
kba
ea05461dfe add documentation on eynollah layout from eynollah wiki 2025-09-29 15:04:46 +02:00
kba
56c4b7af88 📝 align pre-merge docs/train.md with former upstream train.md syntactically 2025-09-29 14:59:41 +02:00
kba
3b9548d0bd Merge sbb_pixelwise_segmentation training code into eynollah 2025-09-29 14:44:31 +02:00
Robert Sachunsky
a48e52c00e 📝 extend changelog for v0.5.0 2025-09-29 13:51:20 +02:00
Konstantin Baierer
a6f0af07d1
Merge pull request #185 from bertsky/patch-4
CD: master is now main
2025-09-29 10:44:27 +02:00
Robert Sachunsky
92c1e824dc
CD: master is now main 2025-09-26 23:05:47 +02:00
kba
6ea6a62801 📝 v0.5.0 2025-09-26 16:23:46 +02:00
Konstantin Baierer
882e242946
Merge pull request #178 from qurator-spk/prepare-release-v0.5.0
Prepare release v0.5.0
2025-09-26 16:21:09 +02:00
kba
37e64b4e45 📝 changelog 2025-09-26 16:19:04 +02:00
kba
3123add815 📝 update README 2025-09-26 15:07:32 +02:00
kba
830cc2c30a comment out the offending test outright 2025-09-26 14:37:04 +02:00
kba
eb8d4573a8 tests: also disable ...ocr_directory test 2025-09-26 13:57:08 +02:00
kba
42fb452a7e disable the -doit OCR test 2025-09-26 12:55:29 +02:00
Robert Sachunsky
480daa4c7c test_run: make ocr -doit work (add truetype file) 2025-09-25 22:28:15 +02:00
kba
4c6405713a ci: ocr models 2025-09-25 22:19:36 +02:00
kba
b4d460ca79 makefile forgot the OCR models 2025-09-25 22:16:38 +02:00
kba
f3f5426597 Merge branch 'adapt-ocrd' of https://github.com/qurator-spk/eynollah into adapt-ocrd 2025-09-25 21:47:27 +02:00
kba
0bb1fb1a05 tests: adapt to layout/ocr model split 2025-09-25 21:47:15 +02:00
kba
2ec773128b Merge branch 'adapt-ocrd' of https://github.com/qurator-spk/eynollah into adapt-ocrd 2025-09-25 21:40:48 +02:00
kba
f37d80c188 Merge branch 'adapt-ocrd' of https://github.com/qurator-spk/eynollah into adapt-ocrd 2025-09-25 21:39:55 +02:00
kba
57ee1cdc72 Merge remote-tracking branch 'bertsky/mbro_dead_code-plus-fixes-plus-tests' into adapt-ocrd 2025-09-25 21:39:36 +02:00
kba
5c0ab509c4 CI: Update model name 2025-09-25 21:17:32 +02:00
kba
9303ded11f ocrd-tool.json: use models_layout instead of eynollah_layouts for consistency 2025-09-25 21:12:52 +02:00
Robert Sachunsky
7c79902835 enhancement/mbreorder: make all path options kwargs to run() instead of attributes 2025-09-25 20:51:02 +02:00
kba
e6ee26fde3 make models: adapt to zenodo/v0.5.0 2025-09-25 20:35:54 +02:00
kba
11de8a025d Adapt ocrd-eynollah-segment for release 2025-09-25 20:11:48 +02:00
kba
5e15c4f248 Merge remote-tracking branch 'bertsky/mbro_dead_code-plus-fixes-plus-tests' into prepare-release-v0.5.0 2025-09-25 20:05:03 +02:00
Robert Sachunsky
5c7e1f21fb test_run: add tests for ocr 2025-09-25 19:53:19 +02:00
Robert Sachunsky
2d14d57e4f ocr: minimal debug logging 2025-09-25 19:52:50 +02:00
Robert Sachunsky
1dcc7b5795 ocr CLI: make --model vs --model_name xor 2025-09-25 16:38:43 +02:00
Robert Sachunsky
5b1e0c1327 layout/ocr: make all path options kwargs to run() instead of attributes; ocr: drop redundant prediction_with_both_of_rgb_and_bin in favour of just bool(dir_in_bin) 2025-09-25 16:26:31 +02:00
Robert Sachunsky
ef1304a764 CLIs: reorder options, explain -i vs -di 2025-09-25 16:11:39 +02:00
Robert Sachunsky
df5448cdcd CLIs: add required=True where missing 2025-09-25 16:08:40 +02:00
Robert Sachunsky
58dd192fad smoke-test: also add enhancement and mbreorder here 2025-09-25 16:05:45 +02:00
b-vr103
369ef573f9 get textlines sorted in textregions - detection of vertical and horizontal regions improved 2025-09-25 12:51:02 +02:00
Robert Sachunsky
f07df080f0 add tests for enhancement and mbreorder 2025-09-25 01:16:19 +02:00
Robert Sachunsky
9967510327 mbreorder: filter by .xml suffix in dir-in mode 2025-09-25 01:15:37 +02:00
Robert Sachunsky
b094a6b77f mbreorder: avoid spaces in logger name 2025-09-25 01:15:37 +02:00
Robert Sachunsky
d6cdb69acb binarize/enhance/layout/ocr ls_imgs: use the same file name suffix filter for dir-in mode 2025-09-25 01:15:37 +02:00
Robert Sachunsky
96a0d22496 mbreorder CLI: change options to mimic other commands 2025-09-25 01:15:37 +02:00
Robert Sachunsky
93f7588bfa binarizer CLI: add --log-level 2025-09-24 23:08:50 +02:00
Robert Sachunsky
8a1e5a8950 enhancement / layout CLI: do not override logger name 2025-09-24 23:03:11 +02:00
Robert Sachunsky
960b11f51f machine-based-reading-order CLI: no foreign logger, add --log-level 2025-09-24 22:58:57 +02:00
kba
45b05c2316 Merge branch 'mbro_dead_code' into prepare-release-v0.5.0 2025-09-24 17:18:31 +02:00
vahidrezanezhad
80d50d4bf6 get textlines sorted in textregion - verticals 2025-09-24 17:17:27 +02:00
b-vr103
6d8641a518 get textlines sorted in textregion - verticals 2025-09-24 17:17:21 +02:00
vahidrezanezhad
6904a98182 get textlines inside textregion sorted debugging 2025-09-24 17:17:12 +02:00
vahidrezanezhad
ce13d8c5a3 get textlines inside textregion sorted 2025-09-24 17:16:47 +02:00
kba
8b30bdbae2 image_enhancer: use latest page extraction model 2025-09-24 16:39:31 +02:00
kba
c8ebe84697 image_enhancer: add missing models, remove dead code 2025-09-24 16:36:18 +02:00
kba
b75ca0d31f mb_ro_on_layout: remove copy-pasta code not actually used 2025-09-24 16:29:05 +02:00
Konstantin Baierer
9c129c7f54
Merge pull request #180 from bertsky/prepare-release-v0.5.0-fixlogging
prepare release v0.5.0: fix logging
2025-09-24 12:28:10 +02:00
Robert Sachunsky
5bd318e657 rm print statement (already log msg) 2025-09-24 12:14:32 +02:00
Robert Sachunsky
90f1d7aa47 rm summary msg (info already logged elsewhere) 2025-09-24 12:10:11 +02:00
Robert Sachunsky
7933b103f5 log modes only once (in run, not in run_single) 2025-09-24 12:09:30 +02:00
Robert Sachunsky
d0817f5744 fix typo 2025-09-24 12:08:50 +02:00
kba
9ead58b99a Merge remote-tracking branch 'michalbubula/add-feedback' into prepare-release-v0.5.0 2025-09-23 19:50:27 +02:00
kba
7bde99e866 Merge remote-tracking branch 'origin/updating_readme_for_eynollah_use_cases' into prepare-release-v0.5.0 2025-09-23 19:42:55 +02:00
kba
df8d93dbfa Merge branch 'main' into add-feedback 2025-09-23 19:20:20 +02:00
vahidrezanezhad
a65405bead tables are visulaized within layout 2025-09-22 15:56:14 +02:00
vahidrezanezhad
554f3988c9 default cnn-rnn and transformer ocr models have changed to model_eynollah_ocr_cnnrnn_20250904 and model_eynollah_ocr_trocr_20250919 respectively 2025-09-21 16:33:14 +02:00
vahidrezanezhad
6bbdfe1074 extending image types 2025-09-21 02:32:40 +02:00
vahidrezanezhad
e97e3ab192 Merge text of textlines and handle hyphenated words by joining them correctly 2025-09-19 23:23:30 +02:00
vahidrezanezhad
b38331b4ab writing page contour correctly in xml output + ignore unsupported file types when loading images 2025-09-19 18:06:18 +02:00
vahidrezanezhad
994bc8a1c0 debug new page extraction in the case of ignoring page extraction 2025-09-19 15:24:34 +02:00
vahidrezanezhad
530897c6c2 renaming argument names 2025-09-19 13:20:26 +02:00
kba
5c9cf8472b remove redundant/brittle interval logging 2025-09-18 13:19:57 +02:00
kba
146102842a convert all print stmts to logger.info calls 2025-09-18 13:15:18 +02:00
kba
c64d102613 move logging to CLI and make initialization optional 2025-09-18 13:07:41 +02:00
vahidrezanezhad
310679eeb8 page extraction model name is changed 2025-09-16 14:27:15 +02:00
vahidrezanezhad
542646791d For TrOCR, the cropped text lines will no longer be added to a list before prediction. Instead, for each batch size, the text line images will be collected and predictions will be made directly on them. 2025-09-23 19:03:13 +02:00
vahidrezanezhad
68a71be8bc Running inference on files in a directory 2025-09-13 22:40:11 +02:00
vahidrezanezhad
0711166524 changed the drop capitals bonding box to contour ratio threshold 2025-09-01 11:37:22 +02:00
vahidrezanezhad
e15640aa8a new page extraction model integration 2025-09-15 13:36:58 +02:00
vahidrezanezhad
6a735daa60
Update README.md 2025-08-31 23:30:54 +02:00
vahidrezanezhad
9b9d21d8ac eynollah ocr: support using either a specific model name or a models directory (default model) 2025-08-28 11:30:59 +02:00
vahidrezanezhad
41365645ef Marginals are divided into left and right, and written from top to bottom. 2025-08-26 22:38:03 +02:00
vahidrezanezhad
7741502876 reading order on given layout 2025-08-18 02:31:13 +02:00
Clemens Neudecker
a2359ea4c4
Merge pull request #171 from bertsky/ocrd-machine-based-ro
OCR-D processor: expose reading_order_machine_based
2025-08-15 18:40:13 +02:00
Robert Sachunsky
21615a986d OCR-D processor: expose reading_order_machine_based 2025-08-13 14:14:37 +02:00
michalbubula
8ebba5ac04 add feedback to command line interface 2025-08-12 16:21:15 +02:00
vahidrezanezhad
268aa141d7 avoiding float in range 2025-08-12 12:50:15 +02:00
vahidrezanezhad
cf4983da54 visualize vertical ocr text vertically 2025-08-08 16:12:55 +02:00
vahidrezanezhad
52d9cc9baf deskewing with faster multiprocessing 2025-08-08 11:32:02 +02:00
vahidrezanezhad
263da755ef loading xmls with UTF-8 encoding 2025-08-07 10:32:49 +02:00
vahidrezanezhad
6462ea5b33 adding visualization of ocr text of xml file 2025-08-06 22:33:42 +02:00
vahidrezanezhad
322b04145f use the latest ocr model with balanced fraktur-antiqua training dataset 2025-08-05 14:22:22 +02:00
vahidrezanezhad
1b95f8f38d threshold for textline ocr + new ocr model 2025-07-25 13:18:38 +02:00
Clemens Neudecker
2996fc8b30
Merge pull request #166 from qurator-spk/updating_readme_for_eynollah_use_cases-cli
Updating readme for eynollah use cases cli
2025-07-24 15:30:57 +02:00
vahidrezanezhad
fd0595f920
Update Makefile 2025-07-24 13:52:38 +02:00
vahidrezanezhad
da141bb42e resolving tests error 2025-07-23 16:44:17 +02:00
vahidrezanezhad
6b8893b188
Merge pull request #167 from qurator-spk/ocrd-fixes
Ocrd fixes
2025-07-22 14:46:25 +02:00
vahidrezanezhad
daa597dbaa should merged text for the whole page be written in xml? 2025-07-21 14:50:05 +02:00
vahidrezanezhad
673e67a847 update model names 2025-07-21 10:54:20 +02:00
vahidrezanezhad
fee40049cd ocr model renamed - image text font for ocr result is now using Charis-7.000 font (downloaded from here https://software.sil.org/charis/download/) 2025-07-16 14:00:12 +02:00
vahidrezanezhad
04fead348f ocr: make sure that image height or width is not zero 2025-07-03 15:24:52 +02:00
vahidrezanezhad
53dd4b26a9 decorated with confidence value for cnnrnn ocr model 2025-07-03 11:50:47 +02:00
vahidrezanezhad
1b222594d6 Update README.md: how to train model using docker image 2025-06-25 18:33:55 +02:00
vahidrezanezhad
f5a1d1a255 docker file to train model with desired cuda and cudnn 2025-06-25 18:24:16 +02:00
kba
b7b218ff11 OCR-D processor: same behavior as standalone wrt light_version/textline_light 2025-06-12 15:30:17 +02:00
vahidrezanezhad
c194a20c9c Fixed duplicate textline_light assignments (true and false) in the OCR-D framework for the Eynollah light version, which caused rectangles to be used instead of contours for textlines 2025-06-12 15:27:22 +02:00
kba
32889ef1e0 adapt binarization CLI according to #156 2025-06-12 13:57:41 +02:00
vahidrezanezhad
9b4e78c55c
Fixed duplicate textline_light assignments (true and false) in the OCR-D framework for the Eynollah light version, which caused rectangles to be used instead of contours for textlines 2025-06-11 18:57:08 +02:00
Clemens Neudecker
0e7de52f5e Merge pull request #24 from johnlockejrr/unifying-training-models
Unifying training models
2025-06-03 09:00:56 +02:00
vahidrezanezhad
eb91000490 layout visualization updated 2025-06-02 18:23:34 +02:00
vahidrezanezhad
f79af201ab Fix: Resolved OCR bug when text region type is undefined 2025-06-02 18:21:33 +02:00
vahidrezanezhad
e26c4ab9b4 image enhancer updated 2025-06-01 22:44:50 +02:00
vahidrezanezhad
9342b76038 saving enhanced image in org or scaled resolution 2025-06-01 22:10:13 +02:00
vahidrezanezhad
3b475915c7 image enhancer is integrated 2025-06-01 15:53:04 +02:00
vahidrezanezhad
df903aa1b4 Parametrize OCR for handling curved lines 2025-05-31 01:09:14 +02:00
vahidrezanezhad
1e7cecfcf9 updating ocr 2025-05-28 01:17:21 +02:00
vahidrezanezhad
03f52e7a46 updating ocr 2025-05-27 23:45:22 +02:00
vahidrezanezhad
31d9fa0c80 strings alignment function is added + new changes needed for prediction with both bin and rgb inputs is implemented 2025-05-25 21:44:36 +02:00
vahidrezanezhad
b18691f96a rnn ocr for all layout textregion types 2025-05-25 03:33:54 +02:00
vahidrezanezhad
ba3420b2d8 Drop capitals are written separately and are not attached to their corresponding text line. The OCR use case also supports single-image input. 2025-05-25 01:12:58 +02:00
vahidrezanezhad
25e3a2a99f visualizing ro for single xml file 2025-05-23 18:30:51 +02:00
vahidrezanezhad
0250a6d3d0 enhancing ocr 2025-05-23 18:06:53 +02:00
vahidrezanezhad
089029cec7 commit 21ec4fb is picked + rnn ocr at the same time with segmentation + enhancement of mb reading order 2025-05-23 15:55:03 +02:00
vahidrezanezhad
ee2c7e9013 enhancing curved lines OCR 2025-05-21 17:42:44 +02:00
vahidrezanezhad
14b70c2556 Implement hyphenated textline merging in OCR engine and a bug fixed for curved textline OCR 2025-05-21 14:39:31 +02:00
vahidrezanezhad
3ad621e956 ocr for curved lines 2025-05-20 19:01:52 +02:00
vahidrezanezhad
44ff51f5c1 mb reading order now can be done faster. Text regions are clustered using dilation, and mb reading order needs to be implemented for fewer regions 2025-05-20 16:51:08 +02:00
vahidrezanezhad
5016039cd7 enhancing marginal detection for light version 2025-05-18 02:48:05 +02:00
vahidrezanezhad
f9390c71e7 updating inference for mb reading order 2025-05-17 02:18:27 +02:00
vahidrezanezhad
1cbc669d36 marginals detection enhanced for light version 2025-05-15 15:33:50 +02:00
vahidrezanezhad
1b229ba7ae enhancement for vertical textlines 2025-05-15 00:45:22 +02:00
cneud
7a22e51f5d resolve some comments from review 2025-05-14 21:56:03 +02:00
vahidrezanezhad
ed46615f00 enhance ocr for vertical textlines 2025-05-14 18:34:58 +02:00
johnlockejrr
25abc0fabc Update gt_gen_utils.py
Keep safely the full basename without extension
2025-05-14 03:34:51 -07:00
vahidrezanezhad
88e0315321 Accurately writing text line contours into xml file when the deskewing exceeds 45 degrees and the text line is in light mode 2025-05-13 15:53:05 +02:00
vahidrezanezhad
54088c6b04 The initial attempt at reading heavily deskewed or vertically aligned lines. 2025-05-13 14:40:57 +02:00
vahidrezanezhad
4a7728bb34 visuliazation layout from eynollah page-xml output 2025-05-12 22:39:47 +02:00
vahidrezanezhad
4ddc84dee8 visulizing textline detection from eynollah page-xml output 2025-05-12 18:31:40 +02:00
vahidrezanezhad
c12b09a868 I have tried to address the issues #163 and #161 . The changes have also improved marginal detection and enhanced the isolation of headers. 2025-05-12 00:10:18 +02:00
johnlockejrr
3a9fc0efde Update utils.py
Changed unsafe basename extraction:
`file_name = i.split('.')[0]` to `file_name = os.path.splitext(i)[0]`
and
`filename = n[i].split('.')[0]` to `filename = os.path.splitext(n[i])[0]`
because
`"Vat.sam.2_206.jpg` -> `Vat` instead of `"Vat.sam.2_206`
2025-05-11 06:09:17 -07:00
johnlockejrr
6fa766d6a5 Update utils.py 2025-05-11 05:31:34 -07:00
vahidrezanezhad
21ec4fbfb5 The text region coordinates are now correctly written into the XML output when using the skip layout and reading order option 2025-05-07 14:04:01 +02:00
vahidrezanezhad
83211ae684 In the case of skip_layout_and_reading_order, the confidence value was not set correctly, leading to an error while writing to the XML file. 2025-05-07 12:33:03 +02:00
Clemens Neudecker
3dcbb20cac
Merge pull request #159 from bertsky/main
update docker
2025-05-06 15:14:06 +02:00
vahidrezanezhad
92954b1b7b resolving issued with saving model by steps 2025-05-05 16:13:38 +02:00
vahidrezanezhad
5694d971c5 saving model by steps is added to reading order and pixel wise segmentation use cases training 2025-05-05 15:39:05 +02:00
vahidrezanezhad
3b123b039c adding min_early parameter for generating training dataset for machine based reading order model 2025-05-03 19:25:32 +02:00
vahidrezanezhad
89aa545049 let to add dataset abbrevation to extracted textline images and text 2025-05-03 02:59:16 +02:00
vahidrezanezhad
48e8dd4ab3 machine based model name changed to public one 2025-05-02 12:57:26 +02:00
vahidrezanezhad
a1a004b19d inference batch size for ocr is passed as an argument 2025-05-02 12:53:33 +02:00
vahidrezanezhad
5d8c864c08 adding space between splitted textline predicted text in the case of trocr 2025-05-02 01:02:32 +02:00
vahidrezanezhad
184af46664 displaying detexted text on an image is provided for trocr case 2025-05-02 00:30:36 +02:00
Robert Sachunsky
e9179e1d34 docker: use latest core base stage 2025-05-02 00:16:22 +02:00
Robert Sachunsky
f8b4d29a59 docker: prepackage ocrd-all-module-dir.json 2025-05-02 00:16:22 +02:00
vahidrezanezhad
e2da7a6239 Fix model name to return the correct machine-based model name 2025-04-30 16:06:29 +02:00
vahidrezanezhad
b227736094 Fix OCR text cleaning to correctly handle 'U', 'K', and 'N' starting sentence; update text line splitting size 2025-04-30 16:04:34 +02:00
vahidrezanezhad
4cb4414740 Resolve remaining issue with #158 and resolving #124 2025-04-30 16:01:52 +02:00
vahidrezanezhad
208bde706f resolving issue #158 2025-04-30 13:55:09 +02:00
Konstantin Baierer
3e8adb86c2
Merge pull request #157 from qurator-spk/kba-patch-1
CI: Use most recent actions/setup-python@v5
2025-04-29 11:42:18 +02:00
Konstantin Baierer
77dae129d5
CI: Use most recent actions/setup-python@v5 2025-04-22 13:22:28 +02:00
vahidrezanezhad
192b9111e3 updating eynollah README, how to use it for use cases 2025-04-22 00:23:01 +02:00
Clemens Neudecker
b4df978dd5
Merge pull request #154 from qurator-spk/ci-pypi
CI: pypi
2025-04-17 17:01:20 +02:00
Clemens Neudecker
44d02687c6 Merge pull request #18 from johnlockejrr/unifying-training-models
Deprecations in train.py and check an argument in inference.py
2025-04-17 15:43:28 +02:00
vahidrezanezhad
4635dd219d updating:rotation augmentation is provided for machine based reading order 2025-04-17 00:12:30 +02:00
vahidrezanezhad
dd21a3b33a updating:rotation augmentation is provided for machine based reading order 2025-04-17 00:05:59 +02:00
vahidrezanezhad
825b2634f9 rotation augmentation is provided for machine based reading order 2025-04-16 23:36:41 +02:00
kba
30ba234641 CI: pypi 2025-04-16 19:27:17 +02:00
kba
41318f0404 📝 changelog 2025-04-15 11:14:26 +02:00
vahidrezanezhad
a22df11ebb Restoring the contour in the original image caused an error due to an empty tuple. This issue has been resolved, and as expected, the confidence score for this contour is set to zero 2025-04-14 00:42:08 +02:00
vahidrezanezhad
363c343b37 visualising reaidng order- Overlaying on image is provided 2025-03-17 20:09:48 +01:00
vahidrezanezhad
90a1b186f7 this enables to visualize reading order of textregions provided in page-xml files 2025-03-14 17:20:33 +01:00
vahidrezanezhad
e9b860b275 artificial_class_label for table region 2024-11-18 16:34:53 +01:00
vahidrezanezhad
238ea3bd8e update resizing in inference 2024-11-14 16:26:19 +01:00
vahidrezanezhad
7b4d14b19f addinh shifting augmentation 2024-10-29 17:06:22 +01:00
vahidrezanezhad
fd14e656aa early_erosion is added 2024-10-25 14:01:39 +02:00
johnlockejrr
f09eed1197 Changed deprecated lr to learning_rate and model.fit_generator to model.fit 2024-10-19 13:25:50 -07:00
johnlockejrr
a524f8b1a7 Update inference.py to check if save_layout was passed as argument otherwise can give an cv2 error 2024-10-19 13:21:29 -07:00
vahidrezanezhad
3f354e1c34 new augmentations for patchwise training 2024-08-30 15:30:18 +02:00
vahidrezanezhad
e3da494470 fixing artificial class bug 2024-08-28 17:34:06 +02:00
vahidrezanezhad
a57a31673d adding foreground rgb to augmentation 2024-08-28 02:09:27 +02:00
vahidrezanezhad
5bbd0980b2 early dilation for textline artificial class 2024-08-28 00:04:19 +02:00
vahidrezanezhad
61cdd2acb8 using prepared binarized images in the case of augmentation 2024-08-22 21:58:09 +02:00
vahidrezanezhad
aeb2ee4e3e scaling, channels shuffling, rgb background and red content added to no patch augmentation 2024-08-21 19:33:23 +02:00
vahidrezanezhad
445c45cb87 updating augmentations 2024-08-21 16:17:59 +02:00
vahidrezanezhad
5e1821a741 augmentation function for red textlines, rgb background and scaling for no patch case 2024-08-21 00:48:30 +02:00
vahidrezanezhad
bf5837bf6e update 2024-08-09 13:20:09 +02:00
vahidrezanezhad
3b90347a94 save only layout output. different from overlayed layout on image 2024-08-09 12:46:18 +02:00
Clemens Neudecker
2d83b8faad add documentation from wiki as markdown file to the codebase 2024-08-08 16:35:06 +02:00
vahidrezanezhad
6fb28d6ce8 erosion rate changed 2024-08-01 14:30:51 +02:00
vahidrezanezhad
381976099f inference updated 2024-07-24 18:00:39 +02:00
vahidrezanezhad
2c822dae4e erosion and dilation parameters are changed & separators are written in label images after artificial label 2024-07-24 16:52:05 +02:00
b-vr103
840d7c2283 increasing margin in the case of pixelwise inference 2024-07-23 11:29:05 +02:00
b-vr103
861f0b1ebd brightness augmentation modified 2024-07-17 18:20:24 +02:00
vahidrezanezhad
453d0fbf92 adding degrading and brightness augmentation to no patches case training 2024-07-17 17:14:20 +02:00
vahidrezanezhad
3bceec9c19 printspace_as_class_in_layout is integrated. Printspace can be defined as a class for layout segmentation 2024-07-16 18:29:27 +02:00
vahidrezanezhad
9260d2962a resolving typo 2024-07-09 03:04:29 +02:00
vahidrezanezhad
fe69b9c4a8 update inference 2024-06-21 23:42:25 +02:00
vahidrezanezhad
b3cd01de37 update reading order machine based 2024-06-21 13:06:26 +02:00
vahidrezanezhad
66022cf771 update config 2024-06-12 17:40:40 +02:00
vahidrezanezhad
22d7359db2 Transformer+CNN structure is added to vision transformer type 2024-06-12 17:39:57 +02:00
vahidrezanezhad
95faf1a4c8 transformer patch size is dynamic now. 2024-06-12 13:26:27 +02:00
vahidrezanezhad
29da23da76 binarization as a separate task of segmentation 2024-06-11 17:48:30 +02:00
vahidrezanezhad
1921e6754f updating train.py nontransformer backend 2024-06-10 22:15:30 +02:00
vahidrezanezhad
cc91e4b12c updating train.py 2024-06-07 16:24:31 +02:00
vahidrezanezhad
4c376289e9 just defined graphic region types can be extracted as label 2024-06-06 18:55:22 +02:00
vahidrezanezhad
0e4dd0b9ef just defined textregion types can be extracted as label 2024-06-06 18:47:30 +02:00
vahidrezanezhad
5a5914e06c just defined textregion types can be extracted as label 2024-06-06 18:45:47 +02:00
vahidrezanezhad
742e3c2aa2 Update README.md 2024-06-06 14:46:06 +02:00
vahidrezanezhad
13ebe71d13 replacement in a list done correctly 2024-06-06 14:38:29 +02:00
vahidrezanezhad
3ef0dbdd42 scaling and cropping of labels and org images 2024-05-30 16:59:50 +02:00
vahidrezanezhad
47a1646451 modifying xml parsing 2024-05-30 12:56:56 +02:00
vahidrezanezhad
09789619a8 min_area size of regions considered for reading order detection passed as an argument for inference 2024-05-29 13:07:06 +02:00
vahidrezanezhad
06ed006193 reading order detection on xml with layout + result will be written in an output directory with the same file name 2024-05-29 11:18:35 +02:00
vahidrezanezhad
4fb45a6711 inference for reading order 2024-05-28 16:48:51 +02:00
vahidrezanezhad
cc7577d2c1 min area size of text region passes as an argument for machine based reading order 2024-05-28 10:14:16 +02:00
vahidrezanezhad
467bbb2884 pass degrading scales for image enhancement as a json file 2024-05-28 10:01:17 +02:00
vahidrezanezhad
ccf520d3c7 adding rest_as_paragraph and rest_as_graphic to elements 2024-05-27 17:23:49 +02:00
vahidrezanezhad
9638098ae7 machine based reading order training is integrated 2024-05-24 16:39:48 +02:00
vahidrezanezhad
d346b317fb machine based reading order training dataset generator is added 2024-05-24 14:42:58 +02:00
vahidrezanezhad
61487bf782 use case printspace is added 2024-05-23 17:36:23 +02:00
vahidrezanezhad
a83d53c27d use cases like textline, word and glyph are added 2024-05-23 17:14:31 +02:00
vahidrezanezhad
348d323c7c missing text types are added 2024-05-23 15:43:31 +02:00
vahidrezanezhad
47c6bf6b97 dynamic layout decorated with artificial class on text elements boundry 2024-05-23 11:14:14 +02:00
vahidrezanezhad
f1c2913c03 page2label with a dynamic layout 2024-05-22 12:38:24 +02:00
vahidrezanezhad
b2085a1d01 update requirements 2024-05-17 09:08:25 +02:00
vahidrezanezhad
faeac997e1 page to label enable textline new concept 2024-05-17 09:10:13 +02:00
vahidrezanezhad
d6a057ba70 adding page xml to label generator 2024-05-16 15:03:23 +02:00
vahidrezanezhad
d277ec4b31 Update utils.py 2024-05-12 08:32:28 +02:00
vahidrezanezhad
241cb907cb Update train.py
avoid ensembling if no model weights met the threshold f1 score in the case of classification
2024-05-08 14:47:16 +02:00
vahidrezanezhad
bc2ca71802 modifications 2024-05-07 16:24:12 +02:00
vahidrezanezhad
e1f62c2e98 inference script is added 2024-05-07 13:34:03 +02:00
vahidrezanezhad
c989f7ac61 adding enhancement training 2024-05-06 18:31:48 +02:00
vahidrezanezhad
ca63c097c3 integrating first working classification training model 2024-04-29 20:59:36 +02:00
vahidrezanezhad
6e06742e66 first working update of branch 2024-04-16 01:00:48 +02:00
cneud
666a62622e code formatting with black; typos 2024-04-10 22:20:23 +02:00
cneud
39aa88669b update parameter config docs (fix #11) 2024-04-10 21:40:23 +02:00
cneud
d0b0395059 add info on helpful tools (fix #14) 2024-04-10 20:26:26 +02:00
cneud
4565229497 use headless cv2 2024-04-10 20:03:02 +02:00
vahidrezanezhad
ced1f851e2 adding requirements 2024-04-04 11:30:12 +02:00
vahidrezanezhad
57dae564b3 adjusting to tf2 2024-04-04 11:26:28 +02:00
vahid
5282caa328 supposed to solve https://github.com/qurator-spk/sbb_binarization/issues/41 2022-08-22 13:03:10 +02:00
vahidrezanezhad
083f5ae881 Update README.md 2021-07-14 06:01:33 -04:00
vahidrezanezhad
bcc900be17 Update README.md 2021-06-29 07:22:34 -04:00
vahidrezanezhad
09c0d5e318 Update README.md 2021-06-29 07:22:13 -04:00
vahidrezanezhad
49853bb291 Update README.md 2021-06-29 07:21:34 -04:00
vahidrezanezhad
b1c8bdf106 Update README.md 2021-06-29 07:19:32 -04:00
vahidrezanezhad
310a709ac7 Update README.md 2021-06-23 08:23:20 -04:00
vahidrezanezhad
76c75d1365 Update README.md 2021-06-23 08:22:03 -04:00
vahidrezanezhad
491cdbf934 Update README.md 2021-06-23 08:21:12 -04:00
vahidrezanezhad
15407393e2 Update README.md 2021-06-23 07:55:36 -04:00
vahidrezanezhad
2d9ba85467 Update README.md 2021-06-23 07:25:49 -04:00
vahidrezanezhad
2e2b6eeafd Merge pull request #15 from vahidrezanezhad/master
continue training, loss functions, rotation and ...
2021-06-23 00:54:00 +02:00
vahid
8884b90f05 continue training, losses and etc 2021-06-22 18:47:59 -04:00
vahid
070c2e0462 first updates, padding, rotations 2021-06-22 14:20:51 -04:00
vahidrezanezhad
b54285b196 Update README.md 2020-01-16 16:05:06 +01:00
vahidrezanezhad
4e216475dc Update README.md 2020-01-16 15:53:39 +01:00
vahidrezanezhad
325864eef1 Merge pull request #7 from qurator-spk/update-readme
Update README.md
2020-01-16 15:41:56 +01:00
Clemens Neudecker
66d7138343 Update README.md 2020-01-15 19:43:31 +01:00
Clemens Neudecker
ad1360b179 Update README.md 2020-01-15 19:37:27 +01:00
Clemens Neudecker
c07d16d843 Merge pull request #2 from cneud/add-license-1
Add LICENSE
2020-01-15 17:48:16 +01:00
Clemens Neudecker
df536d62c0 Add LICENSE 2019-12-10 16:39:41 +01:00
vahidrezanezhad
b5f9b9c54a Update main.py 2019-12-10 14:01:55 +01:00
b-vr103
943628e0b2 Merge commit '4229ad92d7' 2019-12-10 11:59:24 +01:00
vahidrezanezhad
4229ad92d7 Update README.md 2019-12-10 11:58:02 +01:00
vahidrezanezhad
8084e136ba Update README 2019-12-10 11:57:37 +01:00
979b824aa8 📝 howto: Be more verbose with the subtree pull 2019-12-09 15:33:53 +01:00
Rezanezhad, Vahid
350378af16 Add new file 2019-12-05 16:14:00 +01:00
Rezanezhad, Vahid
ac54266581 Delete README 2019-12-05 16:13:40 +01:00
Rezanezhad, Vahid
cf18aa7fbb Update README 2019-12-05 16:13:37 +01:00
Rezanezhad, Vahid
7eb3dd26ad Update README 2019-12-05 16:11:31 +01:00
Rezanezhad, Vahid
99a02a1bf5 Update README 2019-12-05 14:11:37 +01:00
Rezanezhad, Vahid
e8afb370ba Update README 2019-12-05 14:08:08 +01:00
Rezanezhad, Vahid
1882dd8f53 Update config_params.json 2019-12-05 14:05:55 +01:00
b-vr103
226330535d add files needed for training 2019-12-05 14:05:07 +01:00
b-vr103
4601237427 add files needed for training 2019-12-05 12:10:55 +01:00
Rezanezhad, Vahid
95635d5b9c code to produce models 2019-12-05 12:01:54 +01:00
193 changed files with 22500 additions and 9204 deletions

View file

@ -2,5 +2,9 @@ tests
dist
build
env*
venv*
*.egg-info
models_eynollah*
reloaded
*.h5
config_files*

View file

@ -2,7 +2,7 @@ name: CD
on:
push:
branches: [ "master" ]
branches: [ "main" ]
workflow_dispatch: # run manually
jobs:
@ -35,7 +35,7 @@ jobs:
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 -t ghcr.io/qurator-spk/eynollah"
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

24
.github/workflows/pypi.yml vendored Normal file
View file

@ -0,0 +1,24 @@
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

View file

@ -24,36 +24,62 @@ jobs:
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
df -h
- uses: actions/checkout@v4
- uses: actions/cache@v4
id: seg_model_cache
# - 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
with:
path: models_eynollah
key: ${{ runner.os }}-models
- uses: actions/cache@v4
id: bin_model_cache
with:
path: default-2021-03-09
key: ${{ runner.os }}-modelbin
key: models_eynollah-${{ hashFiles('src/eynollah/model_zoo/default_specs.py') }}
- name: Download models
if: steps.seg_model_cache.outputs.cache-hit != 'true' || steps.bin_model_cache.outputs.cache-hit != 'true'
run: make 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') }}
- 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
make deps-test EXTRAS=OCR,plotting
- 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:
@ -63,12 +89,15 @@ jobs:
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

13
.gitignore vendored
View file

@ -1,7 +1,18 @@
*.egg-info
__pycache__
sbb_newspapers_org_image/pylint.log
models_eynollah*
default-2021-03-09
output.html
/build
*.tif
*.sw?
TAGS
uv.lock
/dist
/ignore
*.log
.env
models/reloaded
models/packages
models/models_eynollah
models/pretrained_model

View file

@ -5,12 +5,270 @@ 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)
* avoid Numpy warnings (empty slices etc.)
* remove deprecated Numpy types
* binarization CLI: make `dir_in` usable again
@ -183,6 +441,16 @@ 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

View file

@ -15,7 +15,7 @@ LABEL \
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-tf2
org.opencontainers.image.base.name=ocrd/core-cuda-onnx
ENV DEBIAN_FRONTEND=noninteractive
# set proper locales
@ -36,8 +36,13 @@ 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
RUN make install EXTRAS=OCR && rm -rf /build/eynollah
# 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

View file

@ -2,19 +2,23 @@ PYTHON ?= python3
PIP ?= pip3
EXTRAS ?=
# DOCKER_BASE_IMAGE = artefakt.dev.sbb.berlin:5000/sbb/ocrd_core:v2.68.0
DOCKER_BASE_IMAGE = docker.io/ocrd/core-cuda-tf2:v3.3.0
DOCKER_TAG = ocrd/eynollah
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://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=%)
BIN_MODEL := https://github.com/qurator-spk/sbb_binarization/releases/download/v0.0.11/saved_model_2021_03_09.zip
PYTEST_ARGS ?= -vv
PYTEST_ARGS ?= -vv --isolate
# BEGIN-EVAL makefile-parser --make-help Makefile
@ -27,7 +31,8 @@ help:
@echo " install Install package 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)/models_eynollah"
@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"
@ -36,29 +41,22 @@ help:
@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 " SEG_MODEL URL of 'models' archive to download for segmentation 'test' [$(SEG_MODEL)]"
@echo " BIN_MODEL URL of 'models' archive to download for binarization 'test' [$(BIN_MODEL)]"
@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)
# Download and extract models to $(PWD)/models_eynollah
models: models_eynollah default-2021-03-09
# do not download these files if we already have the directories
.INTERMEDIATE: $(EYNOLLAH_MODELS_ZIP)
models_eynollah: models_eynollah.tar.gz
tar zxf models_eynollah.tar.gz
$(EYNOLLAH_MODELS_ZIP):
$(WGET) $@ $(EYNOLLAH_MODELS_URL)
models_eynollah.tar.gz:
wget $(SEG_MODEL)
default-2021-03-09: $(notdir $(BIN_MODEL))
unzip $(notdir $(BIN_MODEL))
mkdir $@
mv $(basename $(notdir $(BIN_MODEL))) $@
$(notdir $(BIN_MODEL)):
wget $(BIN_MODEL)
$(EYNOLLAH_MODELS_DIR): $(EYNOLLAH_MODELS_ZIP)
unzip $<
build:
$(PIP) install build
@ -72,41 +70,48 @@ install:
install-dev:
$(PIP) install -e .$(and $(EXTRAS),[$(EXTRAS)])
deps-test: models_eynollah
deps-test:
$(PIP) install -r requirements-test.txt
smoke-test: TMPDIR != mktemp -d
smoke-test: tests/resources/kant_aufklaerung_1784_0020.tif
smoke-test: tests/resources/2files/kant_aufklaerung_1784_0020.tif
# layout analysis:
eynollah layout -i $< -o $(TMPDIR) -m $(CURDIR)/models_eynollah
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
# directory mode (skip one, add one):
eynollah layout -di $(<D) -o $(TMPDIR) -m $(CURDIR)/models_eynollah
# 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 binarization -m $(CURDIR)/default-2021-03-09 $< $(TMPDIR)/$(<F)
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/kant_aufklaerung_1784_0020.tif
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)/models_eynollah
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)/default-2021-03-09
ocrd-sbb-binarize -w $(TMPDIR) -I OCR-D-SEG -O OCR-D-SEG-BIN -P model $(CURDIR)/default-2021-03-09 -P operation_level region
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)
# Run unit tests
test: export EYNOLLAH_MODELS=$(CURDIR)/models_eynollah
test: export SBBBIN_MODELS=$(CURDIR)/default-2021-03-09
test: export EYNOLLAH_MODELS_DIR := $(CURDIR)
test:
$(PYTHON) -m pytest tests --durations=0 --continue-on-collection-errors $(PYTEST_ARGS)
@ -115,12 +120,19 @@ coverage:
$(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 \
$(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_TAG) .
-t $(DOCKER_TAGS) .
.PHONY: models build install install-dev test smoke-test ocrd-test coverage docker help

230
README.md
View file

@ -1,30 +1,36 @@
# Eynollah
> Document Layout Analysis with Deep Learning and Heuristics
> Document Layout Analysis, Binarization and OCR with Deep Learning and Heuristics
[![Python Versions](https://img.shields.io/pypi/pyversions/eynollah.svg)](https://pypi.python.org/pypi/eynollah)
[![PyPI Version](https://img.shields.io/pypi/v/eynollah)](https://pypi.org/project/eynollah/)
[![GH Actions Test](https://github.com/qurator-spk/eynollah/actions/workflows/test-eynollah.yml/badge.svg)](https://github.com/qurator-spk/eynollah/actions/workflows/test-eynollah.yml)
[![GH Actions Deploy](https://github.com/qurator-spk/eynollah/actions/workflows/build-docker.yml/badge.svg)](https://github.com/qurator-spk/eynollah/actions/workflows/build-docker.yml)
[![License: ASL](https://img.shields.io/github/license/qurator-spk/eynollah)](https://opensource.org/license/apache-2-0/)
[![License: ASL](https://img.shields.io/pypi/l/eynollah)](https://opensource.org/license/apache-2-0/)
[![DOI](https://img.shields.io/badge/DOI-10.1145%2F3604951.3605513-red)](https://doi.org/10.1145/3604951.3605513)
![](https://user-images.githubusercontent.com/952378/102350683-8a74db80-3fa5-11eb-8c7e-f743f7d6eae2.jpg)
## Features
* Support for up to 10 segmentation classes:
* Document layout analysis using pixelwise segmentation models with support for 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)
* 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)
* 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
* 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 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.
: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.
## Installation
Python `3.8-3.11` with Tensorflow `<2.13` on Linux are currently supported.
For (limited) GPU support the CUDA toolkit needs to be installed.
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.
You can either install from PyPI
@ -41,78 +47,192 @@ 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).
For documentation on methods and models, have a look at [`models.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/models.md).
Pretrained models can be downloaded from [Zenodo](https://doi.org/10.5281/zenodo.17194823) or [Hugging Face](https://huggingface.co/SBB?search_models=eynollah).
## Train
In case you want to train your own model with Eynollah, have a look at [`train.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/train.md).
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.
## Usage
The command-line interface can be called like this:
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:
```sh
eynollah \
eynollah [GENERIC_OPTIONS] layout \
-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 |
| `-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`) |
| `-eoi` | extract only images to output directory (other processing will not be done) |
| `-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 |
| 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 |
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 default is to only perform layout detection of main regions
(background, text, images, separators and marginals).
#### Use as OCR-D processor
The best output quality is achieved when RGB images are used as input
rather than greyscale or binarized images.
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).
Additional documentation can be found in
[`usage.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/usage.md).
In this case, the source image file group with (preferably) RGB images should be used as input like this:
### Binarization
ocrd-eynollah-segment -I OCR-D-IMG -O OCR-D-SEG -P models 2022-04-05
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]
```
| 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 |
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`)
### Reading Order Detection
Reading order can be detected either during layout analysis,
or as a separate module, which requires a PAGE-XML input file.
ocrd-eynollah-segment -I OCR-D-XYZ -O OCR-D-SEG -P models 2022-04-05
The command-line interface for machine based reading order can be called like this:
Still, in general, it makes more sense to add other workflow steps **after** Eynollah.
```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>
```
#### Additional documentation
Please check the [wiki](https://github.com/qurator-spk/eynollah/wiki).
## Use as OCR-D processor
See [`ocrd.md`](https://github.com/qurator-spk/eynollah/tree/main/docs/ocrd.md).
## How to cite
If you find this tool useful in your work, please consider citing our paper:
```bibtex
@inproceedings{hip23rezanezhad,

43
docs/docker.md Normal file
View file

@ -0,0 +1,43 @@
## 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

18
docs/examples.md Normal file
View file

@ -0,0 +1,18 @@
# 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%">

View file

@ -1,5 +1,6 @@
# Models documentation
This suite of 14 models presents a document layout analysis (DLA) system for historical documents implemented by
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.
@ -17,12 +18,14 @@ Two Arabic/Persian terms form the name of the model suite: عين الله, whic
See the flowchart below for the different stages and how they interact:
![](https://user-images.githubusercontent.com/952378/100619946-1936f680-331e-11eb-9297-6e8b4cab3c16.png)
<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
@ -30,12 +33,14 @@ the detection of document layout exhibits inadequate performance, the proposed e
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
@ -43,6 +48,7 @@ manual classification of all documents into six classes with either one, two, th
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
@ -52,6 +58,7 @@ capability of the model enables improved accuracy and reliability in subsequent
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
@ -61,6 +68,7 @@ during the inference phase. By incorporating this methodology, improved efficien
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
@ -69,12 +77,14 @@ categorizing and isolating such elements, thereby enhancing its overall performa
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.
@ -82,16 +92,19 @@ By employing this approach, the model achieves a high level of resilience and st
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
@ -106,6 +119,7 @@ segmentation is first deskewed and then the textlines are separated with the sam
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
@ -119,6 +133,7 @@ enhancing the model's ability to accurately identify and delineate individual te
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
@ -128,20 +143,84 @@ effectively identify and delineate tables within the historical document images,
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]()
TODO
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-RNNbased 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.
* For text region detection, the image is scaled up to make it easier for the model to detect background space between text regions.
* 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.
* Deskewing is applied on the text region level (due to regions having different degrees of skew) in order to improve the textline segmentation result.
* After deskewing, a calculation of the pixel distribution on the X-axis allows the separation of textlines (foreground) and background pixels.
* Finally, using the derived coordinates, bounding boxes are determined for each textline.
* 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 Normal file
View file

@ -0,0 +1,26 @@
## 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

View file

@ -1,38 +1,93 @@
# 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 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/sbb_pixelwise_segmentation/tree/unifying-training-models) directory:
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.
* generate training dataset
* train a model
* inference with the trained model
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 three different commands:
`python generate_gt_for_training.py --help`
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:
These three commands are:
```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
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:
`python generate_gt_for_training.py 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"`
```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
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
@ -42,32 +97,47 @@ serve as labels. The enhancement model can be trained with this generated datase
```
### 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
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
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:
`python generate_gt_for_training.py 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"`
```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 GT page XML files for various pixel-wise segmentation use cases,
including 'layout,' 'textline,' 'printspace,' 'glyph,' and 'word' segmentation.
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
`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
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 file would resemble this:
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
{
@ -75,57 +145,77 @@ For example, in the case of 'textline' detection, the JSON file would resemble t
}
```
In the case of layout segmentation a custom config json file can look like this:
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}
"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}
}
```
A possible custom config json file for layout segmentation where the "printspace" is a class:
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
"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
}
```
For the layout use case, it is beneficial to first understand the structure of the page XML file and its elements.
In a given image, the annotations of elements are recorded in a page XML file, including their contours and classes.
For an image document, the known regions are 'textregion', 'separatorregion', 'imageregion', 'graphicregion',
'noiseregion', and 'tableregion'.
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`.
Text regions and graphic regions also have their own specific types. The known types for text regions are 'paragraph',
'header', 'heading', 'marginalia', 'drop-capital', 'footnote', 'footnote-continued', 'signature-mark', 'page-number',
and 'catch-word'. The known types for graphic regions are 'handwritten-annotation', 'decoration', 'stamp', and
'signature'.
Since we don't know all types of text and graphic regions, unknown cases can arise. To handle these, we have defined
two additional types, "rest_as_paragraph" and "rest_as_decoration", to ensure that no unknown types are missed.
This way, users can extract all known types from the labels and be confident that no unknown types are overlooked.
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`.
In the custom JSON file shown above, "header" and "heading" are extracted as the same class, while "marginalia" is shown
as a different class. All other text region types, including "drop-capital," are grouped into the same class. For the
graphic region, "stamp" has its own class, while all other types are classified together. "Image region" and "separator
region" are also present in the label. However, other regions like "noise region" and "table region" will not be
included in the label PNG file, even if they have information in the page XML files, as we chose not to include them.
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`)
`python generate_gt_for_training.py pagexml2label -dx "dir of GT xml files" -do "dir where output label png files will
be written" -cfg "custom config json file" -to "output type which has 2d and 3d. 2d is used for training and 3d is just
to visualise the labels" "`
(That way, users can extract all known types from the labels and be confident that no subtypes are overlooked.)
We have also defined an artificial class that can be added to the boundary of text region types or text lines. This key
is called "artificial_class_on_boundary." If users want to apply this to certain text regions in the layout use case,
the example JSON config file should look like this:
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
{
@ -147,14 +237,15 @@ the example JSON config file should look like this:
}
```
This implies that the artificial class label, denoted by 7, will be present on PNG files and will only be added to the
elements labeled as "paragraph," "header," "heading," and "marginalia."
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 "textline", "word", and "glyph", the artificial class on the boundaries will be activated only if the
"artificial_class_label" key is specified in the config file. Its value should be set as 2 since these elements
represent binary cases. For example, if the background and textline are denoted as 0 and 1 respectively, then the
artificial class should be assigned the value 2. The example JSON config file should look like this for "textline" use
case:
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
{
@ -163,26 +254,38 @@ case:
}
```
If the coordinates of "PrintSpace" or "Border" are present in the page XML ground truth files, and the user wishes to
crop only the print space area, this can be achieved by activating the "-ps" argument. However, it should be noted that
in this scenario, since cropping will be applied to the label files, the directory of the original images must be
provided to ensure that they are cropped in sync with the labels. This ensures that the correct images and labels
required for training are obtained. The command should resemble the following:
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:
`python generate_gt_for_training.py pagexml2label -dx "dir of GT xml files" -do "dir where output label png files will
be written" -cfg "custom config json file" -to "output type which has 2d and 3d. 2d is used for training and 3d is just
to visualise the labels" -ps -di "dir where the org images are located" -doi "dir where the cropped output images will
be written" `
```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 classification use case, we haven't provided a ground truth generator, as it's unnecessary. For classification,
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:
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
{
@ -204,18 +307,18 @@ example. If, for instance, we aim to classify "apple" and "orange," with a total
}
```
The "dir_train" should be like this:
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 the "dir_eval" the same structure as train directory:
And `dir_eval` analogously:
```
```
.
└── eval # evaluation directory
├── apple # directory of images for apple class
@ -225,11 +328,13 @@ And the "dir_eval" the same structure as train directory:
The classification model can be trained using the following command line:
`python train.py with config_classification.json`
```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".
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
@ -271,67 +376,91 @@ And the "dir_eval" the same structure as train directory:
└── labels # directory of labels
```
The classification model can be trained like the classification case command line.
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
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.
* backbone_type: For segmentation tasks (such as text line, binarization, and layout detection) and enhancement, we
* offer two backbone options: a "nontransformer" and a "transformer" backbone. For the "transformer" backbone, we first
* apply a CNN followed by a transformer. In contrast, the "nontransformer" backbone utilizes only a CNN ResNet-50.
* task : The task parameter can have values such as "segmentation", "enhancement", "classification", and "reading_order".
* patches: If you want to break input images into smaller patches (input size of the model) you need to set this
* parameter to ``true``. In the case that the model should see the image once, like page extraction, patches should be
* set to ``false``.
* 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.
* input_height: This indicates the height of model's input.
* input_width: This indicates the width of model's input.
* weight_decay: Weight decay of l2 regularization of model layers.
* pretraining: Set to ``true`` to load pretrained weights of ResNet50 encoder. The downloaded weights should be saved
* in a folder named "pretrained_model" in the same directory of "train.py" script.
* augmentation: If you want to apply any kind of augmentation this parameter should first set to ``true``.
* flip_aug: If ``true``, different types of filp will be applied on image. Type of flips is given with "flip_index" parameter.
* blur_aug: If ``true``, different types of blurring will be applied on image. Type of blurrings is given with "blur_k" parameter.
* scaling: If ``true``, scaling will be applied on image. Scale of scaling is given with "scales" parameter.
* degrading: If ``true``, degrading will be applied to the image. The amount of degrading is defined with "degrade_scales" parameter.
* brightening: If ``true``, brightening will be applied to the image. The amount of brightening is defined with "brightness" parameter.
* rotation_not_90: If ``true``, rotation (not 90 degree) will be applied on image. Rotation angles are given with "thetha" parameter.
* rotation: If ``true``, 90 degree rotation will be applied on image.
* binarization: If ``true``,Otsu thresholding will be applied to augment the input data with binarized images.
* 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.
* flip_index: Type of flips.
* blur_k: Type of blurrings.
* scales: Scales of scaling.
* brightness: The amount of brightenings.
* thetha: Rotation angles.
* degrade_scales: The amount of degradings.
* continue_training: If ``true``, it means that you have already trained a model and you would like to continue the training. So it is needed to provide the dir of trained model with "dir_of_start_model" and index for naming the models. For example if you have already trained for 3 epochs then your last index is 2 and if you want to continue from model_1.h5, you can set ``index_start`` to 3 to start naming model with index 3.
* weighted_loss: If ``true``, this means that you want to apply weighted categorical_crossentropy as loss fucntion. Be carefull if you set to ``true``the parameter "is_loss_soft_dice" should be ``false``
* data_is_provided: If you have already provided the input data you can set this to ``true``. Be sure that the train and eval data are in "dir_output". Since when once we provide training data we resize and augment them and then we write them in sub-directories train and eval in "dir_output".
* dir_train: This is the directory of "images" and "labels" (dir_train should include two subdirectories with names of images and labels ) for raw images and labels. Namely they are not prepared (not resized and not augmented) yet for training the model. When we run this tool these raw data will be transformed to suitable size needed for the model and they will be written in "dir_output" in train and eval directories. Each of train and eval include "images" and "labels" sub-directories.
* index_start: Starting index for saved models in the case that "continue_training" is ``true``.
* dir_of_start_model: Directory containing pretrained model to continue training the model in the case that "continue_training" is ``true``.
* 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.
* transformer_cnn_first: We have two types of vision transformers. In one type, a CNN is applied first, followed by a transformer. In the other type, this order is reversed. If transformer_cnn_first is true, it means the CNN will be applied before the transformer. Default value is true.
* `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 the case of segmentation and enhancement the train and evaluation directory should be as following.
In case of segmentation and enhancement the train and evaluation data should be organised as follows.
The "dir_train" should be like this:
The "dir_train" directory should be like this:
```
.
@ -349,12 +478,40 @@ And the "dir_eval" the same structure as train directory:
└── labels # directory of labels
```
After configuring the JSON file for segmentation or enhancement, training can be initiated by running the following
command, similar to the process for classification and reading order:
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:
`python train.py with config_classification.json`
```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
@ -398,7 +555,7 @@ An example config json file for binarization can be like this:
"thetha" : [10, -10],
"continue_training": false,
"index_start" : 0,
"dir_of_start_model" : " ",
"dir_of_start_model" : " ",
"weighted_loss": false,
"is_loss_soft_dice": false,
"data_is_provided": false,
@ -443,7 +600,7 @@ An example config json file for binarization can be like this:
"thetha" : [10, -10],
"continue_training": false,
"index_start" : 0,
"dir_of_start_model" : " ",
"dir_of_start_model" : " ",
"weighted_loss": false,
"is_loss_soft_dice": false,
"data_is_provided": false,
@ -488,7 +645,7 @@ An example config json file for binarization can be like this:
"thetha" : [10, -10],
"continue_training": false,
"index_start" : 0,
"dir_of_start_model" : " ",
"dir_of_start_model" : " ",
"weighted_loss": false,
"is_loss_soft_dice": false,
"data_is_provided": false,
@ -498,7 +655,7 @@ An example config json file for binarization can be like this:
}
```
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
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
@ -536,7 +693,7 @@ image.
"thetha" : [10, -10],
"continue_training": false,
"index_start" : 0,
"dir_of_start_model" : " ",
"dir_of_start_model" : " ",
"weighted_loss": false,
"is_loss_soft_dice": false,
"data_is_provided": false,
@ -546,10 +703,11 @@ image.
}
```
For page segmentation (or printspace or border segmentation), the model needs to view the input image in its entirety,
hence the patches parameter should be set to false.
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
@ -593,7 +751,7 @@ An example config json file for layout segmentation with 5 classes (including ba
"thetha" : [10, -10],
"continue_training": false,
"index_start" : 0,
"dir_of_start_model" : " ",
"dir_of_start_model" : " ",
"weighted_loss": false,
"is_loss_soft_dice": false,
"data_is_provided": false,
@ -605,28 +763,42 @@ An example config json file for layout segmentation with 5 classes (including ba
## Inference with the trained model
### classification
For conducting inference with a trained model, you simply need to execute the following command line, specifying the
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:
`python inference.py -m "model dir" -i "image" `
```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:
`python inference.py -m "model dir" -xml "page xml file" -o "output dir to write new xml with 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:
`python inference.py -m "model dir" -i "image" -p -s "output image" `
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
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.

View file

@ -3,49 +3,69 @@ 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> \
-m <directory containing model files> \
[OPTIONS]
[LAYOUT_OPTIONS]
```
## Processing options
The following options can be used to further configure the processing:
## Generic options
Pass any of the following options:
| option | description |
| **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 |
| `-light` | lighter and faster but simpler method for main region detection and deskewing |
| `-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 instead of bounding boxes |
| `-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`) |
| `-eoi` | extract only images to output directory (other processing will not be done) |
| `-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 `--no-full-layout`
### `--full-layout` vs shallow
Here are the difference in elements detected depending on the `--full-layout`/`--no-full-layout` command line flags:
Here are the differences in segment types detected:
| | `--full-layout` | `--no-full-layout` |
|--------------------------|-----------------|--------------------|
| reading order | x | x |
| header regions | x | - |
| text regions | x | x |
| text regions / text line | x | x |
| drop-capitals | x | - |
| marginals | x | x |
| marginals / text line | x | x |
| image region | x | x |
| | `-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
@ -54,13 +74,13 @@ Eynollah ships with a CLI interface to be used as [OCR-D](https://ocr-d.de) proc
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 models
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 models
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.

142
models/Makefile Normal file
View file

@ -0,0 +1,142 @@
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

View file

@ -0,0 +1 @@
../../../../models_eynollah/characters_org.txt

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-binarization_20210309

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-binarization_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-column-classifier_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-enhancement_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-rotation_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-scaling_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions-ensembled_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions_20220314.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-tables_20210319.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/model_eynollah_ocr_cnnrnn_20250930

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_cnnrnn__degraded_20250805

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_trocr_20250919

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/model_eynollah_page_extraction_20250915.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/model_eynollah_reading_order_20250824.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_full_lay_1__4_3_091124.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_table_0t4_201124.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_textline_0_1__2_4_16092024.onnx

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-binarization_20210309

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-binarization_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-scaling_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-tables_20210319.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_textline_0_1__2_4_16092024.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-binarization_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-column-classifier_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-enhancement_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-rotation_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions-aug-scaling_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions-ensembled_20210425.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions_20220314.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/model_eynollah_page_extraction_20250915.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/model_eynollah_reading_order_20250824.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_full_lay_1__4_3_091124.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_table_0t4_201124.onnx

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/modelens_textline_0_1__2_4_16092024.onnx

View file

@ -0,0 +1 @@
../../../../models_eynollah/characters_org.txt

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/model_eynollah_ocr_cnnrnn_20250930

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_cnnrnn__degraded_20250805

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_trocr_20250919

View file

@ -0,0 +1 @@
../../../../models_eynollah/characters_org.txt

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-binarization-hybrid_20230504

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-binarization_20210309

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-binarization_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-column-classifier_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-enhancement_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions-aug-rotation_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions-aug-scaling_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions-ensembled_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions_20220314

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-tables_20210319

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_cnnrnn_20250930

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_cnnrnn__degraded_20250805

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_trocr_20250919

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_page_extraction_20250915

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_reading_order_20250824

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_full_lay_1__4_3_091124

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_table_0t4_201124

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_textline_0_1__2_4_16092024

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-binarization_20210309

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-binarization_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions-aug-scaling_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-tables_20210319

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_textline_0_1__2_4_16092024

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-column-classifier_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-enhancement_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions-aug-rotation_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions-aug-scaling_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions-ensembled_20210425

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions_20220314

View file

@ -0,0 +1 @@
../../../../models_eynollah/eynollah-main-regions_20231127_672_org_ens_11_13_16_17_18

View file

@ -0,0 +1 @@
../../../../reloaded/models_eynollah/model_eynollah_page_extraction_20250915

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_reading_order_20250824

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_e_l_all_sp_0_1_2_3_4_171024

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_full_lay_1__4_3_091124

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_table_0t4_201124

View file

@ -0,0 +1 @@
../../../../models_eynollah/modelens_textline_0_1__2_4_16092024

View file

@ -0,0 +1 @@
../../../../models_eynollah/characters_org.txt

View file

@ -0,0 +1 @@
../../../../models_eynollah/model_eynollah_ocr_cnnrnn_20250930

Some files were not shown because too many files have changed in this diff Show more