Upload text_detection/detect.py with huggingface_hub
Browse files- text_detection/detect.py +79 -0
text_detection/detect.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os.path
|
| 2 |
+
from functools import lru_cache
|
| 3 |
+
from typing import List, Tuple
|
| 4 |
+
|
| 5 |
+
import cv2
|
| 6 |
+
import numpy as np
|
| 7 |
+
from huggingface_hub import HfApi, HfFileSystem, hf_hub_download
|
| 8 |
+
from imgutils.data import ImageTyping
|
| 9 |
+
from imgutils.utils import open_onnx_model
|
| 10 |
+
|
| 11 |
+
hf_client = HfApi()
|
| 12 |
+
hf_fs = HfFileSystem()
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
@lru_cache()
|
| 16 |
+
def _get_available_models():
|
| 17 |
+
for f in hf_fs.glob('deepghs/text_detection/*/end2end.onnx'):
|
| 18 |
+
yield os.path.relpath(f, 'deepghs/text_detection').split('/')[0]
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
_ALL_MODELS = list(_get_available_models())
|
| 22 |
+
_DEFAULT_MODEL = 'dbnetpp_resnet50_fpnc_1200e_icdar2015'
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
@lru_cache()
|
| 26 |
+
def _get_onnx_session(model):
|
| 27 |
+
return open_onnx_model(hf_hub_download(
|
| 28 |
+
'deepghs/text_detection',
|
| 29 |
+
f'{model}/end2end.onnx'
|
| 30 |
+
))
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def _get_heatmap_of_text(image: ImageTyping, model: str) -> np.ndarray:
|
| 34 |
+
origin_width, origin_height = width, height = image.size
|
| 35 |
+
align = 32
|
| 36 |
+
if width % align != 0:
|
| 37 |
+
width += (align - width % align)
|
| 38 |
+
if height % align != 0:
|
| 39 |
+
height += (align - height % align)
|
| 40 |
+
|
| 41 |
+
input_ = np.array(image).transpose((2, 0, 1)).astype(np.float32) / 255.0
|
| 42 |
+
# noinspection PyTypeChecker
|
| 43 |
+
input_ = np.pad(input_[None, ...], ((0, 0), (0, 0), (0, height - origin_height), (0, width - origin_width)))
|
| 44 |
+
|
| 45 |
+
def _normalize(data, mean=(0.48145466, 0.4578275, 0.40821073), std=(0.26862954, 0.26130258, 0.27577711)):
|
| 46 |
+
mean, std = np.asarray(mean), np.asarray(std)
|
| 47 |
+
return (data - mean[None, :, None, None]) / std[None, :, None, None]
|
| 48 |
+
|
| 49 |
+
ort = _get_onnx_session(model)
|
| 50 |
+
|
| 51 |
+
input_ = _normalize(input_).astype(np.float32)
|
| 52 |
+
output_, = ort.run(['output'], {'input': input_})
|
| 53 |
+
heatmap = output_[0]
|
| 54 |
+
heatmap = heatmap[:origin_height, :origin_width]
|
| 55 |
+
|
| 56 |
+
return heatmap
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def _get_bounding_box_of_text(image: ImageTyping, model: str, threshold: float) \
|
| 60 |
+
-> List[Tuple[Tuple[int, int, int, int], float]]:
|
| 61 |
+
heatmap = _get_heatmap_of_text(image, model)
|
| 62 |
+
c_rets = cv2.findContours((heatmap * 255.0).astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
| 63 |
+
contours = c_rets[0] if len(c_rets) == 2 else c_rets[1]
|
| 64 |
+
bboxes = []
|
| 65 |
+
for c in contours:
|
| 66 |
+
x, y, w, h = cv2.boundingRect(c)
|
| 67 |
+
x0, y0, x1, y1 = x, y, x + w, y + h
|
| 68 |
+
score = heatmap[y0:y1, x0:x1].mean().item()
|
| 69 |
+
if score >= threshold:
|
| 70 |
+
bboxes.append(((x0, y0, x1, y1), score))
|
| 71 |
+
|
| 72 |
+
return bboxes
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def detect_text(image: ImageTyping, model: str = _DEFAULT_MODEL, threshold: float = 0.05):
|
| 76 |
+
bboxes = []
|
| 77 |
+
for (x0, y0, x1, y1), score in _get_bounding_box_of_text(image, model, threshold):
|
| 78 |
+
bboxes.append(((x0, y0, x1, y1), 'text', score))
|
| 79 |
+
return bboxes
|