LinhKL2002 commited on
Commit
4dbe5d1
·
verified ·
1 Parent(s): 35b4c2a

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .dockerignore +73 -0
  2. .dockerignore.bak +68 -0
  3. .gitattributes +1 -0
  4. .gradio/certificate.pem +31 -0
  5. Dockerfile +27 -0
  6. README.md +3 -9
  7. __init__.py +5 -0
  8. __pycache__/__init__.cpython-310.pyc +0 -0
  9. __pycache__/image_enhancement.cpython-310.pyc +0 -0
  10. __pycache__/image_enhancement.cpython-311.pyc +0 -0
  11. __pycache__/image_enhancement.cpython-313.pyc +0 -0
  12. __pycache__/main.cpython-310.pyc +0 -0
  13. __pycache__/main.cpython-311.pyc +0 -0
  14. __pycache__/main.cpython-313.pyc +0 -0
  15. app.py +29 -0
  16. cal_rec_boxes/__init__.py +4 -0
  17. cal_rec_boxes/__pycache__/__init__.cpython-310.pyc +0 -0
  18. cal_rec_boxes/__pycache__/__init__.cpython-311.pyc +0 -0
  19. cal_rec_boxes/__pycache__/__init__.cpython-312.pyc +0 -0
  20. cal_rec_boxes/__pycache__/__init__.cpython-313.pyc +0 -0
  21. cal_rec_boxes/__pycache__/main.cpython-310.pyc +0 -0
  22. cal_rec_boxes/__pycache__/main.cpython-311.pyc +0 -0
  23. cal_rec_boxes/__pycache__/main.cpython-312.pyc +0 -0
  24. cal_rec_boxes/__pycache__/main.cpython-313.pyc +0 -0
  25. cal_rec_boxes/main.py +281 -0
  26. ch_ppocr_cls/__init__.py +4 -0
  27. ch_ppocr_cls/__pycache__/__init__.cpython-310.pyc +0 -0
  28. ch_ppocr_cls/__pycache__/__init__.cpython-311.pyc +0 -0
  29. ch_ppocr_cls/__pycache__/__init__.cpython-312.pyc +0 -0
  30. ch_ppocr_cls/__pycache__/__init__.cpython-313.pyc +0 -0
  31. ch_ppocr_cls/__pycache__/text_cls.cpython-310.pyc +0 -0
  32. ch_ppocr_cls/__pycache__/text_cls.cpython-311.pyc +0 -0
  33. ch_ppocr_cls/__pycache__/text_cls.cpython-312.pyc +0 -0
  34. ch_ppocr_cls/__pycache__/text_cls.cpython-313.pyc +0 -0
  35. ch_ppocr_cls/__pycache__/utils.cpython-310.pyc +0 -0
  36. ch_ppocr_cls/__pycache__/utils.cpython-311.pyc +0 -0
  37. ch_ppocr_cls/__pycache__/utils.cpython-312.pyc +0 -0
  38. ch_ppocr_cls/__pycache__/utils.cpython-313.pyc +0 -0
  39. ch_ppocr_cls/text_cls.py +114 -0
  40. ch_ppocr_cls/utils.py +28 -0
  41. ch_ppocr_det/__init__.py +4 -0
  42. ch_ppocr_det/__pycache__/__init__.cpython-310.pyc +0 -0
  43. ch_ppocr_det/__pycache__/__init__.cpython-311.pyc +0 -0
  44. ch_ppocr_det/__pycache__/__init__.cpython-312.pyc +0 -0
  45. ch_ppocr_det/__pycache__/__init__.cpython-313.pyc +0 -0
  46. ch_ppocr_det/__pycache__/text_detect.cpython-310.pyc +0 -0
  47. ch_ppocr_det/__pycache__/text_detect.cpython-311.pyc +0 -0
  48. ch_ppocr_det/__pycache__/text_detect.cpython-312.pyc +0 -0
  49. ch_ppocr_det/__pycache__/text_detect.cpython-313.pyc +0 -0
  50. ch_ppocr_det/__pycache__/utils.cpython-310.pyc +0 -0
