onnxocr-ppocrv6 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
onnxocr/__init__.py ADDED
File without changes
@@ -0,0 +1,4 @@
1
+ """Bundled defaults for the PP-OCRv6 small distribution."""
2
+
3
+ MODEL_DIRECTORY = 'ppocrv6/small'
4
+ CHARACTER_DICTIONARY = 'ppocrv6_dict.txt'
onnxocr/check_npu.py ADDED
@@ -0,0 +1,54 @@
1
+ import platform
2
+ import subprocess
3
+ import re
4
+
5
+ def check_npu_driver_valid(logger):
6
+ npu_driver_valid = False
7
+ sys_plat = platform.system()
8
+ try:
9
+ def parse_version(v):
10
+ return tuple(map(int, re.findall(r'\d+', v)))
11
+
12
+ if sys_plat == "Windows":
13
+ # Intel NPU only: require Intel OEM, but allow the different NPU
14
+ # device names Windows exposes across driver/platform versions.
15
+ ps = (
16
+ "Get-WmiObject Win32_PnPSignedDriver | Where-Object { "
17
+ "$_.Manufacturer -imatch 'Intel' -and $_.DeviceName -and "
18
+ "$_.DeviceName -imatch '(\\bNPU\\b|AI Boost)' "
19
+ "} | Select-Object -First 1 -ExpandProperty DriverVersion"
20
+ )
21
+ cmd = ['powershell', '-NoProfile', '-Command', ps]
22
+ creationflags = getattr(subprocess, 'CREATE_NO_WINDOW', 0x08000000)
23
+ result = subprocess.run(cmd, capture_output=True, text=True, creationflags=creationflags)
24
+ output = result.stdout.strip()
25
+ if output:
26
+ version_str = output.split('\n')[0].strip()
27
+ if not parse_version(version_str):
28
+ logger.warning("Could not parse NPU driver version on Windows, use cpu instead.")
29
+ elif parse_version(version_str) > parse_version("32.0.100.4181"):
30
+ npu_driver_valid = True
31
+ logger.info(f"NPU driver version {version_str} is > 32.0.100.4181")
32
+ else:
33
+ logger.warning(f"NPU driver version {version_str} is <= 32.0.100.4181, use cpu instead. Please update driver.")
34
+ else:
35
+ logger.warning("Could not detect NPU driver version on Windows, use cpu instead.")
36
+ elif sys_plat == "Linux":
37
+ cmd = ['dpkg-query', '-W', '-f=${Version}', 'intel-driver-compiler-npu']
38
+ result = subprocess.run(cmd, capture_output=True, text=True)
39
+ output = result.stdout.strip()
40
+ if output:
41
+ version_str = output.split('\n')[0].strip()
42
+ if parse_version(version_str) >= parse_version("1.30.0"):
43
+ npu_driver_valid = True
44
+ logger.info(f"NPU driver version {version_str} is >= 1.30.0")
45
+ else:
46
+ logger.warning(f"NPU driver version {version_str} is < 1.30.0, use cpu instead. Please update driver.")
47
+ else:
48
+ logger.warning("Could not detect NPU driver version on Linux, use cpu instead.")
49
+ else:
50
+ npu_driver_valid = True
51
+ except Exception as e:
52
+ logger.warning(f"Failed to check NPU driver version: {e}, use cpu instead.")
53
+
54
+ return npu_driver_valid
@@ -0,0 +1,30 @@
1
+
2
+ # import paddle
3
+
4
+
5
+ class ClsPostProcess(object):
6
+ """ Convert between text-label and text-index """
7
+
8
+ def __init__(self, label_list=None, key=None, **kwargs):
9
+ super(ClsPostProcess, self).__init__()
10
+ self.label_list = label_list
11
+ self.key = key
12
+
13
+ def __call__(self, preds, label=None, *args, **kwargs):
14
+ if self.key is not None:
15
+ preds = preds[self.key]
16
+
17
+ label_list = self.label_list
18
+ if label_list is None:
19
+ label_list = {idx: idx for idx in range(preds.shape[-1])}
20
+
21
+ # if isinstance(preds, paddle.Tensor):
22
+ # preds = preds.numpy()
23
+
24
+ pred_idxs = preds.argmax(axis=1)
25
+ decode_out = [(label_list[idx], preds[i, idx])
26
+ for i, idx in enumerate(pred_idxs)]
27
+ if label is None:
28
+ return decode_out
29
+ label = [(label_list[idx], 1.0) for idx in label]
30
+ return decode_out, label
@@ -0,0 +1,277 @@
1
+ # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """
15
+ This code is refered from:
16
+ https://github.com/WenmuZhou/DBNet.pytorch/blob/master/post_processing/seg_detector_representer.py
17
+ """
18
+ from __future__ import absolute_import
19
+ from __future__ import division
20
+ from __future__ import print_function
21
+
22
+ import numpy as np
23
+ import cv2
24
+ # import paddle
25
+ from shapely.geometry import Polygon
26
+ import pyclipper
27
+
28
+
29
+ class DBPostProcess(object):
30
+ """
31
+ The post process for Differentiable Binarization (DB).
32
+ """
33
+
34
+ def __init__(self,
35
+ thresh=0.3,
36
+ box_thresh=0.7,
37
+ max_candidates=1000,
38
+ unclip_ratio=2.0,
39
+ use_dilation=False,
40
+ score_mode="fast",
41
+ box_type='quad',
42
+ **kwargs):
43
+ self.thresh = thresh
44
+ self.box_thresh = box_thresh
45
+ self.max_candidates = max_candidates
46
+ self.unclip_ratio = unclip_ratio
47
+ self.min_size = 3
48
+ self.score_mode = score_mode
49
+ self.box_type = box_type
50
+ assert score_mode in [
51
+ "slow", "fast"
52
+ ], "Score mode must be in [slow, fast] but got: {}".format(score_mode)
53
+
54
+ self.dilation_kernel = None if not use_dilation else np.array(
55
+ [[1, 1], [1, 1]])
56
+
57
+ def polygons_from_bitmap(self, pred, _bitmap, dest_width, dest_height):
58
+ '''
59
+ _bitmap: single map with shape (1, H, W),
60
+ whose values are binarized as {0, 1}
61
+ '''
62
+
63
+ bitmap = _bitmap
64
+ height, width = bitmap.shape
65
+
66
+ boxes = []
67
+ scores = []
68
+
69
+ contours, _ = cv2.findContours((bitmap * 255).astype(np.uint8),
70
+ cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
71
+
72
+ for contour in contours[:self.max_candidates]:
73
+ epsilon = 0.002 * cv2.arcLength(contour, True)
74
+ approx = cv2.approxPolyDP(contour, epsilon, True)
75
+ points = approx.reshape((-1, 2))
76
+ if points.shape[0] < 4:
77
+ continue
78
+
79
+ score = self.box_score_fast(pred, points.reshape(-1, 2))
80
+ if self.box_thresh > score:
81
+ continue
82
+
83
+ if points.shape[0] > 2:
84
+ box = self.unclip(points, self.unclip_ratio)
85
+ if len(box) > 1:
86
+ continue
87
+ else:
88
+ continue
89
+ box = box.reshape(-1, 2)
90
+
91
+ _, sside = self.get_mini_boxes(box.reshape((-1, 1, 2)))
92
+ if sside < self.min_size + 2:
93
+ continue
94
+
95
+ box = np.array(box)
96
+ box[:, 0] = np.clip(
97
+ np.round(box[:, 0] / width * dest_width), 0, dest_width)
98
+ box[:, 1] = np.clip(
99
+ np.round(box[:, 1] / height * dest_height), 0, dest_height)
100
+ boxes.append(box.tolist())
101
+ scores.append(score)
102
+ return boxes, scores
103
+
104
+ def boxes_from_bitmap(self, pred, _bitmap, dest_width, dest_height):
105
+ '''
106
+ _bitmap: single map with shape (1, H, W),
107
+ whose values are binarized as {0, 1}
108
+ '''
109
+
110
+ bitmap = _bitmap
111
+ height, width = bitmap.shape
112
+
113
+ outs = cv2.findContours((bitmap * 255).astype(np.uint8), cv2.RETR_LIST,
114
+ cv2.CHAIN_APPROX_SIMPLE)
115
+ if len(outs) == 3:
116
+ img, contours, _ = outs[0], outs[1], outs[2]
117
+ elif len(outs) == 2:
118
+ contours, _ = outs[0], outs[1]
119
+
120
+ num_contours = min(len(contours), self.max_candidates)
121
+
122
+ boxes = []
123
+ scores = []
124
+ for index in range(num_contours):
125
+ contour = contours[index]
126
+ points, sside = self.get_mini_boxes(contour)
127
+ if sside < self.min_size:
128
+ continue
129
+ points = np.array(points)
130
+ if self.score_mode == "fast":
131
+ score = self.box_score_fast(pred, points.reshape(-1, 2))
132
+ else:
133
+ score = self.box_score_slow(pred, contour)
134
+ if self.box_thresh > score:
135
+ continue
136
+
137
+ box = self.unclip(points, self.unclip_ratio).reshape(-1, 1, 2)
138
+ box, sside = self.get_mini_boxes(box)
139
+ if sside < self.min_size + 2:
140
+ continue
141
+ box = np.array(box)
142
+
143
+ box[:, 0] = np.clip(
144
+ np.round(box[:, 0] / width * dest_width), 0, dest_width)
145
+ box[:, 1] = np.clip(
146
+ np.round(box[:, 1] / height * dest_height), 0, dest_height)
147
+ boxes.append(box.astype("int32"))
148
+ scores.append(score)
149
+ return np.array(boxes, dtype="int32"), scores
150
+
151
+ def unclip(self, box, unclip_ratio):
152
+ poly = Polygon(box)
153
+ distance = poly.area * unclip_ratio / poly.length
154
+ offset = pyclipper.PyclipperOffset()
155
+ offset.AddPath(box, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
156
+ expanded = np.array(offset.Execute(distance))
157
+ return expanded
158
+
159
+ def get_mini_boxes(self, contour):
160
+ bounding_box = cv2.minAreaRect(contour)
161
+ points = sorted(list(cv2.boxPoints(bounding_box)), key=lambda x: x[0])
162
+
163
+ index_1, index_2, index_3, index_4 = 0, 1, 2, 3
164
+ if points[1][1] > points[0][1]:
165
+ index_1 = 0
166
+ index_4 = 1
167
+ else:
168
+ index_1 = 1
169
+ index_4 = 0
170
+ if points[3][1] > points[2][1]:
171
+ index_2 = 2
172
+ index_3 = 3
173
+ else:
174
+ index_2 = 3
175
+ index_3 = 2
176
+
177
+ box = [
178
+ points[index_1], points[index_2], points[index_3], points[index_4]
179
+ ]
180
+ return box, min(bounding_box[1])
181
+
182
+ def box_score_fast(self, bitmap, _box):
183
+ '''
184
+ box_score_fast: use bbox mean score as the mean score
185
+ '''
186
+ h, w = bitmap.shape[:2]
187
+ box = _box.copy()
188
+ xmin = np.clip(np.floor(box[:, 0].min()).astype("int32"), 0, w - 1)
189
+ xmax = np.clip(np.ceil(box[:, 0].max()).astype("int32"), 0, w - 1)
190
+ ymin = np.clip(np.floor(box[:, 1].min()).astype("int32"), 0, h - 1)
191
+ ymax = np.clip(np.ceil(box[:, 1].max()).astype("int32"), 0, h - 1)
192
+
193
+ mask = np.zeros((ymax - ymin + 1, xmax - xmin + 1), dtype=np.uint8)
194
+ box[:, 0] = box[:, 0] - xmin
195
+ box[:, 1] = box[:, 1] - ymin
196
+ cv2.fillPoly(mask, box.reshape(1, -1, 2).astype("int32"), 1)
197
+ return cv2.mean(bitmap[ymin:ymax + 1, xmin:xmax + 1], mask)[0]
198
+
199
+ def box_score_slow(self, bitmap, contour):
200
+ '''
201
+ box_score_slow: use polyon mean score as the mean score
202
+ '''
203
+ h, w = bitmap.shape[:2]
204
+ contour = contour.copy()
205
+ contour = np.reshape(contour, (-1, 2))
206
+
207
+ xmin = np.clip(np.min(contour[:, 0]), 0, w - 1)
208
+ xmax = np.clip(np.max(contour[:, 0]), 0, w - 1)
209
+ ymin = np.clip(np.min(contour[:, 1]), 0, h - 1)
210
+ ymax = np.clip(np.max(contour[:, 1]), 0, h - 1)
211
+
212
+ mask = np.zeros((ymax - ymin + 1, xmax - xmin + 1), dtype=np.uint8)
213
+
214
+ contour[:, 0] = contour[:, 0] - xmin
215
+ contour[:, 1] = contour[:, 1] - ymin
216
+
217
+ cv2.fillPoly(mask, contour.reshape(1, -1, 2).astype("int32"), 1)
218
+ return cv2.mean(bitmap[ymin:ymax + 1, xmin:xmax + 1], mask)[0]
219
+
220
+ def __call__(self, outs_dict, shape_list):
221
+ pred = outs_dict['maps']
222
+ # if isinstance(pred, paddle.Tensor):
223
+ # pred = pred.numpy()
224
+ if len(pred.shape) == 4:
225
+ pred = pred[:, 0, :, :]
226
+ segmentation = pred > self.thresh
227
+
228
+ boxes_batch = []
229
+ for batch_index in range(pred.shape[0]):
230
+ src_h, src_w, ratio_h, ratio_w = shape_list[batch_index]
231
+ if self.dilation_kernel is not None:
232
+ mask = cv2.dilate(
233
+ np.array(segmentation[batch_index]).astype(np.uint8),
234
+ self.dilation_kernel)
235
+ else:
236
+ mask = segmentation[batch_index]
237
+ if self.box_type == 'poly':
238
+ boxes, scores = self.polygons_from_bitmap(pred[batch_index],
239
+ mask, src_w, src_h)
240
+ elif self.box_type == 'quad':
241
+ boxes, scores = self.boxes_from_bitmap(pred[batch_index], mask,
242
+ src_w, src_h)
243
+ else:
244
+ raise ValueError("box_type can only be one of ['quad', 'poly']")
245
+
246
+ boxes_batch.append({'points': boxes})
247
+ return boxes_batch
248
+
249
+
250
+ class DistillationDBPostProcess(object):
251
+ def __init__(self,
252
+ model_name=["student"],
253
+ key=None,
254
+ thresh=0.3,
255
+ box_thresh=0.6,
256
+ max_candidates=1000,
257
+ unclip_ratio=1.5,
258
+ use_dilation=False,
259
+ score_mode="fast",
260
+ box_type='quad',
261
+ **kwargs):
262
+ self.model_name = model_name
263
+ self.key = key
264
+ self.post_process = DBPostProcess(
265
+ thresh=thresh,
266
+ box_thresh=box_thresh,
267
+ max_candidates=max_candidates,
268
+ unclip_ratio=unclip_ratio,
269
+ use_dilation=use_dilation,
270
+ score_mode=score_mode,
271
+ box_type=box_type)
272
+
273
+ def __call__(self, predicts, shape_list):
274
+ results = {}
275
+ for k in self.model_name:
276
+ results[k] = self.post_process(predicts[k], shape_list=shape_list)
277
+ return results
Binary file
onnxocr/imaug.py ADDED
@@ -0,0 +1,32 @@
1
+ from .operators import *
2
+
3
+
4
+ def transform(data, ops=None):
5
+ """transform"""
6
+ if ops is None:
7
+ ops = []
8
+ for op in ops:
9
+ data = op(data)
10
+ if data is None:
11
+ return None
12
+ return data
13
+
14
+
15
+ def create_operators(op_param_list, global_config=None):
16
+ """
17
+ create operators based on the config
18
+
19
+ Args:
20
+ params(list): a dict list, used to create some operators
21
+ """
22
+ assert isinstance(op_param_list, list), "operator config should be a list"
23
+ ops = []
24
+ for operator in op_param_list:
25
+ assert isinstance(operator, dict) and len(operator) == 1, "yaml format error"
26
+ op_name = list(operator)[0]
27
+ param = {} if operator[op_name] is None else operator[op_name]
28
+ if global_config is not None:
29
+ param.update(global_config)
30
+ op = eval(op_name)(**param)
31
+ ops.append(op)
32
+ return ops
onnxocr/logger.py ADDED
@@ -0,0 +1,45 @@
1
+ import logging
2
+
3
+ LogName = 'Umi-OCR_log'
4
+ LogFileName = 'Umi-OCR_debug.log'
5
+
6
+
7
+ class Logger:
8
+
9
+ def __init__(self):
10
+ self.initLogger()
11
+
12
+ def initLogger(self):
13
+ '''初始化日志'''
14
+
15
+ # 日志
16
+ self.logger = logging.getLogger(LogName)
17
+ self.logger.setLevel(logging.DEBUG)
18
+
19
+ # 控制台
20
+ streamHandler = logging.StreamHandler()
21
+ streamHandler.setLevel(logging.DEBUG)
22
+ formatPrint = logging.Formatter(
23
+ '【%(levelname)s】 %(message)s')
24
+ streamHandler.setFormatter(formatPrint)
25
+ # self.logger.addHandler(streamHandler)
26
+
27
+ return
28
+ # 日志文件
29
+ fileHandler = logging.FileHandler(LogFileName)
30
+ fileHandler.setLevel(logging.ERROR)
31
+ formatFile = logging.Formatter(
32
+ '''
33
+ 【%(levelname)s】 %(asctime)s
34
+ %(message)s
35
+ 文件:%(module)s | 函数:%(funcName)s | 行号:%(lineno)d
36
+ 线程id:%(thread)d | 线程名:%(thread)s''')
37
+ fileHandler.setFormatter(formatFile)
38
+ self.logger.addHandler(fileHandler)
39
+
40
+
41
+ LOG = Logger()
42
+
43
+
44
+ def GetLog():
45
+ return LOG.logger
Binary file
@@ -0,0 +1,52 @@
1
+ Global:
2
+ model_name: PP-OCRv6_small_det
3
+ Hpi:
4
+ backend_configs:
5
+ paddle_infer:
6
+ trt_dynamic_shapes: &id001
7
+ x:
8
+ - - 1
9
+ - 3
10
+ - 32
11
+ - 32
12
+ - - 1
13
+ - 3
14
+ - 736
15
+ - 736
16
+ - - 1
17
+ - 3
18
+ - 4000
19
+ - 4000
20
+ tensorrt:
21
+ dynamic_shapes: *id001
22
+ PostProcess:
23
+ box_thresh: 0.45
24
+ max_candidates: 3000
25
+ name: DBPostProcess
26
+ thresh: 0.2
27
+ unclip_ratio: 1.4
28
+ PreProcess:
29
+ transform_ops:
30
+ - DecodeImage:
31
+ channel_first: false
32
+ img_mode: BGR
33
+ - DetLabelEncode: null
34
+ - DetResizeForTest: null
35
+ - NormalizeImage:
36
+ mean:
37
+ - 0.485
38
+ - 0.456
39
+ - 0.406
40
+ order: hwc
41
+ scale: 1./255.
42
+ std:
43
+ - 0.229
44
+ - 0.224
45
+ - 0.225
46
+ - ToCHWImage: null
47
+ - KeepKeys:
48
+ keep_keys:
49
+ - image
50
+ - shape
51
+ - polys
52
+ - ignore_tags
@@ -0,0 +1,22 @@
1
+ {
2
+ "tier": "small",
3
+ "license": "Apache-2.0",
4
+ "assets": {
5
+ "det": {
6
+ "repo": "PaddlePaddle/PP-OCRv6_small_det_onnx",
7
+ "revision": "28fe5895c24fd108c19eb3e8479f4ab385fbfc62",
8
+ "sha256": "d73e0058b7a8086bbd57f3d10b8bcd4ff95363f67e06e2762b5e814fe9c9410e",
9
+ "bytes": 9880512,
10
+ "config_sha256": "193f435274bf9f0b5f71a929bbfbcf148282df7e633b34e7c373e8f44741b516"
11
+ },
12
+ "rec": {
13
+ "repo": "PaddlePaddle/PP-OCRv6_small_rec_onnx",
14
+ "revision": "b8f84f0b80c529de40b4fbb3544b84fa7233a513",
15
+ "sha256": "5435fd747c9e0efe15a96d0b378d5bd157e9492ed8fd80edf08f30d02fa24634",
16
+ "bytes": 21159378,
17
+ "config_sha256": "ab078671bb49f06228eadccd34f1bb501e157f7a047095ffb943ba81512c77d1"
18
+ }
19
+ },
20
+ "dictionary_characters": 18708,
21
+ "dictionary_sha256": "b5f2bfe2bdd9448429e3e82b51c789775d9b42f2403d082b00662eb77e401c5d"
22
+ }