Skip to content

Commit

Permalink
dev(narugo): try create plot
Browse files Browse the repository at this point in the history
  • Loading branch information
narugo1992 committed Oct 16, 2023
1 parent c894c6a commit 6058425
Show file tree
Hide file tree
Showing 16 changed files with 145 additions and 31 deletions.
Binary file added docs/source/_libs/SimHei.ttf
Binary file not shown.
8 changes: 8 additions & 0 deletions docs/source/_libs/font.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import os.path

import matplotlib.font_manager as fm


def get_cn_fp() -> fm.FontProperties:
ttf_file = os.path.join(os.path.dirname(__file__), 'SimHei.ttf')
return fm.FontProperties(fname=ttf_file)
Binary file added docs/source/_static/SimHei.ttf
Binary file not shown.
Binary file added docs/source/api_doc/ocr/SimHei.ttf
Binary file not shown.
Binary file added docs/source/api_doc/ocr/anime_subtitle.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/api_doc/ocr/comic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions docs/source/api_doc/ocr/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
imgutils.ocr
========================

.. currentmodule:: imgutils.ocr

.. automodule:: imgutils.ocr


detect_text_with_ocr
------------------------------------------------------

.. autofunction:: detect_text_with_ocr



ocr
------------------------------------------------------

.. autofunction:: ocr



list_det_models
------------------------------------------------------

.. autofunction:: list_det_models



list_rec_models
------------------------------------------------------

.. autofunction:: list_rec_models



30 changes: 30 additions & 0 deletions docs/source/api_doc/ocr/ocr_demo.plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import font
from imgutils.data import load_image
from imgutils.detect.visual import detection_visualize
from imgutils.ocr import ocr
from plot import image_plot

_max_size = 480


def _detect(img, **kwargs):
img = load_image(img, mode='RGB', force_background='white')
if min(img.height, img.width) > _max_size:
r = _max_size / min(img.height, img.width)
img = img.resize((
int(round(img.width * r)),
int(round(img.height * r)),
))

return detection_visualize(img, ocr(img, **kwargs), fp=font.get_cn_fp())


if __name__ == '__main__':
image_plot(
(_detect('post_text.jpg', recognize_model='japan_PP-OCRv3_rec'), 'Text of Post'),
(_detect('anime_subtitle.jpg'), 'Subtitle of Anime'),
(_detect('comic.jpg'), 'Comic'),
(_detect('plot.png'), 'Complex'),
columns=2,
figsize=(12, 9),
)
Binary file added docs/source/api_doc/ocr/plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/api_doc/ocr/post_text.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ configuration file's structure and their versions.
api_doc/detect/index
api_doc/edge/index
api_doc/metrics/index
api_doc/ocr/index
api_doc/operate/index
api_doc/restore/index
api_doc/sd/index
Expand Down
8 changes: 4 additions & 4 deletions imgutils/detect/visual.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from imgutils.data import ImageTyping, load_image


def _try_get_font_from_matplotlib(fontsize: int = 12):
def _try_get_font_from_matplotlib(fp=None, fontsize: int = 12):
try:
# noinspection PyPackageRequirements
import matplotlib
Expand All @@ -21,13 +21,13 @@ def _try_get_font_from_matplotlib(fontsize: int = 12):
else:
# noinspection PyPackageRequirements
from matplotlib.font_manager import findfont, FontProperties
font = findfont(FontProperties(family=['sans-serif']))
font = findfont(fp or FontProperties(family=['sans-serif']))
return ImageFont.truetype(font, fontsize)