.dockerignore ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python bytecode and cache
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .pytest_cache/
7
+ .coverage
8
+
9
+ # IDE/editor files
10
+ .idea/
11
+ .vscode/
12
+ *.swp
13
+ *.swo
14
+
15
+ # Build and distribution outputs
16
+ dist/
17
+ build/
18
+ out/
19
+
20
+ # Test and debug artifacts
21
+ test/
22
+ tests/
23
+ debug/
24
+ *.log
25
+
26
+ # Version control
27
+ .git/
28
+ .gitignore
29
+ .svn/
30
+ .hg/
31
+
32
+ # Environment and secrets
33
+ .env*
34
+ *.env
35
+ *.pem
36
+ *.key
37
+ *.crt
38
+ config.local.*
39
+ *.local.yml
40
+
41
+ # Documentation and markdown
42
+ README*
43
+ *.md
44
+ docs/
45
+
46
+ # Docker and compose files
47
+ Dockerfile*
48
+ docker-compose*
49
+
50
+ # Temporary and local files
51
+ tmp/
52
+ temp/
53
+ *.tmp
54
+ .local/
55
+ local/
56
+
57
+ # Backup files
58
+ *.bak
59
+
60
+ # Project-specific: results and models (if not needed in build)
61
+ results/
62
+
63
+ # Exclude empty model placeholder, but keep actual models
64
+ models/.gitkeep
65
+
66
+ # Allow ONNX models to be included (remove models/ if you want to exclude all models)
67
+ # models/
68
+
69
+ # Miscellaneous
70
+ *.DS_Store
71
+
72
+ # Exclude self
73
+ .dockerignore
.dockerignore.bak ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python bytecode and cache
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .pytest_cache/
7
+ .coverage
8
+
9
+ # Development and IDE artifacts
10
+ .idea/
11
+ .vscode/
12
+ *.swp
13
+ *.swo
14
+
15
+ # Build outputs
16
+ build/
17
+ dist/
18
+ out/
19
+
20
+ # Test and debug files
21
+ test/
22
+ tests/
23
+ debug/
24
+ *.log
25
+
26
+ # Version control
27
+ .git/
28
+ .gitignore
29
+ .svn/
30
+ .hg/
31
+
32
+ # Environment and secrets
33
+ .env*
34
+ *.env
35
+ *.pem
36
+ *.key
37
+ *.crt
38
+ config.local.*
39
+ *.local.yml
40
+
41
+ # Documentation
42
+ README*
43
+ *.md
44
+ docs/
45
+
46
+ # Docker files (do not ignore Dockerfile and docker-compose.yml in root)
47
+ Dockerfile*
48
+ docker-compose*
49
+ !Dockerfile
50
+ !docker-compose.yml
51
+
52
+ # Temporary and local files
53
+ tmp/
54
+ temp/
55
+ *.tmp
56
+ .local/
57
+ local/
58
+
59
+ # Project-specific: results and model artifacts (keep models/ for .onnx, ignore results/)
60
+ results/
61
+
62
+ # Miscellaneous
63
+ *.bak
64
+ *.orig
65
+ *.old
66
+
67
+ # Exclude .gitkeep from ignore (if needed for empty dirs)
68
+ !models/.gitkeep
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tmp/uploaded_1745856378.pdf filter=lfs diff=lfs merge=lfs -text
.gradio/certificate.pem ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ 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
31
+ -----END CERTIFICATE-----
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # syntax=docker/dockerfile:1.4
2
+
3
+ # Base image
4
+ FROM python:3.12-slim AS base
5
+
6
+ # Install system dependencies for OpenCV and ffmpeg at runtime
7
+ RUN apt-get update && apt-get install -y --no-install-recommends \
8
+ build-essential \
9
+ libgl1-mesa-glx \
10
+ libglib2.0-0 \
11
+ libsm6 \
12
+ libxext6 \
13
+ libx11-dev \
14
+ ffmpeg \
15
+ && rm -rf /var/lib/apt/lists/*
16
+
17
+ # Builder stage: install Python dependencies
18
+ WORKDIR /app
19
+ # 4. Copy requirements and install
20
+ COPY requirements.txt .
21
+ RUN pip install --no-cache-dir --upgrade pip && \
22
+ pip install --default-timeout=100 --no-cache-dir -r requirements.txt
23
+ # 5. Copy app source
24
+ COPY . .
25
+
26
+ EXPOSE 7860
27
+ CMD ["python", "demo_v5.py"]
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Rapidocr Ort
3
- emoji: 🏆
4
- colorFrom: green
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 5.27.1
8
- app_file: app.py
9
- pinned: false
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: rapidocr_ort
3
+ app_file: demo_v5.py
 
 
4
  sdk: gradio
5
+ sdk_version: 5.27.0
 
 
6
  ---
 
 
__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # -*- encoding: utf-8 -*-
2
+ # @Author: SWHL
3
+ # @Contact: liekkaskono@163.com
4
+ from .main import RapidOCR
5
+ from .utils import LoadImageError, VisRes
__pycache__/__init__.cpython-310.pyc ADDED
Binary file (246 Bytes). View file
 
__pycache__/image_enhancement.cpython-310.pyc ADDED
Binary file (41.3 kB). View file
 
__pycache__/image_enhancement.cpython-311.pyc ADDED
Binary file (68.9 kB). View file
 
__pycache__/image_enhancement.cpython-313.pyc ADDED
Binary file (62.3 kB). View file
 
__pycache__/main.cpython-310.pyc ADDED
Binary file (9.89 kB). View file
 
__pycache__/main.cpython-311.pyc ADDED
Binary file (20 kB). View file
 
__pycache__/main.cpython-313.pyc ADDED
Binary file (17.7 kB). View file
 
app.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ from pathlib import Path
5
+
6
+ from main import RapidOCR
7
+
8
+
9
+ ocr_engine = RapidOCR()
10
+
11
+ def extract_text_from_bottom(image: np.ndarray):
12
+ h = image.shape[0]
13
+ # bottom_crop = image[int(h * 0.7):, :]
14
+ result, _ = ocr_engine(image, use_det=True, use_cls=False, use_rec=True)
15
+ if not result:
16
+ return "No text found."
17
+
18
+ texts = [r[1] for r in result]
19
+ return "\n".join(texts)
20
+
21
+ demo = gr.Interface(
22
+ fn=extract_text_from_bottom,
23
+ inputs=gr.Image(type="numpy"),
24
+ outputs="text",
25
+ title="",
26
+ description="",
27
+ )
28
+
29
+ demo.launch()
cal_rec_boxes/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # -*- encoding: utf-8 -*-
2
+ # @Author: SWHL
3
+ # @Contact: liekkaskono@163.com
4
+ from .main import CalRecBoxes
cal_rec_boxes/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (174 Bytes). View file
 
cal_rec_boxes/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (222 Bytes). View file
 
cal_rec_boxes/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (226 Bytes). View file
 
cal_rec_boxes/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (215 Bytes). View file
 
cal_rec_boxes/__pycache__/main.cpython-310.pyc ADDED
Binary file (7.78 kB). View file
 
cal_rec_boxes/__pycache__/main.cpython-311.pyc ADDED
Binary file (16.8 kB). View file
 
cal_rec_boxes/__pycache__/main.cpython-312.pyc ADDED
Binary file (14.8 kB). View file
 
cal_rec_boxes/__pycache__/main.cpython-313.pyc ADDED
Binary file (14.8 kB). View file
 
cal_rec_boxes/main.py ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- encoding: utf-8 -*-
2
+ # @Author: SWHL / Joker1212
3
+ # @Contact: liekkaskono@163.com
4
+ import copy
5
+ import math
6
+ from typing import Any, List, Optional, Tuple
7
+
8
+ import cv2
9
+ import numpy as np
10
+
11
+
12
+ class CalRecBoxes:
13
+ """计算识别文字的汉字单字和英文单词的坐标框。代码借鉴自PaddlePaddle/PaddleOCR和fanqie03/char-detection"""
14
+
15
+ def __init__(self):
16
+ pass
17
+
18
+ def __call__(
19
+ self,
20
+ imgs: Optional[List[np.ndarray]],
21
+ dt_boxes: Optional[List[np.ndarray]],
22
+ rec_res: Optional[List[Any]],
23
+ ):
24
+ res = []
25
+ for img, box, rec_res in zip(imgs, dt_boxes, rec_res):
26
+ direction = self.get_box_direction(box)
27
+
28
+ rec_txt, rec_conf, rec_word_info = rec_res[0], rec_res[1], rec_res[2]
29
+ h, w = img.shape[:2]
30
+ img_box = np.array([[0, 0], [w, 0], [w, h], [0, h]])
31
+ word_box_content_list, word_box_list, conf_list = self.cal_ocr_word_box(
32
+ rec_txt, img_box, rec_word_info
33
+ )
34
+ word_box_list = self.adjust_box_overlap(copy.deepcopy(word_box_list))
35
+ word_box_list = self.reverse_rotate_crop_image(
36
+ copy.deepcopy(box), word_box_list, direction
37
+ )
38
+ res.append(
39
+ [rec_txt, rec_conf, word_box_list, word_box_content_list, conf_list]
40
+ )
41
+ return res
42
+
43
+ @staticmethod
44
+ def get_box_direction(box: np.ndarray) -> str:
45
+ direction = "w"
46
+ img_crop_width = int(
47
+ max(
48
+ np.linalg.norm(box[0] - box[1]),
49
+ np.linalg.norm(box[2] - box[3]),
50
+ )
51
+ )
52
+ img_crop_height = int(
53
+ max(
54
+ np.linalg.norm(box[0] - box[3]),
55
+ np.linalg.norm(box[1] - box[2]),
56
+ )
57
+ )
58
+ if img_crop_height * 1.0 / img_crop_width >= 1.5:
59
+ direction = "h"
60
+ return direction
61
+
62
+ @staticmethod
63
+ def cal_ocr_word_box(
64
+ rec_txt: str, box: np.ndarray, rec_word_info: List[Tuple[str, List[int]]]
65
+ ) -> Tuple[List[str], List[List[int]], List[float]]:
66
+ """Calculate the detection frame for each word based on the results of recognition and detection of ocr
67
+ 汉字坐标是单字的
68
+ 英语坐标是单词级别的
69
+ """
70
+
71
+ col_num, word_list, word_col_list, state_list, conf_list = rec_word_info
72
+ box = box.tolist()
73
+ bbox_x_start = box[0][0]
74
+ bbox_x_end = box[1][0]
75
+ bbox_y_start = box[0][1]
76
+ bbox_y_end = box[2][1]
77
+
78
+ cell_width = (bbox_x_end - bbox_x_start) / col_num
79
+ word_box_list = []
80
+ word_box_content_list = []
81
+ cn_width_list = []
82
+ en_width_list = []
83
+ cn_col_list = []
84
+ en_col_list = []
85
+
86
+ def cal_char_width(width_list, word_col_):
87
+ if len(word_col_) == 1:
88
+ return
89
+ char_total_length = (word_col_[-1] - word_col_[0]) * cell_width
90
+ char_width = char_total_length / (len(word_col_) - 1)
91
+ width_list.append(char_width)
92
+
93
+ def cal_box(col_list, width_list, word_box_list_):
94
+ if len(col_list) == 0:
95
+ return
96
+ if len(width_list) != 0:
97
+ avg_char_width = np.mean(width_list)
98
+ else:
99
+ avg_char_width = (bbox_x_end - bbox_x_start) / len(rec_txt)
100
+
101
+ for center_idx in col_list:
102
+ center_x = (center_idx + 0.5) * cell_width
103
+ cell_x_start = max(int(center_x - avg_char_width / 2), 0) + bbox_x_start
104
+ cell_x_end = (
105
+ min(int(center_x + avg_char_width / 2), bbox_x_end - bbox_x_start)
106
+ + bbox_x_start
107
+ )
108
+ cell = [
109
+ [cell_x_start, bbox_y_start],
110
+ [cell_x_end, bbox_y_start],
111
+ [cell_x_end, bbox_y_end],
112
+ [cell_x_start, bbox_y_end],
113
+ ]
114
+ word_box_list_.append(cell)
115
+
116
+ for word, word_col, state in zip(word_list, word_col_list, state_list):
117
+ if state == "cn":
118
+ cal_char_width(cn_width_list, word_col)
119
+ cn_col_list += word_col
120
+ word_box_content_list += word
121
+ else:
122
+ cal_char_width(en_width_list, word_col)
123
+ en_col_list += word_col
124
+ word_box_content_list += word
125
+
126
+ cal_box(cn_col_list, cn_width_list, word_box_list)
127
+ cal_box(en_col_list, en_width_list, word_box_list)
128
+ sorted_word_box_list = sorted(word_box_list, key=lambda box: box[0][0])
129
+ return word_box_content_list, sorted_word_box_list, conf_list
130
+
131
+ @staticmethod
132
+ def adjust_box_overlap(
133
+ word_box_list: List[List[List[int]]],
134
+ ) -> List[List[List[int]]]:
135
+ # 调整bbox有重叠的地方
136
+ for i in range(len(word_box_list) - 1):
137
+ cur, nxt = word_box_list[i], word_box_list[i + 1]
138
+ if cur[1][0] > nxt[0][0]: # 有交集
139
+ distance = abs(cur[1][0] - nxt[0][0])
140
+ cur[1][0] -= distance / 2
141
+ cur[2][0] -= distance / 2
142
+ nxt[0][0] += distance - distance / 2
143
+ nxt[3][0] += distance - distance / 2
144
+ return word_box_list
145
+
146
+ def reverse_rotate_crop_image(
147
+ self,
148
+ bbox_points: np.ndarray,
149
+ word_points_list: List[List[List[int]]],
150
+ direction: str = "w",
151
+ ) -> List[List[List[int]]]:
152
+ """
153
+ get_rotate_crop_image的逆操作
154
+ img为原图
155
+ part_img为crop后的图
156
+ bbox_points为part_img中对应在原图的bbox, 四个点,左上,右上,右下,左下
157
+ part_points为在part_img中的点[(x, y), (x, y)]
158
+ """
159
+ bbox_points = np.float32(bbox_points)
160
+
161
+ left = int(np.min(bbox_points[:, 0]))
162
+ top = int(np.min(bbox_points[:, 1]))
163
+ bbox_points[:, 0] = bbox_points[:, 0] - left
164
+ bbox_points[:, 1] = bbox_points[:, 1] - top
165
+
166
+ img_crop_width = int(np.linalg.norm(bbox_points[0] - bbox_points[1]))
167
+ img_crop_height = int(np.linalg.norm(bbox_points[0] - bbox_points[3]))
168
+
169
+ pts_std = np.array(
170
+ [
171
+ [0, 0],
172
+ [img_crop_width, 0],
173
+ [img_crop_width, img_crop_height],
174
+ [0, img_crop_height],
175
+ ]
176
+ ).astype(np.float32)
177
+ M = cv2.getPerspectiveTransform(bbox_points, pts_std)
178
+ _, IM = cv2.invert(M)
179
+
180
+ new_word_points_list = []
181
+ for word_points in word_points_list:
182
+ new_word_points = []
183
+ for point in word_points:
184
+ new_point = point
185
+ if direction == "h":
186
+ new_point = self.s_rotate(
187
+ math.radians(-90), new_point[0], new_point[1], 0, 0
188
+ )
189
+ new_point[0] = new_point[0] + img_crop_width
190
+
191
+ p = np.float32(new_point + [1])
192
+ x, y, z = np.dot(IM, p)
193
+ new_point = [x / z, y / z]
194
+
195
+ new_point = [int(new_point[0] + left), int(new_point[1] + top)]
196
+ new_word_points.append(new_point)
197
+ new_word_points = self.order_points(new_word_points)
198
+ new_word_points_list.append(new_word_points)
199
+ return new_word_points_list
200
+
201
+ @staticmethod
202
+ def s_rotate(angle, valuex, valuey, pointx, pointy):
203
+ """绕pointx,pointy顺时针旋转
204
+ https://blog.csdn.net/qq_38826019/article/details/84233397
205
+ """
206
+ valuex = np.array(valuex)
207
+ valuey = np.array(valuey)
208
+ sRotatex = (
209
+ (valuex - pointx) * math.cos(angle)
210
+ + (valuey - pointy) * math.sin(angle)
211
+ + pointx
212
+ )
213
+ sRotatey = (
214
+ (valuey - pointy) * math.cos(angle)
215
+ - (valuex - pointx) * math.sin(angle)
216
+ + pointy
217
+ )
218
+ return [sRotatex, sRotatey]
219
+
220
+ @staticmethod
221
+ def order_points(box: List[List[int]]) -> List[List[int]]:
222
+ """矩形框顺序排列"""
223
+
224
+ def convert_to_1x2(p):
225
+ if p.shape == (2,):
226
+ return p.reshape((1, 2))
227
+ elif p.shape == (1, 2):
228
+ return p
229
+ else:
230
+ return p[:1, :]
231
+
232
+ box = np.array(box).reshape((-1, 2))
233
+ center_x, center_y = np.mean(box[:, 0]), np.mean(box[:, 1])
234
+ if np.any(box[:, 0] == center_x) and np.any(
235
+ box[:, 1] == center_y
236
+ ): # 有两点横坐标相等,有两点纵坐标相等,菱形
237
+ p1 = box[np.where(box[:, 0] == np.min(box[:, 0]))]
238
+ p2 = box[np.where(box[:, 1] == np.min(box[:, 1]))]
239
+ p3 = box[np.where(box[:, 0] == np.max(box[:, 0]))]
240
+ p4 = box[np.where(box[:, 1] == np.max(box[:, 1]))]
241
+ elif np.all(box[:, 0] == center_x): # 四个点的横坐标都相同
242
+ y_sort = np.argsort(box[:, 1])
243
+ p1 = box[y_sort[0]]
244
+ p2 = box[y_sort[1]]
245
+ p3 = box[y_sort[2]]
246
+ p4 = box[y_sort[3]]
247
+ elif np.any(box[:, 0] == center_x) and np.all(
248
+ box[:, 1] != center_y
249
+ ): # 只有两点横坐标相等,先上下再左右
250
+ p12, p34 = (
251
+ box[np.where(box[:, 1] < center_y)],
252
+ box[np.where(box[:, 1] > center_y)],
253
+ )
254
+ p1, p2 = (
255
+ p12[np.where(p12[:, 0] == np.min(p12[:, 0]))],
256
+ p12[np.where(p12[:, 0] == np.max(p12[:, 0]))],
257
+ )
258
+ p3, p4 = (
259
+ p34[np.where(p34[:, 0] == np.max(p34[:, 0]))],
260
+ p34[np.where(p34[:, 0] == np.min(p34[:, 0]))],
261
+ )
262
+ else: # 只有两点纵坐标相等,或者是没有相等的,先左右再上下
263
+ p14, p23 = (
264
+ box[np.where(box[:, 0] < center_x)],
265
+ box[np.where(box[:, 0] > center_x)],
266
+ )
267
+ p1, p4 = (
268
+ p14[np.where(p14[:, 1] == np.min(p14[:, 1]))],
269
+ p14[np.where(p14[:, 1] == np.max(p14[:, 1]))],
270
+ )
271
+ p2, p3 = (
272
+ p23[np.where(p23[:, 1] == np.min(p23[:, 1]))],
273
+ p23[np.where(p23[:, 1] == np.max(p23[:, 1]))],
274
+ )
275
+
276
+ # 解决单字切割后横坐标完全相同的shape错误
277
+ p1 = convert_to_1x2(p1)
278
+ p2 = convert_to_1x2(p2)
279
+ p3 = convert_to_1x2(p3)
280
+ p4 = convert_to_1x2(p4)
281
+ return np.array([p1, p2, p3, p4]).reshape((-1, 2)).tolist()
ch_ppocr_cls/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # -*- encoding: utf-8 -*-
2
+ # @Author: SWHL
3
+ # @Contact: liekkaskono@163.com
4
+ from .text_cls import TextClassifier
ch_ppocr_cls/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (180 Bytes). View file
 
ch_ppocr_cls/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (228 Bytes). View file
 
ch_ppocr_cls/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (232 Bytes). View file
 
ch_ppocr_cls/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (221 Bytes). View file
 
ch_ppocr_cls/__pycache__/text_cls.cpython-310.pyc ADDED
Binary file (3.25 kB). View file
 
ch_ppocr_cls/__pycache__/text_cls.cpython-311.pyc ADDED
Binary file (6.27 kB). View file
 
ch_ppocr_cls/__pycache__/text_cls.cpython-312.pyc ADDED
Binary file (5.62 kB). View file
 
ch_ppocr_cls/__pycache__/text_cls.cpython-313.pyc ADDED
Binary file (5.69 kB). View file
 
ch_ppocr_cls/__pycache__/utils.cpython-310.pyc ADDED
Binary file (1.03 kB). View file
 
ch_ppocr_cls/__pycache__/utils.cpython-311.pyc ADDED
Binary file (1.51 kB). View file
 
ch_ppocr_cls/__pycache__/utils.cpython-312.pyc ADDED
Binary file (1.19 kB). View file
 
ch_ppocr_cls/__pycache__/utils.cpython-313.pyc ADDED
Binary file (1.23 kB). View file
 
ch_ppocr_cls/text_cls.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ import argparse
15
+ import copy
16
+ import math
17
+ import time
18
+ from typing import Any, Dict, List, Tuple, Union
19
+
20
+ import cv2
21
+ import numpy as np
22
+ from rapidocr_onnxruntime.utils import OrtInferSession, read_yaml
23
+
24
+ from .utils import ClsPostProcess
25
+
26
+
27
+ class TextClassifier:
28
+ def __init__(self, config: Dict[str, Any]):
29
+ self.cls_image_shape = config["cls_image_shape"]
30
+ self.cls_batch_num = config["cls_batch_num"]
31
+ self.cls_thresh = config["cls_thresh"]
32
+ self.postprocess_op = ClsPostProcess(config["label_list"])
33
+
34
+ self.infer = OrtInferSession(config)
35
+
36
+ def __call__(
37
+ self, img_list: Union[np.ndarray, List[np.ndarray]]
38
+ ) -> Tuple[List[np.ndarray], List[List[Union[str, float]]], float]:
39
+ if isinstance(img_list, np.ndarray):
40
+ img_list = [img_list]
41
+
42
+ img_list = copy.deepcopy(img_list)
43
+
44
+ # Calculate the aspect ratio of all text bars
45
+ width_list = [img.shape[1] / float(img.shape[0]) for img in img_list]
46
+
47
+ # Sorting can speed up the cls process
48
+ indices = np.argsort(np.array(width_list))
49
+
50
+ img_num = len(img_list)
51
+ cls_res = [["", 0.0]] * img_num
52
+ batch_num = self.cls_batch_num
53
+ elapse = 0
54
+ for beg_img_no in range(0, img_num, batch_num):
55
+ end_img_no = min(img_num, beg_img_no + batch_num)
56
+
57
+ norm_img_batch = []
58
+ for ino in range(beg_img_no, end_img_no):
59
+ norm_img = self.resize_norm_img(img_list[indices[ino]])
60
+ norm_img = norm_img[np.newaxis, :]
61
+ norm_img_batch.append(norm_img)
62
+ norm_img_batch = np.concatenate(norm_img_batch).astype(np.float32)
63
+
64
+ starttime = time.time()
65
+ prob_out = self.infer(norm_img_batch)[0]
66
+ cls_result = self.postprocess_op(prob_out)
67
+ elapse += time.time() - starttime
68
+
69
+ for rno, (label, score) in enumerate(cls_result):
70
+ cls_res[indices[beg_img_no + rno]] = [label, score]
71
+ if "180" in label and score > self.cls_thresh:
72
+ img_list[indices[beg_img_no + rno]] = cv2.rotate(
73
+ img_list[indices[beg_img_no + rno]], 1
74
+ )
75
+ return img_list, cls_res, elapse
76
+
77
+ def resize_norm_img(self, img: np.ndarray) -> np.ndarray:
78
+ img_c, img_h, img_w = self.cls_image_shape
79
+ h, w = img.shape[:2]
80
+ ratio = w / float(h)
81
+ if math.ceil(img_h * ratio) > img_w:
82
+ resized_w = img_w
83
+ else:
84
+ resized_w = int(math.ceil(img_h * ratio))
85
+
86
+ resized_image = cv2.resize(img, (resized_w, img_h))
87
+ resized_image = resized_image.astype("float32")
88
+ if img_c == 1:
89
+ resized_image = resized_image / 255
90
+ resized_image = resized_image[np.newaxis, :]
91
+ else:
92
+ resized_image = resized_image.transpose((2, 0, 1)) / 255
93
+
94
+ resized_image -= 0.5
95
+ resized_image /= 0.5
96
+ padding_im = np.zeros((img_c, img_h, img_w), dtype=np.float32)
97
+ padding_im[:, :, :resized_w] = resized_image
98
+ return padding_im
99
+
100
+
101
+ if __name__ == "__main__":
102
+ parser = argparse.ArgumentParser()
103
+ parser.add_argument("--image_path", type=str, help="image_dir|image_path")
104
+ parser.add_argument("--config_path", type=str, default="config.yaml")
105
+ args = parser.parse_args()
106
+
107
+ config = read_yaml(args.config_path)
108
+
109
+ text_classifier = TextClassifier(config)
110
+
111
+ img = cv2.imread(args.image_path)
112
+ img_list, cls_res, predict_time = text_classifier(img)
113
+ for ino in range(len(img_list)):
114
+ print(f"cls result:{cls_res[ino]}")
ch_ppocr_cls/utils.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from typing import List, Tuple
15
+
16
+ import numpy as np
17
+
18
+
19
+ class ClsPostProcess:
20
+ def __init__(self, label_list: List[str]):
21
+ self.label_list = label_list
22
+
23
+ def __call__(self, preds: np.ndarray) -> List[Tuple[str, float]]:
24
+ pred_idxs = preds.argmax(axis=1)
25
+ decode_out = [
26
+ (self.label_list[idx], preds[i, idx]) for i, idx in enumerate(pred_idxs)
27
+ ]
28
+ return decode_out
ch_ppocr_det/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # -*- encoding: utf-8 -*-
2
+ # @Author: SWHL
3
+ # @Contact: liekkaskono@163.com
4
+ from .text_detect import TextDetector
ch_ppocr_det/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (200 Bytes). View file
 
ch_ppocr_det/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (229 Bytes). View file
 
ch_ppocr_det/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (233 Bytes). View file
 
ch_ppocr_det/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (222 Bytes). View file
 
ch_ppocr_det/__pycache__/text_detect.cpython-310.pyc ADDED
Binary file (3.49 kB). View file
 
ch_ppocr_det/__pycache__/text_detect.cpython-311.pyc ADDED
Binary file (6.56 kB). View file
 
ch_ppocr_det/__pycache__/text_detect.cpython-312.pyc ADDED
Binary file (5.99 kB). View file
 
ch_ppocr_det/__pycache__/text_detect.cpython-313.pyc ADDED
Binary file (6.02 kB). View file
 
ch_ppocr_det/__pycache__/utils.cpython-310.pyc ADDED
Binary file (7.34 kB). View file