From 0e2a0529ba7c9b779b2bf238118748571c3f8588 Mon Sep 17 00:00:00 2001 From: ajkdrag Date: Wed, 6 Mar 2024 18:02:07 +0530 Subject: [PATCH] Updated doctr latest release --- extra-requirements.txt | 10 + notebooks/experiments.ipynb | 224 ++++++++++++------- notebooks/payee_name_extr.ipynb | 4 +- notebooks/prepping_ds_for_clf.ipynb | 4 +- requirements.txt | 1 + setup.cfg | 3 + setup.py | 36 ++- src/ocrtoolkit/models/arch.py | 54 +++++ src/ocrtoolkit/utilities/__init__.py | 3 + src/ocrtoolkit/utilities/det_utils.py | 63 ++++++ src/ocrtoolkit/utilities/draw_utils.py | 2 +- src/ocrtoolkit/utilities/geometry_utils.py | 135 +++++++++++ src/ocrtoolkit/utilities/model_utils.py | 7 +- src/ocrtoolkit/wrappers/detection_results.py | 5 +- 14 files changed, 441 insertions(+), 110 deletions(-) create mode 100644 extra-requirements.txt create mode 100644 src/ocrtoolkit/utilities/det_utils.py create mode 100644 src/ocrtoolkit/utilities/geometry_utils.py diff --git a/extra-requirements.txt b/extra-requirements.txt new file mode 100644 index 0000000..24f0d23 --- /dev/null +++ b/extra-requirements.txt @@ -0,0 +1,10 @@ +# FORMAT +# Put your extra requirements here in the following format +# +# package[version_required]: tag1, tag2, ... + +ultralytics==8.1.11: ultralytics +dill==0.3.8: ultralytics +paddleocr==2.7.0.3: paddle +paddlepaddle-gpu==2.6.0: paddle +python-doctr[torch]==0.8.1: doctr diff --git a/notebooks/experiments.ipynb b/notebooks/experiments.ipynb index f90b7e5..61d767e 100644 --- a/notebooks/experiments.ipynb +++ b/notebooks/experiments.ipynb @@ -2,18 +2,10 @@ "cells": [ { "cell_type": "code", - "execution_count": 38, + "execution_count": 1, "id": "9caf8868-a0bc-4f60-983c-6b0e58deef59", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reloading 'ocrtoolkit.integrations.paddleocr'.\n" - ] - } - ], + "outputs": [], "source": [ "import sys\n", "from pathlib import Path" @@ -21,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 2, "id": "0d20e8b4-8b73-4291-b5c5-15f666d28490", "metadata": { "scrolled": true @@ -33,33 +25,16 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 3, "id": "76eec4c7-deb3-4121-893d-67373e3bbab6", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The autoreload extension is already loaded. To reload it, use:\n", - " %reload_ext autoreload\n" - ] - } - ], + "outputs": [], "source": [ "%load_ext autoreload\n", "%autoreload 3 -p\n", "%matplotlib inline" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "714caa50-225c-47e0-9494-44de0f2e4ffc", - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "id": "e382b2a4-a4df-4f39-8f39-bafd9333fdfd", @@ -70,10 +45,29 @@ }, { "cell_type": "code", - "execution_count": 41, - "id": "2c395fbb-32d1-42bd-a3e2-847e4f88eb70", + "execution_count": 4, + "id": "bf3fb50e-95ca-4d17-87ce-8508a51c15d6", "metadata": {}, "outputs": [], + "source": [ + "# !{sys.executable} -X importtime ../src/ocrtoolkit/wrappers/recognition_results.py" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2c395fbb-32d1-42bd-a3e2-847e4f88eb70", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ajkdrag/workspace/ocrtoolkit/src/ocrtoolkit/utilities/io_utils.py:7: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)\n", + " from tqdm.autonotebook import tqdm\n" + ] + } + ], "source": [ "from ocrtoolkit.wrappers.detection_results import DetectionResults\n", "from ocrtoolkit.wrappers.bbox import BBox\n", @@ -82,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 6, "id": "38e7d429-077e-4875-9e45-738b9c00496d", "metadata": {}, "outputs": [], @@ -93,19 +87,23 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 7, "id": "7b9b8c1b-8b99-4023-ae13-1f90d1620aeb", "metadata": {}, "outputs": [], "source": [ - "from ocrtoolkit.models import UL_RTDETR, DOCTR_DB_RESNET50, DOCTR_CRNN_VGG16, GCV_OCR, PPOCR_DBNET, PPOCR_SVTR_LCNET\n", + "from ocrtoolkit.models import (\n", + "DOCTR_FAST_TINY,\n", + "UL_RTDETR, DOCTR_DB_RESNET50, DOCTR_DB_MOBILENET_L, DOCTR_CRNN_MOBILENET_L,\n", + "DOCTR_CRNN_VGG16, GCV_OCR, PPOCR_DBNET, PPOCR_SVTR_LCNET\n", + ")\n", "from ocrtoolkit.core.detector import detect\n", "from ocrtoolkit.core.recognizer import recognize" ] }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 8, "id": "a75a08e4-724c-44e9-b752-a3bf10395413", "metadata": {}, "outputs": [], @@ -123,7 +121,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 9, "id": "2a54e7c5-ff07-4ba4-9ec4-836fea605543", "metadata": {}, "outputs": [], @@ -149,14 +147,14 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 10, "id": "7ea8ca7e-aeed-45b5-ae6d-a4b5d20074d2", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "5f3fcdf7de0c4386a3fbab6e7f0bfd76", + "model_id": "f7bde98cf7e74291b162de74fc887879", "version_major": 2, "version_minor": 0 }, @@ -171,7 +169,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "\u001b[32m2024-02-26 23:44:55.434\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.utilities.io_utils\u001b[0m:\u001b[36mget_files\u001b[0m:\u001b[36m57\u001b[0m - \u001b[1mFound 235 files.\u001b[0m\n" + "\u001b[32m2024-03-06 16:31:21.761\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.utilities.io_utils\u001b[0m:\u001b[36mget_files\u001b[0m:\u001b[36m57\u001b[0m - \u001b[1mFound 235 files.\u001b[0m\n" ] } ], @@ -181,7 +179,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 11, "id": "f669d319-46a0-42ea-8483-76b79b293d4c", "metadata": {}, "outputs": [], @@ -191,7 +189,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 12, "id": "878901c1-0927-4c01-88ee-c8d48a79aae8", "metadata": {}, "outputs": [ @@ -203,7 +201,7 @@ "" ] }, - "execution_count": 79, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -230,25 +228,88 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 28, + "id": "f245324e-c56d-4c3d-8438-1602e8819a33", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading https://doctr-static.mindee.com/models?id=v0.7.0/db_resnet50-79bd7d70.pt&src=0 to /home/ajkdrag/.cache/doctr/models/db_resnet50-79bd7d70.pt\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "cce31c24e6164ed393600f9b603c5544", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/102021912 [00:00" ] @@ -305,12 +363,12 @@ } ], "source": [ - "filtered[2].draw(mini_ds, show_text=True)" + "words[0].draw(mini_ds, show_text=True)" ] }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 38, "id": "b2b9700e-df35-40c6-a7b2-e1e78e74548b", "metadata": {}, "outputs": [], @@ -320,14 +378,14 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 39, "id": "c8f74c4a-e7c0-46dc-a206-e7140188b738", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "86a31e713480464bb92fdc7ce6a9337c", + "model_id": "a6b3a221fbe64af28f0abf75684ca468", "version_major": 2, "version_minor": 0 }, @@ -358,30 +416,30 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 40, "id": "be57524d-b2de-4af3-a36c-000378fc82e8", "metadata": {}, "outputs": [], "source": [ - "mini_rec_ds = rois[0].create_ds(mini_ds)\n", + "mini_rec_ds = words[0].create_ds(mini_ds)\n", "mini_rec_ds.batched = True" ] }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 41, "id": "76b52a2a-386d-4be5-a4c1-9d8a863560b3", "metadata": {}, "outputs": [ { "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAWADEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD2GK5hntVuYnDwMocOvp1zzXJ6H8RdP10TyJpWsWtnFC87X1zbhYCqddrgnJ64/GugngtLDw9PFbuLa0htnAcKX8tQp529WwMnHU4+leLXlvdeHdA/snS/ENxrGlanoU86q42rHsAIdB1UEE8HnrnmgD03SPiLoerWOo3hW7sksYxNIt3DsZoiMrIozyrdulJYfEbRb7QtR1WSO9s1sADPb3UO2bDAFMLk5DZGMfpXmnjHdNDqLWbZjXwlZ+aV4HNwpH47c/rVvxo4k8QeIZbc5tVGlmYr0A3559sYoA9GsfHmlX3hvUNaSC8iXTyyz2k8QSdGA4G0tjJGMcnrXTxv5kavgjcM4IwfxryK8P2nxh4n0+NgYb/WNMt+Oh2x75D9Nqc/WvRdF12bVdQv7aTRtRsFtHCJNdRbEuOSMoe/TP40AbVFM3r/AM9G/wC+KKAAxo8flMqlH+XaRkEc9R/nrXOaP4C8OaDPeTWOnqrXcZjkWRi6hG5KqD0XnpRRQA/SPAfh7Q7S9s7SwBgvwROsrF9yAcpz0HXA7ZpmneA/D2l6DdaRDZbrW+H78SOWaTAwMseeO2OlFFAEmmeCdD0NbSKztnX7NO9xGWkLFpGG0lifvcHH4V0NFFABzRRRQB//2Q==", - "image/png": "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", + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAALAEgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDSGqeOPFWn+GbzS7u4eSO8ga/+zOIx5TQwOS4yMqSZDjHcj0rsH0K01rUPE15dz6iJ7W58q3aG/ljEI+yxN8iqwA5Zj0rr7DSNO0iJk0+zhtlKqCI1xwq7V/IDFfPXxS8c+JPDPxB1XS9H1N7WzuxHJNGIkfLGMISCykr8qgcEdPWgD2CdoL/wFodxqlvql+zw28rf2c8glLmPJYlGVivJ79xWJo0q+IfCvgW1a7vhBMrRXRiuJYZGkihcEMykNw6nPPOKrfEXxHqvhD4T6NeaFdfZJw1tAG8tZPk8tuMOCP4R+VcPd+INU0L4FeD9c0268nUo764CTmNXIDNMG4YEcj2oA9b8O2s1vqnizRra8uzBA8ItjcXEkzRM8AJIdyW684zx2rN8IaddWHiSS1judUuo9P077JqF1c3kksU14RE4Mau7FcKSTgD7wqj8D9Yv/EXh7Vdb1Wf7RqNzqRilm2Km5Uhj2jaoAGMnoK6rwwN+s+Lg3zD+1hw3I/49oRQBz/wh8QLceAdEj1TVTLqV7JcCJbiUtLLsdicZOThR9KueItWtdK+KPhoT6y1rHcWtxHJavcFY3OVER2dCxZmH/AfaqOq6Bo+ifFDwKdK0uzsfNkvhJ9mgWPfi3OM4HP41xXxpkaD4oeEpoztkjWF1OM4InGDQB03jHxD4rv8AUNe0Dw+WF3bL5lp9mwspKNZMRknBG2eU4x0wO3JXo1roemxatJq6WwF/MGDzb2ydyxhuM45EMfb+H3OSgD//2Q==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAEgAAAALCAIAAABTQ1zSAAAFO0lEQVR4AXXWS0jWWxQFcB9fD3uZVpZakQN7YDqIKJAa1MRX0ChJwaAaBY4CcZIShNBInYmOjKJxFEWTEixKUQoUsotklHgtNbOyMnt4f7pvDS7cMzic/zl7r73W3vuc70teWFhI+j1+Lo3ly5fb+PTp09q1a4eHh79//97X1/f27duysjI7O3bsCHMGq1evvn79emZm5qZNm/r7+0+ePLlmzZr5+Xn7z58/Z2ydnJy8bNmy9+/f792793ecJEEHBgays7MZrFixwunOnTsFT01NHRwcNO/atcscO4yBzMzMAE8kEm/evJmdnd2yZYtPBl++fBEI8rdv30BZfPjwYd26dUkcPn/+zHlsbKy+vr6goGD37t1oCSmedXp6el5e3ubNm/ft24fxpUuXYLEn2IwQrFA7MjJi58ePH69fv+ZiHw8zihs2bBgfH//69euvX7+4d3R02F+1apXZEBRFRy9fvly/fr39e/fugcLBpoUxNzdnfvfuXWVlJcDa2tql7X9pCBoqnj59evjw4ba2tpSSkhLazpw5I/Gy/tfS6OnpiTRPTk4+ePBAxV68ePHo0aOzZ88+fvwYLjaimjGYmpoaGhqSfqUOKtA3btz499KAgE1ubm5zc3PoTEtLQ4KxcLLb3t6O9KK+pCRFQAbIYsqXMqJWPuVCNZjRvG3bNllgxkDpYE5MTNy+fdvizp07EoHwuXPnUnp7e+XJGVM1JV0mzEZWVlZRUVFhYaF8QyS1vLx8eno6ehU/0Bj7FP7jx48MrM0CSxOp+OHKFy2BmQnMK+iqP4MjR47wTUlJsakLgoO+Ct6SAhMCzJUrV8K5ePEiPlu3bmUAnC+Q6urqmzdvVlRUaDE2umyxVXQtGY5F8mnoB0mS11evXkVlgn0ECBv5ow2baHElYu+IvWDsJUiMMKY2qNu0o6tbWlq2b98u7q1btxSBYAbMXF0psPhTtzgSSH0QIEbLKANflj41uUsuF/gzsDAS0NkB4gnawEmy7djHVaqCH6nEuGzc2ETFGhsbdZz6qKSb6Wo5Ql08gHENYIYeO6GzuLjYTdDe58+fl+mqqirgXFgyEDojIyMaXkSFskkng3jShJAaqsDCRJI7VdwjuVwS3gzHsJzV1dWVlpYqlw7kbJ+kEACatSTRKYWGwAwACUYVtRcuXNizZ4/m5IUQQC5sDO6hKma+oGy6nN5VOpGGCZyBN8ZrnJ+f7zV6+PDhqVOnqCKDve64f/8+X4/n1atXjx07JgVqI5ag9snr7OyMKEl37971lF+7dg0DEEtMFqDD9V75FA9Ri66urv3794cBScRoD5+0nT59Gqjq+XSVT5w4EWYxo97Q0GCNfezIBXL0xGfEhYO9S0HPs2fPNI5PdONU+zE+fvy4TYNUrwUagnr9r1y5As1LFoAJisGR69jdhaJ63CRV6fSutRLTZmGOxrDWzWaFpZmxnOFhoK7H9L3T/xsCiUubCsiO6LEeHR2Nrj506JCucfnVX4oxhu9J8JaQDZYLRw2CBjSnnhOztVM8E62trUePHsXvwIEDJEWXO7bmKame/oMHD/qUiRs3biiLSPozul9SRIVFTORVanJycrwlPqNdYVJrQAipkTvZpR976XB1HSHa3d3t19kr7dM91DXww90OVQGLGw5ajgZd4wH3AulJxWCwWIYo3H/maDwha2pqgkrMCnj58mWPHnvpMcf/iUiHqBoD6JMnT/RGuMTdoEQ8+VKZP7GkzMPtxyZ2nLKxBmKWPg0MmQafMmhGLCgRAL+pqcnvpP2gFAZm4x8eD2/334YaOAAAAABJRU5ErkJggg==", "text/plain": [ - "" + "" ] }, - "execution_count": 94, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -392,41 +450,33 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 42, "id": "bb86a16b-9eb6-4f27-8356-c4694509c572", "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reloading 'ocrtoolkit.integrations.paddleocr'.\n" - ] - }, { "name": "stderr", "output_type": "stream", "text": [ - "\u001b[32m2024-02-26 19:48:08.351\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.core.recognizer\u001b[0m:\u001b[36mrecognize\u001b[0m:\u001b[36m30\u001b[0m - \u001b[1mStream mode: False\u001b[0m\n", - "\u001b[32m2024-02-26 19:48:08.352\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.core.recognizer\u001b[0m:\u001b[36mrecognize\u001b[0m:\u001b[36m31\u001b[0m - \u001b[1mBatched mode: True\u001b[0m\n", - "\u001b[32m2024-02-26 19:48:08.353\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.core.recognizer\u001b[0m:\u001b[36mrecognize\u001b[0m:\u001b[36m32\u001b[0m - \u001b[1mRunning predict on 5 samples\u001b[0m\n", - "\u001b[32m2024-02-26 19:48:08.513\u001b[0m | \u001b[34m\u001b[1mDEBUG \u001b[0m | \u001b[36mocrtoolkit.integrations.paddleocr\u001b[0m:\u001b[36m_predict\u001b[0m:\u001b[36m29\u001b[0m - \u001b[34m\u001b[1m[('02122016', 0.9866495132446289), ('0260000200024240029', 0.9434717893600464), ('SELF', 0.9935069680213928), ('5000-', 0.8739107251167297), ('PAY', 0.985064685344696)]\u001b[0m\n" + "\u001b[32m2024-03-06 16:53:32.115\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.core.recognizer\u001b[0m:\u001b[36mrecognize\u001b[0m:\u001b[36m30\u001b[0m - \u001b[1mStream mode: False\u001b[0m\n", + "\u001b[32m2024-03-06 16:53:32.125\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.core.recognizer\u001b[0m:\u001b[36mrecognize\u001b[0m:\u001b[36m31\u001b[0m - \u001b[1mBatched mode: True\u001b[0m\n", + "\u001b[32m2024-03-06 16:53:32.127\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mocrtoolkit.core.recognizer\u001b[0m:\u001b[36mrecognize\u001b[0m:\u001b[36m32\u001b[0m - \u001b[1mRunning predict on 63 samples\u001b[0m\n" ] } ], "source": [ - "rec_results = recognize(model, mini_rec_ds, stream=False)" + "rec_results = recognize(rec_model, mini_rec_ds, stream=False)" ] }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 46, "id": "802b2ea2-5ac0-4911-ba00-0d8197b01251", "metadata": {}, "outputs": [ { "data": { - "image/png": "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GidOKPWLv1g7quLzaYNHRvq++c3acxGNaj6VBskLXlCdz3p77SmB+XltDG50zq7GxwXcPaXU49/43/1du2XzS79U+9lbb9XhE07m3/xNbSuoqUkL/0Z51s5OrSiICxf05Nb7TiKhPTfppb397RvLk8rP8LB+Lxn/rrtq53IjEbtwu3ixuvL0+ZR697vtIcinPa12G571LEsIlcs6DFprUb33vRbdtTWl7rijNt3nPMdO9w1vqE33/e+3W+1PfnJtuj/7s7pPpPu611V/LhBQat++xkZSKKTzx9JLft7zaj9/443a2mdk5CMfqS2IWlvtnudDD1VXcn6/9i7Yhqkp7YXXGq+Xv9zyPEslpV784urP+v2aX0l3YkKPSS26r3ylne6LXlR7HAYG3CmrJz7RLoj//d83VrPh82mDh8ZKqaQNYvKAmxxyOKwNmUbebjyujUGOVy6nZc9G1rTPp9TP/IxlBBWLOjrC9jZSyPG4Uv/5n1YbHn1UG0C15ved77SezWSU+rEfq/5sIqFD4Hz26FFtkNei+653Wc+m0zrSWKu9u3Y1lrfNzdp4JObmahv/Bw7oNAp55jOf0Uq6Fu1nPMMua/7qr344XrILuHtKqce34S0tFtMxx1aLOQA9uF/9qtVWN8qz0cfv154tMT+vvdx6z0srr1xW6q//evMFYYBemFTuhUJtwcrP855nWd3Fog7hOBdCX589lPUf/1HfQ0wkdHSCeOCB6kZBf7/OkcoQbL1CsGRSh9aJ+++vbrgMDGihQ7rf/GZ9A6epSSs24r77qnt8G/m89KX20Got4wHQ9QbSeKglAAE9N695jWV45vNKPfvZlz+3a5f2zPn+f/qn+jUNfX3aIOPzd91VvRBr924dhuVz//iP9QXVwID9+X//940VjlX79PbaDd8HH9RpGLff373bznf/+q/aEKSCdqOQN/J529vsdSsvfOHGvr9vnz3y9/nP65TA8rKm2Ugh33679Wylor3jeu+77jor71upaOOy2hw/+cn25975zvp0b7jBHpH727+9ciX3kY9YfLC2VlvJ/87vWGumXNYGTj26zc2W4auUTo1craK8jXxcYGseDDI4qEvjuVft/vuB2dnaz5dKesuPUvrn7m7gttuurA1K6e0ORDCot0XUQn8/8OpX620ISgEPPQS8+916i8dmEAjorTLcu7qyAnz3u/W/88ADeisY2/vjP67/ldi9W3+4xeI736m/7SaX09sROLYjI3rLlRN79gC7dtnpptO16Wazdrqjo3prmxP79gE7d1p0//M/gUymNt1MRm/3kHT376/9vBusrdm3TLS1VX8uHNZjTr6dmtJzUgtK6XFaW9M/RyJ6zp14whOAvj79/1JJ969YrE13aUlvJ1JKt+XQIWD79up0ubWnVNLzUW9r18KC3gon6Q4N1X7eDUol+3zG43oc3SCZBN7+dmt+H3oIeP3rdTuvFaRM8Pn0dh63aG4G3vEOvVYA4MgR4A1vcL9V0efTWzWbmvTP6+uaF+phbAx4+GFrzp74RL1NqBpdyrd8vjHdixf1tjWltIy6/Xa9jfNKIMc2ENDj5UQgoLdhcb/x8rLe9lkPa2t66xsxMKBl4BbE1lTIN96o92sCWhA+8EDjPWQPPggUCvr/0agWNhSMm4HPZwkrQG8wr6cIfv7nLYVULgMf/ODG9uk50dWllRH7cPKkFrT1MDFh33N4442XGxG33KIFP6AXNBdrLXD8KahbWqorZEk3n3dH98gRi25rqzu6jzyyMbptbXrf95Wgu9t+4IAUHBJDQ3bFd/RofZ4B9B7M+XnrZ9lfQAu7W27Re4T57kYCaH1dKyeumb4+bdRI+P163zXprqwAJ05sjG5/P7BjR/3vNEIkYhfkuVx9Y4Pw+4EXv1jvc/f7gbk54Pd/3/3+3c2it9d+qAWNqUbw+4GXvlTv6/X7gZkZ4Pd+T++7dYtoFLjpJosXp6e1YqwHnlNA7NplGXf16I6N1afr5MNqdDcKKW8rleoGfTisz4zgHCwvu3N6HnnETqOa8b8FsDUV8nXXWZ5hpdJYAAF6Qc7N6f/7/doKjUY334bBQbsgn5+vvdhbW4HnPc9i6DNngG9+c/PvBjTTDQxYP58715jxnGPV0qI9RInrr7f+Xyi4OzBhfNxSQoGAZmapoKrRPXPGHV0KNDd083l3dC9dsrz+QEDPo3+TrB6N6sMiGGkoFrXxVw1DQ3blcuJE4xOICgXg1Cnr5+5uregIv1+vByKV0v1rhLNn9XgBuu1Oo8RJd23NPd319dp0N4pDh6z+KqXHws0hIYcPA298o1bo+TzwrnfpqMC1REuLNmKIXM4u6OvhppuA171OG0C5nPaU/+d/Nvb+SEQb6cTcnN2Yqwal7HwYCl0eMYpGgb17rZ9nZ93TpXEWDtvbtlF0d+s5JWoZiD6f3dGSp4jVg3RUAgFg27ZNN/VaYuspZL9fn1xDlEpWGLYeUik9icTQkPvQV7U2/OIvWgqxUgH+9V/t9CWGhzUz8WSg739fM3Vzs1bsO3ZoC3J4WCtaZxi5Gjo6rHCYUpoeIwD1IBkvEtHvJ4JBuwe3vl4/FUAsLuoQMzEyYldwTrr5vDu6Cwt2uqOjl9OVIdH1dcvo2ghdZ3s3goMHdRiZc/vQQ7UVcm+vDrkCmmcmJxtHdvgc0dSkhRMRDtuFRybjLsQ5M2P3NJ2GmZM30ml3inB62k73SjzkeBz4P//H8tLX14E772zM501NwJvfbJ3S9uUvAx//+LU77pa44w4r8qaUTp+48XCbm4G3vEV7kEppWfKP/7jx9iaTlheplJ4vN6e8TUxYUSWentaIbr10k6RL/q5GdyN41rO0jAQ0zX//9+prvVDQcpj9aWuz1lw9LC/bx6BW2umHjK13dGY0qhURrZ61Ncsir4ds1s5EbhVfNRw4APzWb1nfP38e+MQnaodKb7vNLojTaeCtb9X5mp07tdcUDFrezX33AZ/8pA6t1grP9fRYY1Auu88zSSYOhfQ4EMmk/pDu0pK74yDX1ixvi22TCo50ieVld3RXV+1zK/sMaMEr6S4tuQtnOunKMONG0NoKvOlNltdbKAAf/nBt70GOS7FY24CTUMpOLxaz5yVbW/XviIUFd0cAOufWGU5sa7PTXVx0pyCcdGWYcSPw+fTxp898pv6ZCq5R7hLQxjK/d/GiXmtuFMiVoLdX53sZdVtd1cfeNkpJAMALXmDVBpw7B/zJn7j7nhOdnZbxAmheqJe+Iebn7crIOWdXi+5mQ9ajozp8TwdqakofJ1xtrZdKOgpYqWhPt6VFH0cso0zVUCppepGIbmsoZBlWWwhbTyGHw3aLJ5t1JygKBbsQbm6+PPzpBt3dwHveY3l8+Tzw3vfWz03ROwa0QP7t37ZfgkFEItrzveEGLVQ+8AHgL/6iupXb0mL9Xyn3AkfSchZGxGL2/GQ67U64O/N60mC6Err5fGO6MsqRTrtbQI3a6wbhsDbKnvUsq6DsK1/R3k01+Hz2OSuV3OW2nHPr5P9k0m5YuuWDTMa+bpzFR066bs/TzmTcFbg1wuHDwNveZhkFs7M6jNsoJ7t9uxbe0ajmn/e/v7EwvlLEYtojv+02Pc+lkjbQGxVZAjo685rX6PWRy+n1fu7c5trR3GznY7dz5lw3Tl5oadkcXedzGylwk99517useplCAfibv9H1F7Xw3e/quU8k9Hde/GJ9ln8jA5h8q9SWvXRi6ynkQMBurRUK7oS788ajcHjjYcq2Nq2Mn/50y3r6zGeAT32q9uQ5Q4qAfu/srLbkJie1URGL6ZDM4cNamHR06BxYMqm9MGeYTua/lXIXrgbsz/l8doUWDNqNlELBHVOWSvY5oJVZj64bFIsbo7u+7q69jeg2QiCgF/nrX6/bwHzZW95SX2FIo6RScefNK2U3JJ387+RjN9Ei4PK5lW27lnTdYNcuXfS4Y4eel1wOeOc7deSoHnw+4BWv0PlOpXTO+JOfvLaXBoTDwGtfqwuyAgHrvX/+54353O8HfvM3dUUvK+o/85nNt9fJx27nzLlunLU14fDVobtRXkgmtVH23OfqsWL64cMfrj9GR4/qsfypn9LtfvrTgT/4A+DP/swezgY03Xhc5/ClLJQRvy2EraeQN1sZzd1em6XT1qat1xe8wBLCd98N/NEf1Q8vxeN2D2x+Xgvub35Th/fo4dNbveMOvZh37dIM/LKXAffcA3zhC3a6zva7teYaLXZJ1y1N59jWo+nm+Y3Q3Wx7NwtW7/7pn1rbSyYmgFe9qrEn5jQAN9te2efN8kE9mm6er/fclayzHTuAj31MV47TI/rQh/TvGkXCbrwReNGL9DgvLmol7rbKeTOgMn796/U6V0rfGvSa1+gcfSM84QnAr/yKbu/8vG7vRm/2krhavODEteDbRkgmdUTkZS/T46yULnJ7wxsaz2kqpb978KBVK/Sa1+jbqb72NX07WbmsnZ59+3RkY3jYXih8LbfGXQG2nkIul+05qmDQ3UQHAvYQXLHonrFaW3VY+ld+RXsnZI7f+R17wU01hMN2i/PCBeDzn7+8QKZU0gr6i1/UQuhTn9JGQHOztvq/+lV7iNNpfbstUJNWqlL2sawWRXAztk5P1Tm2Tg/aLd1QqDHdzbQ3FLILGbe8EAhogf/nf27t1Zye1vvLv/OdxjSkZ+H3u6thcEYxKhX7nDm9fbd84BwrJz9Vi3q4gXNs3UZDAF1P8fGP6z2rfr/u2yc/qXOqjcL7oZBejyyM+sIX9NV61wqRiN5G9Qd/YNUxnD2rPd564VT5/Ve9StcVKAX8y7/oKwavBM6xdjtnTl5wRm6cUY+rxWO10NSk94+/4hW6D0rpavXf+i3328Duuw94+cu13N6/X7fl5pv1pxHK5cZy/YeErVdlXSzaF2cs5i4XHArZQ33ptLvcc0uLFsC/+qv6+5WKnuyXvczdliCnIeAmN3H33fYtGjfccPnBDXKvK8MubiCfK5ftFnk+b1808bg7BReJ2Odgbc3ex2tJVwqPq0W3GgIBbZC9+91WIdzMDPC7v6uNKDdhRmnZBwLut93JOSsW7RXizlww9+c3QjRqV5xOr8NJ1y1/xWL2Oai1J9uJXbu0F0xlXCoBn/2s3grkxsu97TZ9TzOgjaQPfWhz91O7QTSq5/1Nb9LKWCmtKF7xCr2Dwg2e+ER9Dzaghf+HP3zlVeCplJ0PNyMTgMvnzLk+3PKY8zk3vJBM6iK8V77SUsaPPqqr7d1uIQP0977xDeBnf1av2Ucf1Q4PU5y82/7MGeBzn9MynX0sFq993cEmsfU85HzeYhAWyrix2OJxe0Xu4mLjBZtM6tDkS15iKeMjR4Bf//XGhyQQlYp9kbB6rx6KRX3p/XOeo39OJHRl98mT1jOy8jYQcH8KjtwyQ6+cSKft4ff2dnfGTnOzXbnI6spqdNvaNkd3bs5ON5WyK6fNttdJ14lAQKcq/uIvrHHmQRN33uk+/M5xodfrpsjF77dXwudydgW1smL3vDs63BklrOwnnNvQlpftdDs7dVsaKY1GdKthdBT4+7/X+7mpjO+8Uys9N5XokYgW2Cwgu/9+LSe4TcaJ7dstPvH59Jrgs8vL9cOV4bD2xP/wD60w9aVLWoH8x380biugee9lL7OK/O67T491rfYODVnGk8+nvWo+u7Rk7bBYWLDPj+Sbeujqsugrdfl2ImeFvVu68oCOanSdiMX0uP72b1uRyOPH9dweOeLunU6cO6ejGO97n06HdHbqOSwU9NhdvKjX0113Wd+Zn9eRzC2IraeQSyX7CVehkGaoRgOYTNoriicm6odQIhFdOfnSl1rK+MEHtXJ2cxAJsb5uVxqJhDulcf68JbxDIbsiBTTTpFJWn7q6tCBsZGTIQyXW1+2hmUJBbynge6NRLWAbWbbOvX5jY/YFTLpELKbpNvJ8nFtvxsbsxo2Tbjyuv9MoD9feblfIFy/WVqo+n95C8973Wsp4YUF7bp/73Mby0TMzWlHQi+Q2rno0/H77dpF02m6M5XKaLvd4NjVpnmi0Z7i72x4xcp7olMtpZToyYtFtamqsIBvRdaKnR1fNUhmXyzrc/OpXNz55jujoAJ7xDEv4P+c5lvdZDT6ftQYDAV3T8eY365/f9z5dTFkNfr9OWbzlLRa/T0xoz/juu921FdBrlUeoKqW9OBrfjdobDOpCp7e+Vf/8nvdYbU+lNG9SJnBdSvlTDX19diPOOWdra1ops2aC67JRGqG/367o6/FCMKjn/FWvsnLGJ05o+Xv//fXf4wbz87W3I153nT4oivNxzz3XtvbgCrD1QtYA8NhjlmDmqVuN0NGhFwKgB/3MmdrVgn4/8MIX6pwFwya01B57bGNtzWTsm847Otx59LLKj0pZYmlJh+b495ERu/KqBp/PfuJONnt5TubRR63/RyKXH6lYDQMDlhBwntBDyHGLRNwdGDE4aAmBWnSd7d0s3Vqe38GDWkjTIEqntQD89Kc3Xg07MWEpSp9PV9c2Ms4CAfu5uktLdiPKefpaMunulKGRESvHWKlcztfO3zU12Q8KqYXRUTvdesZrNKo9omc8Q6+5SkUX3bz61RsrqgmH7WvK77dSVNU+su6Eyo5/qzcfd9yhlSEjbXNz2pv75jc3ZpjJ9jrfv5H2BoOXV8LzpDqfT8s7N97snj0WnXL58jmTJ+BthC7PxCfdWlFFn0+nG173Oi3DmAJ42cvsZ0xfKzzzmdb6Xl8Hvv5195XkjzO2nocMWAdmcC/vDTcA//RP9b+zd6+V0ygU9FnKtYTwgQPAH/+xtfBmZrTltpEcBlEsambmQQUtLVqBNTpdTIZ7SqXLPZ65Oc20ZPo9e7TQrOcddnTYc9EnTlzu8fzgB3pcgkEtWA8erG/9+3y6aIJCOJ3WStIpoO6/36omJ91vf9s93VRKKwgnXbaXOdkDB/QBEvXoHjhg0V1bq21kNTfr4hJeXlEq6bD1Jz6xuXzfxYualxilOHRIC+Z6UY2BAbuHfOyYPfxfqegxeOlL9VpoadHtrVdYFAzqMWBoeXHx8n305bKm+5KX2OlKA8iJUMh+vOnCQv2jTJ/7XKvdSukI1Kte5S7MLZFKAf/wD40NUqKtTb87EtHj9/3vWzxwzz3Vv9PdraugeYhMJqMNs7vu2rhhtrqq8+Vuawg6OvQhKZGInpfvfc9SbnIrWC6n5RpPjuvt1bxW78jTeFzLRsqa8fHLz9jn2fM/9mP6uf5+zZPy1L/N0CVGRnRVNFMOS0s6XXHPPdd+L/DQkN41Qe/4/Hmde96qcHUnlFLc7PD4fLq69DVsvKLsv/9bqba22s/7fPq+WGJmpvZdmrGYUp/6lHUpeD6vr/NqdBdqvc8v/IJ1TWKji+b5efe7rfYuL1e/NPv1r7euesvn9d3E9Wg+/emX313svH5xZESpc+fs19XF47VphsP6KkXixAk9P87nRkeVOn9eP1OpKPUv/1L/6slwWF/9SBw/Xv3+3J079XWapHvnnfXvPo1E9IXkxKOP1r5q7cUvtq5VLJeV+rd/q89nbj5/+ZfWNW+Li/Wv7GQb8nmLd6rdMXz4sL5jmWPwV39V/x7ntjZ9JSGf/973ql+FedNN9nvE3/e++nQ7OpR67DHr+e9+t/YVm/39+hpM8tnMjFJPecqVja3bz/79G7t+0edT6k1vsq70K5X0ner1+Oxqfg4dcn/94k//tL5/mHPw2tfWp71zp74/m89/7nPV+/XsZ9vp/t7v1ae7a5dS09PW85/5TPWrOEMhfQ2tvEb2D//w8bmPOBLR88h3U9Y3upv5Wn1cwN1TSj2+DecF2BzIehdgA/pOVCm0P/vZ2pfCP/nJ1j2elYpSX/5y/fuA3Xy2b7e//9vf1nc613q+o8N+Z++RI9UF28GD+h5m0v3EJ2rfPxsIKPWBD1jKYHZWqRtvvPy5YFCpj3/cem5+Xt+ZWqutt91mvwz8/e+vztDBoL5Pl3Tn5nT7a9H9kR+x033ve2vT/ad/sujOzGiBW4vu7bdbwrhSUeo976k9B//zPxbd8XGlrr/+ynn3aU+zjKJSSam3v722kovHtRFApXX2rDaYnM+Fw0p9/esWv5w+re8mrtWGn/kZ617uSkWp172u+nORiFLf+IZF9+TJ+veOy/u2KxWlfv/3az/7qldZCq5QUOqP/qi+sr+an40q5KEhPabEI48oNTj4+LQV2JhCbmtT6uGHrbZ+//v15ddv/7Zl1K+vK/X851d/rr1d95uoZ2xxfqWz8Iu/WP2566+3jEml9D337e3XfkxjMX1vuTQyvvrV+nL5Wn9cwN1TSj3+jd+3T6mJCWsw77qr+kRGItpjIHMsLyv1Ez9RnWYwqC/o5rPptL4c/ErbGgwq9Rd/YdHN5ZR62cuqC6BAQAtIemaFglK/+7vVlVEkotTf/Z27vt1xh1ZWHK96l80/6UmWACiXtaJPJi9/rrlZW9R8/9RUdSUv28BLzstlrfgTiep077zTUoaTk9oLrEX3qU+1X4b+939fnW5Li/bMSXdiQl+kXo3ms55l90zf+c6rozASCaW+8hWrDZcuVe+b368jK6mU1a8/+7Pa1vvP/ZxSmYzFM+98Z3Wjs7dXRwio5M+c0dGLWu39+Z+3033726vT7evTQpp0T52qbjwAmpfuv9+SHSdO6HZd6di6/WxEIft8Sr3iFXbj4Td+4/FrK7AxhezzaWVI+ZHL6f5Vi/Dt3q0jRJyze+6pHS3y+5V6zWssutmsUi9/eXW6e/boSImMYFaTzX6/5lM6VrmcNhav5Vj6fJrfP/hBi68rFW1sHDjw+M6r8+MC7p5S6vFvfCCg1BvfqIVmpaIXyt/+rfYMgkE92R0d+hlaQaWSVmC1vOPubm1dUlg++qgOFY+OuvsMD9emvXOn9jDIpLOzOvzY0qLb6vdr6/aVr1Rqacl67vvfrx4C5ufAAR0K5vPHj2svLB7XzBeLaa9Q9uv8+freXjisjZhSyQrbv+MdSvX06HEPBLQAfu97rQVaLOpn6oX2ZYioUtEL8G1v0+NOuv392niRdN/2tsZ0P/hBO923vtWiGwxquu9/v+YT0n3rW2vTff/7rfFKpZT65V92zwejo/Ut7Tvu0BECKQhvukmHCn0+rbSf9SwdVeEzjzyi+asWzURCqX/+Z+v51VWdGuno0H0MBvX3P/lJu+fSKESXSFjGUaWiDarf+R0tYP1+HXIcGbHSPBSsv/mbtenefLMV2VFKt3vXLvdjOzBwZSmkjSjkUEipz3/eHoH5yZ/cGC9UMw438tmIQgb0nEuja3pae77NzXrcwmGl9u7VTgz7tbKi1M/+bGO60uiamtKer6S7b59SX/uaRXd5ubaSbW7W6RIpl570JPfjOjJSP21A/kwmtcF3881aRp06ZaUky2Udgbzlliubo6vxcaNmXT2l1A+nAy0tOjchczvHjin1D/+gFe+992oG5sD/138ptW1bbXqjoxbjK6W/UyhoGm4+s7O1rSyfTzPm7KzF0NmsbtNHP6o/3/ueZWBUKhaD1hsDv1+pX/olHd7l9xYXlfriF5X60Id0Dnh+3vrb0lL1PKTz09enc8Nk3GJRqQce0N7nxz6mFTwVYKmk1Je+VD3H6/z09+uQvaT7gx9ouh//uFY8ku4Xv1jbapefgQEd7nJL99/+rT5dGaqlweeWD9bXdSiwFu1AQHsx6bRdaH7+83rO7rpLK1Qp+J75zMZjsHu3Fi783vq6Nug++lEdETl50hqfQkHPY7XIh/OzZ4+9ZiOf17xKulLAFQp67dWj+7znWQYX1+1Gxvaee64sl78RhRyNWvn2zfBCPq/Uc597ZXJuowoZ0MrnzBlrztJppe6+W0cAP/1ppS5etBRhNquN3lCoMd1bb9WpE0n3m9+sTjeT0UZvLbrd3Vb+ejNju7qqU1u11sLf/I1OZ33965pHs1mLT9n2T39aO0tXMj9X6+NGzbp6SqkfXie6u7XQpXBzgpN81116kurR2rvX8qA2g6Wl+nnRQEAr5RMnLOVQrb1Ufk95irsCg2BQW8Dnz1teipNmuazzoL/2a+4LJkZGlPrCF7THU6utuZzOyW8kpzY6qhViI7qf+Uz9XKjzs2OHVuCN6H7qU/Xp+nxK3XffBiffgVe9qn5bo1HtaU5P156zUkkr0Wc/2324/LrrtGFSKNQeg1RK1xO4MXT4ueEGbTw2ovvXf904B/iiF1Wn4RY/+MHjp5DjcZ1W2CzKZW2AXImM24xC9vl0JObIkfqyZnFRqbe8pX7hppPuU56iDbRGdN/85vqFm/39VkpmM8hmdfSvGu3bb7dqNWS7ikUdDfjSl7Qsdtvvx+PjAj6llHJVjr3ZSx+uBmIxva3ol39Z35bEAxcWF/Weun/5F33YQKODBnp79WURm72sPpvVB0jU29Lk8+mtRy98oT4cYPduXe7v8+mtTadP660Un/50461REn6/pvXSlwI/+qN6PygPBbh4UV9J9vGP620rG9mm0dSkt4j8wi/oDfRdXZp95uf1NrDPfU5fFr7RQ/Gbmy26hw5ZdOfm9Jadz35Wj8Nm6D7veRbdzk6L7iOP6Nt0vva1xnTf+EZ94PxmceedjU9uCgb1lr2XvEQfjLF9u94Kk0rpE4buvltvseIhMW7R2Qk8//l6q8z+/fpAk3JZ71s/ckRvEfyP/3B3/aNEV5dFd98+O90HHrDoNrop57bbgF/7tY29W2JsDPirv2p84EUt9PXpPa/xuF4L//zPwH/9V/Vnw2F9lvZmr5FUCvjoR4GHHtrc9wG99e21r9VyrlzWPOzmnG5uUXrxi7V83L1bb18rFPQWpPvu0zLh3nvd3Twm6Q4MWHR37bLTvfdevQ2tEd2WFr2vezM3ggGa9l/+ZfXrKg8f1vuJw2G9tXNmRj935Ijebnnu3ObunL6WcLHG/3coZCIe10KCJyHl81rJXckNKtcKPp9WHq2tFkOur+s9iqurGxPAEoGAdSkFT+5KpbQxciVn5SaTmi73TuZyemyvlKmr0eUtWFuR7rVAMKj3miaTev6KRb0/enn5yq4OJH9Fo5qfslltpF7p1XLNzXpsuY83m9Vju0WvrPt/Hj6f5gMeM1yp6HW7uLixyz8eL7pXA5GIPiBHKS1XeeTsRgyPxxv/1ylkDx48ePDg4X8jXKjarXl0pgcPHjx48PD/GDyF7MGDBw8ePGwBeArZgwcPHjx42ALwFLIHDx48ePCwBeApZA8ePHjw4GELwFPIHjx48ODBwxaAp5A9ePDgwYOHLQBPIXvw4MGDBw9bAJ5C9uDBgwcPHrYAPIXswYMHDx48bAEEXT+52bOXPXjw4MGDBw8N4XnIHjx48ODBwxaAp5A9ePDgwYOHLQBPIXvw4MGDBw9bAJ5C9uDBgwcPHrYAPIXswYMHDx48bAF4CtmDBw8ePHjYAvAUsgcPHjx48LAF4ClkDx48ePDgYQvAU8gePHjw4MHDFsD/B7wwjgHz4QfDAAAAAElFTkSuQmCC", + "image/png": "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", "text/plain": [ "
" ] @@ -436,7 +486,7 @@ } ], "source": [ - "rec_results[1].draw(mini_rec_ds)" + "rec_results[11].draw(mini_rec_ds)" ] }, { @@ -2249,9 +2299,9 @@ ], "metadata": { "kernelspec": { - "display_name": "ocrtoolkit", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "ocrtoolkit" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/payee_name_extr.ipynb b/notebooks/payee_name_extr.ipynb index b253137..dfdbe86 100644 --- a/notebooks/payee_name_extr.ipynb +++ b/notebooks/payee_name_extr.ipynb @@ -2396,9 +2396,9 @@ ], "metadata": { "kernelspec": { - "display_name": "ocrtoolkit", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "ocrtoolkit" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/prepping_ds_for_clf.ipynb b/notebooks/prepping_ds_for_clf.ipynb index 0299b31..2a9be80 100644 --- a/notebooks/prepping_ds_for_clf.ipynb +++ b/notebooks/prepping_ds_for_clf.ipynb @@ -2049,9 +2049,9 @@ ], "metadata": { "kernelspec": { - "display_name": "ocrtoolkit", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "ocrtoolkit" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/requirements.txt b/requirements.txt index c2c69dc..45b09da 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ matplotlib tqdm loguru h5py +scikit-learn diff --git a/setup.cfg b/setup.cfg index 95896e8..e96faf2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,3 +22,6 @@ exclude = # Provide a comma-separate list of glob patterns to include for checks. filename = *.py + +[isort] +profile = black diff --git a/setup.py b/setup.py index 7b6976e..592661a 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,30 @@ from setuptools import find_packages, setup + +def get_extra_requires(path, add_all=True): + import re + from collections import defaultdict + + with open(path) as fp: + extra_deps = defaultdict(set) + for k in fp: + if k.strip() and not k.startswith("#"): + tags = set() + if ":" in k: + k, v = k.split(":") + tags.update(vv.strip() for vv in v.split(",")) + tags.add(re.split("[<=>]", k)[0]) + for t in tags: + extra_deps[t].add(k) + + # add tag `all` at the end + if add_all: + extra_deps["all"] = set(vv for v in extra_deps.values() for vv in v) + + return extra_deps + + regexp = re.compile(r".*__version__ = [\'\"](.*?)[\'\"]", re.S) base_package = "ocrtoolkit" @@ -53,17 +77,7 @@ def parse_requirements(filename): maintainer_email="", python_requires="==3.8.*", install_requires=requirements, - extras_require={ - "ultralytics": ["ultralytics==8.1.11"], - "paddle": ["paddleocr==2.7.0.3", "paddlepaddle-gpu==2.6.0"], - "doctr": ["python-doctr[torch]==0.7.0"], - "all": [ - "ultralytics==8.1.11", - "python-doctr[torch]==0.7.0", - "paddleocr==2.7.0.3", - "paddlepaddle-gpu==2.6.0", - ], - }, + extras_require=get_extra_requires("extra-requirements.txt"), keywords=["ocrtoolkit"], package_dir={"": "src"}, packages=find_packages("src"), diff --git a/src/ocrtoolkit/models/arch.py b/src/ocrtoolkit/models/arch.py index 4d3e651..a3656a1 100644 --- a/src/ocrtoolkit/models/arch.py +++ b/src/ocrtoolkit/models/arch.py @@ -35,6 +35,24 @@ def load(path, device, model_kwargs, **kwargs): ) +class DOCTR_CRNN_MOBILENET_L(metaclass=BaseArch): + @staticmethod + def load(path, device, model_kwargs, **kwargs): + import ocrtoolkit.integrations.doctr as framework + + return framework.load( + "rec", "crnn_mobilenet_v3_large", path, device, model_kwargs, **kwargs + ) + + +class DOCTR_PARSEQ(metaclass=BaseArch): + @staticmethod + def load(path, device, model_kwargs, **kwargs): + import ocrtoolkit.integrations.doctr as framework + + return framework.load("rec", "parseq", path, device, model_kwargs, **kwargs) + + class DOCTR_DB_RESNET50(metaclass=BaseArch): @staticmethod def load(path, device, model_kwargs, **kwargs): @@ -45,6 +63,42 @@ def load(path, device, model_kwargs, **kwargs): ) +class DOCTR_DB_RESNET34(metaclass=BaseArch): + @staticmethod + def load(path, device, model_kwargs, **kwargs): + import ocrtoolkit.integrations.doctr as framework + + return framework.load( + "det", "db_resnet34", path, device, model_kwargs, **kwargs + ) + + +class DOCTR_DB_MOBILENET_L(metaclass=BaseArch): + @staticmethod + def load(path, device, model_kwargs, **kwargs): + import ocrtoolkit.integrations.doctr as framework + + return framework.load( + "det", "db_mobilenet_v3_large", path, device, model_kwargs, **kwargs + ) + + +class DOCTR_FAST_TINY(metaclass=BaseArch): + @staticmethod + def load(path, device, model_kwargs, **kwargs): + import ocrtoolkit.integrations.doctr as framework + + return framework.load("det", "fast_tiny", path, device, model_kwargs, **kwargs) + + +class DOCTR_FAST_SMALL(metaclass=BaseArch): + @staticmethod + def load(path, device, model_kwargs, **kwargs): + import ocrtoolkit.integrations.doctr as framework + + return framework.load("det", "fast_small", path, device, model_kwargs, **kwargs) + + class GCV_OCR(metaclass=BaseArch): """Google Cloud Vision OCR Here `path` arg points to service account json file diff --git a/src/ocrtoolkit/utilities/__init__.py b/src/ocrtoolkit/utilities/__init__.py index e7113b8..257b654 100644 --- a/src/ocrtoolkit/utilities/__init__.py +++ b/src/ocrtoolkit/utilities/__init__.py @@ -4,3 +4,6 @@ from .io_utils import * from .misc_utils import * from .network_utils import * +from .geometry_utils import * +from .det_utils import * +from .model_utils import * diff --git a/src/ocrtoolkit/utilities/det_utils.py b/src/ocrtoolkit/utilities/det_utils.py new file mode 100644 index 0000000..9b812a8 --- /dev/null +++ b/src/ocrtoolkit/utilities/det_utils.py @@ -0,0 +1,63 @@ +import numpy as np +from typing import List, Tuple +from ocrtoolkit.utilities.geometry_utils import ( + estimate_page_angle, + rotate_boxes, +) + + +def sort_boxes(boxes: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: + """Sort bounding boxes from top to bottom, left to right.""" + if boxes.ndim == 3: # Rotated boxes + angle = -estimate_page_angle(boxes) + boxes = rotate_boxes( + loc_preds=boxes, angle=angle, orig_shape=(1024, 1024), min_angle=5.0 + ) + boxes = np.concatenate((boxes.min(axis=1), boxes.max(axis=1)), axis=-1) + sort_indices = ( + boxes[:, 0] + 2 * boxes[:, 3] / np.median(boxes[:, 3] - boxes[:, 1]) + ).argsort() + return sort_indices, boxes + + +def resolve_sub_lines( + boxes: np.ndarray, word_idcs: List[int], paragraph_break: float +) -> List[List[int]]: + """Split a line in sub-lines.""" + lines = [] + word_idcs = sorted(word_idcs, key=lambda idx: boxes[idx, 0]) + + if len(word_idcs) < 2: + return [word_idcs] + + sub_line = [word_idcs[0]] + for i in word_idcs[1:]: + if boxes[i, 0] - boxes[sub_line[-1], 2] < paragraph_break: + sub_line.append(i) + else: + lines.append(sub_line) + sub_line = [i] + lines.append(sub_line) + return lines + + +def resolve_lines(boxes: np.ndarray, paragraph_break: float) -> List[List[int]]: + """Order boxes to group them in lines.""" + idxs, boxes = sort_boxes(boxes) + y_med = np.median(boxes[:, 3] - boxes[:, 1]) + + lines, words, y_center_sum = [], [idxs[0]], boxes[idxs[0], [1, 3]].mean() + for idx in idxs[1:]: + y_dist = abs(boxes[idx, [1, 3]].mean() - y_center_sum / len(words)) + + if y_dist < y_med / 2: + words.append(idx) + y_center_sum += boxes[idx, [1, 3]].mean() + else: + lines.extend(resolve_sub_lines(boxes, words, paragraph_break)) + words, y_center_sum = [idx], boxes[idx, [1, 3]].mean() + + if words: # Process the last line + lines.extend(resolve_sub_lines(boxes, words, paragraph_break)) + + return lines diff --git a/src/ocrtoolkit/utilities/draw_utils.py b/src/ocrtoolkit/utilities/draw_utils.py index d9c3e76..6c94094 100644 --- a/src/ocrtoolkit/utilities/draw_utils.py +++ b/src/ocrtoolkit/utilities/draw_utils.py @@ -4,7 +4,7 @@ import numpy as np from PIL import Image, ImageDraw, ImageFont -FONT_PATH = Path(__file__).parent.parent / "assets/Ubuntu-R.ttf" +FONT_PATH = Path(__file__).parent.parent.joinpath("assets/Ubuntu-R.ttf") def draw_bbox( diff --git a/src/ocrtoolkit/utilities/geometry_utils.py b/src/ocrtoolkit/utilities/geometry_utils.py new file mode 100644 index 0000000..da441e1 --- /dev/null +++ b/src/ocrtoolkit/utilities/geometry_utils.py @@ -0,0 +1,135 @@ +import numpy as np +from typing import Optional, Tuple + + +def estimate_page_angle(polys: np.ndarray) -> float: + """Takes a batch of rotated previously + ORIENTED polys (N, 4, 2) (rectified by the classifier) and return the + estimated angle ccw in degrees + """ + # Compute mean left points and mean right point + # with respect to the reading direction (oriented polygon) + xleft = polys[:, 0, 0] + polys[:, 3, 0] + yleft = polys[:, 0, 1] + polys[:, 3, 1] + xright = polys[:, 1, 0] + polys[:, 2, 0] + yright = polys[:, 1, 1] + polys[:, 2, 1] + with np.errstate(divide="raise", invalid="raise"): + try: + return float( + np.median( + np.arctan((yleft - yright) / (xright - xleft)) * 180 / np.pi + ) # Y axis from top to bottom! + ) + except FloatingPointError: + return 0.0 + + +def remap_boxes( + loc_preds: np.ndarray, orig_shape: Tuple[int, int], dest_shape: Tuple[int, int] +) -> np.ndarray: + """Remaps a batch of rotated locpred (N, 4, 2) + expressed for an origin_shape to a destination_shape. + This does not impact the absolute shape of the boxes, + but allow to calculate the new relative RotatedBbox + coordinates after a resizing of the image. + + Args: + ---- + loc_preds: (N, 4, 2) array of RELATIVE loc_preds + orig_shape: shape of the origin image + dest_shape: shape of the destination image + + Returns: + ------- + A batch of rotated loc_preds (N, 4, 2) expressed in the destination referencial + """ + if len(dest_shape) != 2: + raise ValueError(f"Mask length should be 2, was found at: {len(dest_shape)}") + if len(orig_shape) != 2: + raise ValueError( + f"Image_shape length should be 2, was found at: {len(orig_shape)}" + ) + orig_height, orig_width = orig_shape + dest_height, dest_width = dest_shape + mboxes = loc_preds.copy() + mboxes[:, :, 0] = ( + (loc_preds[:, :, 0] * orig_width) + (dest_width - orig_width) / 2 + ) / dest_width + mboxes[:, :, 1] = ( + (loc_preds[:, :, 1] * orig_height) + (dest_height - orig_height) / 2 + ) / dest_height + + return mboxes + + +def rotate_boxes( + loc_preds: np.ndarray, + angle: float, + orig_shape: Tuple[int, int], + min_angle: float = 1.0, + target_shape: Optional[Tuple[int, int]] = None, +) -> np.ndarray: + """Rotate a batch of straight bounding boxes (xmin, ymin, xmax, ymax, c) + or rotated bounding boxes + (4, 2) of an angle, if angle > min_angle, around the center of the page. + If target_shape is specified, the boxes are + remapped to the target shape after the rotation. This + is done to remove the padding that is created by rotate_page(expand=True) + + Args: + ---- + loc_preds: (N, 5) or (N, 4, 2) array of RELATIVE boxes + angle: angle between -90 and +90 degrees + orig_shape: shape of the origin image + min_angle: minimum angle to rotate boxes + target_shape: shape of the destination image + + Returns: + ------- + A batch of rotated boxes (N, 4, 2): or a batch of straight bounding boxes + """ + # Change format of the boxes to rotated boxes + _boxes = loc_preds.copy() + if _boxes.ndim == 2: + _boxes = np.stack( + [ + _boxes[:, [0, 1]], + _boxes[:, [2, 1]], + _boxes[:, [2, 3]], + _boxes[:, [0, 3]], + ], + axis=1, + ) + # If small angle, return boxes (no rotation) + if abs(angle) < min_angle or abs(angle) > 90 - min_angle: + return _boxes + # Compute rotation matrix + angle_rad = angle * np.pi / 180.0 # compute radian angle for np functions + rotation_mat = np.array( + [ + [np.cos(angle_rad), -np.sin(angle_rad)], + [np.sin(angle_rad), np.cos(angle_rad)], + ], + dtype=_boxes.dtype, + ) + # Rotate absolute points + points: np.ndarray = np.stack( + (_boxes[:, :, 0] * orig_shape[1], _boxes[:, :, 1] * orig_shape[0]), axis=-1 + ) + image_center = (orig_shape[1] / 2, orig_shape[0] / 2) + rotated_points = image_center + np.matmul(points - image_center, rotation_mat) + rotated_boxes: np.ndarray = np.stack( + ( + rotated_points[:, :, 0] / orig_shape[1], + rotated_points[:, :, 1] / orig_shape[0], + ), + axis=-1, + ) + + # Apply a mask if requested + if target_shape is not None: + rotated_boxes = remap_boxes( + rotated_boxes, orig_shape=orig_shape, dest_shape=target_shape + ) + + return rotated_boxes diff --git a/src/ocrtoolkit/utilities/model_utils.py b/src/ocrtoolkit/utilities/model_utils.py index ec3c610..9401c0d 100644 --- a/src/ocrtoolkit/utilities/model_utils.py +++ b/src/ocrtoolkit/utilities/model_utils.py @@ -1,8 +1,7 @@ -import torch +def load_state_dict(path, model, ignore_keys: list = None): + import torch - -def load_state_dict(path: str, model: torch.nn.Module, ignore_keys: list = None): - state_dict = torch.load(archive_path, map_location="cpu") + state_dict = torch.load(path, map_location="cpu") if ignore_keys is not None and len(ignore_keys) > 0: for key in ignore_keys: state_dict.pop(key) diff --git a/src/ocrtoolkit/wrappers/detection_results.py b/src/ocrtoolkit/wrappers/detection_results.py index 66a3d02..a34f316 100644 --- a/src/ocrtoolkit/wrappers/detection_results.py +++ b/src/ocrtoolkit/wrappers/detection_results.py @@ -2,12 +2,12 @@ import matplotlib.pyplot as plt import numpy as np -from doctr.models.builder import DocumentBuilder from ocrtoolkit.datasets.base import BaseDS from ocrtoolkit.datasets.imageds import ImageDS from ocrtoolkit.utilities.draw_utils import draw_bbox from ocrtoolkit.utilities.misc_utils import get_samples, get_uuid +from ocrtoolkit.utilities.det_utils import resolve_lines from ocrtoolkit.wrappers.bbox import BBox @@ -81,10 +81,9 @@ def group_bboxes( if groups is None: if detect_lines: - doc_builder = DocumentBuilder(export_as_straight_boxes=True, **kwargs) npy_dets = self.to_numpy(normalize=True) npy_bboxes = npy_dets[:, :4].astype(np.float32) - groups = doc_builder._resolve_lines(npy_bboxes) + groups = resolve_lines(npy_bboxes, **kwargs) else: groups = [range(len(self.bboxes))]