Harry Pham commited on
Commit
8aba89d
·
1 Parent(s): bafa422

update OCR

Browse files
Files changed (1) hide show
  1. src/inference.py +36 -126
src/inference.py CHANGED
@@ -12,22 +12,6 @@ import numpy as np
12
  from pathlib import Path
13
  from ultralytics import RTDETR
14
 
15
- import os
16
- import logging
17
- import cv2
18
- import numpy as np
19
- from paddleocr import PaddleOCR
20
-
21
- # 1. Tắt check network của Paddle (Giúp app khởi động nhanh hơn trên Hugging Face)
22
- os.environ["PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK"] = "True"
23
-
24
- # 2. Tắt log rác của PaddleOCR (Thay thế cho tham số show_log=False đã bị xóa)
25
- logging.getLogger("ppocr").setLevel(logging.ERROR)
26
-
27
- print("[INFO] Loading PaddleOCR...")
28
- # 3. Khởi tạo PaddleOCR (ĐÃ XÓA bỏ show_log=False)
29
- _ocr_engine = PaddleOCR(use_angle_cls=True, lang='vi')
30
-
31
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
32
  print(f"[INFO] Device: {DEVICE}")
33
 
@@ -68,119 +52,20 @@ def preprocess_for_ocr(img_bgr):
68
  gray = cv2.filter2D(gray, -1, kernel)
69
  return cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
70
 
71
- import cv2
72
- import numpy as np
73
- from paddleocr import PaddleOCR
74
-
75
- # Khởi tạo PaddleOCR (tự động tải PP-OCRv4 siêu nhẹ và chính xác)
76
- # use_angle_cls=True giúp lật lại các chữ bị nghiêng trên bản vẽ
77
- print("[INFO] Loading PaddleOCR...")
78
- _ocr_engine = PaddleOCR(use_angle_cls=True, lang='vi')
79
-
80
- def enhance_image_for_ocr(img_bgr):
81
- """
82
- Tiền xử lý nhẹ nhàng: Tăng độ tương phản nhưng không làm đứt nét chữ.
83
- """
84
- # Resize nếu ảnh quá nhỏ
85
- h, w = img_bgr.shape[:2]
86
- if w < 1000:
87
- scale = 1000 / w
88
- img_bgr = cv2.resize(img_bgr, (int(w*scale), int(h*scale)), interpolation=cv2.INTER_CUBIC)
89
-
90
- gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
91
- # Tăng độ tương phản cục bộ (CLAHE)
92
- clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
93
- gray = clahe.apply(gray)
94
-
95
- # Không dùng Denoise mạnh, chỉ chuyển lại sang BGR cho PaddleOCR
96
- return cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
97
-
98
-
99
  def ocr_note(img_path):
100
  img = cv2.imread(img_path)
101
- if img is None: return ""
102
-
103
- img_proc = enhance_image_for_ocr(img)
104
- result = _ocr_engine.ocr(img_proc, cls=True)
105
-
106
- if not result or not result[0]:
 
 
 
 
 
107
  return ""