def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, float, float, float], str, float]],
labels: Optional[List[str]] = None, text_padding: int = 6, fontsize: int = 12,
no_label: bool = False):
fp=None, no_label: bool = False):
"""
Overview:
Visualize the results of the object detection.
Expand All @@ -51,7 +51,7 @@ def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, f
image = load_image(image, force_background=None, mode='RGBA')
visual_image = image.copy()
draw = ImageDraw.Draw(visual_image, mode='RGBA')
font = _try_get_font_from_matplotlib(fontsize) or ImageFont.load_default()
font = _try_get_font_from_matplotlib(fp, fontsize) or ImageFont.load_default()

labels = sorted(labels or {label for _, label, _ in detection})
_colors = list(map(str, rnd_colors(len(labels))))
Expand Down
2 changes: 1 addition & 1 deletion imgutils/ocr/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .entry import detect_text_with_ocr, ocr
from .entry import detect_text_with_ocr, ocr, list_det_models, list_rec_models

Check warning on line 1 in imgutils/ocr/__init__.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/__init__.py#L1

Added line #L1 was not covered by tests
24 changes: 20 additions & 4 deletions imgutils/ocr/detect.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import os.path
from functools import lru_cache
from typing import List

Check warning on line 3 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L1-L3

Added lines #L1 - L3 were not covered by tests

import cv2
import numpy as np
import pyclipper
from huggingface_hub import hf_hub_download
from huggingface_hub import hf_hub_download, HfFileSystem
from shapely import Polygon

Check warning on line 9 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L5-L9

Added lines #L5 - L9 were not covered by tests

from ..data import ImageTyping
from ..data import ImageTyping, load_image
from ..utils import open_onnx_model

Check warning on line 12 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L11-L12

Added lines #L11 - L12 were not covered by tests

_MIN_SIZE = 3
_HF_CLIENT = HfFileSystem()
_REPOSITORY = 'deepghs/paddleocr'

Check warning on line 16 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L14-L16

Added lines #L14 - L16 were not covered by tests


@lru_cache()
def _open_ocr_detection_model(model):
return open_onnx_model(hf_hub_download(

Check warning on line 21 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L19-L21

Added lines #L19 - L21 were not covered by tests
'deepghs/paddleocr',
f'{model}/detection.onnx',
_REPOSITORY,
f'det/{model}/model.onnx',
))

print(ort.get_inputs()[0].shape)
return ort

Check warning on line 27 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L27

Added line #L27 was not covered by tests


def _box_score_fast(bitmap, _box):
h, w = bitmap.shape[:2]
Expand Down Expand Up @@ -150,10 +157,19 @@ def _get_text_points(image: ImageTyping, model: str = 'ch_PP-OCRv4_det_infer',
def _detect_text(image: ImageTyping, model: str = 'ch_PP-OCRv4_det_infer',

Check warning on line 157 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L157

Added line #L157 was not covered by tests
heat_threshold: float = 0.3, box_threshold: float = 0.7,
max_candidates: int = 1000, unclip_ratio: float = 2.0):
image = load_image(image, force_background='white', mode='RGB')
retval = []
for points, score in _get_text_points(image, model, heat_threshold, box_threshold, max_candidates, unclip_ratio):
x0, y0 = points[:, 0].min(), points[:, 1].min()
x1, y1 = points[:, 0].max(), points[:, 1].max()
retval.append(((x0.item(), y0.item(), x1.item(), y1.item()), 'text', score))

Check warning on line 165 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L160-L165

Added lines #L160 - L165 were not covered by tests

return retval

Check warning on line 167 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L167

Added line #L167 was not covered by tests


@lru_cache()
def _list_det_models() -> List[str]:
retval = []
for item in _HF_CLIENT.glob(f'{_REPOSITORY}/det/*/model.onnx', ):
retval.append(os.path.relpath(item, _REPOSITORY).split('/')[1])
return retval

Check warning on line 175 in imgutils/ocr/detect.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/detect.py#L170-L175

Added lines #L170 - L175 were not covered by tests
38 changes: 24 additions & 14 deletions imgutils/ocr/entry.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
from typing import List, Tuple

Check warning on line 1 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L1

Added line #L1 was not covered by tests

from .detect import _detect_text
from .recognize import _text_recognize
from .detect import _detect_text, _list_det_models
from .recognize import _text_recognize, _list_rec_models
from ..data import ImageTyping, load_image
from ..utils import tqdm

Check warning on line 6 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L3-L6

Added lines #L3 - L6 were not covered by tests

_DEFAULT_MODEL = 'ch_PP-OCRv4_det_infer'
_DEFAULT_DET_MODEL = 'ch_PP-OCRv4_det'
_DEFAULT_REC_MODEL = 'ch_PP-OCRv4_rec'

Check warning on line 9 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L8-L9

Added lines #L8 - L9 were not covered by tests


def detect_text_with_ocr(image: ImageTyping, model: str = _DEFAULT_MODEL,
def list_det_models() -> List[str]:
return _list_det_models()

Check warning on line 13 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L12-L13

Added lines #L12 - L13 were not covered by tests


def list_rec_models() -> List[str]:
return _list_rec_models()

Check warning on line 17 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L16-L17

Added lines #L16 - L17 were not covered by tests


def detect_text_with_ocr(image: ImageTyping, model: str = _DEFAULT_DET_MODEL,

Check warning on line 20 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L20

Added line #L20 was not covered by tests
heat_threshold: float = 0.3, box_threshold: float = 0.7,
max_candidates: int = 1000, unclip_ratio: float = 2.0) \
-> List[Tuple[Tuple[int, int, int, int], str, float]]:
Expand All @@ -18,22 +28,22 @@ def detect_text_with_ocr(image: ImageTyping, model: str = _DEFAULT_MODEL,
return retval

Check warning on line 28 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L24-L28

Added lines #L24 - L28 were not covered by tests


def ocr(image: ImageTyping, model: str = _DEFAULT_MODEL,
heat_threshold: float = 0.3, box_threshold: float = 0.7,
max_candidates: int = 1000, unclip_ratio: float = 2.0,
is_remove_duplicate: bool = False):
def ocr(image: ImageTyping, detect_model: str = _DEFAULT_DET_MODEL,

Check warning on line 31 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L31

Added line #L31 was not covered by tests
recognize_model: str = _DEFAULT_REC_MODEL, heat_threshold: float = 0.3, box_threshold: float = 0.7,
max_candidates: int = 1000, unclip_ratio: float = 2.0, rotation_threshold: float = 1.5,
is_remove_duplicate: bool = False, silent: bool = False):
image = load_image(image)
retval = []
for (x0, y0, x1, y1), _, score in _detect_text(image, model, heat_threshold,
box_threshold, max_candidates, unclip_ratio):
for (x0, y0, x1, y1), _, score in \

Check warning on line 37 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L35-L37

Added lines #L35 - L37 were not covered by tests
tqdm(_detect_text(image, detect_model, heat_threshold,
box_threshold, max_candidates, unclip_ratio), silent=silent):
width, height = x1 - x0, y1 - y0
area = image.crop((x0, y0, x1, y1))
if height >= width * 1.5:
if height >= width * rotation_threshold:
area = area.rotate(90)

Check warning on line 43 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L40-L43

Added lines #L40 - L43 were not covered by tests

text, _ = _text_recognize(area, model, is_remove_duplicate)
print(text, score)
retval.append(((x0, y0, x1, y1), text, score))
text, rec_score = _text_recognize(area, recognize_model, is_remove_duplicate)
retval.append(((x0, y0, x1, y1), text, score * rec_score))

Check warning on line 46 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L45-L46

Added lines #L45 - L46 were not covered by tests

retval = sorted(retval, key=lambda x: x[2], reverse=True)
return retval

Check warning on line 49 in imgutils/ocr/entry.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/entry.py#L48-L49

Added lines #L48 - L49 were not covered by tests
29 changes: 21 additions & 8 deletions imgutils/ocr/recognize.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
import os
from functools import lru_cache
from typing import List, Tuple

Check warning on line 3 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L1-L3

Added lines #L1 - L3 were not covered by tests

import numpy as np
from huggingface_hub import hf_hub_download
from huggingface_hub import hf_hub_download, HfFileSystem

Check warning on line 6 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L5-L6

Added lines #L5 - L6 were not covered by tests

from ..data import ImageTyping
from ..data import ImageTyping, load_image
from ..utils import open_onnx_model

Check warning on line 9 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L8-L9

Added lines #L8 - L9 were not covered by tests

_HF_CLIENT = HfFileSystem()
_REPOSITORY = 'deepghs/paddleocr'

Check warning on line 12 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L11-L12

Added lines #L11 - L12 were not covered by tests


@lru_cache()
def _open_ocr_recognition_model(model):
return open_onnx_model(hf_hub_download(

Check warning on line 17 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L15-L17

Added lines #L15 - L17 were not covered by tests
'deepghs/paddleocr',
f'{model}/recognition.onnx',
_REPOSITORY,
f'rec/{model}/model.onnx',
))


@lru_cache()
def _open_ocr_recognition_dictionary(model) -> List[str]:
with open(hf_hub_download(

Check warning on line 25 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L23-L25

Added lines #L23 - L25 were not covered by tests
'deepghs/paddleocr',
f'{model}/dict.txt',
_REPOSITORY,
f'rec/{model}/dict.txt',
), 'r') as f:
dict_ = [line.strip() for line in f]

Check warning on line 29 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L29

Added line #L29 was not covered by tests

Expand Down Expand Up @@ -57,9 +61,10 @@ def decode(text_index, model: str, text_prob=None, is_remove_duplicate=False):

def _text_recognize(image: ImageTyping, model: str = 'ch_PP-OCRv4_det_infer',

Check warning on line 62 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L62

Added line #L62 was not covered by tests
is_remove_duplicate: bool = False) -> Tuple[str, float]:
image = load_image(image, force_background='white', mode='RGB')
r = 48 / image.height
new_height = int(image.height * r)
new_width = int(image.width * r)
new_height = int(round(image.height * r))
new_width = int(round(image.width * r))
image = image.resize((new_width, new_height))

Check warning on line 68 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L64-L68

Added lines #L64 - L68 were not covered by tests

input_ = np.array(image).transpose((2, 0, 1)).astype(np.float32) / 255.0

Check warning on line 70 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L70

Added line #L70 was not covered by tests
Expand All @@ -73,3 +78,11 @@ def _text_recognize(image: ImageTyping, model: str = 'ch_PP-OCRv4_det_infer',
indices = output.argmax(axis=2)
confs = output.max(axis=2)
return decode(indices, model, confs, is_remove_duplicate)[0]

Check warning on line 80 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L78-L80

Added lines #L78 - L80 were not covered by tests


@lru_cache()
def _list_rec_models() -> List[str]:
retval = []
for item in _HF_CLIENT.glob(f'{_REPOSITORY}/rec/*/model.onnx', ):
retval.append(os.path.relpath(item, _REPOSITORY).split('/')[1])
return retval

Check warning on line 88 in imgutils/ocr/recognize.py

View check run for this annotation

Codecov / codecov/patch

imgutils/ocr/recognize.py#L83-L88

Added lines #L83 - L88 were not covered by tests

0 comments on commit 6058425

Please sign in to comment.