diff --git a/.gitignore b/.gitignore
index 394b9648..8fc7b143 100644
--- a/.gitignore
+++ b/.gitignore
@@ -167,4 +167,8 @@ cython_debug/
.idea/
*.sh
-_testbed/cleaner/
+
+.DS_Store
+_testbed/media/**
+_testbed/cleaner/**
+_testbed/model/**
diff --git a/_testbed/README.md b/_testbed/README.md
new file mode 100644
index 00000000..702df030
--- /dev/null
+++ b/_testbed/README.md
@@ -0,0 +1,55 @@
+# PanelCleaner Testbed
+
+## Overview
+The **PanelCleaner** testbed serves as a dedicated area for experimenting and testing new ideas with *PanelCleaner* using Jupyter Notebooks. Currently, it focuses on **OCR** technologies, primarily using **Tesseract** and **IDefics** models. The testbed also begins the development of an evaluation framework to support future experiments. This project utilizes the `nbdev` literate programming environment.
+
+## Installation
+To get started with the notebooks, you'll need Jupyter Lab/Notebook or any Python IDE that supports Jupyter notebooks like *VSCode* or *Google Colab*.
+The setup mostly shares the same requirements as PanelCleaner and its CLI, with a few additional dependencies.
+Here’s how to set up your environment:
+1. Activate a virtual environment.
+2. Navigate to the `_testbed` directory:
+ ```bash
+ cd _testbed
+ ```
+3. Install the required dependencies:
+ ```bash
+ pip install -r requirements.txt
+ ```
+Note: Each notebook may require the installation of additional dependencies.
+
+## Google Colab Support
+The notebooks are ready to use on Google Colab, allowing you to run them directly on the platform without any extra setup or local GPU rigs.
+Instructions to use Google Colab are included in the notebooks (TBD).
+
+## Install Test Images
+The test images are not included in the repository but can be downloaded from the following link:
+- [Test images](https://drive.google.com/drive/folders/101_1_20240229)
+
+After downloading, place the test images in the [media](media) directory. If you want to use your own, each image should have a corresponding text file with the same name, but with the extension `.txt`, which contains the ground truth data, one line per box (as calculated by PanelCleaner). Optionally, you can also include a `.json` file with the same name, specifying the language of the page:
+```json
+{
+ "lang": "Spanish"
+}
+```
+If no language file is found, English will be used by default. In the near future, language detection will be automated.
+
+## Introduction to nbdev
+[nbdev](https://nbdev.fast.ai/) is a **literate programming** environment that allows you to develop a Python library in Jupyter Notebooks, integrating exploratory programming, code, tests, and documentation into a single cohesive workflow. Inspired by **Donald Knuth**'s concept of literate programming, this approach not only makes the development process more intuitive but also eases the maintenance and understanding of the codebase.
+
+## Notebooks (WIP)
+
+#### [helpers.ipynb](helpers.ipynb)
+This notebook includes utility functions and helpers that support the experiments in other notebooks, streamlining repetitive tasks and data manipulation.
+
+#### [ocr_metric.ipynb](ocr_metric.ipynb)
+This notebook focuses on defining and implementing metrics to evaluate the performance and accuracy of OCR engines, crucial for assessing the effectiveness of OCR technologies in various scenarios. It currently develops a basic metric for evaluating OCR models. In the near future, additional metrics will be added, such as precision and recall using Levenshtein distance (edit distance). More importantly, it will introduce a metric tailored to the unique characteristics of Comics/Manga OCR, a topic currently unexplored in technical literature.
+
+#### [experiments.ipynb](experiments.ipynb)
+This notebook details the development of the evaluation framework used in other notebooks, with Tesseract as a case study to illustrate the evaluation process. It's a work in progress, and will be updated continuously. If you're only interested in visualizing the results of the experiments, go directly to `Test_tesseract.ipynb` or `Test_idefics.ipynb`, which are much shorter and more to the point.
+
+#### [test_tesseract.ipynb](test_tesseract.ipynb)
+This notebook is dedicated to testing the Tesseract OCR engine, offering insights into its capabilities and limitations through hands-on experiments.
+
+#### [test_idefics.ipynb](test_idefics.ipynb)
+Similar to `test_tesseract.ipynb`, this notebook focuses on the IDefics LVM model, evaluating its performance and accuracy under different conditions. Here you can compare the results of the Tesseract OCR engine with the IDefics LVM model to see how the two compare in terms of accuracy and performance.
diff --git a/_testbed/experiments.ipynb b/_testbed/experiments.ipynb
new file mode 100644
index 00000000..6c8d3c81
--- /dev/null
+++ b/_testbed/experiments.ipynb
@@ -0,0 +1,6810 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| default_exp experiments"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| hide\n",
+ "# %reload_ext autoreload\n",
+ "# %autoreload 0\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# install (Colab)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# try: \n",
+ "# import fastcore as FC\n",
+ "# except ImportError: \n",
+ "# !pip install -q fastcore\n",
+ "# try:\n",
+ "# import rich\n",
+ "# except ImportError:\n",
+ "# !pip install -q rich\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note: we're using the `testbed` branch of PanelCleaner.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Testing `Tesseract` OCR for Comics\n",
+ "> Accuracy Enhancements for OCR in `PanelCleaner`\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Prologue"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "from __future__ import annotations\n",
+ "\n",
+ "import dataclasses\n",
+ "import difflib\n",
+ "import functools\n",
+ "import json\n",
+ "import shutil\n",
+ "from collections import defaultdict\n",
+ "from enum import Enum\n",
+ "from pathlib import Path\n",
+ "from typing import Any\n",
+ "from typing import Callable\n",
+ "from typing import cast\n",
+ "from typing import Mapping\n",
+ "from typing import Self\n",
+ "from typing import TypeAlias\n",
+ "\n",
+ "import fastcore.all as FC\n",
+ "import ipywidgets as W\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import pcleaner.config as cfg\n",
+ "import pcleaner.ctd_interface as ctm\n",
+ "import pcleaner.image_ops as ops\n",
+ "import pcleaner.ocr.ocr as ocr\n",
+ "import pcleaner.structures as st\n",
+ "import torch\n",
+ "from IPython.display import clear_output\n",
+ "from IPython.display import display\n",
+ "from IPython.display import HTML\n",
+ "from ipywidgets.widgets.interaction import show_inline_matplotlib_plots\n",
+ "from loguru import logger\n",
+ "from pcleaner.ocr.ocr_tesseract import TesseractOcr\n",
+ "from PIL import Image\n",
+ "from PIL import ImageFilter\n",
+ "from rich.console import Console\n",
+ "from tqdm.notebook import tqdm\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "\n",
+ "from helpers import *\n",
+ "from ocr_metric import *\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import copy\n",
+ "\n",
+ "import fastcore.xtras # patch Path with some utils\n",
+ "import pcleaner.cli_utils as cli\n",
+ "import pcleaner.preprocessor as pp\n",
+ "import rich\n",
+ "from fastcore.test import * # type: ignore\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Helpers"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# pretty print by default\n",
+ "# %load_ext rich"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| exporti\n",
+ "console = Console(width=104, tab_size=4, force_jupyter=True)\n",
+ "cprint = console.print\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Tesseract installation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['tesseract 5.3.4',\n",
+ " ' leptonica-1.84.1',\n",
+ " ' libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp 1.4.0 : libopenjp2 2.5.2',\n",
+ " ' Found NEON',\n",
+ " ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n",
+ " ' Found libcurl/8.4.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.11 nghttp2/1.51.0']"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "out = !tesseract --version\n",
+ "out\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Install jpn_vert tesserac lang\n",
+ "> It has much better results than the default `jpn` language model.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best), or from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) trained for vertical Japanese text as found in manga.\n",
+ "\n",
+ "Note: I've not play much with this one, `managa-ocr` is surely a much better fit, but it can be educational to compare.\n",
+ "\n",
+ "I have copied models in my GDrive, and installed (in my Ubuntu, similar in Mac):\n",
+ "```bash\n",
+ "cd model\n",
+ "ln -s jpn_vert_tessdata_best.traineddata /usr/share/tesseract-ocr/5/tessdata/jpn_vert.traineddata\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Path('/opt/homebrew/share/tessdata'),\n",
+ " ['afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n",
+ " 'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n",
+ " 'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n",
+ " 'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n",
+ " 'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n",
+ " 'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n",
+ " 'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n",
+ " 'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, script/Kannada, script/Khmer',\n",
+ " 'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n",
+ " 'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n",
+ " 'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'])"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "out = !tesseract --list-langs\n",
+ "tessdata = Path(out[0].split('\"')[1])\n",
+ "tessdata, [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]]\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
Width x Height: 804 x 1241 pixels\n",
+ " PIL Info DPI: None\n",
+ " Print Size 300 DPI: 2.680 x 4.137 in /6.807 x 10.507 cm\n",
+ "Required DPI Modern Age format: 121.216 dpi (6.625 x 10.250 in)\n",
+ "
\n"
+ ],
+ "text/plain": [
+ " Width x Height: \u001b[1;36m804\u001b[0m x \u001b[1;36m1241\u001b[0m pixels\n",
+ " PIL Info DPI: \u001b[3;35mNone\u001b[0m\n",
+ " Print Size \u001b[1;36m300\u001b[0m DPI: \u001b[1;36m2.680\u001b[0m x \u001b[1;36m4.137\u001b[0m in \u001b[35m/\u001b[0m \u001b[1;36m6.807\u001b[0m x \u001b[1;36m10.507\u001b[0m cm\n",
+ "Required DPI Modern Age format: \u001b[1;36m121.216\u001b[0m dpi \u001b[1m(\u001b[0m\u001b[1;36m6.625\u001b[0m x \u001b[1;36m10.250\u001b[0m in\u001b[1m)\u001b[0m\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(IMAGE_CONTEXT.image_info)\n",
+ "img_visor.image_info()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Balloons and Captions Ground Truth\n",
+ "> The ground truth for the balloons and captions is read from a `.txt` file.\n",
+ "\n",
+ "The file is named `.gt.txt` and contains one entry per line, corresponding to each balloon or caption in the order found in PanelClenaer page data.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.',\n",
+ " 'The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home--',\n",
+ " 'And one in need of some help, it would appear.',\n",
+ " 'Bambu-- we have a guest.',\n",
+ " '--and tonight, he comes most urgently, slamming open the oaken front doors!',\n",
+ " 'Tell me, master-- how may Bambu serve?',\n",
+ " 'Some blankets to keep her warm, Bambu-- and perhaps some dry clothes',\n",
+ " \"The echo of the old man's footsteps fades down the hall as...\",\n",
+ " 'How curious the whims of fate. Had I not chanced to stroll along the river tonight--',\n",
+ " 'As quickly as I can, master',\n",
+ " '--the girl would most surely be dead by now.',\n",
+ " 'Ghede has been generous. the Death God has given the girl a second chance at--',\n",
+ " \"Easy, girl-- there's nothing to scream about anymore.\",\n",
+ " \"You're among friends now, you're safe!\",\n",
+ " 'Continued after next page']"
+ ]
+ },
+ "execution_count": 63,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "IMAGE_CONTEXT.gts\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Experiment\n",
+ "> Use `ExperimentOCR` to perform OCR on the page balloons given a `CropMethod` and a model (i.e., `'Tesseract'` or `'Idefics'`)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| exporti\n",
+ "\n",
+ "def trimmed_mean(data, trim_percent):\n",
+ " sorted_data = np.sort(data)\n",
+ " n = len(data)\n",
+ " trim_count = int(trim_percent * n)\n",
+ " trimmed_data = sorted_data[trim_count:-trim_count]\n",
+ " return np.mean(trimmed_data)\n",
+ "\n",
+ "def mad_based_outlier(points, threshold=3.5):\n",
+ " median = np.median(points)\n",
+ " diff = np.abs(points - median)\n",
+ " mad = np.median(diff)\n",
+ " modified_z_score = 0.6745 * diff / mad\n",
+ " return points[modified_z_score < threshold]\n",
+ "\n",
+ "def iqr_outlier_removal(data):\n",
+ " q1 = np.percentile(data, 25)\n",
+ " q3 = np.percentile(data, 75)\n",
+ " iqr = q3 - q1\n",
+ " lower_bound = q1 - 1.5 * iqr\n",
+ " upper_bound = q3 + 1.5 * iqr\n",
+ " return data[(data >= lower_bound) & (data <= upper_bound)]\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "\n",
+ "@dataclasses.dataclass\n",
+ "class Experiment:\n",
+ " ctx: ExperimentContext\n",
+ "\n",
+ "\n",
+ "@dataclasses.dataclass\n",
+ "class ExperimentOCR(Experiment):\n",
+ " ctx: ImageContext\n",
+ " ocr_model: str\n",
+ "\n",
+ " @property\n",
+ " def img_ctx(self): return self.ctx\n",
+ " @property\n",
+ " def ctxs(self):\n",
+ " img_ctx = self.img_ctx\n",
+ " return cast(OCRExperimentContext, img_ctx.exp), img_ctx\n",
+ "\n",
+ " @classmethod\n",
+ " def file_path_of(cls, page_data: st.PageData, ocr_model: str):\n",
+ " return f\"{Path(page_data.original_path).stem}_{ocr_model}.json\"\n",
+ " \n",
+ " def file_path(self):\n",
+ " img_ctx = self.img_ctx\n",
+ " return type(self).file_path_of(img_ctx.page_data, self.ocr_model)\n",
+ " \n",
+ " def to_dict(self):\n",
+ " \"JSON serializable dict of the experiment\"\n",
+ " img_ctx = self.img_ctx\n",
+ " img_idx = img_ctx.image_idx\n",
+ " results = results_to_dict(self.results())\n",
+ " return {\n",
+ " 'image_name': img_ctx.image_name,\n",
+ " 'ocr_model': self.ocr_model, \n",
+ " 'results': results,\n",
+ " }\n",
+ "\n",
+ " def to_json(self, out_dir: Path | None = None):\n",
+ " img_ctx = self.img_ctx\n",
+ " fp = (out_dir or img_ctx.cache_dir_image) / self.file_path()\n",
+ " data = self.to_dict()\n",
+ " with open(fp, 'w') as f:\n",
+ " json.dump(data, f, indent=2)\n",
+ " return fp, data\n",
+ "\n",
+ " @classmethod\n",
+ " def from_json(cls, experiment: OCRExperimentContext, json_path: Path) -> Self:\n",
+ " try:\n",
+ " with open(json_path, 'r') as f:\n",
+ " data = json.load(f)\n",
+ " except Exception as e:\n",
+ " logger.error(f\"Error loading {json_path}: {e}\")\n",
+ " raise e\n",
+ " ocr_model = data['ocr_model']\n",
+ " img_ctx = ImageContext(experiment, data['image_name'])\n",
+ " results: ResultSetDefault = dict_to_results(\n",
+ " img_ctx.image_idx, \n",
+ " data['results'], \n",
+ " result_factory=experiment._result_from)\n",
+ " experiment.update_results(ocr_model, img_ctx.image_idx, results)\n",
+ " return cls(img_ctx, ocr_model)\n",
+ "\n",
+ " @classmethod\n",
+ " def from_image(cls, \n",
+ " ctx: OCRExperimentContext, \n",
+ " ocr_model: str, \n",
+ " image_idx: ImgSpecT):\n",
+ " idx = cast(ImgIdT, ctx.normalize_idx(image_idx))\n",
+ " img_ctx = ImageContext(ctx, idx)\n",
+ " if img_ctx is None:\n",
+ " raise ValueError(f\"Image {image_idx} not found in experiment context\")\n",
+ " fp = img_ctx.cache_dir / cls.file_path_of(img_ctx.page_data, ocr_model)\n",
+ " if fp.exists(): \n",
+ " return cast(Self, cls.from_json(cast(OCRExperimentContext, img_ctx.exp), fp))\n",
+ " return cls(img_ctx, ocr_model)\n",
+ "\n",
+ " @classmethod\n",
+ " def from_method(cls, \n",
+ " ctx: OCRExperimentContext, \n",
+ " ocr_model: str, \n",
+ " image_idx: ImgIdT | str | Path, \n",
+ " method: CropMethod):\n",
+ " experiment = cls.from_image(ctx, ocr_model, image_idx)\n",
+ " if experiment is None:\n",
+ " return None\n",
+ " return experiment.method_experiment(method)\n",
+ "\n",
+ " @classmethod\n",
+ " def saved_experiment(cls, \n",
+ " ctx: OCRExperimentContext, ocr_model: str, image_idx: ImgIdT | str | Path):\n",
+ " idx = ctx.normalize_idx(image_idx)\n",
+ " if idx is None: \n",
+ " logger.warning(f\"Image {image_idx} not found in experiment context\")\n",
+ " return None\n",
+ " return cls.from_image(ctx, ocr_model, idx)\n",
+ "\n",
+ " @classmethod\n",
+ " def saved_experiments(cls, ctx: OCRExperimentContext, ocr_model: str) -> list[Self]:\n",
+ " return [exp for i in range(len(ctx.image_paths))\n",
+ " if (exp := cls.from_image(ctx, ocr_model, i)) is not None]\n",
+ " \n",
+ "\n",
+ " def result(self, box_idx: BoxIdT, method: CropMethod, ocr: bool=True, rebuild: bool=False):\n",
+ " ctx, img_ctx = self.ctxs\n",
+ " return ctx.result(self.ocr_model, img_ctx.image_idx, box_idx, method, ocr, rebuild)\n",
+ "\n",
+ " def results(self):\n",
+ " ctx, img_ctx = self.ctxs\n",
+ " return cast(ResultSet, ctx.results(self.ocr_model, img_ctx.image_idx))\n",
+ "\n",
+ " def has_run(self):\n",
+ " \"at least one method has run\"\n",
+ " img_ctx = self.img_ctx\n",
+ " return len(self.results()) == len(img_ctx.page_data.boxes)\n",
+ " \n",
+ " def best_results(self):\n",
+ " img_ctx = self.img_ctx\n",
+ " results = self.results()\n",
+ " if len(results) < len(img_ctx.page_data.boxes): # at least one method has run\n",
+ " return None\n",
+ " best = []\n",
+ " for box_idx in results:\n",
+ " methods = results[box_idx]\n",
+ " best_method = max(methods, key=lambda m: methods[m].acc) # type: ignore\n",
+ " best.append((best_method, methods[best_method]))\n",
+ " return best\n",
+ "\n",
+ " def save_results_as_ground_truth(self, overwrite=False):\n",
+ " img_ctx = self.img_ctx\n",
+ " gts_path = ground_truth_path(img_ctx.page_data)\n",
+ " if overwrite or not gts_path.exists():\n",
+ " best_results = self.best_results()\n",
+ " if best_results:\n",
+ " tt = [r.ocr for m,r in best_results]\n",
+ " gts_path.write_text('\\n'.join(tt), encoding=\"utf-8\")\n",
+ " img_ctx.setup_ground_truth()\n",
+ " logger.info(f\"Ground truth data saved successfully to {gts_path}\")\n",
+ " return True\n",
+ " else:\n",
+ " logger.info(\"No best results available to save.\")\n",
+ " return False\n",
+ " else:\n",
+ " return False\n",
+ "\n",
+ " @property\n",
+ " def experiments(self):\n",
+ " if not hasattr(self, '_experiments'):\n",
+ " self._experiments = {}\n",
+ " return self._experiments\n",
+ " def method_experiment(self, method: CropMethod) -> ExperimentOCRMethod:\n",
+ " if method not in self.experiments:\n",
+ " self.experiments[method] = ExperimentOCRMethod(self, method)\n",
+ " return self.experiments[method]\n",
+ " \n",
+ "\n",
+ " def to_dataframe(self):\n",
+ " \"Dataframe with crop methods as columns and box ids as rows\"\n",
+ " methods = list(CropMethod.__members__.values())\n",
+ " experiments = [self.method_experiment(m) for m in methods]\n",
+ " accuracies = [[result.acc for result in exp.results()] for exp in experiments]\n",
+ " # transpose accuracies\n",
+ " accuracies = list(zip(*accuracies))\n",
+ " return pd.DataFrame(accuracies, columns=CropMethod.__display_names__())\n",
+ "\n",
+ " def plot_accuracies(self, \n",
+ " methods: list[CropMethod] | None = None, \n",
+ " ):\n",
+ " \"Plots a horizontal bar chart of the accuracies for a list of method experiments.\"\n",
+ " methods = methods or list(CropMethod.__members__.values())\n",
+ " experiments = [self.method_experiment(m) for m in methods]\n",
+ " if not experiments: return\n",
+ "\n",
+ " ctx, img_ctx = self.ctxs\n",
+ " page_data = img_ctx.page_data\n",
+ " model = self.ocr_model\n",
+ " accuracies = [[result.acc for result in exp.results()] for exp in experiments]\n",
+ " accuracies = [np.mean(a) for a in accuracies]\n",
+ " # accuracies = [np.mean([result.acc for result in exp.results()]) for exp in experiments]\n",
+ "\n",
+ " _, ax = plt.subplots(figsize=(10, 5))\n",
+ " \n",
+ " # Normalize the accuracies for color mapping\n",
+ " norm = plt.Normalize(min(accuracies), max(accuracies))\n",
+ " # Color map from red to green\n",
+ " cmap = plt.get_cmap('RdYlGn')\n",
+ " colors = cmap(norm(accuracies))\n",
+ "\n",
+ " ax.barh([m.value for m in methods], accuracies, color=colors)\n",
+ "\n",
+ " ax.set_xscale('log') # Set the x-axis to a logarithmic scale\n",
+ " ax.set_xlabel('Average Accuracy (log scale)', fontsize=12, fontweight='bold')\n",
+ "\n",
+ " ax.set_ylabel('Method', fontsize=12, fontweight='bold')\n",
+ " ax.set_yticks(range(len(methods)))\n",
+ " ax.set_yticklabels([f'{method.value} ({acc:.2f})' \n",
+ " for method, acc in zip(methods, accuracies)], fontsize=12)\n",
+ " max_acc_index = np.argmax(accuracies)\n",
+ " ax.get_yticklabels()[max_acc_index].set(color='blue', fontweight='bold')\n",
+ "\n",
+ " title_text = (f\"{page_data.original_path} - OCR model: {model}\")\n",
+ " ax.set_title(title_text, fontsize=12, fontweight='bold')\n",
+ "\n",
+ " plt.tight_layout()\n",
+ " plt.show()\n",
+ "\n",
+ "\n",
+ " def summary_box(self, box_idx: int):\n",
+ " results: list[tuple[CropMethod, ResultOCR]] = []\n",
+ " pb = tqdm(CropMethod.__members__.values(), leave=False, desc=f\"Box #{box_idx+1}\")\n",
+ " for m in pb:\n",
+ " r = cast(ResultOCR, self.result(box_idx, m))\n",
+ " results.append((m, r))\n",
+ " methods, images, ocrs, accs = zip(\n",
+ " *map(\n",
+ " lambda t: (t[0].value, t[1].cache_image(), t[1].diff_tagged(), acc_as_html(t[1].acc)), \n",
+ " results))\n",
+ " display_columns([methods, images, accs, ocrs], \n",
+ " headers=[\"Method\", f\"Box #{box_idx+1}\", \"Accuracy\", \"OCR\"])\n",
+ "\n",
+ "\n",
+ " def summary_method(self, method: CropMethod):\n",
+ " results = self.method_experiment(method).results()\n",
+ " methods, images, ocrs, accs = zip(\n",
+ " *map(\n",
+ " lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), \n",
+ " results))\n",
+ " display_columns([methods, images, accs, ocrs], \n",
+ " headers=[\"Box #\", \"Box\", \"Accuracy\", f\"{method.value} OCR\"])\n",
+ "\n",
+ "\n",
+ " def display(self):\n",
+ " out = []\n",
+ " for method in CropMethod:\n",
+ " out.append(f\"---------- {method.value} ----------\")\n",
+ " results = self.method_experiment(method).results()\n",
+ " out.extend(results)\n",
+ " out.append('\\n')\n",
+ " cprint(*out, soft_wrap=True)\n",
+ "\n",
+ "\n",
+ " def reset(self, box_idx: int | None = None, method: CropMethod | None = None):\n",
+ " ctx, img_ctx = self.ctxs\n",
+ " ctx.reset_results(None, img_ctx.image_idx, box_idx, method)\n",
+ "\n",
+ " def perform_methods(self, \n",
+ " methods: CropMethod | list[CropMethod] | None = None, \n",
+ " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n",
+ " rebuild: bool = False,\n",
+ " plot_acc: bool = False\n",
+ " ):\n",
+ " if methods is None:\n",
+ " methods = [*CropMethod.__members__.values()]\n",
+ " elif isinstance(methods, CropMethod):\n",
+ " methods = [methods]\n",
+ " if rebuild:\n",
+ " _methods = tqdm(methods, desc=\"Methods\")\n",
+ " else:\n",
+ " _methods = methods\n",
+ " for method in _methods:\n",
+ " method_exp = self.method_experiment(method)\n",
+ " if method_exp: \n",
+ " if rebuild:\n",
+ " method_exp(box_idxs, rebuild=rebuild)\n",
+ " if plot_acc:\n",
+ " self.plot_accuracies()\n",
+ "\n",
+ " def __call__(self, \n",
+ " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n",
+ " methods: CropMethod | list[CropMethod] | None = None, \n",
+ " save: bool = True,\n",
+ " display=False, \n",
+ " rebuild: bool=False, \n",
+ " save_as_ground_truth=False):\n",
+ " self.perform_methods(methods, box_idxs, rebuild=rebuild)\n",
+ " if save_as_ground_truth:\n",
+ " self.save_results_as_ground_truth(overwrite=True)\n",
+ " if save:\n",
+ " self.to_json()\n",
+ " if display:\n",
+ " self.display()\n",
+ " \n",
+ "\n",
+ "@dataclasses.dataclass\n",
+ "class ExperimentOCRMethod:\n",
+ " ctx: ExperimentOCR\n",
+ " method: CropMethod\n",
+ "\n",
+ " @property\n",
+ " def exp_ctx(self): return self.ctx\n",
+ " @property\n",
+ " def img_ctx(self): return self.ctx.ctx\n",
+ " @property\n",
+ " def ctxs(self):\n",
+ " img_ctx = self.img_ctx\n",
+ " return cast(OCRExperimentContext, img_ctx.exp), img_ctx, self.ctx\n",
+ " \n",
+ " def result(self, box_idx: BoxIdT, ocr: bool=True, rebuild: bool=False) -> ResultOCR | None:\n",
+ " ctx, img_ctx, exp_ctx = self.ctxs\n",
+ " return ctx.result(exp_ctx.ocr_model, img_ctx.image_idx, box_idx, self.method, ocr, rebuild)\n",
+ "\n",
+ " def results(self, \n",
+ " box_idxs: BoxIdT | list[BoxIdT] | None = None, \n",
+ " ocr: bool=True, rebuild: bool=False) -> list[ResultOCR]:\n",
+ " ctx, img_ctx, exp_ctx = self.ctxs\n",
+ " if box_idxs is None:\n",
+ " box_idxs = list(range(len(img_ctx.boxes)))\n",
+ " elif isinstance(box_idxs, int):\n",
+ " box_idxs = [box_idxs]\n",
+ " model = exp_ctx.ocr_model\n",
+ " results = ctx.method_results(model, img_ctx.image_idx, self.method)\n",
+ " results = {i:results[i] if i in results else None for i in box_idxs}\n",
+ " pb = rebuild or not results or any(r is None for r in results.values())\n",
+ " if pb and len(results) > 2:\n",
+ " progress_bar = tqdm(list(results.keys()), desc=f\"{self.method.value} - {model}\")\n",
+ " else:\n",
+ " progress_bar = list(results.keys())\n",
+ " results = []\n",
+ " for i in progress_bar:\n",
+ " results.append(self.result(i, ocr, rebuild=rebuild))\n",
+ " return results\n",
+ "\n",
+ "\n",
+ " def get_results_html(self, \n",
+ " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n",
+ " max_image_width: int | None = None): \n",
+ " _, img_ctx, exp_ctx = self.ctxs\n",
+ " results: list[ResultOCR] = self.results(box_idxs)\n",
+ " accs = np.array([r.acc for r in results])\n",
+ " mean_accuracy = np.mean(accs)\n",
+ " mean_trimmed = trimmed_mean(accs, 0.1)\n",
+ " # filtered_data = mad_based_outlier(accs)\n",
+ " # mean_mad = np.mean(filtered_data)\n",
+ " # filtered_data = iqr_outlier_removal(accs)\n",
+ " # mean_iqr = np.mean(filtered_data)\n",
+ " \n",
+ " descriptions, images, ocrs, accs = zip(*map(\n",
+ " lambda r: (\n",
+ " r.block_idx+1, \n",
+ " r.cache_image(), \n",
+ " r.diff_tagged(), \n",
+ " acc_as_html(r.acc)\n",
+ " ), results))\n",
+ " non_breakin_space = u'\\u00A0'\n",
+ " tmpl = \"{}\"\n",
+ " padded_s = lambda s,n: tmpl.format(s.rjust(n))\n",
+ " acc_fmt = f\"{mean_accuracy:.2f}/{mean_trimmed:.2f}\"\n",
+ " w, h = img_ctx.base_image.size\n",
+ " dim, _dpi = size(w, h), dpi(w, h)\n",
+ " dim_fmt = f\"{w}x{h} px: {dim[0]:.2f} x {dim[1]:.2f} in @ {_dpi:.2f} dpi\"\n",
+ " return '\\n \\n'.join([\n",
+ " (\"
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3 0.90
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.⎕⎕
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as 0.85
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orl⎕⎕⎕eans, kept tidy by a white-haired ⎕old man known only as Bambu.
Eneowered by great gnarled cypress jrfes, the ancient manor !⎕⎕⎕⎕⎕ alone on the eit⎕⎕⎕⎕⎕⎕ of mew ⎕rce: eans, kept tipy by a white-haired ao⎕⎕han known only as⎕⎕⎕⎕⎕⎕⎕
Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as 0.95
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as⎕⎕⎕⎕⎕⎕⎕
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as 0.88
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orl⎕⎕⎕eans, kept tidy by a white-haired ⎕o⎕ld man known only as Bambu.
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew ⎕rce: eans, kept tipy by a white-haired ao⎕lo man known only as⎕⎕⎕⎕⎕⎕⎕
Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as 0.88
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired ⎕o⎕ld man known only as Bambu.
Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile⎕ of new orleans, kept tipy by a white-haired ao⎕lo man known om⎕y as⎕⎕⎕⎕⎕⎕⎕
Embowered by great gnarled cypress trees, the ancient ⎕manor stands alone on the outskirts of New Orleans, kept tidy by a whi⎕te-haired old man known only as Bambu⎕⎕.
Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi⎕te-haire⎕ old man known only as bambi] .
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a whi⎕te-⎕haired old man known only as B⎕ambu⎕.
Enbonsred by great sha⎕le⎕ cypress trees, the anci⎕⎕⎕ manor stands alone on the [⎕tskirts of new orleans, kept tidy by a whi⎕te-⎕haired old man known only as b8ambl .
Embowered by great gnarled cypress trees, the ancient ⎕manor stands alone on the outskirts of New Orleans, kept tidy by a whi⎕te-haired old man known only as Bambu⎕⎕.
Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi⎕te-haired old man known only as 8ambli .
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
O⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕utskirts of new orleans, kept tipy by a white-haired old man known only as sams .
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a whi⎕te-haired old man known only as B⎕ambu⎕.
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi⎕te-haired old man known only as b8ambl .
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a whi⎕te-haired old man known only as B⎕ambu⎕.
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi⎕te-haired old man known only as b8ambl .
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
Default
0.85
Eneowered by great gnarled cypress jrfes, the ancient manor !⎕⎕⎕⎕⎕ alone on the eit⎕⎕⎕⎕⎕⎕ of mew ⎕rce: eans, kept tipy by a white-haired ao⎕⎕han known only as⎕⎕⎕⎕⎕⎕⎕
Default, grey pad
0.95
Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as⎕⎕⎕⎕⎕⎕⎕
Padded 4px
0.88
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew ⎕rce: eans, kept tipy by a white-haired ao⎕lo man known only as⎕⎕⎕⎕⎕⎕⎕
Padded 8px
0.88
Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile⎕ of new orleans, kept tipy by a white-haired ao⎕lo man known om⎕y as⎕⎕⎕⎕⎕⎕⎕
Extracted, init box
0.92
Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi⎕te-haire⎕ old man known only as bambi] .
Padded 4, extracted
0.91
Enbonsred by great sha⎕le⎕ cypress trees, the anci⎕⎕⎕ manor stands alone on the [⎕tskirts of new orleans, kept tidy by a whi⎕te-⎕haired old man known only as b8ambl .
Padded 8, extracted
0.94
Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi⎕te-haired old man known only as 8ambli .
Padded 8, dilation 1
0.61
O⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕utskirts of new orleans, kept tipy by a white-haired old man known only as sams .
Pad 8, fract. 0.5
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi⎕te-haired old man known only as b8ambl .
Pad 8, fract. 0.2
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi⎕te-haired old man known only as b8ambl .
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew ⎕rce: eans, kept tipy by a white-haired ao⎕lo man known only as⎕⎕⎕⎕⎕⎕⎕
2
0.93
The house and the old⎕man are alike in many ways; tall, proud, patient, contented aways 0⎕ wait until their.⎕aster comes home ~~ | }
3
0.69
F and one in ⎕ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.77
" bambli-— we have a gliest.
5
0.55
P⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ comes⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.57
Tel⎕oe⎕⎕⎕⎕⎕er-- 5 ow ⎕a⎕=⎕⎕⎕⎕7⎕⎕⎕⎕⎕
7
0.38
W⎕⎕e⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps c o⎕e /⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
8
0.75
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall sra⎕⎕⎕⎕
9
0.92
How curious the a⎕whims of fate⎕. - had i not chanced to stroll along the river yl⎕tonight~-⎕
10
0.79
A⎕⎕⎕ulckly as t can, ‘masrer.
11
0.92
<⎕the girl wolld⎕- most surely be dead by now.
12
0.88
Ghede has been generous. the oeath gop has given -⎕the girl. a second chance ye,⎕alem
13
0.67
Soe⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕er⎕eke⎕othing to scream ay⎕⎕⎕ anymore.
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3 0.90
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.⎕⎕
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0⎕ wait until. their. master cones mome ~~
3
0.70
“and one in ⎕ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.62
Re bambli-~ we have a⎕⎕⎕⎕⎕⎕⎕
5
0.70
T⎕⎕⎕⎕⎕⎕onight, he comes noost⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.82
Tell me⎕naster.⎕ how may bambli serve 7
7
0.56
£7⎕⎕»⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
8
0.81
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man'⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall as...⎕7
9
0.85
How curious the 4⎕fate.⎕whims of h⎕⎕⎕⎕⎕⎕ad t not chanced to stroll along the river yl⎕tonight ==
10
0.80
Fas oulckly as t ca⎕, master.
11
0.91
<⎕the girl would -⎕most slirely be dead by now.
12
0.47
A⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕th⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ the girl. a second chance ge⎕a ee yg adil
13
0.84
Ah⎕⎕⎕ girl--⎕there's ⎕othing to scream nt⎕⎕t anymore⎕.
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0⎕ wait until. their. master cones mome ~~
7
0.56
£7⎕⎕»⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0⎕ wait until. their. master cones mome ~~
3
0.70
“and one in ⎕ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.62
Re bambli-~ we have a⎕⎕⎕⎕⎕⎕⎕
5
0.70
T⎕⎕⎕⎕⎕⎕onight, he comes noost⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.82
Tell me⎕naster.⎕ how may bambli serve 7
7
0.56
£7⎕⎕»⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
8
0.81
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man'⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall as...⎕7
9
0.85
How curious the 4⎕fate.⎕whims of h⎕⎕⎕⎕⎕⎕ad t not chanced to stroll along the river yl⎕tonight ==
10
0.80
Fas oulckly as t ca⎕, master.
11
0.91
<⎕the girl would -⎕most slirely be dead by now.
12
0.47
A⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕th⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ the girl. a second chance ge⎕a ee yg adil
13
0.84
Ah⎕⎕⎕ girl--⎕there's ⎕othing to scream nt⎕⎕t anymore⎕.
14
0.93
You're among friends now. you're sale⎕
15
1.00
Continued after next page
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "method = CropMethod.INITIAL_BOX\n",
+ "# method = CropMethod.DEFAULT\n",
+ "# method = CropMethod.PADDED_4\n",
+ "# method = CropMethod.PADDED_8\n",
+ "# method = CropMethod.EXTRACTED_INIT_BOX\n",
+ "# method = CropMethod.PAD_8_FRACT_0_5\n",
+ "# method = CropMethod.PAD_8_FRACT_0_2\n",
+ "\n",
+ "# image_experiment.method_experiment(CropMethod.INITIAL_BOX).results()\n",
+ "initial_box_exp = image_experiment.method_experiment(CropMethod.INITIAL_BOX)\n",
+ "initial_box_exp(display=True)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Other method"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 102,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as,\n",
+ " ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~,\n",
+ " ResultOCR#block 02: 0.74||And one in ee would appear.,\n",
+ " ResultOCR#block 03: 0.41||Rir guest.,\n",
+ " ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo,\n",
+ " ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _,\n",
+ " ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps,\n",
+ " ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00,\n",
+ " ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >,\n",
+ " ResultOCR#block 09: 0.50||Aulckly “master as t can,,\n",
+ " ResultOCR#block 10: 0.94||"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "image_experiment.perform_methods(plot_acc=True)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 101,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
---------- Initial box ----------\n",
+ "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski)2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
+ "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
+ "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
+ "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
+ "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
+ "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
+ "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes...7/\n",
+ "ResultOCR#block 07: 0.81||The the old man's fades down the hall as...7\n",
+ "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
+ "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
+ "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
+ "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
+ "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
+ "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
+ "ResultOCR#block 14: 1.00||Continued after next page\n",
+ "\n",
+ " ---------- Default ----------\n",
+ "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
+ "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
+ "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
+ "ResultOCR#block 03: 0.41||Rir guest.\n",
+ "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
+ "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
+ "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
+ "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
+ "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
+ "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
+ "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
+ "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
+ "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
+ "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
+ "ResultOCR#block 14: 1.00||Continued after next page\n",
+ "\n",
+ " ---------- Default, grey pad ----------\n",
+ "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
+ "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
+ "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
+ "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
+ "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
+ "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+ "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7/.\n",
+ "ResultOCR#block 07: 0.06||As.\n",
+ "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
+ "ResultOCR#block 09: 0.55||Ickl as t can\n",
+ "ResultOCR#block 10: 0.00||\n",
+ "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
+ "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
+ "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
+ "ResultOCR#block 14: 0.54||“continued a\n",
+ "\n",
+ " ---------- Padded 4px ----------\n",
+ "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
+ "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
+ "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
+ "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
+ "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
+ "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
+ "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
+ "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
+ "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
+ "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
+ "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
+ "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
+ "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
+ "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
+ "ResultOCR#block 14: 1.00||Continued after next page\n",
+ "\n",
+ " ---------- Padded 8px ----------\n",
+ "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
+ "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
+ "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
+ "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
+ "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
+ "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
+ "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
+ "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
+ "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
+ "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
+ "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
+ "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
+ "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
+ "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
+ "ResultOCR#block 14: 0.94||“continued after next page\n",
+ "\n",
+ " ---------- Extracted, init box ----------\n",
+ "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
+ "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
+ "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+ "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
+ "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
+ "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
+ "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
+ "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
+ "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
+ "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
+ "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
+ "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
+ "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+ "\n",
+ " ---------- Padded 4, extracted ----------\n",
+ "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
+ "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
+ "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+ "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
+ "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
+ "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
+ "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
+ "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
+ "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
+ "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
+ "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
+ "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
+ "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+ "\n",
+ " ---------- Padded 8, extracted ----------\n",
+ "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
+ "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
+ "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
+ "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+ "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+ "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
+ "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
+ "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
+ "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
+ "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
+ "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ " ---------- Padded 8, dilation 1 ----------\n",
+ "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
+ "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
+ "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
+ "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
+ "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
+ "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+ "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
+ "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
+ "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
+ "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
+ "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
+ "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ " ---------- Pad 8, fract. 0.5 ----------\n",
+ "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+ "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
+ "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
+ "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+ "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+ "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+ "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
+ "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+ "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
+ "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
+ "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ " ---------- Pad 8, fract. 0.2 ----------\n",
+ "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+ "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
+ "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
+ "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+ "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+ "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+ "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
+ "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+ "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
+ "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
+ "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ "\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "---------- Initial box ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
+ "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n",
+ "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n",
+ "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n",
+ "\n",
+ " ---------- Padded 4px ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m||"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "image_experiment.plot_accuracies()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 103,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "
[\n",
+ " (\n",
+ " 'Default, grey pad',\n",
+ " '0.953',\n",
+ " 'Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of \n",
+ "new orleans, kept tipy by a white-haired old man known only as'\n",
+ " ),\n",
+ " (\n",
+ " 'Padded 8px',\n",
+ " '0.988',\n",
+ " 'The house and the old man are alike in many ways; tall, proud, patient, contented always to \n",
+ "wait until their. master comes home'\n",
+ " ),\n",
+ " ('Padded 8, dilation 1', '0.968', 'And one in need of some help, it wolld appear .'),\n",
+ " ('Default, grey pad', '0.880', '\" bambl-- we have a guest.'),\n",
+ " ('Padded 8, dilation 1', '0.794', '=and tonight, he comes most slamming open the front'),\n",
+ " ('Default, grey pad', '0.857', 'Tell me, master: how may bambli serve 7'),\n",
+ " (\n",
+ " 'Pad 8, fract. 0.5',\n",
+ " '0.935',\n",
+ " 'Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes'\n",
+ " ),\n",
+ " ('Initial box', '0.811', \"The the old man's fades down the hall as... 7\"),\n",
+ " (\n",
+ " 'Padded 8, extracted',\n",
+ " '0.959',\n",
+ " 'How curious the whims of fate . had i not chanced to stroll along the river tonight-~'\n",
+ " ),\n",
+ " ('Extracted, init box', '0.846', 'Aulckly as t can, master,'),\n",
+ " ('Extracted, init box', '1.000', '--the girl would most surely be dead by now.'),\n",
+ " (\n",
+ " 'Padded 8, extracted',\n",
+ " '0.935',\n",
+ " 'Ghede has been generous. the peath god has given the girl a second chance po'\n",
+ " ),\n",
+ " ('Default, grey pad', '0.953', \"Easy, girl--there's | nothing to scream about anyaore.\"),\n",
+ " ('Default, grey pad', '0.974', \"You're among friends now. you're safe!\"),\n",
+ " ('Initial box', '1.000', 'Continued after next page')\n",
+ "]\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "\u001b[1m[\u001b[0m\n",
+ " \u001b[1m(\u001b[0m\n",
+ " \u001b[32m'Default, grey pad'\u001b[0m,\n",
+ " \u001b[32m'0.953'\u001b[0m,\n",
+ " \u001b[32m'Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of \u001b[0m\n",
+ "\u001b[32mnew orleans, kept tipy by a white-haired old man known only as'\u001b[0m\n",
+ " \u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\n",
+ " \u001b[32m'Padded 8px'\u001b[0m,\n",
+ " \u001b[32m'0.988'\u001b[0m,\n",
+ " \u001b[32m'The house and the old man are alike in many ways; tall, proud, patient, contented always to \u001b[0m\n",
+ "\u001b[32mwait until their. master comes home'\u001b[0m\n",
+ " \u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Padded 8, dilation 1'\u001b[0m, \u001b[32m'0.968'\u001b[0m, \u001b[32m'And one in need of some help, it wolld appear .'\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.880'\u001b[0m, \u001b[32m'\" bambl-- we have a guest.'\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Padded 8, dilation 1'\u001b[0m, \u001b[32m'0.794'\u001b[0m, \u001b[32m'=and tonight, he comes most slamming open the front'\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.857'\u001b[0m, \u001b[32m'Tell me, master: how may bambli serve 7'\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\n",
+ " \u001b[32m'Pad 8, fract. 0.5'\u001b[0m,\n",
+ " \u001b[32m'0.935'\u001b[0m,\n",
+ " \u001b[32m'Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes'\u001b[0m\n",
+ " \u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Initial box'\u001b[0m, \u001b[32m'0.811'\u001b[0m, \u001b[32m\"The the old man's fades down the hall as... 7\"\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\n",
+ " \u001b[32m'Padded 8, extracted'\u001b[0m,\n",
+ " \u001b[32m'0.959'\u001b[0m,\n",
+ " \u001b[32m'How curious the whims of fate . had i not chanced to stroll along the river tonight-~'\u001b[0m\n",
+ " \u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Extracted, init box'\u001b[0m, \u001b[32m'0.846'\u001b[0m, \u001b[32m'Aulckly as t can, master,'\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Extracted, init box'\u001b[0m, \u001b[32m'1.000'\u001b[0m, \u001b[32m'--the girl would most surely be dead by now.'\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\n",
+ " \u001b[32m'Padded 8, extracted'\u001b[0m,\n",
+ " \u001b[32m'0.935'\u001b[0m,\n",
+ " \u001b[32m'Ghede has been generous. the peath god has given the girl a second chance po'\u001b[0m\n",
+ " \u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.953'\u001b[0m, \u001b[32m\"Easy, girl--there's | nothing to scream about anyaore.\"\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.974'\u001b[0m, \u001b[32m\"You're among friends now. you're safe!\"\u001b[0m\u001b[1m)\u001b[0m,\n",
+ " \u001b[1m(\u001b[0m\u001b[32m'Initial box'\u001b[0m, \u001b[32m'1.000'\u001b[0m, \u001b[32m'Continued after next page'\u001b[0m\u001b[1m)\u001b[0m\n",
+ "\u001b[1m]\u001b[0m\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "ll = image_experiment.best_results()\n",
+ "if ll:\n",
+ " cprint([(m.value, f\"{r.acc:.3f}\", r.ocr) for m,r in ll])\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Perfom experiments given a list of `CropMethod`s\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 105,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# methods = [*CropMethod.__members__.values()]\n",
+ "methods = [CropMethod.INITIAL_BOX, CropMethod.DEFAULT]\n",
+ "image_experiment.perform_methods(methods)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Plot the perfomance of the experiments"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 106,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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lagPAP9A7qMs7n/Jb9CggVU+adIkq7xkyZJGkgkODrbKmjRpkuVfwiWZGjVqGGOMef/9962yzp07e7SlcePG1rrLjXSnpaWZ0aNHm/r165uIiAivIzM//vijVX/69OlGkhk7dmyG12Dq1Knmxhtv9LqPiIgI88cff1h1Bw8enOVf+N1HuteuXZth/V9//WX69+9vqlatao18uj9CQkKsuu6jgh07drTKt23bZpW3bt3aGGPMjh07PEY/3Eeunn/++QwjIStWrLjseybJzJ07N8MxXE5Wo0k5Pf6ctts10hQUFGQefPBB8+6775ply5aZkydPZvu43GVnpDs5Odn63Pj5+Zldu3ZlWf/w4cMeI1UvvfSSx/rKlStb69xPe01LS/N4Df7880+zbt066+fSpUt77OfDDz+01rVp08YqnzZtmpk9e7Y5ePCgOXfunPn5559N3bp1rbruo+5Z8dYH3N/T//u///Oo7/75X7hwoUlKSjJ+fn5Gco40ur9nEydOtOraMdLtPiL89NNPe63z1FNPWXXatm1rjDFm5MiRVlmtWrV8ei737+BLH8WKFTMfffSRT/tx/9w1bNjQKp8wYYJVftNNN1nlgwYNssr/85//GGM8+4T7d44xxnTo0MFa52qTq19LMtu2bbPqLlu2zCp3jVKfO3fOBAQEXPaz+/jjjxtjsh7pzqnMvpvs+l6pXbu29Xvk8ccfNxMnTjSrVq0yZ86csers2rXLp+cePXp0hmOoWLGi18ui1q5da9q3b28iIyO9jt4/8sgjxhhjvv76a6usQoUKHr83LnW5332AN8xeDgBeVKxY0VoODQ21lsuVK2ctu0ZuXH8Zl7yPkl3KNULgPnJ66WhIdHS0fvjhB5/a+vTTT1sj5plxjSxK0pw5cyTJ6+hmz5491bNnTx0/flw//PCDFi9erGnTpiktLU0JCQn66quv1K9fP5/a5a5evXoeP1+4cEEtW7bU1q1bM90ms1sQuU/oFhYWlqG+++taunRp+fv7Wz97m/jKl/fs0v1eqSs5fpfstvvtt99WXFycvvvuO3344YfW+sDAQD3xxBMaM2aMT/u7EjNnztSff/4pSerQoYPH5+xS27dv1x133GGNtA4bNkwvvfSSR50SJUro999/lySPszlcI46S8/gKFy7scZaDe91L65coUcJa7tGjh0e9unXr6t1331XTpk0lSevWrcu0/dkRHR2d4WfX5//48eM6efKkLly4IMk5Ku8+Up+d25BNnTrVGuVzad68uddbvXlr2969e73WcS931Xcf/d69e7dSUlJyPNotOb9nczI5Vna+y6WLnzv3z9el74/7a+6ql9n3+aXbSrLOmric3D67xhd2fa98/PHH6tWrl7Zu3erx+yo0NFTDhg3TM888c0XfxXXq1LHuUuCyfv163XLLLTp//nym+3L9bnR9L0lS9erVPX5vALmB08sBwIvMTtm83Kmc7v9h/+GHH7zOeOw6dbxo0aJW3UOHDnnsx3WKpi9mzJhhLc+bN08pKSkyxni9rU5iYqKWL1+uhg0bqmzZsh7rEhISrOXixYurQ4cO+vDDDz1uExYfH28tZ+dervny5fP4edu2bVbgLFGihLZt26b09HSPNmQmMDAwyzYUK1bMWj5y5IgVViTPU15d3N+z1q1be33PXDNb55YrOf6ctjs6Olrffvutjh07ppUrV+rDDz9UgwYNlJaWprFjx+rHH3/MtePLzFtvvWUtP/vss5nWW7t2rZo2baqDBw8qMDBQn3zySYbALUmNGjWylt1POXW/tVWdOnUUGBio8uXLq3jx4pKcs6C7f8bc6zds2FCSPPpNZi79T35OXfp5d/+5ePHiKlSokBUCTp8+7dFPvPXp3HTHHXdYy0uXLtXRo0c91h8+fFjLli2zfm7Tpo0kqWXLltYfxc6ePat3333X6/4zC5+DBw9WamqqFi1apHz58ikhIUFPPvmkxyUYvsiN7/JL3x/3Wehd9TL7Pvf2XV6kSBHr+cPDw63v7Esfn376aZZttINd3yt16tTRli1bdOjQIS1btkzjx49XlSpVdO7cOQ0YMEBHjhzxeO6qVat6fW5jjHWJlrtLf8dIzlP0XYG7W7duiouLkzHGa18sWbKktfzbb79l+fnnPubICUI3AOSijh07WsuPPfaYfv75Z6WkpCg+Pl5ffvmlunTpohEjRkiSbrvtNuuX96JFi7R48WKdOXNG06ZN83mUW/L8z2N4eLjS09M1adIkj3sRuyxevFjJycnWdYMu6enpKlu2rJ588kl98803OnnypNLS0rR161atXbvWqnfDDTdYy+7X4v73v//1aeTGW5v9/f2VP39+nT592uO68pyqVKmSNRJ1/Phxvf7669Z1eR999FGG+k2aNLGC+vLlyzV69GjFx8crJSVFO3bs0MiRI7Mckc2J3Dj+7Lb7zTff1MyZM5WQkKBGjRrp3nvv9bjdl/u1u5dz9uxZxcXFKS4uzuN9P336tFV+qeXLl1vBuGHDhmrSpInXfc+ePVutWrXSyZMnVaBAAS1dulQPPPCA17q9evWywuiECRO0adMmHTlyxOOaywcffNBa7tOnj7U8cOBAxcXFaeXKldbZHxEREbrvvvskOV+PBg0aaPr06Tpy5IhSUlK0adMmPfXUU9Y+mjdv7tEeh8Mhh8ORrdFnSdY9qC/9/IeGhqpp06bKly+fNbpujNHAgQN18uRJbdu2TaNGjfL5eXr16pUhwGQ1yi1J7du3t655TklJUefOnbVlyxalpaVpy5Yt6ty5s1JTUyVJ9evXV/v27SU5r5t/+eWXrf28/PLLGjVqlI4ePaq0tDTt2bNHY8eOtep7ExgYqDvvvFOvv/66VfbUU095nF1klzZt2igoKEiS83vziy++UFJSkubPn29dax0UFKTWrVtLklq1amVt+8ILL+jYsWM6ePCgR190CQkJsf44kZiYaF0/nJaWpkOHDmnatGlq0qSJx3dvZlx9LreCoF3fKy+++KLmz5+v9PR0NWvWTPfee6+1H2OM/vjjD1WsWFE1atSQJO3YsUMDBgyw+svevXs1YcIE1apVy+c/Srt/z4aEhCg0NFRbtmzRO++84/W4XX+U2717tx5++GEdPHhQSUlJWr9+vSZNmmTVvZLffbiO2XjqOgDkKZndpst9NnL3cvdrll2Sk5NNixYtsrwezX1W3sxmL3efcfdy13Q/8sgjGbbPly+fKV26dIZ9dOzY0Uiet0syJuM1sN4ejRs39rjOzf1WOO4P121YvL0+Lunp6aZGjRoZtnW/Rtd9u8xm787sWsfMZi93n0nY/RZTCxcuNEFBQVkef05kdt1kbh1/dtrdsmXLTOuEh4ebI0eO+Hxc7tc0+vp6tWrVylo3Z86cTPft3m982ffw4cMzrXfnnXd6XOd55swZU6dOHa91/fz8rOt5jfHsW5l9Ri+dwdzbe51Zuft76t4v3R/ut9lav36915mV3bft1atXlu9bTh06dMjUrFkzy9ejZs2a1t0Q3D377LNZbhcbG2vVzWz28tTUVFOpUiVr3ahRo7Js76W3knJxf83dyzO7Rvdydxhw3XLRmMxnL3f/Lnf/jtq7d2+m77vr4fre/rtnL7fje6VChQqZ1itdurQ5d+6cMcY5e3lERESWz+36HZPZ++yybt06ay4E94f796z7dr7MXm7M5X/3Ad4w0g0AuSg4OFgrVqzQe++9p8aNGysiIkJBQUEqXbq0mjVrpmHDhnmcrv32229r2LBhKlOmjIKCglSjRg3NnDnTminVF2PGjFH//v0VFRWlkJAQNW7cWCtWrPC4plKSkpKStHTpUtWvXz/DdYYBAQH65JNP1KdPH9WsWVPFixdXQECAwsLCFBsbqyFDhmj58uUe17nVq1dPEyZMUKVKlawRIV/5+/tr0aJFuvvuu1WoUCFFRESoc+fO+uabb7K1n8x07NhR8+fPV2xsrIKCglS2bFkNHTrUY+Zr99NB27dvr59//lk9evRQ2bJlFRgYqAIFCqhatWrq0aOHZs2alSvtcsmt489Ou3v16qW77rpL0dHRCgsLk7+/vyIjI9W5c2d9++23ioyMzNVjdPfrr79q+fLlkpzX0rqfEXKlXnjhBc2bN0/NmjVT/vz5FRISopo1a2rUqFGaN2+exyngYWFhWrNmjV566SWr3xYsWFBt2rTRqlWr1LVrV6tuyZIl9c4776ht27aKiYlRaGioQkJCVKVKFfXv319bt25VlSpVLts+91GwzD4n/fr108SJE1W5cmUFBQWpYsWKGj9+vJ5//nmrToMGDfT111+rcePGCg4OVokSJfT00097jAK79+ncVLp0aW3YsEHjxo1T8+bNVbhwYQUEBKhw4cJq1qyZ3nvvPW3YsMG6G4K70aNHa/369erdu7cqVKig0NBQhYWFqVKlSurevbvefPPNyz5/YGCgR73XX3/9b7neuX///lqxYoXatWunokWLyt/fX0WKFFHbtm21fPlyj7Meypcvr2+//Va33367QkNDVahQIT3wwAOZng5frlw5/fLLLxo4cKCqV69ujcSWL19e7du318SJE71eIvR3sON75YknnlDr1q1VunRphYSEKDAwUGXKlFHPnj21du1ahYSESHKeLbF161Y9+uijqlixooKDg5U/f35VqlRJXbp00dSpUxUVFeXTcTRu3Fhz5sxRrVq1FBISoujoaA0fPlyDBg3yWr9t27bavHmzevfurZiYGAUFBSk8PFyxsbEeZzJcye8+XL8cxvzvnioAgGva7Nmzdd9992nkyJEet9q6FiUmJmrDhg1q1qyZdQ349u3b1a5dO+3fv19+fn7avn27T6EJuBIbN25UgwYNJDmvkV26dKkkz0nNBg8erCFDhlx2X4sWLdJtt91mTQh24MABdenSxbrN1YoVK3TbbbfZcBQAgCvB7OUAcJ249957de+9917tZvwt4uPjddtttykwMFDFixdXcnKyxyRwgwcPJnDDdvXq1fOY4O1K7+N71113yd/fX8WKFdOFCxf0119/Wfej7927N4EbAP6hOL0cAHDNKViwoLp3766yZcvq1KlTSkhIUFRUlDp27Khly5bplVdeydF+W7Ro4TFx0aWPKw1VV1tMTEyWx+fLaCwu2rNnj4wxqlq1qsaNG+dx+npO9OvXT5UrV1ZSUpJOnDihYsWKqU2bNpo1a5Y+/vjjXGo1ACC3MdINALjmFCxYUNOnT7/azcB17tL7gbvr1atXtv9I434fZABA3sE13QAAAAAA2ITTywEAAAAAsAmhGwAAAAAAm3BNN/A/Fy5c0JEjRxQeHi6Hw3G1mwMAAADgH8wYo8TEREVFRcnPL/PxbEI38D9HjhxRmTJlrnYzAAAAAOQhhw4dUunSpTNdT+gG/ic8PFyS80MTERFxlVsDAAAA4J8sISFBZcqUsXJEZgjdwP+4TimPiIggdAMAAADwyeUuTWUiNQAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmAVe7AcA/zewCdZVP/le7GZKk+83Oq90EAAAAAFeAkW4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELoBgAAAADAJoRuAAAAAABsQugGAAAAAMAmhG4AAAAAAGxC6AYAAAAAwCaEbgAAAAAAbELozsLUqVPlcDisR0hIiEqWLKlbbrlFI0aM0PHjx69o/ytXrtSNN96osLAwORwOffHFF7nT8Ev06tVLMTExHmXDhw/P9vPt2bNHwcHB+uGHHzzK9+7dq06dOqlgwYLKnz+/br/9dm3atMmnfbq/vpc+qlat6lPdN954w6Pev//9b9WtW1cXLlzI1vEBAAAAQG4LuNoNyAumTJmiqlWrKi0tTcePH9d3332nkSNHavTo0Zo1a5Zuu+22bO/TGKN7771XlStX1sKFCxUWFqYqVarY0Hrvhg8frnvuuUd33323z9sMGDBAt99+uxo3bmyV/fXXX7r55ptVqFAhffzxxwoJCdGIESPUokULbdy48bLHdGmAl6T169erf//+6tixY4Z199xzj5599lmPsrJly2Zo57hx4zRt2jT17t3b5+MDAAAAgNxG6PZBjRo1dOONN1o/d+7cWU8//bSaNm2qTp06adeuXSpRokS29nnkyBGdOHFCHTt2VMuWLXO7ybnut99+0xdffKGlS5d6lI8aNUp//fWX1q1bp+joaElS06ZNVaFCBb3yyiuaNWtWlvtt1KhRhrIPPvhADodDffv2zbCuRIkSXrdxV6BAAXXv3l1vvPGGevXqJYfDcbnDAwAAAABbcHp5DpUtW1ZjxoxRYmKiPvjgA491P/30k+666y4VLlxYISEhqlOnjmbPnm2tHzJkiEqXLi1Jev755+VwOKzTv3fv3q3evXurUqVKypcvn0qVKqX27dtr27ZtHs/hOvV9//79HuWrV6+Ww+HQ6tWrM227w+FQUlKSpk2bZp2i3aJFiyyPd+LEiSpZsqRuv/12j/L58+fr1ltvtQK3JEVERKhTp05atGiR0tPTs9zvpRITEzVnzhw1b95cFStWzNa27h544AH9/vvvWrVqVY73AQAAAABXitB9Bdq2bSt/f3+tXbvWKlu1apWaNGmiU6dO6f3339eCBQtUu3Zt3XfffZo6daokqV+/fpo3b54k6YknntAPP/yg+fPnS3KOgBcpUkRvvPGGli5dqvHjxysgIEANGzbUzp07c6XdP/zwg0JDQ9W2bVv98MMP+uGHHzRhwoQst1myZImaNWsmP7+LXebcuXPas2ePatWqlaF+rVq1dO7cOe3duzdbbfvss8+UlJSkfv36eV3/6aefKjQ0VMHBwapXr56mTJnitV69evWUP39+LVmyJNPnSklJUUJCgscDAAAAAHITp5dfgbCwMBUtWlRHjhyxyh599FHdcMMN+uabbxQQ4Hx5W7durbi4OL344ovq0aOHSpcubY0Aly1b1uN06WbNmqlZs2bWz+fPn1e7du10ww036IMPPtDYsWOvuN2NGjWSn5+fihUrdtlTtSXp+PHj2rt3rx566CGP8pMnT8oYo8KFC2fYxlUWHx+frbZNnjxZBQsWVOfOnTOsu//++9WuXTuVKVNGx48f1+TJk9WnTx/t3btXQ4cO9ajr7++v2NhYff/995k+14gRI/Tqq69mq30AAAAAkB2MdF8hY4y1vHv3bu3YsUPdunWTJKWnp1uPtm3b6ujRo5cdrU5PT9fw4cNVvXp1BQUFKSAgQEFBQdq1a5d+++03W48lM64/KhQvXtzr+qyumc7O9dS//vqr1q9fr27duikkJCTD+pkzZ+r+++/XzTffrM6dO+vLL7/UnXfeqTfeeEN//fVXhvrFixfX4cOHM32+F154QadPn7Yehw4d8rmtAAAAAOALQvcVSEpKUnx8vKKioiRJx44dk+ScPTswMNDj8eijj0qS4uListznM888o3//+9+6++67tWjRIq1fv14bN25UbGyszp07Z+8BZcL1vJcG4UKFCsnhcHgdzT5x4oQkeR0F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adOmqUmTJj7fRssV4CVZszbv2bNHw4YNy1C3UqVK1ojk8ePH9frrr1vXFn/00UcZ6jdp0sQKWsuXL9fo0aMVHx+vlJQU7dixQyNHjlTFihWzbF9OXssmTZqoePHikqTdu3fr4Ycf1sGDB5WUlKT169dr0qRJkqQ77rjDCtSrVq3SK6+8omPHjikhIUGrVq3SrFmzJDkDlaver7/+qn379un8+fN66aWXshytzoz7ax4SEqLQ0FBt2bJF77zzToa6vh6LyzPPPCM/Pz8ZY7R69WpJUteuXVWwYMHLtqt06dLWdc6//PKLT8dy1113WctvvfWWfvnlFyUkJOjf//63NcpdvXp1VahQIdv9JzNr1qzR8OHD9euvvyomJkZ333237r77bmv9wYMHJckjNI8aNUqfffaZEhISdPz4cX366afW/bHd34/8+fPL4XBowYIFXudFyEzHjh0lOf/407NnT/32229KS0vTn3/+qblz56pNmzbWmSsumzZtspYbNWrk83MBuI79XeexAwDwT/fJJ59Y12rWqVMnw3r32colmdWrV1vrXnzxRY/rQGNiYjJcE7x3797LXkO6atUqY0zW1yO79pUvX74M21euXNnrdpnNPu3eHvfrZxcuXOj1OnH3hx2vZW7OXm6MMQ8++KBV7u/vb/Lly2cCAgI8js3F/Zpu1wzx7tatW+f1Od1fc/ftfD0Wl86dO3vUWb9+fZavsTvXcfr7+5sTJ054rMts9vJOnTpl+t7my5fPfP/999Y+stt/vJk+fXqW/em9996z6vbo0SPTeq7Zy994440M6/z8/EyFChWsn6dMmWLt01V26ezlN9xwQ5btct+HMcY8+eST1nMdPHjQ5/cIwPWLkW4AAP7H/ZRx17XY7vz9/T1O93U/ffrBBx/0uNazX79+Ga4JLleunH755RcNHDhQ1atXt0ZLy5cvr/bt22vixIkeMyNnpVy5cvryyy/VqFEj5cuXT5GRkRowYIDXU50l54je/PnzFRsbq6CgIJUtW1ZDhw7V448/btUpWrSotdy+fXv9/PPP6tGjh8qWLavAwEAVKFBA1apVU48ePazR5Mzk9LVs27atNm/erN69eysmJkZBQUEKDw9XbGysWrVqZdV/8MEHtW7dOt13330qVaqUAgMDVbBgQTVo0EBNmza16o0dO1YPP/ywIiMjFRQUpPr16+ubb77xOCXbV40bN9acOXNUq1YthYSEKDo6WsOHD9egQYO81vf1WFzcr0+uU6eOGjRo4HPbXPduP3/+/GXfG8l5OvWcOXP0/vvvq1GjRgoPD1dAQIDKlCmjnj17avPmzbrpppus+tntP97Uq1dP/fr1U82aNVW4cGH5+/srPDxcjRo10qRJkzz2NW3aNH366adq2bKlChcurICAABUvXly33367dZbFgAED9NprrykmJkbBwcGKjY3V/PnzPd7/yylcuLDWr1+voUOHqk6dOgoLC1NwcLCio6N1++23a8yYMbrjjjus+ufPn7fuTHDXXXepTJkyPj8XgOuXw5hLZhYBAADXnMTERG3YsEHNmjVTYGCgJGn79u1q166d9u/fLz8/P23fvl1VqlS5yi29fs2fP986tfrjjz+2bkXmqzvvvFNLlixRbGysNm/enKsTftF/nObMmaN7771XDodD69evV/369a92kwDkAYRuAACuA/v371e5cuUUGBio4sWLKzk52bp2V5JeffVVvfLKK1exhdevF154QbNnz9a+fftkjFHVqlW1bds2j2uWfbFr1y7VqFFDqampmjt3rjp37pxrbaT/OK/7jo2N1bZt29S7d299/PHHV7tJAPIIbhkGAMB1oGDBgurevbt++OEH/fnnn0pNTVVUVJQaNmyoRx55xOvpzvh7HD16VHv37lV4eLiaNm2q8ePHZztwS84J81JSUmxoIf1Hcp6Sv3Xr1qvdDAB5ECPdAAAAAADYhInUAAAAAACwCaEbAAAAAACbELoBAAAAALAJoRsAAAAAAJsQugEAAAAAsAmhGwAAAAAAmxC6AQAAAACwCaEbAAAAAACbELoBAAAAALDJ/wPycqSMHEO5YQAAAABJRU5ErkJggg==",
+ "text/plain": [
+ "
\n",
+ " \n",
+ "
Box #
Image
Accuracy
OCR
1
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi⎕te-haired old man known only as b8ambl .
2
0.97
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~
3
0.77
And one in ⎕eet⎕⎕⎕ sv⎕e⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.86
Bambl ~~ we have a guest.
5
0.64
=~and tonight, he comes ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕slamming open urg⎕⎕⎕⎕en⎕⎕⎕⎕⎕tly,⎕⎕⎕⎕
6
0.82
Tell me⎕ master... how may bambli serve'7
7
0.94
Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes
8
0.75
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall ⎕sere
9
0.96
How curious the whims of fate⎕. had i not chanced to stroll along the river tonight-~
10
0.81
A⎕⎕⎕ulckry as t can, master.
11
0.95
~<the girl would most surely be dead by now.
12
0.94
Ghede has been generous. the ceath god has given the girl a second chance po⎕⎕
13
0.67
Yi⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕renee⎕othing to scream sea⎕⎕⎕t anh⎕ore⎕.
---------- Initial box ----------\n",
+ "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski)2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
+ "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
+ "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
+ "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
+ "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
+ "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
+ "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes...7/\n",
+ "ResultOCR#block 07: 0.81||The the old man's fades down the hall as...7\n",
+ "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
+ "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
+ "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
+ "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
+ "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
+ "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
+ "ResultOCR#block 14: 1.00||Continued after next page\n",
+ "\n",
+ " ---------- Default ----------\n",
+ "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
+ "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
+ "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
+ "ResultOCR#block 03: 0.41||Rir guest.\n",
+ "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
+ "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
+ "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
+ "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
+ "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
+ "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
+ "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
+ "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
+ "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
+ "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
+ "ResultOCR#block 14: 1.00||Continued after next page\n",
+ "\n",
+ " ---------- Default, grey pad ----------\n",
+ "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
+ "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
+ "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
+ "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
+ "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
+ "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+ "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7/.\n",
+ "ResultOCR#block 07: 0.06||As.\n",
+ "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
+ "ResultOCR#block 09: 0.55||Ickl as t can\n",
+ "ResultOCR#block 10: 0.00||\n",
+ "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
+ "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
+ "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
+ "ResultOCR#block 14: 0.54||“continued a\n",
+ "\n",
+ " ---------- Padded 4px ----------\n",
+ "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
+ "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
+ "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
+ "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
+ "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
+ "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
+ "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
+ "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
+ "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
+ "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
+ "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
+ "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
+ "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
+ "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
+ "ResultOCR#block 14: 1.00||Continued after next page\n",
+ "\n",
+ " ---------- Padded 8px ----------\n",
+ "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
+ "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
+ "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
+ "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
+ "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
+ "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
+ "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
+ "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
+ "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
+ "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
+ "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
+ "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
+ "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
+ "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
+ "ResultOCR#block 14: 0.94||“continued after next page\n",
+ "\n",
+ " ---------- Extracted, init box ----------\n",
+ "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
+ "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
+ "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+ "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
+ "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
+ "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
+ "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
+ "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
+ "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
+ "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
+ "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
+ "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
+ "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+ "\n",
+ " ---------- Padded 4, extracted ----------\n",
+ "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
+ "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
+ "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+ "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
+ "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
+ "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
+ "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
+ "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
+ "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
+ "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
+ "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
+ "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
+ "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+ "\n",
+ " ---------- Padded 8, extracted ----------\n",
+ "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
+ "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
+ "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
+ "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+ "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+ "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
+ "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
+ "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
+ "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
+ "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
+ "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ " ---------- Padded 8, dilation 1 ----------\n",
+ "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
+ "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
+ "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
+ "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
+ "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
+ "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+ "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
+ "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
+ "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
+ "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
+ "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
+ "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ " ---------- Pad 8, fract. 0.5 ----------\n",
+ "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+ "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
+ "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
+ "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+ "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+ "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+ "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
+ "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+ "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
+ "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
+ "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ " ---------- Pad 8, fract. 0.2 ----------\n",
+ "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+ "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
+ "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
+ "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+ "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+ "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+ "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
+ "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
+ "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+ "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+ "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+ "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
+ "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
+ "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
+ "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+ "\n",
+ "\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "---------- Initial box ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
+ "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n",
+ "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n",
+ "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n",
+ "\n",
+ " ---------- Padded 4px ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m||---------- Initial box ----------\n",
+ "ResultOCR#block 00: 0.90||Suddenly.\n",
+ "ResultOCR#block 01: 0.81||>gasp!z everything's w- whirling around me!t can't stand sr rea\n",
+ "ResultOCR#block 02: 0.81||Clark!i'm falling' “help! help! —\n",
+ "ResultOCR#block 03: 0.67||I-i'm bs \"passing ohhh\n",
+ "ResultOCR#block 04: 0.92||Action comics\n",
+ "ResultOCR#block 05: 1.00||Then, seconds later...\n",
+ "ResultOCR#block 06: 0.89||Great caesars ghost! { this /s black magic! we've been transportel to the weirdest world, tit ever saw!\n",
+ "ResultOCR#block 07: 0.91||...|t certainly isn't our earth, perry. look at the size of those bees.\n",
+ "ResultOCR#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCR#block 09: 0.73||Owwww.\n",
+ "ResultOCR#block 10: 0.85||Yet the bee's stinger went ws. right through my uniform and penetrated my skin! that means. the fabric of pe ay costume has become dj} satie fued 1,\n",
+ "ResultOCR#block 11: 0.87||Hurry. let's beat it before we get stung, foo = aii\n",
+ "ResultOCR#block 12: 0.86||Ggreat guns!...2g, .pa/n i feel n pain! as superman, i should be > invulnerable! 1 have unbreakabl ‘skin! under my clark kent clothes, im wearing an woestructisle superman uniform ! =\n",
+ "ResultOCR#block 13: 1.00||Abruptly...\n",
+ "ResultOCR#block 14: 0.77||Great caesar's ghost. he's spinning a web of g/ant, sr strands --\n",
+ "ResultOCR#block 15: 0.89||I-i feel the heat of the sun...the pain of the bee-sting ... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers! i've become an ordinary mortal in this world. /\n",
+ "ResultOCR#block 16: 0.84||Enormous spider- like creature is going berserk, as if the sight of us excited him (into mad spinning get back! that 2\n",
+ "\n",
+ " ---------- Default ----------\n",
+ "ResultOCR#block 00: 1.00||Suddenly...\n",
+ "ResultOCR#block 01: 0.80||Gasp! everything's w- whi rns atound me!i can't stand we a\n",
+ "ResultOCR#block 02: 0.87||Clark!i'm falling! help! help\n",
+ "ResultOCR#block 03: 0.45||I-i'm se ou\n",
+ "ResultOCR#block 04: 0.92||Action comics\n",
+ "ResultOCR#block 05: 0.95||Then, seconds later.\n",
+ "ResultOCR#block 06: 0.92||Great caesar's ghost! this /s black magic! we've been transported, to the weirdest world, i ever saw!\n",
+ "ResultOCR#block 07: 0.93||...|t certainly isn't our earth, perry look at the size of those bees!\n",
+ "ResultOCR#block 08: 0.88||Watch out, clark)\n",
+ "ResultOCR#block 09: 0.67||Owwww.,\n",
+ "ResultOCR#block 10: 0.97||Yet the bee's stinger went = right through my uniform ando penetrated my skin! that mean the fabric of my superman costume has become ordinary, cloth! £\n",
+ "ResultOCR#block 11: 0.89||Hurry. let's beat it before we get stung, tod yi\n",
+ "ResultOCR#block 12: 0.88||Ggreat guns!...2gasp/z...pain i feel n fan! as superman, i should be invulnerable! 1 have unbreakable skin! under my clark kent clothes, i'm wearing an /noestruct/ele superman uniform !\n",
+ "ResultOCR#block 13: 1.00||Abruptly...\n",
+ "ResultOCR#block 14: 0.76||Great caesars ° ghost! he's spinning & web of g/a, silk strands\n",
+ "ResultOCR#block 15: 0.89||I-i feel the heat of the sum...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all my super -powersx ve become an ordinary mortal in this world! j\n",
+ "ResultOCR#block 16: 0.70||Like creature is going berserk, as if the sight of us excited him into mad spinning, get back! that \\ enormous spider-\n",
+ "\n",
+ " ---------- Default, grey pad ----------\n",
+ "ResultOCR#block 00: 0.78||Sudden.\n",
+ "ResultOCR#block 01: 0.82||5gasp!z everything's | w- whirling around] me!t can't stand ue a\n",
+ "ResultOCR#block 02: 0.57||Ark!i'm falling\n",
+ "ResultOCR#block 03: 0.85||I-t'm eq \"passing out... ohhh.\n",
+ "ResultOCR#block 04: 0.92||Action comics\n",
+ "ResultOCR#block 05: 0.00||\n",
+ "ResultOCR#block 06: 0.88||‘great caesar's ghost! || this /§ black magic! we've been transportel to the weirdest world, i ever saw.\n",
+ "ResultOCR#block 07: 0.87||\"...it certainly isn't our | earth, perry look at the| \\s|ze of those bees.\n",
+ "ResultOCR#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCR#block 09: 0.73||Owwww.\n",
+ "ResultOCR#block 10: 0.90||Yet the bee's stinger went ~ right through my uniform and penetrated my skin! that means. the fabric of sera ry costume vis become din a s clots! a\n",
+ "ResultOCR#block 11: 0.80||Hurry. let's ) beat it before] we get stung, k 00! __j\n",
+ "ResultOCR#block 12: 0.86||Ggreat guns!...3gasp/=... rain t feel fan! as superman, i should be invulnerable® 1 have unbreakabli skin! under my clark kent clothes, ia wearing an /noestryct/iele supe iperman uniform !\n",
+ "ResultOCR#block 13: 0.90||Abruptly.\n",
+ "ResultOCR#block 14: 0.92||Great caesar's | ghost! he's spinning k web of giant, silk strands -- as tough as steel! ne]\n",
+ "ResultOCR#block 15: 0.89||\\i-t feel the heat of the sun...the pain of the bee-sting... the heavy weight of my & pack! every human discomfort... good grief! i've lost all my super-powers i've become an ordinary mortal in this world. /.\n",
+ "ResultOCR#block 16: 0.94||(get back! that enormous spider- like creature 1 § going berserk, as if the sight of us excited him into mad spinning]\n",
+ "\n",
+ " ---------- Padded 4px ----------\n",
+ "ResultOCR#block 00: 0.90||Suddenly.\n",
+ "ResultOCR#block 01: 0.83||Fgasp/= everything's whirling around me!i can't stand ea\n",
+ "ResultOCR#block 02: 0.68||Ie lottie eto clark!i'm falling help! help!\n",
+ "ResultOCR#block 03: 0.55||I-i'm yr a ohh hh.\n",
+ "ResultOCR#block 04: 0.92||Action comics\n",
+ "ResultOCR#block 05: 0.74||Then, seconds\n",
+ "ResultOCR#block 06: 0.62||Great caesar's ghost! \\ this /§ black magic! i ever saw!\n",
+ "ResultOCR#block 07: 0.87||T certainly isn't our earth, perry! look at the \\s|ze of those bees.\n",
+ "ResultOCR#block 08: 0.76||#3 watch out, clark!\n",
+ "ResultOCR#block 09: 0.73||Owwww.\n",
+ "ResultOCR#block 10: 0.95||\"yet the bee's stinger went ~~ right through my uniform and enetrated my skin! that means. the fabric of my superman costume has become ordinary, clot! &\n",
+ "ResultOCR#block 11: 0.86||Hurry! let's beat it b=fore we get stung, ¢ tool: puma\n",
+ "ResultOCR#block 12: 0.86||‘ggreat guns!...3gasp/5... pain i feel pain? as superman, i should be invilnerable | t ne unbreakasle gkin! under my clark kent clothes, tih wearing an indestructible superman uniform\n",
+ "ResultOCR#block 13: 1.00||Abruptly...\n",
+ "ResultOCR#block 14: 0.91||Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!\n",
+ "ResultOCR#block 15: 0.89||I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all \\my super-powersx ve become an ordinary mortal in this world.\n",
+ "ResultOCR#block 16: 0.81||(get back! that enormous spider- as if the sight of us excited him [into mad spinning\n",
+ "\n",
+ " ---------- Padded 8px ----------\n",
+ "ResultOCR#block 00: 0.00||\n",
+ "ResultOCR#block 01: 0.76||Ega5p/% everything s\\ w- whirling around me! t can't stand ue... slee\n",
+ "ResultOCR#block 02: 0.41||\\ help! help’\n",
+ "ResultOCR#block 03: 0.86||-i'm passing qut... ohh hh.\n",
+ "ResultOCR#block 04: 0.92||Action comics\n",
+ "ResultOCR#block 05: 0.00||\n",
+ "ResultOCR#block 06: 0.18||I ever saw/\n",
+ "ResultOCR#block 07: 0.86||It certainly isn't our earth, perry! poor a the size of thos!\n",
+ "ResultOCR#block 08: 0.62||“watch out” ial ae clark!\n",
+ "ResultOCR#block 09: 0.73||Owwww.\n",
+ "ResultOCR#block 10: 0.98||Yet the bee's stinger went right through my uniform and \\penetrated my skin! that means. the fabric of my superman costume has become ordinar! cloth!\n",
+ "ResultOCR#block 11: 0.93||Hurry. let's beat it before we get stung, too!\n",
+ "ResultOCR#block 12: 0.88||Ggreat guns!...2gasp/z...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ele $ superman uniform ! &\n",
+ "ResultOCR#block 13: 0.00||\n",
+ "ResultOCR#block 14: 0.91||Great caesai ghost. he's spinning a web of g/ant, silk strands -- as tough as steel!\n",
+ "ResultOCR#block 15: 0.88||I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my ! every human discomfort... good grief! i've lost all \\my super-powers! ‘ve become an ordinary mortal in this world. x\n",
+ "ResultOCR#block 16: 0.60||As if the sight of us excited him {into mad spinning\n",
+ "\n",
+ " ---------- Extracted, init box ----------\n",
+ "ResultOCRExtracted#block 00: 0.90||Suddenly.\n",
+ "ResultOCRExtracted#block 01: 0.83||Fgasp!z everything § w- whirling around me!i can't stand ue.\n",
+ "ResultOCRExtracted#block 02: 0.89||Clark!i'm falling! help! help!\n",
+ "ResultOCRExtracted#block 03: 0.71||I-i'm passing ohhh?\n",
+ "ResultOCRExtracted#block 04: 0.92||Action comics\n",
+ "ResultOCRExtracted#block 05: 0.98||Then, seconds later..\n",
+ "ResultOCRExtracted#block 06: 0.91||Great caesar's ghost! this /s black magic! we've been transportel to the weirdest world tit ever saw.\n",
+ "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n",
+ "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCRExtracted#block 09: 0.62||Oowwwww.\n",
+ "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block 11: 0.93||Hurry. let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block 12: 0.88||Ggreat guns!...2g/ pain t feel pain? as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform *\n",
+ "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n",
+ "ResultOCRExtracted#block 14: 0.80||Great caesar's ghost. he's spinning a web of g/ant, silk strands --\n",
+ "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal im this world.\n",
+ "ResultOCRExtracted#block 16: 0.97||Get back. that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning\n",
+ "\n",
+ " ---------- Padded 4, extracted ----------\n",
+ "ResultOCRExtracted#block 00: 1.00||Suddenly...\n",
+ "ResultOCRExtracted#block 01: 0.83||Sgasp/z everything s w- whirling around me!i can't stand ue.\n",
+ "ResultOCRExtracted#block 02: 0.87||Clark! i'm falling’ help! help!\n",
+ "ResultOCRExtracted#block 03: 0.78||I-i'm passing ohhhh.\n",
+ "ResultOCRExtracted#block 04: 0.92||Action comics\n",
+ "ResultOCRExtracted#block 05: 0.98||Then, seconds later..\n",
+ "ResultOCRExtracted#block 06: 0.93||Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw!\n",
+ "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n",
+ "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCRExtracted#block 09: 0.67||Owwww.,\n",
+ "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block 12: 0.89||Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !\n",
+ "ResultOCRExtracted#block 13: 1.00||Abruptly...\n",
+ "ResultOCRExtracted#block 14: 0.94||Great caesar's ghost! he's spinning a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block 16: 0.97||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning\n",
+ "\n",
+ " ---------- Padded 8, extracted ----------\n",
+ "ResultOCRExtracted#block 00: 0.91||Suddemly...\n",
+ "ResultOCRExtracted#block 01: 0.85||Sgasp/z everything s w- whirling around me!i can't stand up.\n",
+ "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n",
+ "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n",
+ "ResultOCRExtracted#block 04: 0.92||Action comics\n",
+ "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n",
+ "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw.\n",
+ "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n",
+ "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCRExtracted#block 09: 0.67||Owwww.,\n",
+ "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block 12: 0.89||Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !\n",
+ "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n",
+ "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block 15: 0.89||I-t feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block 16: 0.95||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [\n",
+ "\n",
+ " ---------- Padded 8, dilation 1 ----------\n",
+ "ResultOCRExtracted#block 00: 1.00||Suddenly...\n",
+ "ResultOCRExtracted#block 01: 0.83||Gasp! everything s w-whirling around wel] i can't stand\n",
+ "ResultOCRExtracted#block 02: 0.86||Clark!i'm falling! . help! help!\n",
+ "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n",
+ "ResultOCRExtracted#block 04: 0.92||Action comics\n",
+ "ResultOCRExtracted#block 05: 0.95||Then, seconds later.\n",
+ "ResultOCRExtracted#block 06: 0.91||Great caesar's ghost! e this /5 black magic! we've been transported to the weirdest world i ever saw/\n",
+ "ResultOCRExtracted#block 07: 0.91||...|it certainly isnt our earth, perry” look at the size of those bees!\n",
+ "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCRExtracted#block 09: 0.73||Owwww.\n",
+ "ResultOCRExtracted#block 10: 0.94||Yet the bee's stinger we right through my tform and penetrated my skin! that means. the fabric of my superman othe has become ordinary clot?\n",
+ "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block 12: 0.82||Fain! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n",
+ "ResultOCRExtracted#block 13: 0.00||\n",
+ "ResultOCRExtracted#block 14: 0.67||Great caesars ghost! he's spinning _ a web of g/ant,\n",
+ "ResultOCRExtracted#block 15: 0.86||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve ie an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block 16: 0.96||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning’ g [\n",
+ "\n",
+ " ---------- Pad 8, fract. 0.5 ----------\n",
+ "ResultOCRExtracted#block 00: 0.91||Suddemly...\n",
+ "ResultOCRExtracted#block 01: 0.87||Gasp/z everything s w- whirling around me!i can't stand up.\n",
+ "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n",
+ "ResultOCRExtracted#block 03: 0.78||I-i'm passing ohhhh.\n",
+ "ResultOCRExtracted#block 04: 0.92||Action comics\n",
+ "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n",
+ "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw.\n",
+ "ResultOCRExtracted#block 07: 0.92||...it certainly isnt our earth, perry! look at the size of those bees.\n",
+ "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCRExtracted#block 09: 0.67||Owwww.,\n",
+ "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block 12: 0.90||Ggreat guns!...2gasp/:...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /nodestruct/ible superman uniform !\n",
+ "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n",
+ "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block 16: 0.95||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [\n",
+ "\n",
+ " ---------- Pad 8, fract. 0.2 ----------\n",
+ "ResultOCRExtracted#block 00: 1.00||Suddenly...\n",
+ "ResultOCRExtracted#block 01: 0.87||Gasp/z everything s w- whirling around me!i can't stand up.\n",
+ "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n",
+ "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n",
+ "ResultOCRExtracted#block 04: 0.92||Action comics\n",
+ "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n",
+ "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw!\n",
+ "ResultOCRExtracted#block 07: 0.92||...it certainly isnt our earth, perry! look at the size of those bees.\n",
+ "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n",
+ "ResultOCRExtracted#block 09: 0.67||Owwww.,\n",
+ "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block 12: 0.91||Ggreat guns!...2gasp/:... pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n",
+ "ResultOCRExtracted#block 13: 0.96||Abruptly....\n",
+ "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block 16: 0.96||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning gs [\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ "---------- Initial box ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.81\u001b[0m||>gasp!z everything's w- whirling around me!t can't stand sr rea\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.81\u001b[0m||Clark!i'm falling' “help! help! —\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.67\u001b[0m||I-i'm bs \"passing ohhh\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.89\u001b[0m||Great caesars ghost! \u001b[1m{\u001b[0m this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transportel to the weirdest world, tit ever saw!\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.91\u001b[0m||\u001b[33m...\u001b[0m|t certainly isn't our earth, perry. look at the size of those bees.\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.85\u001b[0m||Yet the bee's stinger went ws. right through my uniform and penetrated my skin! that means. the fabric of pe ay costume has become dj\u001b[1m}\u001b[0m satie fued \u001b[1;36m1\u001b[0m,\n",
+ "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.87\u001b[0m||Hurry. let's beat it before we get stung, foo = aii\n",
+ "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2g, .pa/n i feel n pain! as superman, i should be > invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl ‘skin! under my clark kent clothes, im wearing an woestructisle superman uniform ! =\n",
+ "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.77\u001b[0m||Great caesar's ghost. he's spinning a web of g/ant, sr strands --\n",
+ "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting \u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers! i've become an ordinary mortal in this world. \u001b[35m/\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.84\u001b[0m||Enormous spider- like creature is going berserk, as if the sight of us excited him \u001b[1m(\u001b[0minto mad spinning get back! that \u001b[1;36m2\u001b[0m\n",
+ "\n",
+ " ---------- Default ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.80\u001b[0m||Gasp! everything's w- whi rns atound me!i can't stand we a\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.87\u001b[0m||Clark!i'm falling! help! help\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.45\u001b[0m||I-i'm se ou\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.95\u001b[0m||Then, seconds later.\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.92\u001b[0m||Great caesar's ghost! this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transported, to the weirdest world, i ever saw!\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.93\u001b[0m||\u001b[33m...\u001b[0m|t certainly isn't our earth, perry look at the size of those bees!\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark\u001b[1m)\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.97\u001b[0m||Yet the bee's stinger went = right through my uniform ando penetrated my skin! that mean the fabric of my superman costume has become ordinary, cloth! £\n",
+ "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.89\u001b[0m||Hurry. let's beat it before we get stung, tod yi\n",
+ "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/z\u001b[33m...\u001b[0mpain i feel n fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakable skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mele\u001b[0m superman uniform !\n",
+ "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.76\u001b[0m||Great caesars ° ghost! he's spinning & web of g/a, silk strands\n",
+ "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sum\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my \u001b[1m{\u001b[0m pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super -powersx ve become an ordinary mortal in this world! j\n",
+ "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.70\u001b[0m||Like creature is going berserk, as if the sight of us excited him into mad spinning, get back! that \\ enormous spider-\n",
+ "\n",
+ " ---------- Default, grey pad ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.78\u001b[0m||Sudden.\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.82\u001b[0m||5gasp!z everything's | w- whirling around\u001b[1m]\u001b[0m me!t can't stand ue a\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.57\u001b[0m||Ark!i'm falling\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.85\u001b[0m||I-t'm eq \"passing out\u001b[33m...\u001b[0m ohhh.\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.88\u001b[0m||‘great caesar's ghost! || this \u001b[35m/\u001b[0m§ black magic! we've been transportel to the weirdest world, i ever saw.\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.87\u001b[0m||\"\u001b[33m...\u001b[0mit certainly isn't our | earth, perry look at the| \\s|ze of those bees.\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.90\u001b[0m||Yet the bee's stinger went ~ right through my uniform and penetrated my skin! that means. the fabric of sera ry costume vis become din a s clots! a\n",
+ "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.80\u001b[0m||Hurry. let's \u001b[1m)\u001b[0m beat it before\u001b[1m]\u001b[0m we get stung, k \u001b[1;36m00\u001b[0m! __j\n",
+ "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m3gasp/=\u001b[33m...\u001b[0m rain t feel fan! as superman, i should be invulnerable® \u001b[1;36m1\u001b[0m have unbreakabli skin! under my clark kent clothes, ia wearing an \u001b[35m/noestryct/\u001b[0m\u001b[95miele\u001b[0m supe iperman uniform !\n",
+ "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.90\u001b[0m||Abruptly.\n",
+ "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.92\u001b[0m||Great caesar's | ghost! he's spinning k web of giant, silk strands -- as tough as steel! ne\u001b[1m]\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||\\i-t feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my & pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers i've become an ordinary mortal in this world. \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.94\u001b[0m||\u001b[1m(\u001b[0mget back! that enormous spider- like creature \u001b[1;36m1\u001b[0m § going berserk, as if the sight of us excited him into mad spinning\u001b[1m]\u001b[0m\n",
+ "\n",
+ " ---------- Padded 4px ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Fgasp/= everything's whirling around me!i can't stand ea\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.68\u001b[0m||Ie lottie eto clark!i'm falling help! help!\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.55\u001b[0m||I-i'm yr a ohh hh.\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.74\u001b[0m||Then, seconds\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.62\u001b[0m||Great caesar's ghost! \\ this \u001b[35m/\u001b[0m§ black magic! i ever saw!\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.87\u001b[0m||T certainly isn't our earth, perry! look at the \\s|ze of those bees.\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.76\u001b[0m||#\u001b[1;36m3\u001b[0m watch out, clark!\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.95\u001b[0m||\"yet the bee's stinger went ~~ right through my uniform and enetrated my skin! that means. the fabric of my superman costume has become ordinary, clot! &\n",
+ "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.86\u001b[0m||Hurry! let's beat it \u001b[33mb\u001b[0m=\u001b[35mfore\u001b[0m we get stung, ¢ tool: puma\n",
+ "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||‘ggreat guns!\u001b[33m...\u001b[0m3gasp/\u001b[1;36m5\u001b[0m\u001b[33m...\u001b[0m pain i feel pain? as superman, i should be invilnerable | t ne unbreakasle gkin! under my clark kent clothes, tih wearing an indestructible superman uniform\n",
+ "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n",
+ "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!\n",
+ "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my \u001b[1m{\u001b[0m pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all \\my super-powersx ve become an ordinary mortal in this world.\n",
+ "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.81\u001b[0m||\u001b[1m(\u001b[0mget back! that enormous spider- as if the sight of us excited him \u001b[1m[\u001b[0minto mad spinning\n",
+ "\n",
+ " ---------- Padded 8px ----------\n",
+ "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.76\u001b[0m||Ega5p/% everything s\\ w- whirling around me! t can't stand ue\u001b[33m...\u001b[0m slee\n",
+ "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.41\u001b[0m||\\ help! help’\n",
+ "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.86\u001b[0m||-i'm passing qut\u001b[33m...\u001b[0m ohh hh.\n",
+ "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.18\u001b[0m||I ever saw/\n",
+ "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.86\u001b[0m||It certainly isn't our earth, perry! poor a the size of thos!\n",
+ "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.62\u001b[0m||“watch out” ial ae clark!\n",
+ "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n",
+ "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.98\u001b[0m||Yet the bee's stinger went right through my uniform and \\penetrated my skin! that means. the fabric of my superman costume has become ordinar! cloth!\n",
+ "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.93\u001b[0m||Hurry. let's beat it before we get stung, too!\n",
+ "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/z\u001b[33m...\u001b[0mpain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mele\u001b[0m $ superman uniform ! &\n",
+ "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n",
+ "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesai ghost. he's spinning a web of g/ant, silk strands -- as tough as steel!\n",
+ "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.88\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my ! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all \\my super-powers! ‘ve become an ordinary mortal in this world. x\n",
+ "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.60\u001b[0m||As if the sight of us excited him \u001b[1m{\u001b[0minto mad spinning\n",
+ "\n",
+ " ---------- Extracted, init box ----------\n",
+ "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n",
+ "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Fgasp!z everything § w- whirling around me!i can't stand ue.\n",
+ "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.89\u001b[0m||Clark!i'm falling! help! help!\n",
+ "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.71\u001b[0m||I-i'm passing ohhh?\n",
+ "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.98\u001b[0m||Then, seconds later..\n",
+ "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesar's ghost! this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transportel to the weirdest world tit ever saw.\n",
+ "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n",
+ "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.62\u001b[0m||Oowwwww.\n",
+ "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.93\u001b[0m||Hurry. let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2g/ pain t feel pain? as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform *\n",
+ "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n",
+ "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.80\u001b[0m||Great caesar's ghost. he's spinning a web of g/ant, silk strands --\n",
+ "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal im this world.\n",
+ "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.97\u001b[0m||Get back. that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning\n",
+ "\n",
+ " ---------- Padded \u001b[1;36m4\u001b[0m, extracted ----------\n",
+ "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Sgasp/z everything s w- whirling around me!i can't stand ue.\n",
+ "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.87\u001b[0m||Clark! i'm falling’ help! help!\n",
+ "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.78\u001b[0m||I-i'm passing ohhhh.\n",
+ "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.98\u001b[0m||Then, seconds later..\n",
+ "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw!\n",
+ "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n",
+ "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n",
+ "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.89\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain t feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform !\n",
+ "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.94\u001b[0m||Great caesar's ghost! he's spinning a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.97\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning\n",
+ "\n",
+ " ---------- Padded \u001b[1;36m8\u001b[0m, extracted ----------\n",
+ "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.91\u001b[0m||Suddemly\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.85\u001b[0m||Sgasp/z everything s w- whirling around me!i can't stand up.\n",
+ "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n",
+ "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n",
+ "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw.\n",
+ "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n",
+ "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n",
+ "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.89\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain t feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform !\n",
+ "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n",
+ "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-t feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.95\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning g \u001b[1m[\u001b[0m\n",
+ "\n",
+ " ---------- Padded \u001b[1;36m8\u001b[0m, dilation \u001b[1;36m1\u001b[0m ----------\n",
+ "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Gasp! everything s w-whirling around wel\u001b[1m]\u001b[0m i can't stand\n",
+ "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.86\u001b[0m||Clark!i'm falling! . help! help!\n",
+ "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n",
+ "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.95\u001b[0m||Then, seconds later.\n",
+ "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesar's ghost! e this \u001b[35m/\u001b[0m\u001b[95m5\u001b[0m black magic! we've been transported to the weirdest world i ever saw/\n",
+ "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.91\u001b[0m||\u001b[33m...\u001b[0m|it certainly isnt our earth, perry” look at the size of those bees!\n",
+ "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n",
+ "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m||Yet the bee's stinger we right through my tform and penetrated my skin! that means. the fabric of my superman othe has become ordinary clot?\n",
+ "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.82\u001b[0m||Fain! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n",
+ "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n",
+ "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.67\u001b[0m||Great caesars ghost! he's spinning _ a web of g/ant,\n",
+ "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.86\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve ie an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.96\u001b[0m||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning’ g \u001b[1m[\u001b[0m\n",
+ "\n",
+ " ---------- Pad \u001b[1;36m8\u001b[0m, fract. \u001b[1;36m0.5\u001b[0m ----------\n",
+ "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.91\u001b[0m||Suddemly\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.87\u001b[0m||Gasp/z everything s w- whirling around me!i can't stand up.\n",
+ "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n",
+ "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.78\u001b[0m||I-i'm passing ohhhh.\n",
+ "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw.\n",
+ "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.92\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry! look at the size of those bees.\n",
+ "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n",
+ "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.90\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0mpain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/nodestruct/\u001b[0m\u001b[95mible\u001b[0m superman uniform !\n",
+ "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n",
+ "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.95\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning g \u001b[1m[\u001b[0m\n",
+ "\n",
+ " ---------- Pad \u001b[1;36m8\u001b[0m, fract. \u001b[1;36m0.2\u001b[0m ----------\n",
+ "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.87\u001b[0m||Gasp/z everything s w- whirling around me!i can't stand up.\n",
+ "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n",
+ "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n",
+ "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n",
+ "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n",
+ "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw!\n",
+ "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.92\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry! look at the size of those bees.\n",
+ "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n",
+ "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n",
+ "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n",
+ "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n",
+ "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.91\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n",
+ "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly\u001b[33m...\u001b[0m.\n",
+ "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n",
+ "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n",
+ "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.96\u001b[0m||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning gs \u001b[1m[\u001b[0m\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "image_action_experiment: ExperimentOCR = cast(ExperimentOCR, ExperimentOCR.from_image(\n",
+ " CONTEXT, 'Tesseract', 'Action_Comics_1960-01-00_(262).JPG'))\n",
+ "image_action_experiment.display()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 114,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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UKECli9fjh07diAlJQX29vZwc3PD0KFDpXzKtixevBg+Pj5wdnbG9OnTERkZKU24lpVt27Zh5cqV2LJlCzZu3Ai5XI6yZcti69at6Nmzp1rehIQEnQLnj21TRtu3b8eYMWMwefJkpKamwsPDA8ePH9dYDqxkyZJYtmwZli9fDk9PT6SlpWHTpk0ak6UBYg/6/v374e/vj02bNmH+/PmwsbFBnz59sGDBgjy933j37t0aM3Ur1xSfPXt2tuuU9+rVCytXrkRKSopau8qXL4+TJ09iypQp6Ny5M/T19eHl5YXAwECNe9XT0tLURgbo6enh+PHjWLp0Kfbs2YPAwECYmpqiQoUKOHz4MFq2bCnlPXToED58+ICLFy9qndH+3r17akPJ9+/fDxsbGzRr1izbY0NERERE9CWTCVl1WRKpePPmDaytrbFs2TKMGDGioJvzVXn8+DFKliyJzZs3a8x0/6lJS0uDi4sLevbsifnz5+u8XXx8PCwsLLD+wiAYmxrkYwuJiIgoL/Qst6qgm0BUoJS/X+Pi4jRGOKviPd2ks1OnTkm9/fTfcnBwwNixYzF//nxpPe1P1datW5GQkCCtfU5ERERE9DXj8HLSWevWrTWGc9N/Z+bMmTA2NsajR49QvHjxgm5Opj58+IBt27ZluVwZEREREdHXgkE30WfCzMwMs2fPLuhmZKt///4F3QQiIiIiok8Gh5cTERERERER5RMG3URERERERET5hEE3ERERERERUT7hPd1E9EnpWubbLJdcICIiIiL6nLCnm4iIiIiIiCifMOgmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoJuIiIiIiIgon3D2ciL6pBSd3xYyBb+aiIiIiL4UCXPDC7oJBYo93URERERERET5hEE3ERERERERUT5h0E1ERERERESUTxh0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE++uqA7ODgYMplMeujr66NYsWLo378/Hj16lGf1ODs7w9fXV+f2REdH51ndvr6+cHZ2zjafIAhYv349atasCXNzcxQuXBiNGjXCoUOH8qwtH2v79u1YtmxZgbZh9erVCA4OzpeyZTIZ/P39dcp7+vRpKBQK3L9/Xy394sWLaNKkCUxNTWFpaQkfHx/cvXtXpzJTUlKwdOlSVKpUCSYm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Pj44evQonj17Bjs7O7Ro0QKOjo552T4iIiIiIiKiz1aug24AcHR0xMCBA/OqLURERERERERflFwH3QkJCTh8+DCio6ORnJys8b6fn99HNYyIiIiIiIjoc5eroPvixYto2bIlXr58mWkeBt1ERERERET0tcv17OUvXrzI9H2ZTJbrBhERERERERF9KXI1e/mlS5cgk8ng6emJFStWYOPGjdi0aZP02LhxY16385MQHBwMmUyW6ePkyZM5Ki8xMRH+/v453i4vPX78GP7+/rh06VKel608XtHR0TneNjo6GjKZDMHBwbmq29nZGb6+vtLrnO6nsu0XLlzIVf35ITY2FjY2Nti5c6da+vPnz+Hr6wsbGxsYGxvD3d0d4eHhOpcbGhoKDw8PWFtbw9LSErVr18aWLVs08sXHx2PGjBkoW7YsjI2N4ejoiC5duuD69etq+YKCguDo6Ii3b9/mbkeJiIiIiL4guerpNjMzw9u3bxEaGgorK6u8btMnb9OmTShfvrxGeoUKFXJUTmJiIubMmQMA8PT0zIum5djjx48xZ84cODs7o1q1agXSBm2KFi2Ks2fPonTp0rnaft++fTA3N5def6r7mRNz5syBg4MDunXrJqWlpKTA29sbsbGxWL58OWxtbbFq1Sq0aNECYWFhaNSoUZZlbty4EQMHDkSnTp0wc+ZMyGQyhISEoG/fvnj58iXGjRsn5W3bti0uXLgAf39/1KpVCw8fPsTcuXPh7u6Oq1evwsnJCQDQr18/LF68GEuWLJE+30REREREX6tcBd29e/dGYGAg7t2791UG3ZUqVUKtWrX+83oTExNhbGz8n9dbEBQKBerWrZvr7atXr56HrSl4r169wo8//ojvv/9e7faNoKAgXLt2Db///jvc3d0BAI0bN0bVqlUxefJk/PHHH1mWu3HjRjg5OWH37t3Q0xMHvjRv3hyXLl1CcHCwFHTfvn0bp06dwsyZMzFp0iRpexcXF9SrVw979+6V8urr6+Obb75BQEAApkyZ8tV8ZomIiIiItNF5ePmpU6ekh6enJ+zs7NChQwesXLkS4eHhau+fOnUqP9v8ydu5cydkMhlWrlyplj579mwUKlQIx48fR3R0NIoUKQJA7MFUDlFXDon29/eHTCbDxYsX0blzZ1hZWUm9vhcuXED37t3h7OwMIyMjODs7o0ePHrh//75GWx49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SBOoAUDx4sURGRmJPXv25GkjiYiIiIiIiD5HuRpeHhAQgISEBBgYGODdu3dSeo8ePbBixQpERkbmWQOJ6Oty+5udWd4TQ0RERET0OclVT3d4eDhkMhmOHDmill65cmUAwIMHDz6+ZURERERERESfuVwF3cplnzIuCSSTyQAAr1+//shmEREREREREX3+chV0K4d+Pn36VC1duYSYlZXVRzaLiIiIiIiI6POXq6C7Zs2aAIChQ4dKaUuWLEHfvn0hk8ng5uaWN60jIiL6v/buOyyK630b+L3u0kEElC5gx44o9gIidjRi76DYjb1EVCwo2GKJvSBg76LEFnsFxdhj7PVrI4IKIiJl3j94d36MuxSNGwTvz3XtdbFnnjnzzLCb+HDOnCEiIiLKx76q6B48eDAEQcDBgwfFKeUTJkwQp5UPHjz422VIRERERERElE99VdHdtm1bjBs3TnxcWObHhv3yyy9o0aLFN02SiIiIiIiIKD+SCcpq+StcvHgRe/bswatXr2BhYYGffvpJnHpORPQl4uPjYWxsjNUoBX3I8ySHbsLtPDkuEREREeU/yn+/vnv3LttH3ub6Od2Zn8etVKVKFVSpUkVtnLa2dm67JiIiIiIiIiqQcl106+np5bpTmUyG1NTUr0qIiIiIiIiIqKDIddH9L2ahExEREREREf2QvmghNZlMJq5WTkRERERERETZ+6KiWznaXbJkScybNw9v3rxBenq6yistLU0jyRIRERERERHlJ7kuus+fP49u3bpBS0sLDx48wNixY1G8eHEMGjQIf/31lyZzJCIiIiIiIsqXcl10u7i4YMOGDXjy5AmmTp0KS0tLvH//HqtWrUKVKlXg7u6Oo0ePajJXIiIiIiIionzli6aXA4C5uTn8/f3x+PFjbNy4EaamphAEASdOnMDSpUs1kSP9R0JDQ8X79mUyGRQKBWxtbeHj44Nnz559s+M4ODjA29s71/k8evTomx3b29sbDg4OOcYJgoDVq1ejevXqKFy4MMzMzNCoUSPs27fvm+XyNaZPn44KFSogPT1d0r5lyxY4OTlBV1cX1tbWGDFiBN6/f5/rfh8/fow+ffrA2toaOjo6sLGxQbt27SQxu3btQteuXVG6dGno6enBwcEB3bt3x927dyVxKSkpKFWqFBYuXPjV50lEREREVFB8cdENZDwEfMmSJfD390dc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tvDx8cGzZ8++2XEcHBzg7e2d63wePXr0zY7t7e0NBweHL9pHEAQ0bNgQMpkMQ4cO/Wa5fI3p06ejQoUKSE9Pl7Rv2bIFTk5O0NXVhbW1NUaMGIH379/nqs+XL19i6NChKFmyJPT09GBvb4++ffviyZMnkrhdu3aha9euKF26NPT09ODg4IDu3bvj7t27kriUlBSUKlUKCxcu/FfnSkRERERUELDoJhUhISGIjIzE4cOH0a9fP2zevBkNGjRAYmJiXqeWJ5YuXYp79+7ldRp4/vw55syZg+nTp6NQof/76m7cuBFdu3aFi4sLDhw4gClTpiA0NBReXl459pmcnIyGDRti69atGDNmDA4cOAA/Pz/s27cPdevWRUJCghg7e/ZsfPjwARMnTsTBgwcxY8YMXL58Gc7Ozvjrr7/EOC0tLfj7+2P69OmIjY39theBiIiIiCifUeR1AvT9qVSpEmrUqAEAcHNzQ1paGgICAhAeHo7u3bvncXb/rUePHmHChAlYt25dropYTVq0aBGKFCkiySMtLQ1jx45F06ZNsXr1agAZvzMjIyN0794dBw4cQIsWLbLs8/Tp07h79y7WrFmDvn37AgBcXV1RuHBhdOvWDUeOHEG7du0AABERETA3N5fs37hxYzg4OGDBggVYs2aN2N61a1eMGjUKK1euhJ+f3ze7BkRERERE+Q1HuilHtWvXBgA8fvwYADBt2jTUqlULpqamKFy4MJydnREcHAxBECT7paSkYNy4cbC0tIS+vj7q16+PCxcuqD1GVFQU6tWrJ06PnjBhAlJSUtTGbt26FXXq1IGBgQEMDQ3RrFkzXL58WSUuNDQU5cqVg46ODsqXL49169Z98bn3798fHh4eYuH5uRMnTkAmk2HDhg0YNWoULC0toaenh0aNGklyev36NYoXL466detKzuvmzZswMDBAz549s83j06dPCA4ORrdu3SSj3FFRUXjx4gV8fHwk8R07doShoSF2796dbb9aWloAAGNjY0l7kSJFAAC6urpi2+cFNwBYW1vD1tYWT58+lbRra2ujc+fOWLVqlcrngoiIiIjoR8Kim3KknFpdrFgxABmjvwMGDMC2bduwa9cueHl54eeff0ZAQIBkv379+mHevHno1asX9uzZg/bt28PLywtv3ryRxN28eRPu7u54+/YtQkNDsWLFCly+fBkzZsxQySUw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ZDKBD9Glf+HmzZuoWLEifv/991wV7597+PAhHB0dMWXKFPj5+X3z/K5du4aqVati6dKl4gh1TkJDQ+Hj44Po6GjUqFHjm+f0tX7++WccPXoUf/311xevSv5fCw4OxvDhw/H06dNcj3THx8fD2NgYkQ+nwNBIddE4IiKi/KyS2S95nQIRfWPKf7++e/cOhQsXzjKO93TTv3L8+HHUqVMnVwX31atX8csvv2Dv3r04ceIEVq5ciSZNmqBw4cIqz4X+t+7fv49jx46hf//+sLKyUjsKnt9MmjQJz549w86dO/M6lWylpqZi9uzZmDBhAqeWExEREdEPj0U3/StDhgzBuXPnchVrYGCAixcvom/fvvDw8MDEiRNRrVo1nDlzJsvHhn2tgIAAeHh44P3799i+fTv09fW/af95wcLCAhs3bvyuHgWnztOnT9GjRw+MHj06r1MhIiIiIspznF5ORN8FTi8nIqKCjNPLiQoeTi8nIiIiIiIiymMsuomIiIiIiIg0hEU3ERERERERkYbwOd1E9F2pYDoq23tiiIiIiIjyE450ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOgmIiIiIiIi0hA+MoyIviu+hwdBy0A7r9MgIiIiytLG5iF5nQLlIxzpJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3fbdCQ0Mhk8nEl66uLiwtLeHm5oagoCDExMT8q/6PHj2KGjVqwMDAADKZDOHh4d8m8c94e3vDwcFB0hYYGPjFx7t//z50dHQQGRkpaX/w4AG8vLxQpEgRGBoawsPDA5cuXcpVn4IgYPXq1ahevToKFy4MMzMzNGrUCPv27VOJzfy7yPyaNWuWJG7y5MlwdnZGenr6F50fEREREVFBxKKbvnshISGIjIzE4cOHsXTpUjg5OWH27NkoX748jhw58lV9CoKATp06QUtLC3v37kVkZCQaNWr0jTPP2tcU3WPGjIGHhwfq1Kkjtv3zzz9o0KAB7ty5g7Vr12Lbtm34+PEjXF1dcfv27Rz7nDJlCvr374+aNWti586dCA0NhY6ODlq3bo1du3apxHfo0AGRkZGSV69evVTyfPjwIcLCwr7o/IiIiIiICiJFXidAlJNKlSqhRo0a4vv27dtj5MiRqF+/Pry8vHD37l1YWFh8UZ/Pnz9HXFwc2rVrB3d392+d8jf3999/Izw8HAcPHpS0z507F//88w/OnTsHe3t7AED9+vVRqlQp+Pv7Y+vWrdn2u3btWtSvXx/Lly8X2zw8PGBpaYmwsDB4eXlJ4i0sLFC7du1s+zQ2NkaPHj0wa9YseHt7QyaTfcmpEhEREREVKBzppnzJzs4Ov/76KxISErBy5UrJtosXL6JNmzYwNTWFrq4uqlWrhm3btonbp06dCltbWwDA+PHjIZPJxOnf9+7dg4+PD8qUKQN9fX3Y2NjA09MT169flxxDOfX90aNHkvYTJ05AJpPhxIkTWeYuk8mQmJiIsLAwcYq2q6trtue7fPlyWFpawsPDQ9K+e/duNG7cWCy4AaBw4cLw8vJCREQEUlNTs+1XS0sLxsbGkjZdXV3x9bV69uyJO3fu4Pjx41/dBxERERFRQcCim/Ktli1bQi6X49SpU2Lb8ePHUa9ePbx9+xYrVqzAnj174OTkhM6dOyM0NBQA4OvrK06d/vnnnxEZGYndu3cDyBgBNzMzw6xZs3Dw4EEsXboUCoUCtWrVytV07dyIjIyEnp4eWrZsKU7RXrZsWbb77Nu3Dw0bNkShQv/3lU1KSsL9+/dRpUoVlfgqVaogKSkJDx48yLbf4cOH4+DBgwgODsabN2/w4sULjBo1Cu/evcOwYcNU4jdt2gQ9PT3o6OigevXqCAkJUdtv9erVYWhoqPbecCIiIiKiHwmnl1O+ZWBggKJFi+L58+di2+DBg1GxYkUcO3YMCkXGx7tZs2Z4/fo1/Pz80KtXL9ja2oojwHZ2dpLp0g0bNkTDhg3F92lpaWjVqhUqVqyIlStXYv78+f8679q1a6NQoUIoVqxYjlO1ASAmJgYPHjxA//79Je1v3ryBIAgwNTVV2UfZFhsbm23fI0aMgJ6eHoYMGQJfX19x34iICNSrV08S261bN7Rq1QrFixdHTEwMgoOD0adPHzx48AABAQGSWLlcjqpVq+Ls2bNZHjs5ORnJycni+/j4+GxzJSIiIiLKjzjSTfmaIAjiz/fu3cOtW7fQvXt3AEBqaqr4atmyJV68eJHjaHVqaioCAwNRoUIFaGtrQ6FQQFtbG3fv3sXff/+t0XPJivKPCubm5mq3Z3fPdE73U4eEhGD48OEYOnQojhw5gv3796Np06Zo27YtDh06JInduHEjunXrhgYNGqB9+/bYv38/WrdujVmzZuGff/5R6dvc3BzPnj3L8thBQUEwNjYWX8WLF882VyIiIiKi/IhFN+VbiYmJiI2NhbW1NQDg1atXADJWz9bS0pK8Bg8eDAB4/fp1tn2OGjUKkydPxk8//YSIiAicP38e0dHRqFq1KpKSkjR7QllQHvfze6xNTEwgk8nUjmbHxcUBgNpRcKU3b96II9zz5s2Du7s7WrRogc2bN8PFxQUDBw7MMbcePXogNTUVFy9eVNmmq6ub7TWbMGEC3r17J76ePn2a4/GIiIiIiPIbTi+nfGvfvn1IS0sTFyErWrQogIxi7vNVt5XKlSuXbZ8bNmxAr169EBgYKGl//fo1ihQpIr5XFsCZp0cr47415XkpC2klPT09lC5dWmWRNwC4fv069PT0ULJkySz7vX37NpKSkuDi4qKyrUaNGjh58iTev38PQ0PDLPtQzjTIfK+5UlxcnJi7Ojo6OtDR0clyOxERERFRQcCRbsqXnjx5gjFjxsDY2BgDBgwAkFFQlylTBlevXkWNGjXUvoyMjLLtVyaTqRSC+/btU5kmrVzt/Nq1a5L2vXv35ip/HR2dXI+c29vbQ09PD/fv31fZ1q5dOxw7dkwySpyQkIBdu3ahTZs24n3t6ihnCERFRUnaBUFAVFQUTExMYGBgkG1u69evh5aWFqpXr66y7cGDB6hQoUK2+xMRERERFXQc6abv3o0bN8R7s2NiYnD69GmEhIRALpdj9+7dKFasmBi7cuVKtGjRAs2aNYO3tzdsbGwQFxeHv//+G5cuXcL27duzPVbr1q0RGhoKR0dHVKlSBX/++Sfmzp0rPmJMycXFBeXKlcOYMWOQmpoKExMT7N69G2fOnMnVOVWuXBknTpxAREQErKysYGRklOUovLa2NurUqaNSHAMZU+nXr1+PVq1aYfr06dDR0cGsWbPw8eNHTJ06VRJbunRpABn3vgMZi8h5eXlh1apV0NHRQcuWLZGcnIywsDCcPXsWAQEB4j3hc+fOxc2bN+Hu7g5bW1txIbU//vgDU6dOVRnRjo2Nxd27d/Hzzz/n6noQERERERVULLrpu+fj4wMgo/gsUqQIypcvj/Hjx8PX11dScAOAm5sbLly4gJkzZ2LEiBF48+YNzMzMUKFCBXTq1CnHYy1atAhaWloICgrC+/fv4ezsjF27dmHSpEmSOLlcjoiICAwdOhQDBw6Ejo4OunTpgiVLlqBVq1a5Os6QIUPQpUsXfPjwAY0aNcr22d7du3dH//798eLFC1hZWYntxYoVw+nTpzFmzBj07t0bqampqFOnDk6cOAFHR0dJH+qe2b1x40YsWbIE69evx9q1a6GlpYWyZctiw4YN6Natmxjn6OiIvXv3Yt++fXjz5g309PTg5OSEzZs3o0uXLir97tmzB1paWrm65kREREREBZlMyLz8MxF9lz5+/Ag7OzuMHj0a48ePz+t0ctSgQQPY2dlh48aNud4nPj4exsbG6LijG7QMtDWYHREREdG/s7F5SF6nQN8B5b9f3717h8KFC2cZx3u6ifIBXV1dTJs2DfPnz0diYmJep5OtU6dOITo6WuXZ3UREREREPyJOLyfKJ/r374+3b9/iwYMHqFy5cl6nk6XY2FisW7cu25XTiYiIiIh+FCy6ifIJuVyOCRMm5HUaOWrXrl1ep0BERERE9N3g9HIiIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIT3dBPRd2WNx/JsH7lARERERJSfcKSbiIiIiIiISENYdBMRERERERFpCItuIiIiIiIiIg1h0U1ERERERESkISy6iYiIiIiIiDSERTcRERERERGRhvCRYUT0XWkf0Q8Kfe28ToOIiIjomzrQbn1ep0B5hCPdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOimbyY0NBQymQwXL178qv1lMhmmTp0qvr958yamTp2KR48eqcR6e3vDwcHhq46T231dXV1RqVKlrzqGpqxbtw7FihVDQkKCpP3IkSOoU6cO9PX1UbRoUXh7eyMmJiZXfcbHx2PixIkoW7Ys9PX1YWNjg44dO+Kvv/5SG3/mzBm0bNkSJiYm0NPTQ5kyZRAQECCJadiwIUaMGPFV50hEREREVJCw6KbvRmRkJHx9fcX3N2/exLRp09QW3ZMnT8bu3bv/w+zy3ocPH+Dn54fx48fDyMhIbD958iRatGgBCwsL7NmzB4sWLcKRI0fg7u6O5OTkHPv19PTEwoUL0a9fP+zbtw+zZs3ClStXUKdOHTx+/FgSu2nTJjRq1AjGxsZYt24d9u/fj/Hjx0MQBElcQEAAli1bhtu3b3+bkyciIiIiyqcUeZ0AkVLt2rVzHVuqVCkNZvJ9CgsLQ2xsrOQPEwAwduxYlC1bFjt27IBCkfGVLlGiBOrVq4e1a9di0KBBWfZ57949nDp1CpMmTcLYsWPF9tKlS6Nu3brYtWsXRo4cCQB49uwZ+vfvjwEDBmDZsmVirJubm0q/jRo1Qrly5fDrr79i1apV/+q8iYiIiIjyM450k0Z5e3vD0NAQ9+7dQ8uWLWFoaIjixYtj9OjRKqOwmaeXh4aGomPHjgAyijqZTAaZTIbQ0FCx38+niC9duhQNGzaEubk5DAwMULlyZcyZMwcpKSn/6hxOnz6N2rVrQ09PDzY2Npg8eTLS0tIkMXFxcRg8eDBsbGygra2NkiVLYuLEieI5fvz4EdWqVUPp0qXx7t07cb+XL1/C0tISrq6uKn1+bvny5fD09ESRIkXEtmfPniE6Oho9e/YUC24AqFu3LsqWLZvjbAAtLS0AgLGxsaRdeQxdXV2xbc2aNUhMTMT48eOz7VOpZ8+e2LRpk8pUeCIiIiKiHwmLbtK4lJQUtGnTBu7u7tizZw/69OmDBQsWYPbs2Vnu06pVKwQGBgLIKKYjIyMRGRmJVq1aZbnP/fv30a1bN6xfvx6///47+vbti7lz52LAgAFfnfvLly/RpUsXdO/eHXv27EGHDh0wY8YMDB8+XIz5+PEj3NzcsG7dOowaNQr79u1Djx49MGfOHHh5eQHIKF63bduGmJgY9OnTBwCQnp6O7t27QxAEbN68GXK5PMs8/ve//+H69esqo8o3btwAAFSpUkVlnypVqojbs2Jvb4+2bdtiwYIFOH78ON6/f49bt25h2LBhsLOzQ5cuXcTYU6dOwdTUFLdu3YKTkxMUCgXMzc0xcOBAxMfHq/Tt6uqKxMREnDhxQu2xk5OTER8fL3kRERERERU0nF5OGvfp0ydMmzZNHLl2d3fHxYsXsWnTJvj7+6vdp1ixYihTpgwAoEKFCrmaej5//nzx5/T0dDRo0ABmZmbw8fHBr7/+ChMTky/OPTY2Fnv27EGbNm0AAE2bNkVSUhKWL1+OcePGwc7ODmFhYbh27Rq2bdsmnqOHhwcMDQ0xfvx4HD58GB4eHihTpgzWrFmDzp07Y9GiRYiLi8OJEydw8OBBWFlZZZvHuXPnAADOzs4q+QGAqampyj6mpqbi9uxs374dQ4YMQePGjcW2KlWq4OTJk5Jr9uzZM3z48AEdO3bEhAkTsHDhQkRHR2PKlCm4ceMGTp8+DZlMJsZXq1YNMpkMZ8+ehaenp8pxg4KCMG3atBzzIyIiIiLKzzjSTRonk8lUiq4qVaqoLNL1b12+fBlt2rSBmZkZ5HI5tLS00KtXL6SlpeHOnTtf1aeRkZFYcCt169YN6enpOHXqFADg2LFjMDAwQIcOHSRx3t7eAICjR4+KbZ06dcKgQYMwduxYzJgxA35+fvDw8Mgxj+fPnwMAzM3N1W7PXOzmpj2zQYMGYefOnViwYAFOnjyJrVu3QltbG40bN5b8jtLT0/Hx40f4+flhwoQJcHV1xdixYxEUFISzZ89KzhPImLpepEgRPHv2TO1xJ0yYgHfv3omvp0+f5pgrEREREVF+w6KbNE5fX19ybzAA6Ojo4OPHj9/sGE+ePEGDBg3w7NkzLFq0CKdPn0Z0dDSWLl0KAEhKSvqqfi0sLFTaLC0tAfzfKHNsbCwsLS1VClxzc3MoFAqV0eY+ffogJSUFCoUCw4YNy1Ueyvw/v45mZmaSXDKLi4tTOwKe2cGDBxEcHIyVK1dixIgRaNiwITp16oTDhw8jLi5O8gg35bGaNWsm6aNFixYAgEuXLqn0r6urm+W119HRQeHChSUvIiIiIqKChkU3FQjh4eFITEzErl270KNHD9SvXx81atSAtrb2v+r31atXKm0vX74E8H9FqJmZGV69eqXy2KyYmBikpqaiaNGiYltiYiJ69uyJsmXLQk9PT2Ul8qwo+4iLi5O0K58jfv36dZV9rl+/nuNzxq9cuQIAcHFxkbQXKVIEpUuXltwTru6+cQDieRcqpPqfkzdv3kjOn4iIiIjoR8Oim75bOjo6AHI3Sq0cZVbuA2QUg6tXr/5XOSQkJGDv3r2Stk2bNqFQoUJo2LAhgIx71N+/f4/w8HBJ3Lp168TtSgMHDsSTJ0+wa9cuBAcHY+/evViwYEGOeTg6OgLIWCwuMxsbG9SsWRMbNmyQrH4eFRWF27dviwu5ZcXa2lqMzyw2NhZ37tyBra2t2Na+fXsAwIEDBySx+/fvB6D6yLfnz5/j48ePqFChQo7nR0RERERUUHEhNfpuKUdpV61aBSMjI+jq6qJEiRLiCHNmHh4e0NbWRteuXTFu3Dh8/PgRy5cvx5s3b/5VDmZmZhg0aBCePHmCsmXLYv/+/Vi9ejUGDRoEOzs7AECvXr2wdOlS9O7dG48ePULlypVx5swZBAYGomXLlmjSpAmAjEdubdiwASEhIahYsSIqVqyIoUOHYvz48ahXrx5q1qyZZR61atWCnp4eoqKiVO4xnz17Njw8PNCxY0cMHjwYMTEx+OWXX1CpUiX4+PiIcY8fP0apUqXQu3dvBAcHAwC8vLzg7++PQYMG4X//+x+cnZ3x4sULzJ07Fx8+fJCs0t60aVN4enpi+vTpSE9PR+3atXHx4kVMmzYNrVu3Rv369SV5KQt5dc/xJiIiIiL6UXCkm75bJUqUwMKFC3H16lW4urrCxcUFERERamMdHR2xc+dOvHnzBl5eXvj555/h5OSE33777V/lYGlpiU2bNiEsLAxt2rTBtm3b4OfnJ+lXV1cXx48fR/fu3TF37ly0aNECoaGhGDNmDHbt2gUgY6r3sGHD0Lt3b3GBNQCYN28eqlSpgs6dO+Pt27dZ5qGtrY0OHTpgz549KttcXV2xf/9+vHjxAp6envj555/h5uaGo0ePqoz8p6WlSUbEDQ0NERUVhe7du2PFihVo2bIlxo4dCxsbG5w5cwaurq6SY23duhUjRozAqlWr0KJFCyxfvhwjR47Ejh07VPIKDw9H5cqVUbly5ZwuMxERERFRgSUTPr8RlYi+SxcvXoSLiwuioqJQq1atvE4nW/Hx8bC2tsaCBQvQr1+/XO9jbGyMJhs6QaH/7+7FJyIiIvreHGi3Pq9ToG9M+e/Xd+/eZbsoMEe6ifKJGjVqoFOnTggICMjrVHK0YMEC2NnZSaa3ExERERH9iFh0E+Ujv/76K1xcXJCQkJDXqWSrcOHCCA0NhULBZSOIiIiI6MfG6eVE9F3g9HIiIiIqyDi9vODh9HIiIiIiIiKiPMaim4iIiIiIiEhDWHQTERERERERaQhXOSKi78pOz9XZ3hNDRERERJSfcKSbiIiIiIiISENYdBMRERERERFpCItuIiIiIiIiIg1h0U1ERERERESkISy6iYiIiIiIiDSERTcRERERERGRhrDoJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBqiyOsEiIgAQBAEAEB8fHweZ0JERERElDPlv1uV/47NCotuIvouJCQkAACKFy+ex5kQEREREeVeQkICjI2Ns9wuE3Iqy4mI/gPp6el4/vw5jIyMIJPJ8jodIsqCi4sLoqOj8zoNogKP3zX60eWH74AgCEhISIC1tTUKFcr6zm2OdBPRd6FQoUKwtbXN6zSIKAdyuRyFCxfO6zSICjx+1+hHl1++A9mNcCtxITUiIiLKtSFDhuR1CkQ/BH7X6EdXkL4DnF5OREREREREpCEc6SYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWkIi24iIiL6brRr1w4mJibo0KFDXqdCVKDxu0Y/uv/yO8Cim4iIiL4bw4YNw7p16/I6DaICj981+tH9l98BFt1ERET03XBzc4ORkVFep0FU4PG7Rj+6//I7wKKbiIgon3NwcIBMJlN5DRky5Jsd49SpU/D09IS1tTVkMhnCw8PVxi1btgwlSpSArq4uqlevjtOnT3+zHIjyWmpqKiZNmoQSJUpAT08PJUuWxPTp05Genv7NjsHvGn3PEhISMGLECNjb20NPTw9169ZFdHT0Nz1GQfwOsOgmIiLK56Kjo/HixQvxdfjwYQBAx44d1cafPXsWKSkpKu23bt3Cy5cv1e6TmJiIqlWrYsmSJVnmsXXrVowYMQITJ07E5cuX0aBBA7Ro0QJPnjwRY6pXr45KlSqpvJ4/f/4lp0yUJ2bPno0VK1ZgyZIl+PvvvzFnzhzMnTsXixcvVhvP7xoVNL6+vjh8+DDWr1+P69evo2nTpmjSpAmePXumNp7fgf9PICIiogJl+PDhQqlSpYT09HSVbWlpaULVqlWFDh06CKmpqWL77du3BUtLS2H27Nk59g9A2L17t0p7zZo1hYEDB0raHB0dhV9++eWL8j9+/LjQvn37L9qH6L/QqlUroU+fPpI2Ly8voUePHiqx/K5RQfPhwwdBLpcLv//+u6S9atWqwsSJE1Xi+R34PxzpJiIiKkA+ffqEDRs2oE+fPpDJZCrbCxUqhP379+Py5cvo1asX0tPTcf/+fTRu3Bht2rTBuHHjvvq4f/75J5o2bSppb9q0Kc6dO/dVfRJ9b+rXr4+jR4/izp07AICrV6/izJkzaNmypUosv2tU0KSmpiItLQ26urqSdj09PZw5c0Ylnt+B/6PI6wSIiIjo2wkPD8fbt2/h7e2dZYy1tTWOHTuGhg0bolu3boiMjIS7uztWrFjx1cd9/fo10tLSYGFhIWm3sLDIcgqhOs2aNcOlS5eQmJgIW1tb7N69Gy4uLl+dF9G3NH78eLx79w6Ojo6Qy+VIS0vDzJkz0bVrV7Xx/K5RQWJkZIQ6deogICAA5cuXh4WFBTZv3ozz58+jTJkyavfhdyADi24iIqICJDg4GC1atIC1tXW2cXZ2dli3bh0aNWqEkiVLIjg4WO3I+Jf6vA9BEL6o30OHDv3rHIg0ZevWrdiwYQM2bdqEihUr4sqVKxgxYgSsra3Ru3dvtfvwu0YFyfr169GnTx/Y2NhALpfD2dkZ3bp1w6VLl7Lch98BLqRGRERUYDx+/BhHjhyBr69vjrGvXr1C//794enpiQ8fPmDkyJH/6thFixaFXC5XGWWIiYlRGY0gyq/Gjh2LX375BV26dEHlypXRs2dPjBw5EkFBQVnuw+8aFSSlSpXCyZMn8f79ezx9+hQXLlxASkoKSpQokeU+/A6w6CYiIiowQkJCYG5ujlatWmUb9/r1a7i7u6N8+fLYtWsXjh07hm3btmHMmDFffWxtbW1Ur15dXDld6fDhw6hbt+5X90v0Pfnw4QMKFZL+81kul2f5yDB+16igMjAwgJWVFd68eYNDhw6hbdu2auP4HcjA6eVEREQFQHp6OkJCQtC7d28oFFn/7z09PR3NmzeHvb09tm7dCoVCgfLly+PIkSNwc3ODjY2N2lGI9+/f4969e+L7hw8f4sqVKzA1NYWdnR0AYNSoUejZsydq1KiBOnXqYNWqVXjy5AkGDhz47U+YKA94enpi5syZsLOzQ8WKFXH58mXMnz8fffr0UYnld40KokOHDkEQBJQrVw737t3D2LFjUa5cOfj4+KjE8juQicbXRyciIiKNO3TokABAuH37do6xf/zxh5CUlKTSfvnyZeHJkydq9zl+/LgAQOXVu3dvSdzSpUsFe3t7QVtbW3B2dhZOnjz5VedD9D2Kj48Xhg8fLtjZ2Qm6urpCyZIlhYkTJwrJyclq4/ldo4Jm69atQsmSJQVtbW3B0tJSGDJkiPD27dss4/kdyCATBEH470t9IiIiIiIiooKP93QTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWkIi24iIqICqm/fvpDJZOJr2rRpeZ1SvsVrqXl3796Fjo4OZDIZdu7cKba7urqK1/3Ro0d5l2AeU14DBweHr9pfEARUrlwZMpkMffr0+bbJEVG2WHQTEREVQB8+fMD27dslbWFhYRAEIY8yyr94Lf8bo0aNwqdPn1C5cmV4eXnldToFjkwmg7+/PwAgNDQU0dHReZwR0Y+DRTcREVEBtHPnTiQkJADI+Mc2ADx8+BCnTp3Ky7QAZBSx+cn3fC1z63u/5levXsXvv/8OABg0aJB4nenb8vLygoWFBQRBQFBQUF6nQ/TDYNFNRERUAIWGhoo/Dxw4UG373r17xSmr/fv3l+x/9uxZcVuHDh3E9piYGIwePRqOjo7Q09ODgYEBXFxcsHLlSsnI76NHj8T9XV1d8fvvv6NGjRrQ1dXF4MGDAQCrVq2Cu7s7bG1tYWBgAG1tbdja2qJLly64du2ayjnt3bsXTk5O0NXVRYkSJTBr1iysXbtWPM7UqVMl8VevXkX37t1ha2sLbW1tmJqaonnz5jh69Og3v5aZ/f333+jbty9KlCgBHR0dGBsbw8nJCcuWLZPEnT9/Hl26dJHkV6tWLezYsUPtNczMwcFB3KZ04sQJsc3b2xshISGoVKkStLW1MWfOHADAzJkz0aBBA1hbW0NPTw+6urooWbIk+vbtq3bqdnbnkp6ejjJlykAmk0FfXx9xcXGSfatUqQKZTAYdHR38888/2V5j5bVRKBTo0qVLtrFKgiBgzZo1qFevHoyNjaGtrQ17e3v06dMH9+7dU4n/0s+POr///jsaNWoEExMTKBQKmJmZwcnJCX379sWbN28ksVu2bIGHhweKFi0KbW1tWFpaolmzZrhx4wYA4OPHj/Dx8YGTkxOKFSsGbW1tGBgYoEqVKvD390diYmKursP79+8xbdo0VKlSBQYGBtDT00PlypUxa9YsfPr0SRIrl8vRuXNn8Xo8e/YsV8cgon9JICIiogLl8ePHQqFChQQAgrW1tRAfHy/o6ekJAARDQ0Ph/fv3giAIQmpqqmBjYyMAEIoUKSJ8/PhR7GPAgAECAAGAcOjQIUEQBOH+/fuClZWV2P75q0uXLuL+Dx8+FNtNTEzEfAAIvXv3FgRBENq2bZtlX4aGhsKdO3fE/nbt2iXIZDKVuOLFi4s/T5kyRYzfs2ePoKWlpbZvmUwmLF++/JteS6V9+/YJOjo6ao/btm1bMW7VqlWSa5L5NXz4cJVr2KhRI8lx7O3txW1Kx48fF9uKFi0q6VN5bapWrZrlNbeyshJiY2O/6FyWLVsmts2ePVvc99q1a2o/F1mxtbUVAAjOzs4q2xo1aiT29fDhQ0EQBCE9PV3o2LFjtp+fqKgosY8v/fyoc/HiRUGhUGR5zLt374qxPXv2zDJu9+7dgiAIwps3b7KMASA0bdpUcnxlu729vdgWGxsrVKhQIcs+GjZsKCQnJ0v62bVrl7h9zZo1Of5uiOjf40g3ERFRARMWFob09HQAQMeOHWFkZISWLVsCyBgVU46kyuVycUGlt2/fIiIiAgDw6dMnbNu2DQBQokQJeHh4AACGDx+OFy9eQKFQYPv27fjw4QNevXqFjh07AsgY2du3b59KPm/evEHHjh3x9OlTxMfHw8/PDwAwePBgXLx4Ea9fv0ZKSgpiY2MxadIkMc8VK1YAyBjRHDlypDiS7ufnh7dv3+L06dNqRwOTkpLg6+uLlJQUODg4IDo6GsnJybh9+zbKlSsHQRAwatQovH79+ptdS+D/Ri6Tk5MBAH369MGjR4+QkJCAM2fOiPs9f/4cw4YNE/v18/PDixcv8PbtW/zxxx+oU6dOjnnl5PXr1xgxYgRevXqF2NhY9O7dGwAwdepUXLt2DXFxcUhJScGrV6/g4+MDAHjx4gU2btz4Refi7e2NYsWKAQCWL18untOGDRvEXDLPDlDnf//7H/73v/8BAKpWrZqr89uxY4d4n729vT3+/PNPvH37FuPHjweQ8bvp27cvgC///GTl5MmTSE1NBQBs3boVnz59QkxMDM6dOwd/f38YGhoCAHbt2oX169cDAAwMDLBhwwa8ffsWL168QFhYGGxsbAAAenp62LhxI+7fv4+EhAR8+vQJ9+7dg5OTEwDgjz/+wPXr17PNacqUKbh58yYAYMmSJYiPj8fbt28xbNgwAMCpU6ewevVqyT7Ozs7iz1FRUbk+fyL6F/K05CciIqJvrnTp0uJI1rlz5wRBEIRt27aJba6urmJs5pFcT09PQRAEYceOHWLszJkzBUEQhKSkpGxH+ZSvoUOHCoIgHaUtXLiwyoiwIAjC1atXhS5dugjFixcXtLW1Vfpq3ry5IAiCcOvWLckIbmpqqtjH+PHjVUYqDx8+nGOeAIQdO3Z802t55MgRsb1UqVKSPDNbs2aN2v0/929GukuXLi2kpaWp9Hnq1CnB09NTsLKyUjsTYODAgV90LoIgCFOnThVj9+zZI6Snp4sjyOXLl89yP6ULFy6I+48bN05lu7qR7u7du4ttixYtEmNTUlIEMzMzcdu9e/e++POTlfDwcMkIckBAgLBt2zbJjAxBEIQePXqIcVOnTs22z+DgYKF+/foqs0GUry1btoixyrbMI93KmSrZvVq3bi05ZmJioritVatW2eZHRN+GItfVOREREX33Tp8+Ld7PamJiAl1dXVy5cgU2NjZQKBRITU3FyZMn8ejRIzg4OMDOzg7NmjXDgQMHcPDgQbx+/VocpVMoFOJIeGxsrDjKlx11o8flypWDgYGBpO3x48eoW7dutiONSUlJKn3a2tpCLpeL79U9PunVq1c55plVrpl96bV8+fKluG+FChUkeWaWOa5y5cq5ylX4bKX0nH4X1apVQ6FC0gmN58+fh5ubG9LS0rLcT3nNc3suADBkyBDMnj0bSUlJWLJkCQoXLoynT58CAAYMGJBtnl8r8+/Y3t5e/FmhUMDW1haxsbFiXOZrl5vPT1batm2L0aNHY/ny5Th16pRkIT1nZ2dERETA2to617/fX3/9FWPGjMn2mMrfR1Zy81n//HPOReqI/nucXk5ERFSAZF7c682bN3B2dka1atVQr149sVATBAFhYWFiXL9+/QAAKSkpWLp0Kfbv3w8AaNOmDSwtLQEAZmZmUCgy/lZvZGSE5ORkCIKg8tq0aZNKTvr6+ipt4eHhYsHduHFjPHv2DIIgYO/evSqxyunLQMbUbOUUZiBjFfHPWVhYiD83a9ZMbZ7p6ek5FoRfei2V1wrIWIAsc56ZZY5TLqqljq6urvhz5tXH379/Lyns1FF3zbds2SIW3N27d8fr168hCAJ+++23bHPM7lwAoGjRovD29gYAHDlyRHyGuZ6enjitPTtWVlbizzktuKaU+Xf8+PFj8ee0tDRxqroy7ks/P9mZN28e4uLiEB0djW3btmHIkCEAgEuXLmH69OkAcv/7zTwFf9GiRfjw4QMEQfiix6Upr4NMJsPz58/VftbPnTsn2ScmJkb8OXOuRKQ5LLqJiIgKCHXPk85K5udMe3p6ioXPjBkzkJKSAgCSFc11dXXRvHlzAEBCQoJ4j29KSgqePn2KsLAw1KtXL9eP0VIW8ADEVZvv37+PGTNmqMSWKVNGHJGMiYnBzJkzxXuL16xZoxJfr149sdD6448/MG/ePMTGxiI5ORm3bt3C7NmzUbp06Wzz+5prWa9ePZibmwMA7t27hwEDBuDJkydITEzE+fPnsWrVKgBAixYtxIL6+PHj8Pf3x6tXrxAfH4/jx49j69atADIKKmXcX3/9hYcPHyItLQ0TJ07MdrQ6K5mvua6uLvT09HD16lUsWrRIJTa356I0atQoFCpUCIIg4MSJEwCALl26oEiRIjnmZWtrK97nfOXKlVydS5s2bcSfFyxYgCtXriA+Ph6TJ08WR7krVKiAUqVKffHnJysnT55EYGAg/vrrLzg4OOCnn37CTz/9JG5/8uQJAEiK5rlz52LLli2Ij49HTEwMNm3aJD4fO/Pvw9DQEDKZDHv27FG7LkJW2rVrByDjjz+9e/fG33//jZSUFLx8+RI7duxA8+bNxZkrSpcuXRJ/rl27dq6PRUT/wn81j52IiIg0a926deK9mtWqVVPZnnm1cgDCiRMnxG1+fn6S+0AdHBxU7gl+8OBBjveQHj9+XBCE7O9HVvalr6+vsn/ZsmXV7pfV6tOZ88l8/+zevXvV3iee+aWJa/ktVy8XBEHo16+f2C6XywV9fX1BoVBIzk0p8z3dyhXiMzt37pzaY2a+5pn3y+25KLVv314Sc/78+WyvcWbK85TL5UJcXJxkW1arl3t5eWX5u9XX1xfOnj0r9vGlnx911q9fn+3nafHixWJsr169soxTrl4+a9YslW2FChUSSpUqJb4PCQkR+1S2fb56ecWKFbPNK3MfgiAIw4YNE4/15MmTXP+OiOjrcaSbiIiogMg8ZVx5L3ZmcrlcMt038/Tpfv36Se719PX1VbknuESJErhy5QrGjRuHChUqiKOlJUuWhKenJ5YvXy5ZGTk7JUqUwP79+1G7dm3o6+vDysoKY8aMUTvVGcgY0du9ezeqVq0KbW1t2NnZISAgAEOHDhVjihYtKv7s6emJP//8E7169YKdnR20tLRgbGyM8uXLo1evXuJocla+9lq2bNkSly9fho+PDxwcHKCtrQ0jIyNUrVoVTZs2FeP79euHc+fOoXPnzrCxsYGWlhaKFCmCmjVron79+mLc/PnzMWDAAFhZWUFbWxsuLi44duyYZEp2btWpUwfbt29HlSpVoKurC3t7ewQGBuKXX35RG5/bc1HKfH9ytWrVULNmzVznpnx2e1paWo6/GyBjOvX27duxYsUK1K5dG0ZGRlAoFChevDh69+6Ny5cvo27dumL8l35+1KlevTp8fX1RuXJlmJqaQi6Xw8jICLVr18aqVaskfYWFhWHTpk1wd3eHqakpFAoFzM3N4eHhIc6yGDNmDKZPnw4HBwfo6OigatWq2L17t+T3nxNTU1OcP38eAQEBqFatGgwMDKCjowN7e3t4eHjg119/RYsWLcT4tLQ08ckEbdq0QfHixXN9LCL6ejJB+GxlDiIiIqLvTEJCAi5cuICGDRtCS0sLAHDz5k20atUKjx49QqFChXDz5k2UK1cujzP9ce3evVucWr127VrxUWS51bp1a+zbtw9Vq1bF5cuXv+mCX/z8ZNi+fTs6deoEmUyG8+fPw8XFJa9TIvohsOgmIiKi796jR49QokQJaGlpwdzcHB8/fhTv3QWAadOmwd/fPw8z/HFNmDAB27Ztw8OHDyEIAhwdHXH9+nXJPcu5cffuXVSqVAmfPn3Cjh070L59+2+WIz8/Gfd9V61aFdevX4ePjw/Wrl2b1ykR/TD4yDAiIiL67hUpUgQ9evRAZGQkXr58iU+fPsHa2hq1atXCwIED1U53pv/Gixcv8ODBAxgZGaF+/fpYunTpFxfcQMaCecnJyRrIkJ8fIGNK/rVr1/I6DaIfEke6iYiIiIiIiDSEC6kRERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWnI/wMd2zX/ZNR0/QAAAABJRU5ErkJggg==",
+ "text/plain": [
+ "
\"\n",
+ " for width in max_widths:\n",
+ " html_str += f\"
\"\n",
+ " html_str += \"
\"\n",
+ "\n",
+ " if headers:\n",
+ " if len(headers) != len(columns):\n",
+ " raise ValueError(\"Headers list must match the number of columns.\")\n",
+ " html_str += (\n",
+ " \"
\"\n",
+ " + \"\".join(\n",
+ " f\"
{header}
\"\n",
+ " for header in headers\n",
+ " )\n",
+ " + \"
\"\n",
+ " )\n",
+ "\n",
+ " for row_items in zip(*columns):\n",
+ " html_str += \"
\"\n",
+ " for i, item in enumerate(row_items):\n",
+ " if isinstance(item, (Image.Image, Path)):\n",
+ " img_html = get_image_html(item, max_width=max_image_width)\n",
+ " html_str += f\"
{img_html}
\"\n",
+ " else: # Assume the item is a string\n",
+ " style = \"font-weight: bold;\" if i == 0 else \"\"\n",
+ " html_str += f\"
{item}
\"\n",
+ " html_str += \"
\"\n",
+ "\n",
+ " html_str += \"
\"\n",
+ " return html_str\n",
+ "\n",
+ "\n",
+ "def display_columns(\n",
+ " columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None\n",
+ "):\n",
+ " \"\"\"\n",
+ " Displays a table with any combination of columns, which can be lists of strings or lists \n",
+ " of PIL Image objects, within a Jupyter notebook cell.\n",
+ "\n",
+ " :param columns: A list of lists, where each sublist represents a column in the table. \n",
+ " Each sublist can contain either strings or PIL Image objects.\n",
+ " :param max_image_width: The maximum size of the images in pixels. This controls the max-height \n",
+ " of the images.\n",
+ " :param headers: A list of header labels for the table. If None, no headers are displayed.\n",
+ " \"\"\"\n",
+ " return display(HTML(get_columns_html(columns, max_image_width, headers)))\n",
+ "\n",
+ "\n",
+ "def get_image_grid_html(\n",
+ " images: list[Image.Image | Path | str],\n",
+ " rows: int,\n",
+ " columns: int,\n",
+ " titles: list[str] | None = None,\n",
+ " max_image_width: int | None = None,\n",
+ " caption: str | None = None\n",
+ "):\n",
+ " if titles and len(titles) != len(images):\n",
+ " raise ValueError(\"Titles list must match the number of images if provided.\")\n",
+ "\n",
+ " html_str = \"
\" # Empty cell if no more images\n",
+ " image_index += 1\n",
+ " html_str += \"
\"\n",
+ "\n",
+ " html_str += \"
\"\n",
+ " return html_str\n",
+ "\n",
+ "\n",
+ "def display_image_grid(\n",
+ " images: list[Image.Image | Path | str],\n",
+ " rows: int,\n",
+ " columns: int,\n",
+ " titles: list[str] | None = None,\n",
+ " max_image_width: int | None = None,\n",
+ " caption: str | None = None,\n",
+ "):\n",
+ " \"\"\"\n",
+ " Displays a grid of images in a HTML table within a Jupyter notebook cell.\n",
+ "\n",
+ " :param images: A list of PIL Image objects to be displayed.\n",
+ " :param rows: The number of rows in the grid.\n",
+ " :param columns: The number of columns in the grid.\n",
+ " :param titles: An optional list of titles for each image. If provided, it must match the length \n",
+ " of the images list.\n",
+ " :param max_image_width: The maximum width of the images in pixels.\n",
+ " \"\"\"\n",
+ " display(HTML(get_image_grid_html(images, rows, columns, titles, max_image_width, caption)))\n",
+ "\n",
+ "\n",
+ "def acc_as_html(acc):\n",
+ " return f\"
+ """
+ display(HTML(html_content))
+
+ def _ipython_display_(self):
+ self.display()
+
+# %% helpers.ipynb 29
+def page_boxes(self: st.PageData, out_dir: Path | None = None) -> tuple[Image.Image, Path]:
+ """
+ Visualize the boxes on an image.
+ Typically, this would be used to check where on the original image the
+ boxes are located.
+
+ :param image_path: The path to the image to visualize the boxes on.
+ """
+ image_path = Path(self.image_path)
+ image = Image.open(image_path)
+ draw = ImageDraw.Draw(image)
+ data_path = resources.files(pcleaner.data)
+ font_path = str(data_path / "LiberationSans-Regular.ttf")
+ # Figure out the optimal font size based on the image size. E.g. 30 for a 1600px image.
+ font_size = int(image.size[0] / 50) + 5
+
+ for index, box in enumerate(self.boxes):
+ draw.rectangle(box.as_tuple, outline="green")
+ # Draw the box number, with a white background, respecting font size.
+ draw.text(
+ (box.x1 + 4, box.y1),
+ str(index + 1),
+ fill="green",
+ font=ImageFont.truetype(font_path, font_size),
+ stroke_fill="white",
+ stroke_width=3,
+ )
+
+ for box in self.extended_boxes:
+ draw.rectangle(box.as_tuple, outline="red")
+ for box in self.merged_extended_boxes:
+ draw.rectangle(box.as_tuple, outline="purple")
+ for box in self.reference_boxes:
+ draw.rectangle(box.as_tuple, outline="blue")
+
+ # Save the image.
+ extension = "_boxes"
+ out_path = image_path.with_stem(image_path.stem + extension)
+ if out_dir is not None:
+ out_dir.mkdir(parents=True, exist_ok=True)
+ out_path = out_dir / image_path.name
+ image.save(out_path)
+
+ return image, out_path
+
+# %% helpers.ipynb 31
+def crop_box(box: st.Box, image: Image.Image) -> Image.Image:
+ return image.crop(box.as_tuple)
+
+# %% helpers.ipynb 33
+PRINT_FORMATS = {
+ 'Golden Age': (7.75, 10.5), # (1930s-40s)
+ 'Siver Age': (7, 10.375), # (1950s-60s)
+ 'Modern Age': (6.625,10.25), # North American comic books
+ 'Magazine': (8.5, 11),
+ 'Digest': (5.5, 8.5),
+ 'Manga': (5.0, 7.5),
+}
+
+
+def size(w: int, h: int, unit: str = 'in', dpi: float = 300.) -> tuple:
+ """
+ Calculate the print size of an image in inches or centimeters.
+
+ Args:
+ w (int): Width of the image in pixels.
+ h (int): Height of the image in pixels.
+ unit (str): Unit of measurement ('in' for inches, 'cm' for centimeters).
+ dpi (float): Dots per inch (resolution).
+
+ Returns:
+ tuple: Width and height of the image in the specified unit.
+ """
+ if unit == 'cm':
+ return (w / dpi * 2.54, h / dpi * 2.54)
+ else: # default to inches
+ return (w / dpi, h / dpi)
+
+
+def dpi(w: int, h: int, print_format: str = 'Modern Age') -> float:
+ """
+ Calculate the dpi (dots per inch) needed to print an image at a specified format size.
+
+ Args:
+ w (int): Width of the image in pixels.
+ h (int): Height of the image in pixels.
+ print_format (str): Print format as defined in the formats dictionary.
+
+ Returns:
+ float: Required dpi to achieve the desired print format size.
+ """
+ # Default to 'Modern Age' if format not found
+ format_size = PRINT_FORMATS.get(print_format, PRINT_FORMATS['Modern Age'])
+ width_inch, height_inch = format_size
+ dpi_w = w / width_inch
+ dpi_h = h / height_inch
+ return (dpi_w + dpi_h) / 2 # Average dpi for width and height
+
+
+# %% helpers.ipynb 35
+def get_image_html(image: Image.Image | Path | str, max_width: int | None = None):
+ """
+ Converts a PIL image to an HTML image tag containing the image as a base64 blob.
+
+ :param image: A PIL Image object.
+ :param max_size: A PIL Image object.
+ :return: A string containing an HTML tag with the image.
+ """
+ style = f' style="max-width: {max_width}px;"' if max_width is not None else ''
+ if isinstance(image, (Path, str)):
+ return f''
+ else:
+ buffered = BytesIO()
+ image.save(buffered, format='PNG')
+ img_str = base64.b64encode(buffered.getvalue()).decode()
+ return f''
+
+
+def get_columns_html(
+ columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None
+):
+ if not all(len(col) == len(columns[0]) for col in columns):
+ raise ValueError("All columns must have the same length.")
+
+ # Calculate the maximum width of images in each column
+ max_widths = []
+ for col_index in range(len(columns)):
+ max_col_width = 0
+ for item in columns[col_index]:
+ if isinstance(item, (Image.Image, Path)):
+ if isinstance(item, (Path, str)):
+ item = Image.open(item)
+ width, _ = item.size
+ max_col_width = max(max_col_width, width)
+ if max_col_width > 0:
+ max_widths.append(
+ f"{min(max_col_width, max_image_width)}px"
+ if max_image_width is not None else
+ f"{max_col_width}px"
+ )
+ else:
+ max_widths.append('auto')
+
+ html_str = "
"
+
+ # Apply calculated column widths using
and
elements
+ html_str += "
"
+ for width in max_widths:
+ html_str += f"
"
+ html_str += "
"
+
+ if headers:
+ if len(headers) != len(columns):
+ raise ValueError("Headers list must match the number of columns.")
+ html_str += (
+ "
"
+ + "".join(
+ f"
{header}
"
+ for header in headers
+ )
+ + "
"
+ )
+
+ for row_items in zip(*columns):
+ html_str += "
"
+ for i, item in enumerate(row_items):
+ if isinstance(item, (Image.Image, Path)):
+ img_html = get_image_html(item, max_width=max_image_width)
+ html_str += f"
{img_html}
"
+ else: # Assume the item is a string
+ style = "font-weight: bold;" if i == 0 else ""
+ html_str += f"
{item}
"
+ html_str += "
"
+
+ html_str += "
"
+ return html_str
+
+
+def display_columns(
+ columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None
+):
+ """
+ Displays a table with any combination of columns, which can be lists of strings or lists
+ of PIL Image objects, within a Jupyter notebook cell.
+
+ :param columns: A list of lists, where each sublist represents a column in the table.
+ Each sublist can contain either strings or PIL Image objects.
+ :param max_image_width: The maximum size of the images in pixels. This controls the max-height
+ of the images.
+ :param headers: A list of header labels for the table. If None, no headers are displayed.
+ """
+ return display(HTML(get_columns_html(columns, max_image_width, headers)))
+
+
+def get_image_grid_html(
+ images: list[Image.Image | Path | str],
+ rows: int,
+ columns: int,
+ titles: list[str] | None = None,
+ max_image_width: int | None = None,
+ caption: str | None = None
+):
+ if titles and len(titles) != len(images):
+ raise ValueError("Titles list must match the number of images if provided.")
+
+ html_str = "
"
+
+ if caption:
+ html_str += (f"
{caption}
")
+
+ image_index = 0
+ for row in range(rows):
+ html_str += "
"
+ for col in range(columns):
+ if image_index < len(images):
+ img_html = get_image_html(images[image_index], max_width=max_image_width)
+ title_html = (
+ f"
{titles[image_index]}
"
+ if titles
+ else ""
+ )
+ html_str += f"
{title_html}{img_html}
"
+ else:
+ html_str += "
" # Empty cell if no more images
+ image_index += 1
+ html_str += "
"
+
+ html_str += "
"
+ return html_str
+
+
+def display_image_grid(
+ images: list[Image.Image | Path | str],
+ rows: int,
+ columns: int,
+ titles: list[str] | None = None,
+ max_image_width: int | None = None,
+ caption: str | None = None,
+):
+ """
+ Displays a grid of images in a HTML table within a Jupyter notebook cell.
+
+ :param images: A list of PIL Image objects to be displayed.
+ :param rows: The number of rows in the grid.
+ :param columns: The number of columns in the grid.
+ :param titles: An optional list of titles for each image. If provided, it must match the length
+ of the images list.
+ :param max_image_width: The maximum width of the images in pixels.
+ """
+ display(HTML(get_image_grid_html(images, rows, columns, titles, max_image_width, caption)))
+
+
+def acc_as_html(acc):
+ return f"
{acc:.2f}"
+
+
+# %% helpers.ipynb 37
+def strip_uuid(p: Path | str):
+ _p: Path = p if isinstance(p, Path) else Path(p)
+ new_stem = re.sub(r'(?i)[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}', '', _p.stem).strip('_')
+ return _p.with_stem(new_stem)
+
diff --git a/_testbed/ocr_idefics.py b/_testbed/ocr_idefics.py
new file mode 100644
index 00000000..67a50c42
--- /dev/null
+++ b/_testbed/ocr_idefics.py
@@ -0,0 +1,184 @@
+# AUTOGENERATED! DO NOT EDIT! File to edit: test_idefics.ipynb.
+
+# %% test_idefics.ipynb 12
+from __future__ import annotations
+
+import functools
+from pathlib import Path
+
+import pcleaner.ocr.ocr as ocr
+import torch
+import transformers
+from pcleaner.ocr.ocr_tesseract import TesseractOcr
+from PIL import Image
+from rich.console import Console
+from transformers import AutoProcessor
+from transformers import Idefics2ForConditionalGeneration
+from transformers import PreTrainedModel
+
+
+# %% auto 0
+__all__ = ['IdeficsOCR', 'IdeficsExperimentContext']
+
+# %% test_idefics.ipynb 17
+console = Console(width=104, tab_size=4, force_jupyter=True)
+cprint = console.print
+
+
+# %% test_idefics.ipynb 20
+from experiments import *
+from helpers import *
+from ocr_metric import *
+
+
+# %% test_idefics.ipynb 21
+def load_image(img_or_path) -> Image.Image:
+ if isinstance(img_or_path, (str, Path)):
+ return Image.open(img_or_path)
+ elif isinstance(img_or_path, Image.Image):
+ return img_or_path
+ else:
+ raise ValueError(f"img_or_path must be a path or PIL.Image, got: {type(img_or_path)}")
+
+
+# %% test_idefics.ipynb 36
+processor = AutoProcessor.from_pretrained("HuggingFaceM4/idefics2-8b")
+
+# %% test_idefics.ipynb 37
+device = "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu"
+
+model = Idefics2ForConditionalGeneration.from_pretrained(
+ "HuggingFaceM4/idefics2-8b",
+ torch_dtype=torch.bfloat16,
+ _attn_implementation="flash_attention_2",
+ ).to(device) # type: ignore
+
+
+# %% test_idefics.ipynb 39
+prompt_text_tmpl = (
+ "Please perform optical character recognition (OCR) on this image, which displays "
+ "speech balloons from a comic book. The text is in {}. Extract the text and "
+ "format it as follows: transcribe in standard sentence case, avoid using all capital "
+ "letters. Provide the transcribed text clearly and double check the sentence is not all capital letters.")
+
+# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays "
+# f"speech balloons from a manga comic. The text is in {}. Extract the text and "
+# "format it without newlines. Provide the transcribed text clearly.")
+
+# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays "
+# "speech balloons from a comic book. The text is in {}. Extract the text and "
+# "format it as follows: transcribe in standard sentence case (avoid using all capital "
+# "letters) and use asterisks to denote any words that appear in bold within the image. "
+# "Provide the transcribed text clearly.")
+
+# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays "
+# "speech balloons from a comic book. The text is in {}. Extract the text and "
+# "format it as follows: transcribe in standard sentence case, capitalized. Avoid using "
+# "all capital letters. In comics, it is common to use two hyphens '--' to interrupt a sentence. "
+# "Retain any hyphens as they appear in the original text. Provide the transcribed text "
+# "clearly, ensuring it is capitalized where appropriate, including proper nouns.")
+
+prompt_text_tmpl = (
+ "Please perform optical character recognition (OCR) on this image, which displays "
+ "speech balloons from a comic book. The text is in {}. Extract the text and "
+ "format it as follows: transcribe in standard sentence case, capitalized. Avoid using "
+ "all capital letters, but ensure it is capitalized where appropriate, including proper nouns. "
+ "Provide the transcribed text clearly. Double check the text is not all capital letters.")
+
+default_prompt_text_tmpl = prompt_text_tmpl
+
+# %% test_idefics.ipynb 41
+class IdeficsOCR:
+ prompt_text_tmpl: str = default_prompt_text_tmpl
+
+ def __init__(self,
+ lang: str | None = None,
+ prompt_text_tmpl: str|None = None,
+ device: str | None = None
+ ):
+ self.lang = lang
+ self.prompt_text_tmpl = prompt_text_tmpl or self.prompt_text_tmpl
+ self.device = (device or
+ "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu")
+
+ @staticmethod
+ def is_idefics_available() -> bool:
+ return True
+
+ def _generation_args(self, image: Image.Image, resulting_messages: list[dict]):
+ prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True)
+ inputs = processor(text=prompt, images=[image], return_tensors="pt")
+ inputs = {k: v.to(self.device) for k, v in inputs.items()}
+
+ max_new_tokens = 512
+ repetition_penalty = 1.2
+ decoding_strategy = "Greedy"
+ temperature = 0.4
+ top_p = 0.8
+
+ generation_args = {
+ "max_new_tokens": max_new_tokens,
+ "repetition_penalty": repetition_penalty,
+ }
+
+ assert decoding_strategy in [
+ "Greedy",
+ "Top P Sampling",
+ ]
+
+ if decoding_strategy == "Greedy":
+ generation_args["do_sample"] = False
+ elif decoding_strategy == "Top P Sampling":
+ generation_args["temperature"] = temperature
+ generation_args["do_sample"] = True
+ generation_args["top_p"] = top_p
+
+ generation_args.update(inputs)
+ return prompt, generation_args
+
+ def __call__(
+ self,
+ img_or_path: Image.Image | Path | str,
+ prompt_text: str | None = None,
+ lang: str | None = None,
+ config: str | None = None,
+ show_prompt: bool = False,
+ **kwargs,
+ ) -> str:
+ if not self.is_idefics_available():
+ raise RuntimeError("Idefics is not installed or not found.")
+ resulting_messages = [
+ {
+ "role": "user",
+ "content": [{"type": "image"}] + [
+ {"type": "text", "text": prompt_text or self.prompt_text_tmpl.format(lang or self.lang)}
+ ]
+ }
+ ]
+ image = load_image(img_or_path)
+ prompt, generation_args = self._generation_args(image, resulting_messages)
+ generated_ids = model.generate(**generation_args)
+ generated_texts = processor.batch_decode(
+ generated_ids[:, generation_args["input_ids"].size(1):], skip_special_tokens=True)
+ if show_prompt:
+ cprint("INPUT:", prompt, "|OUTPUT:", generated_texts)
+ return generated_texts[0]#.strip('"')
+
+ def postprocess_ocr(self, text):
+ return ' '.join(remove_multiple_whitespaces(text).splitlines())
+
+
+# %% test_idefics.ipynb 43
+class IdeficsExperimentContext(OCRExperimentContext):
+ @functools.lru_cache()
+ def mocr(self, ocr_model: str, lang: str):
+ if ocr_model == 'Idefics':
+ proc = IdeficsOCR(lang)
+ else:
+ engine = self.engines[ocr_model]
+ ocr_processor = ocr.get_ocr_processor(True, engine)
+ proc = ocr_processor[lang2pcleaner(lang)]
+ if isinstance(proc, TesseractOcr):
+ proc.lang = lang2tesseract(lang)
+ return proc
+
diff --git a/_testbed/ocr_metric.ipynb b/_testbed/ocr_metric.ipynb
new file mode 100644
index 00000000..41f2fad4
--- /dev/null
+++ b/_testbed/ocr_metric.ipynb
@@ -0,0 +1,276 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| default_exp ocr_metric"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| hide\n",
+ "# %reload_ext autoreload\n",
+ "# %autoreload 0\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# install (Colab)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# try: \n",
+ "# import fastcore as FC\n",
+ "# except ImportError: \n",
+ "# !pip install -q fastcore\n",
+ "# try:\n",
+ "# import rich\n",
+ "# except ImportError:\n",
+ "# !pip install -q rich\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Developing a metric for OCR of Comics/Manga texts\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Prologue"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "from __future__ import annotations\n",
+ "\n",
+ "import difflib\n",
+ "import html\n",
+ "\n",
+ "from IPython.display import display\n",
+ "from IPython.display import HTML\n",
+ "from rich.console import Console\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import fastcore.all as FC\n",
+ "import fastcore.xtras # patch Path with some utils\n",
+ "import rich\n",
+ "from fastcore.test import * # type: ignore\n",
+ "from loguru import logger\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Helpers"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# pretty print by default\n",
+ "# %load_ext rich"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| exporti\n",
+ "console = Console(width=104, tab_size=4, force_jupyter=True)\n",
+ "cprint = console.print\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## OCR metric\n",
+ "> Some basic ways to compare OCR results"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "\n",
+ "def get_text_diffs_html(str1, str2, ignore_align: bool = False):\n",
+ " matcher = difflib.SequenceMatcher(None, str1, str2)\n",
+ " html_str1, html_str2 = \"\", \"\"\n",
+ " _ch ='⎕' # ▿\n",
+ " ch = f'{ord(_ch):x};'\n",
+ " span1_g = lambda l: f\"{ch*l}\" if l > 0 else \"\"\n",
+ " span1_r = lambda l: f\"{ch*l}\" if l > 0 else \"\"\n",
+ " span2 = lambda s: f\"{html.escape(s)}\" if s else \"\"\n",
+ "\n",
+ " for opcode in matcher.get_opcodes():\n",
+ " tag, i1, i2, j1, j2 = opcode\n",
+ " if tag == \"equal\":\n",
+ " html_str1 += html.escape(str1[i1:i2])\n",
+ " html_str2 += html.escape(str2[j1:j2])\n",
+ " elif tag == \"replace\":\n",
+ " max_span = max(i2 - i1, j2 - j1)\n",
+ " # str1_segment = str1[i1:i2].ljust(max_span)\n",
+ " html_str1 += html.escape(str1[i1:i2]) + span1_g(max_span - (i2 - i1))\n",
+ " html_str2 += span2(str2[j1:j2]) + (span1_r(max_span - (j2 - j1)) if not ignore_align else '')\n",
+ " elif tag == \"delete\":\n",
+ " deleted_segment = str1[i1:i2]\n",
+ " html_str1 += html.escape(deleted_segment)\n",
+ " if not ignore_align: html_str2 += span1_r(len(deleted_segment))\n",
+ " elif tag == \"insert\":\n",
+ " inserted_segment = str2[j1:j2].replace(\" \", _ch)\n",
+ " html_str1 += span1_g(len(inserted_segment))\n",
+ " html_str2 += span2(inserted_segment)\n",
+ " html_str1 = f\"
{html_str1}
\"\n",
+ " html_str2 = f\"
{html_str2}
\"\n",
+ " return html_str1, html_str2\n",
+ "\n",
+ "def display_text_diffs(str1, str2):\n",
+ " \"\"\"\n",
+ " Displays two strings one above the other, with differing characters highlighted in red in the \n",
+ " second string only, using difflib.SequenceMatcher to align the strings and ensure matching \n",
+ " sequences are vertically aligned.\n",
+ "\n",
+ " :param str1: The first string to compare.\n",
+ " :param str2: The second string to compare.\n",
+ " \"\"\"\n",
+ " html_str1, html_str2 = get_text_diffs_html(str1, str2)\n",
+ " display(HTML(f\"
"
+ return html_str1, html_str2
+
+def display_text_diffs(str1, str2):
+ """
+ Displays two strings one above the other, with differing characters highlighted in red in the
+ second string only, using difflib.SequenceMatcher to align the strings and ensure matching
+ sequences are vertically aligned.
+
+ :param str1: The first string to compare.
+ :param str2: The second string to compare.
+ """
+ html_str1, html_str2 = get_text_diffs_html(str1, str2)
+ display(HTML(f"
{html_str1} {html_str2}
"))
diff --git a/_testbed/requirements.txt b/_testbed/requirements.txt
new file mode 100644
index 00000000..4e3d1c68
--- /dev/null
+++ b/_testbed/requirements.txt
@@ -0,0 +1,5 @@
+matplotlib
+rich
+fastcore
+nbdev
+ipywidgets
diff --git a/_testbed/test_idefics.ipynb b/_testbed/test_idefics.ipynb
new file mode 100644
index 00000000..a8978d12
--- /dev/null
+++ b/_testbed/test_idefics.ipynb
@@ -0,0 +1,1497 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| default_exp ocr_idefics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| hide\n",
+ "# %reload_ext autoreload\n",
+ "# %autoreload 0\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# install (Colab)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# try: \n",
+ "# import fastcore as FC\n",
+ "# except ImportError: \n",
+ "# !pip install -q fastcore\n",
+ "# try:\n",
+ "# import rich\n",
+ "# except ImportError:\n",
+ "# !pip install -q rich\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@basic-tesseract"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "need version >4.40 of transformers"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# %pip install git+https://github.com/huggingface/transformers"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Fash attention doesn't support Metal [#412](https://github.com/Dao-AILab/flash-attention/issues/412) (but see [metal-flash-attention](https://github.com/philipturner/metal-flash-attention))\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# %env FLASH_ATTENTION_SKIP_CUDA_BUILD=TRUE\n",
+ "# %pip install flash-attn --no-build-isolation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "notebookRunGroups": {
+ "groupValue": ""
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Fri May 10 18:32:10 2024 \n",
+ "+---------------------------------------------------------------------------------------+\n",
+ "| NVIDIA-SMI 535.161.08 Driver Version: 535.161.08 CUDA Version: 12.2 |\n",
+ "|-----------------------------------------+----------------------+----------------------+\n",
+ "| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
+ "| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
+ "| | | MIG M. |\n",
+ "|=========================================+======================+======================|\n",
+ "| 0 NVIDIA GeForce RTX 3090 Ti On | 00000000:65:00.0 Off | Off |\n",
+ "| 0% 50C P8 33W / 480W | 1MiB / 24564MiB | 0% Default |\n",
+ "| | | N/A |\n",
+ "+-----------------------------------------+----------------------+----------------------+\n",
+ " \n",
+ "+---------------------------------------------------------------------------------------+\n",
+ "| Processes: |\n",
+ "| GPU GI CI PID Type Process name GPU Memory |\n",
+ "| ID ID Usage |\n",
+ "|=======================================================================================|\n",
+ "| No running processes found |\n",
+ "+---------------------------------------------------------------------------------------+\n"
+ ]
+ }
+ ],
+ "source": [
+ "!nvidia-smi"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Testing `Idefics` OCR for Comics\n",
+ "> Accuracy Enhancements for OCR in `PanelCleaner`\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Prologue"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "from __future__ import annotations\n",
+ "\n",
+ "import functools\n",
+ "from pathlib import Path\n",
+ "\n",
+ "import pcleaner.ocr.ocr as ocr\n",
+ "import torch\n",
+ "import transformers\n",
+ "from pcleaner.ocr.ocr_tesseract import TesseractOcr\n",
+ "from PIL import Image\n",
+ "from rich.console import Console\n",
+ "from transformers import AutoProcessor\n",
+ "from transformers import Idefics2ForConditionalGeneration\n",
+ "from transformers import PreTrainedModel\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from typing import cast\n",
+ "\n",
+ "import fastcore.xtras # patch Path with some utils\n",
+ "import pcleaner.config as cfg\n",
+ "from fastcore.test import * # type: ignore\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "notebookRunGroups": {
+ "groupValue": ""
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'4.41.0.dev0'"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "transformers.__version__"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Helpers"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "notebookRunGroups": {
+ "groupValue": ""
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# pretty print by default\n",
+ "# %load_ext rich"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "notebookRunGroups": {
+ "groupValue": ""
+ }
+ },
+ "outputs": [],
+ "source": [
+ "#| exporti\n",
+ "\n",
+ "console = Console(width=104, tab_size=4, force_jupyter=True)\n",
+ "cprint = console.print\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Force reload of `experiments` module"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if 'experiments' in sys.modules:\n",
+ " import importlib; importlib.reload(experiments) # type: ignore\n",
+ "else:\n",
+ " import experiments\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "\n",
+ "from experiments import *\n",
+ "from helpers import *\n",
+ "from ocr_metric import *\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| exporti\n",
+ "\n",
+ "def load_image(img_or_path) -> Image.Image:\n",
+ " if isinstance(img_or_path, (str, Path)):\n",
+ " return Image.open(img_or_path)\n",
+ " elif isinstance(img_or_path, Image.Image):\n",
+ " return img_or_path\n",
+ " else:\n",
+ " raise ValueError(f\"img_or_path must be a path or PIL.Image, got: {type(img_or_path)}\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "----\n",
+ "# Idefics basic usage\n",
+ "\n",
+ "not working, cuda memory error"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# # Note that passing the image urls (instead of the actual pil images) to the processor is also possible\n",
+ "# # image1 = load_image(\"https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg\")\n",
+ "# # image2 = load_image(\"https://cdn.britannica.com/59/94459-050-DBA42467/Skyline-Chicago.jpg\")\n",
+ "# # image3 = load_image(\"https://cdn.britannica.com/68/170868-050-8DDE8263/Golden-Gate-Bridge-San-Francisco.jpg\")\n",
+ "\n",
+ "# image1 = Image.open(\"media/Statue-of-Liberty-Island-New-York-Bay.webp\")\n",
+ "# image2 = Image.open(\"media/Skyline-Chicago.webp\")\n",
+ "# image3 = Image.open(\"media/Golden-Gate-Bridge-San-Francisco.webp\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# processor = AutoProcessor.from_pretrained(\"HuggingFaceM4/idefics2-8b\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# model = Idefics2ForConditionalGeneration.from_pretrained(\n",
+ "# \"HuggingFaceM4/idefics2-8b\",\n",
+ "# torch_dtype=torch.bfloat16,\n",
+ "# #_attn_implementation=\"flash_attention_2\",\n",
+ "# )\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# assert isinstance(model, PreTrainedModel)\n",
+ "# model.to(DEVICE)\n",
+ "# type(model), model.device\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Create inputs"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# messages = [\n",
+ "# {\n",
+ "# \"role\": \"user\",\n",
+ "# \"content\": [\n",
+ "# {\"type\": \"image\"},\n",
+ "# {\"type\": \"text\", \"text\": \"What do we see in this image?\"},\n",
+ "# ]\n",
+ "# },\n",
+ "# {\n",
+ "# \"role\": \"assistant\",\n",
+ "# \"content\": [\n",
+ "# {\"type\": \"text\", \"text\": \"In this image, we can see the city of New York, and more specifically the Statue of Liberty.\"},\n",
+ "# ]\n",
+ "# },\n",
+ "# {\n",
+ "# \"role\": \"user\",\n",
+ "# \"content\": [\n",
+ "# {\"type\": \"image\"},\n",
+ "# {\"type\": \"text\", \"text\": \"And how about this image?\"},\n",
+ "# ]\n",
+ "# }, \n",
+ "# ]\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# prompt = processor.apply_chat_template(messages, add_generation_prompt=True)\n",
+ "# inputs = processor(text=prompt, images=[image1, image2], return_tensors=\"pt\")\n",
+ "# inputs = {k: v.to(DEVICE) for k, v in inputs.items()}\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Generate"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# generated_ids = model.generate(**inputs, max_new_tokens=500)\n",
+ "# generated_texts = processor.batch_decode(generated_ids, skip_special_tokens=True)\n",
+ "\n",
+ "# print(generated_texts)\n",
+ "# # ['User: What do we see in this image? \\nAssistant: In this image, we can see the city of New York, and more specifically the Statue of Liberty. \\nUser: And how about this image? \\nAssistant: In this image we can see buildings, trees, lights, water and sky.']\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# [\n",
+ "# 'User: What do we see in this image? '\n",
+ "# 'Assistant: In this image, we can see the city of New York, and more specifically the Statue of Liberty. '\n",
+ "# 'User: And how about this image? '\n",
+ "# 'Assistant: In this image we can see buildings, trees, lights, water and sky.'\n",
+ "# ]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "----\n",
+ "# Idefics experiments\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Idefics"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Idefics initialization"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n"
+ ]
+ }
+ ],
+ "source": [
+ "#| exporti\n",
+ "\n",
+ "processor = AutoProcessor.from_pretrained(\"HuggingFaceM4/idefics2-8b\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "You are attempting to use Flash Attention 2.0 with a model not initialized on GPU. Make sure to move the model to GPU after initializing it on CPU with `model.to('cuda')`.\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "5a21b61268674a159f210694841c2149",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Loading checkpoint shards: 0%| | 0/7 [00:00, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "#| exporti\n",
+ "\n",
+ "device = \"mps\" if torch.backends.mps.is_available() else \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
+ "\n",
+ "model = Idefics2ForConditionalGeneration.from_pretrained(\n",
+ " \"HuggingFaceM4/idefics2-8b\",\n",
+ " torch_dtype=torch.bfloat16,\n",
+ " _attn_implementation=\"flash_attention_2\",\n",
+ " ).to(device) # type: ignore\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(transformers.models.idefics2.modeling_idefics2.Idefics2ForConditionalGeneration,\n",
+ " device(type='cuda', index=0))"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "type(model), model.device\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| exporti\n",
+ "\n",
+ "prompt_text_tmpl = (\n",
+ " \"Please perform optical character recognition (OCR) on this image, which displays \"\n",
+ " \"speech balloons from a comic book. The text is in {}. Extract the text and \"\n",
+ " \"format it as follows: transcribe in standard sentence case, avoid using all capital \"\n",
+ " \"letters. Provide the transcribed text clearly and double check the sentence is not all capital letters.\")\n",
+ "\n",
+ "# prompt_text_tmpl = (\"Please perform optical character recognition (OCR) on this image, which displays \"\n",
+ "# f\"speech balloons from a manga comic. The text is in {}. Extract the text and \"\n",
+ "# \"format it without newlines. Provide the transcribed text clearly.\")\n",
+ "\n",
+ "# prompt_text_tmpl = (\"Please perform optical character recognition (OCR) on this image, which displays \"\n",
+ "# \"speech balloons from a comic book. The text is in {}. Extract the text and \"\n",
+ "# \"format it as follows: transcribe in standard sentence case (avoid using all capital \"\n",
+ "# \"letters) and use asterisks to denote any words that appear in bold within the image. \"\n",
+ "# \"Provide the transcribed text clearly.\")\n",
+ "\n",
+ "# prompt_text_tmpl = (\"Please perform optical character recognition (OCR) on this image, which displays \"\n",
+ "# \"speech balloons from a comic book. The text is in {}. Extract the text and \"\n",
+ "# \"format it as follows: transcribe in standard sentence case, capitalized. Avoid using \"\n",
+ "# \"all capital letters. In comics, it is common to use two hyphens '--' to interrupt a sentence. \"\n",
+ "# \"Retain any hyphens as they appear in the original text. Provide the transcribed text \"\n",
+ "# \"clearly, ensuring it is capitalized where appropriate, including proper nouns.\")\n",
+ "\n",
+ "prompt_text_tmpl = (\n",
+ " \"Please perform optical character recognition (OCR) on this image, which displays \"\n",
+ " \"speech balloons from a comic book. The text is in {}. Extract the text and \"\n",
+ " \"format it as follows: transcribe in standard sentence case, capitalized. Avoid using \"\n",
+ " \"all capital letters, but ensure it is capitalized where appropriate, including proper nouns. \"\n",
+ " \"Provide the transcribed text clearly. Double check the text is not all capital letters.\")\n",
+ "\n",
+ "default_prompt_text_tmpl = prompt_text_tmpl"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## IdeficsOCR"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "\n",
+ "class IdeficsOCR:\n",
+ " prompt_text_tmpl: str = default_prompt_text_tmpl\n",
+ "\n",
+ " def __init__(self, \n",
+ " lang: str | None = None, \n",
+ " prompt_text_tmpl: str|None = None, \n",
+ " device: str | None = None\n",
+ " ):\n",
+ " self.lang = lang\n",
+ " self.prompt_text_tmpl = prompt_text_tmpl or self.prompt_text_tmpl\n",
+ " self.device = (device or \n",
+ " \"mps\" if torch.backends.mps.is_available() else \"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
+ "\n",
+ " @staticmethod\n",
+ " def is_idefics_available() -> bool:\n",
+ " return True\n",
+ "\n",
+ " def _generation_args(self, image: Image.Image, resulting_messages: list[dict]):\n",
+ " prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True)\n",
+ " inputs = processor(text=prompt, images=[image], return_tensors=\"pt\")\n",
+ " inputs = {k: v.to(self.device) for k, v in inputs.items()}\n",
+ " \n",
+ " max_new_tokens = 512\n",
+ " repetition_penalty = 1.2\n",
+ " decoding_strategy = \"Greedy\"\n",
+ " temperature = 0.4\n",
+ " top_p = 0.8\n",
+ "\n",
+ " generation_args = {\n",
+ " \"max_new_tokens\": max_new_tokens,\n",
+ " \"repetition_penalty\": repetition_penalty,\n",
+ " }\n",
+ "\n",
+ " assert decoding_strategy in [\n",
+ " \"Greedy\",\n",
+ " \"Top P Sampling\",\n",
+ " ]\n",
+ "\n",
+ " if decoding_strategy == \"Greedy\":\n",
+ " generation_args[\"do_sample\"] = False\n",
+ " elif decoding_strategy == \"Top P Sampling\":\n",
+ " generation_args[\"temperature\"] = temperature\n",
+ " generation_args[\"do_sample\"] = True\n",
+ " generation_args[\"top_p\"] = top_p\n",
+ "\n",
+ " generation_args.update(inputs)\n",
+ " return prompt, generation_args\n",
+ "\n",
+ " def __call__(\n",
+ " self,\n",
+ " img_or_path: Image.Image | Path | str,\n",
+ " prompt_text: str | None = None,\n",
+ " lang: str | None = None,\n",
+ " config: str | None = None,\n",
+ " show_prompt: bool = False,\n",
+ " **kwargs,\n",
+ " ) -> str:\n",
+ " if not self.is_idefics_available():\n",
+ " raise RuntimeError(\"Idefics is not installed or not found.\")\n",
+ " resulting_messages = [\n",
+ " {\n",
+ " \"role\": \"user\",\n",
+ " \"content\": [{\"type\": \"image\"}] + [\n",
+ " {\"type\": \"text\", \"text\": prompt_text or self.prompt_text_tmpl.format(lang or self.lang)}\n",
+ " ]\n",
+ " }\n",
+ " ]\n",
+ " image = load_image(img_or_path)\n",
+ " prompt, generation_args = self._generation_args(image, resulting_messages)\n",
+ " generated_ids = model.generate(**generation_args)\n",
+ " generated_texts = processor.batch_decode(\n",
+ " generated_ids[:, generation_args[\"input_ids\"].size(1):], skip_special_tokens=True)\n",
+ " if show_prompt:\n",
+ " cprint(\"INPUT:\", prompt, \"|OUTPUT:\", generated_texts)\n",
+ " return generated_texts[0]#.strip('\"')\n",
+ "\n",
+ " def postprocess_ocr(self, text):\n",
+ " return ' '.join(remove_multiple_whitespaces(text).splitlines())\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## IdeficsExperimentContext"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#| export\n",
+ "\n",
+ "class IdeficsExperimentContext(OCRExperimentContext):\n",
+ " @functools.lru_cache()\n",
+ " def mocr(self, ocr_model: str, lang: str):\n",
+ " if ocr_model == 'Idefics':\n",
+ " proc = IdeficsOCR(lang)\n",
+ " else:\n",
+ " engine = self.engines[ocr_model]\n",
+ " ocr_processor = ocr.get_ocr_processor(True, engine)\n",
+ " proc = ocr_processor[lang2pcleaner(lang)]\n",
+ " if isinstance(proc, TesseractOcr):\n",
+ " proc.lang = lang2tesseract(lang)\n",
+ " return proc\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# PanelCleaner Configuration\n",
+ "> Adapt `PanelCleaner` `Config` current config to this notebook.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "config = cfg.load_config()\n",
+ "config.cache_dir = Path(\".\")\n",
+ "\n",
+ "cache_dir = config.get_cleaner_cache_dir()\n",
+ "\n",
+ "profile = config.current_profile\n",
+ "preprocessor_conf = profile.preprocessor\n",
+ "# Modify the profile to OCR all boxes.\n",
+ "# Make sure OCR is enabled.\n",
+ "preprocessor_conf.ocr_enabled = True\n",
+ "# Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n",
+ "preprocessor_conf.ocr_max_size = 10**10\n",
+ "# Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n",
+ "preprocessor_conf.suspicious_box_min_size = 10**10\n",
+ "# Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n",
+ "preprocessor_conf.ocr_blacklist_pattern = \".*\"\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Test images\n",
+ "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['00: Action_Comics_1960-01-00_(262).JPG',\n",
+ " '01: Adolf_Cap_01_008.jpg',\n",
+ " '02: Barnaby_v1-028.png',\n",
+ " '03: Barnaby_v1-029.png',\n",
+ " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n",
+ " '05: Cannon-292.jpg',\n",
+ " '06: Contrato_con_Dios_028.jpg',\n",
+ " '07: Erase_una_vez_en_Francia_02_88.jpg',\n",
+ " '08: FOX_CHILLINTALES_T17_012.jpg',\n",
+ " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n",
+ " '10: Galactus_12.jpg',\n",
+ " '11: INOUE_KYOUMEN_002.png',\n",
+ " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n",
+ " '13: MCCAY_LITTLENEMO_090.jpg',\n",
+ " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n",
+ " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n",
+ " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n",
+ " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n",
+ " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n",
+ " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n",
+ " '20: Strange_Tales_172005.jpg',\n",
+ " '21: Strange_Tales_172021.jpg',\n",
+ " '22: Tarzan_014-21.JPG',\n",
+ " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n",
+ " '24: Transformers_-_Unicron_000-004.jpg',\n",
+ " '25: Transformers_-_Unicron_000-016.jpg',\n",
+ " '26: WARE_ACME_024.jpg',\n",
+ " '27: Yoko_Tsuno_T01_1972-10.jpg',\n",
+ " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n",
+ " '29: manga_0033.jpg',\n",
+ " '30: ronson-031.jpg',\n",
+ " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "media_path = Path(\"media/\")\n",
+ "\n",
+ "IMAGE_PATHS = sorted(\n",
+ " [_ for _ in media_path.glob(\"*\") if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n",
+ "\n",
+ "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# CONTEXT\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Current Configuration:\n",
+ "\n",
+ "Locale: System default\n",
+ "Default Profile: Built-in\n",
+ "Saved Profiles:\n",
+ "- victess: /home/vic/dev/repo/DL-mac/cleaned/victess.conf\n",
+ "- victmang: /home/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n",
+ "\n",
+ "Profile Editor: System default\n",
+ "Cache Directory: .\n",
+ "Default Torch Model Path: /home/vic/.cache/pcleaner/model/comictextdetector.pt\n",
+ "Default CV2 Model Path: /home/vic/.cache/pcleaner/model/comictextdetector.pt.onnx\n",
+ "GUI Theme: System default\n",
+ "\n",
+ "--------------------\n",
+ "\n",
+ "Config file located at: /home/vic/.config/pcleaner/pcleanerrc\n",
+ "System default cache directory: /home/vic/.cache/pcleaner\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "
INPUT: User:<image>Please perform optical character recognition (OCR) on this image, which displays \n",
+ "speech balloons from a comic book. The text is in English. Extract the text and format it as follows: \n",
+ "transcribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \n",
+ "capitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \n",
+ "check the text is not all capital letters.<end_of_utterance>\n",
+ "Assistant: |OUTPUT:\n",
+ "[\n",
+ " 'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \n",
+ "Orleans, kept tidy by a white-haired old man known only as Bambu.'\n",
+ "]\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "INPUT: User:\u001b[1m<\u001b[0m\u001b[1;95mimage\u001b[0m\u001b[39m>Please perform optical character recognition \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mOCR\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m on this image, which displays \u001b[0m\n",
+ "\u001b[39mspeech balloons from a comic book. The text is in English. Extract the text and format it as follows: \u001b[0m\n",
+ "\u001b[39mtranscribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \u001b[0m\n",
+ "\u001b[39mcapitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \u001b[0m\n",
+ "\u001b[39mcheck the text is not all capital letters.\u001b[0m\n",
+ "Assistant: |OUTPUT:\n",
+ "\u001b[1m[\u001b[0m\n",
+ " \u001b[32m'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \u001b[0m\n",
+ "\u001b[32mOrleans, kept tidy by a white-haired old man known only as Bambu.'\u001b[0m\n",
+ "\u001b[1m]\u001b[0m\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "prompt, generation_args = idefics_generation_args(image, resulting_messages)\n",
+ "generated_ids = model.generate(**generation_args)\n",
+ "\n",
+ "generated_texts = processor.batch_decode(\n",
+ " generated_ids[:, generation_args[\"input_ids\"].size(1):], skip_special_tokens=True)\n",
+ "cprint(\"INPUT:\", prompt, \"|OUTPUT:\", generated_texts)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu. 1.00
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
INPUT: User:<image>Please perform optical character recognition (OCR) on this image, which displays \n",
+ "speech balloons from a comic book. The text is in English. Extract the text and format it as follows: \n",
+ "transcribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \n",
+ "capitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \n",
+ "check the text is not all capital letters.<end_of_utterance>\n",
+ "Assistant: |OUTPUT:\n",
+ "[\n",
+ " 'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \n",
+ "Orleans, kept tidy by a white-haired old man known only as Bambu.'\n",
+ "]\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "INPUT: User:\u001b[1m<\u001b[0m\u001b[1;95mimage\u001b[0m\u001b[39m>Please perform optical character recognition \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mOCR\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m on this image, which displays \u001b[0m\n",
+ "\u001b[39mspeech balloons from a comic book. The text is in English. Extract the text and format it as follows: \u001b[0m\n",
+ "\u001b[39mtranscribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \u001b[0m\n",
+ "\u001b[39mcapitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \u001b[0m\n",
+ "\u001b[39mcheck the text is not all capital letters.\u001b[0m\n",
+ "Assistant: |OUTPUT:\n",
+ "\u001b[1m[\u001b[0m\n",
+ " \u001b[32m'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \u001b[0m\n",
+ "\u001b[32mOrleans, kept tidy by a white-haired old man known only as Bambu.'\u001b[0m\n",
+ "\u001b[1m]\u001b[0m\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu. 1.00
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu. 0.98
\n",
+ " \n",
+ "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
Embow⎕⎕ered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
Encountered by great charles cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.