108
-
109
- # PaddleOCR format: [[[x1,y1], [x2,y2], [x3,y3], [x4,y4]], ('text', conf)]
110
- lines = [line[1][0] for line in result[0] if line[1][1] > 0.6] # Lấy conf > 0.6
111
- return "\n".join(lines)
112
-
113
-
114
- def ocr_table(img_path):
115
- img = cv2.imread(img_path)
116
- if img is None: return {"rows": [], "text": ""}
117
-
118
- img_proc = enhance_image_for_ocr(img)
119
- result = _ocr_engine.ocr(img_proc, cls=True)
120
-
121
- if not result or not result[0]:
122
- return {"rows": [], "text": ""}
123
-
124
- items = []
125
- heights = []
126
-
127
- # 1. Trích xuất text và tọa độ tâm
128
- for line in result[0]:
129
- box = line[0] # 4 điểm của bounding box
130
- text = line[1][0] # Nội dung text
131
- conf = line[1][1] # Độ tin cậy
132
-
133
- if conf < 0.5 or not text.strip():
134
- continue
135
-
136
- # Tính tâm cy, cx và chiều cao của text box
137
- y_top = min(box[0][1], box[1][1])
138
- y_bottom = max(box[2][1], box[3][1])
139
- x_left = min(box[0][0], box[3][0])
140
- x_right = max(box[1][0], box[2][0])
141
-
142
- cy = (y_top + y_bottom) / 2
143
- cx = (x_left + x_right) / 2
144
- h = y_bottom - y_top
145
-
146
- items.append({"text": text.strip(), "cx": cx, "cy": cy, "h": h})
147
- heights.append(h)
148
-
149
- if not items:
150
- return {"rows": [], "text": ""}
151
-
152
- # 2. Thuật toán Dynamic Clustering (Gom hàng thông minh)
153
- # Tính chiều cao median của các chữ làm chuẩn
154
- median_h = np.median(heights)
155
- # Nếu lệch tâm Y nhỏ hơn 40% chiều cao chữ thì coi như cùng 1 hàng
156
- tolerance = median_h * 0.4
157
-
158
- # Sắp xếp các cụm chữ từ trên xuống dưới
159
- items.sort(key=lambda x: x["cy"])
160
-
161
- rows = []
162
- current_row = [items[0]]
163
-
164
- for item in items[1:]:
165
- # So sánh Y của item hiện tại với trung bình Y của hàng hiện tại
166
- avg_y_current_row = sum(i["cy"] for i in current_row) / len(current_row)
167
-
168
- if abs(item["cy"] - avg_y_current_row) <= tolerance:
169
- current_row.append(item)
170
- else:
171
- # Chuyển sang hàng mới: Xếp các chữ trong hàng cũ từ trái qua phải
172
- current_row.sort(key=lambda x: x["cx"])
173
- rows.append([i["text"] for i in current_row])
174
- current_row = [item] # Bắt đầu hàng mới
175
-
176
- # Add hàng cuối c��ng
177
- current_row.sort(key=lambda x: x["cx"])
178
- rows.append([i["text"] for i in current_row])
179
-
180
- # Format đầu ra giống code cũ
181
- formatted_text = "\n".join(" | ".join(r) for r in rows)
182
- return {"rows": rows, "text": formatted_text}
183
-
184
 
185
  def _group_rows(items):
186
  if not items:
@@ -204,6 +89,31 @@ def _group_rows(items):
204
  rows.append([i["text"] for i in cur])
205
  return rows
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  def run_pipeline(image_path, output_dir="outputs",
208
  checkpoint="best.pt", conf_thresh=0.3):
209
  image_path = str(image_path)
 
12
  from pathlib import Path
13
  from ultralytics import RTDETR
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
16
  print(f"[INFO] Device: {DEVICE}")
17
 
 
52
  gray = cv2.filter2D(gray, -1, kernel)
53
  return cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  def ocr_note(img_path):
56
  img = cv2.imread(img_path)
57
+ if img is None:
58
+ return ""
59
+ img_proc = preprocess_for_ocr(img)
60
+ try:
61
+ reader = get_easy_reader()
62
+ results = reader.readtext(img_proc, detail=1, paragraph=False,
63
+ width_ths=0.7, height_ths=0.7)
64
+ lines = [t for (_,t,c) in results if c >= 0.2 and t.strip()]
65
+ return "\n".join(lines)
66
+ except Exception as e:
67
+ print(f"[WARN] ocr_note: {e}")
68
  return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  def _group_rows(items):
71
  if not items:
 
89
  rows.append([i["text"] for i in cur])
90
  return rows
91
 
92
+ def ocr_table(img_path):
93
+ img = cv2.imread(img_path)
94
+ if img is None:
95
+ return {"rows":[], "text":""}
96
+ img_proc = preprocess_for_ocr(img)
97
+ items = []
98
+ try:
99
+ reader = get_easy_reader()
100
+ results = reader.readtext(img_proc, detail=1, paragraph=False,
101
+ width_ths=0.5, height_ths=0.5)
102
+ for (pts, text, conf) in results:
103
+ if conf < 0.2 or not text.strip():
104
+ continue
105
+ items.append({
106
+ "text": text.strip(),
107
+ "y": sum(p[1] for p in pts)/4,
108
+ "x": sum(p[0] for p in pts)/4,
109
+ })
110
+ except Exception as e:
111
+ print(f"[WARN] ocr_table: {e}")
112
+ if not items:
113
+ return {"rows":[], "text":""}
114
+ rows = _group_rows(items)
115
+ return {"rows": rows, "text": "\n".join(" | ".join(r) for r in rows)}
116
+
117
  def run_pipeline(image_path, output_dir="outputs",
118
  checkpoint="best.pt", conf_thresh=0.3):
119
  image_path = str(image_path)