TAK commited on
Commit
07fb4fe
·
1 Parent(s): ada6df8
Files changed (5) hide show
  1. Drawings_RT_DETR_Demo.ipynb +201 -0
  2. app.py +10 -11
  3. blank_test.jpg +0 -0
  4. test_predict.py +22 -0
  5. uploads/test.jpg +1 -0
Drawings_RT_DETR_Demo.ipynb ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Bản Demo Nhận diện Bản vẽ Kỹ thuật (RT-DETR + EasyOCR)\n",
8
+ "Sử dụng Google Colab để chạy thử mô hình của bạn một cách nhanh chóng."
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "metadata": {},
15
+ "outputs": [],
16
+ "source": [
17
+ "!pip install ultralytics easyocr gdown opencv-python-headless matplotlib"
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "code",
22
+ "execution_count": null,
23
+ "metadata": {},
24
+ "outputs": [],
25
+ "source": [
26
+ "import gdown\n",
27
+ "import os\n",
28
+ "\n",
29
+ "# Thay bằng ID file best.pt trên Google Drive của bạn\n",
30
+ "file_id = '1WnIVT9nI7uDmfKzsWw8aTFZQ1VAuVF06'\n",
31
+ "url = f'https://drive.google.com/uc?id={file_id}'\n",
32
+ "\n",
33
+ "output = 'best.pt'\n",
34
+ "if not os.path.exists(output):\n",
35
+ " print(\"Đang tải model weights...\")\n",
36
+ " gdown.download(url, output, quiet=False)\n",
37
+ " print(\"Đã tải xong!\")\n",
38
+ "else:\n",
39
+ " print(\"Model đã tồn tại.\")"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": null,
45
+ "metadata": {},
46
+ "outputs": [],
47
+ "source": [
48
+ "import cv2\n",
49
+ "import easyocr\n",
50
+ "import matplotlib.pyplot as plt\n",
51
+ "from ultralytics import RTDETR\n",
52
+ "from google.colab import files\n",
53
+ "import numpy as np\n",
54
+ "\n",
55
+ "print(\"Loading RT-DETR...\")\n",
56
+ "model = RTDETR('best.pt')\n",
57
+ "\n",
58
+ "print(\"Loading EasyOCR...\")\n",
59
+ "reader = easyocr.Reader(['vi', 'en'], gpu=True) # Trên Colab nhớ chọn Runtime -> GPU\n",
60
+ "print(\"Ready!\")"
61
+ ]
62
+ },
63
+ {
64
+ "cell_type": "code",
65
+ "execution_count": null,
66
+ "metadata": {},
67
+ "outputs": [],
68
+ "source": [
69
+ "# Chạy cell này để upload bức ảnh bản vẽ của bạn lên Colab\n",
70
+ "uploaded = files.upload()\n",
71
+ "image_path = list(uploaded.keys())[0]\n",
72
+ "print(f\"Đã tải lên ảnh: {image_path}\")"
73
+ ]
74
+ },
75
+ {
76
+ "cell_type": "code",
77
+ "execution_count": null,
78
+ "metadata": {},
79
+ "outputs": [],
80
+ "source": [
81
+ "def perform_easyocr_on_crop(cropped_img, is_table=False):\n",
82
+ " if cropped_img is None or cropped_img.size == 0:\n",
83
+ " return \"\"\n",
84
+ " try:\n",
85
+ " gray_img = cv2.cvtColor(cropped_img, cv2.COLOR_BGR2GRAY)\n",
86
+ " blurred_img = cv2.GaussianBlur(gray_img, (3, 3), 0)\n",
87
+ " _, thresh_img = cv2.threshold(blurred_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)\n",
88
+ "\n",
89
+ " if not is_table:\n",
90
+ " result = reader.readtext(thresh_img, detail=0, paragraph=True)\n",
91
+ " return \" \".join(result) if result else \"\"\n",
92
+ " else:\n",
93
+ " result = reader.readtext(thresh_img, detail=1)\n",
94
+ " if not result:\n",
95
+ " return \"\"\n",
96
+ " lines = []\n",
97
+ " for bbox, text, conf in result:\n",
98
+ " y_center = (bbox[0][1] + bbox[2][1]) / 2\n",
99
+ " x_center = (bbox[0][0] + bbox[1][0]) / 2\n",
100
+ " lines.append({\"y\": y_center, \"x\": x_center, \"text\": text})\n",
101
+ " lines.sort(key=lambda item: item['y'])\n",
102
+ " y_tolerance = 20\n",
103
+ " rows = []\n",
104
+ " current_row = []\n",
105
+ " current_y = None\n",
106
+ " for item in lines:\n",
107
+ " if current_y is None:\n",
108
+ " current_y = item['y']\n",
109
+ " current_row.append(item)\n",
110
+ " elif abs(item['y'] - current_y) <= y_tolerance:\n",
111
+ " current_row.append(item)\n",
112
+ " current_y = (current_y * (len(current_row) - 1) + item['y']) / len(current_row)\n",
113
+ " else:\n",
114
+ " rows.append(current_row)\n",
115
+ " current_row = [item]\n",
116
+ " current_y = item['y']\n",
117
+ " if current_row:\n",
118
+ " rows.append(current_row)\n",
119
+ " formatted_text = \"\"\n",
120
+ " for row in rows:\n",
121
+ " row.sort(key=lambda item: item['x'])\n",
122
+ " row_text = \" | \".join([item['text'] for item in row])\n",
123
+ " formatted_text += row_text + \"\\n\"\n",
124
+ " return formatted_text.strip()\n",
125
+ " except Exception as e:\n",
126
+ " print(f\"Lỗi OCR: {e}\")\n",
127
+ " return \"\"\n",
128
+ "\n",
129
+ "# Đọc ảnh\n",
130
+ "cv_img = cv2.imread(image_path)\n",
131
+ "\n",
132
+ "# Dự đoán\n",
133
+ "results = model.predict(image_path, conf=0.25, iou=0.45, verbose=False)\n",
134
+ "boxes = results[0].boxes\n",
135
+ "\n",
136
+ "print(\"\\n--- KẾT QUẢ NHẬN DIỆN ---\")\n",
137
+ "if boxes is not None and len(boxes) > 0:\n",
138
+ " for box in boxes:\n",
139
+ " x1, y1, x2, y2 = box.xyxy[0].tolist()\n",
140
+ " conf_val = float(box.conf[0])\n",
141
+ " cls_id = int(box.cls[0])\n",
142
+ " cls_name = model.names[cls_id]\n",
143
+ " cls_lower = cls_name.lower()\n",
144
+ "\n",
145
+ " if cls_lower == 'table':\n",
146
+ " color = (0, 0, 255) # Đỏ\n",
147
+ " thickness = 3\n",
148
+ " elif cls_lower == 'note':\n",
149
+ " color = (0, 150, 0) # Xanh lá đậm\n",
150
+ " thickness = 2\n",
151
+ " elif cls_lower == 'partdrawing':\n",
152
+ " color = (255, 0, 0) # Xanh biển\n",
153
+ " thickness = 2\n",
154
+ " else:\n",
155
+ " color = (0, 165, 255) # Cam\n",
156
+ " thickness = 2\n",
157
+ "\n",
158
+ " # Crop\n",
159
+ " x1i, y1i, x2i, y2i = max(0, int(x1)), max(0, int(y1)), min(cv_img.shape[1], int(x2)), min(cv_img.shape[0], int(y2))\n",
160
+ " cropped_img = cv_img[y1i:y2i, x1i:x2i]\n",
161
+ " \n",
162
+ " ocr_text = \"\"\n",
163
+ " if cls_lower in ['table', 'note'] and cropped_img.size != 0:\n",
164
+ " ocr_text = perform_easyocr_on_crop(cropped_img, is_table=(cls_lower == 'table'))\n",
165
+ "\n",
166
+ " print(f\"- {cls_name} (Độ tin cậy: {conf_val:.2f})\")\n",
167
+ " if ocr_text:\n",
168
+ " print(f\" [OCR] Nội dung:\\n{ocr_text}\\n\")\n",
169
+ "\n",
170
+ " # Vẽ khung trên ảnh\n",
171
+ " cv2.rectangle(cv_img, (x1i, y1i), (x2i, y2i), color, thickness)\n",
172
+ " label = f\"{cls_name} {conf_val:.2f}\"\n",
173
+ " (tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)\n",
174
+ " label_y = max(y1i, 20)\n",
175
+ " cv2.rectangle(cv_img, (x1i, label_y - 20), (x1i + tw, label_y), color, -1)\n",
176
+ " cv2.putText(cv_img, label, (x1i, label_y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)\n",
177
+ "\n",
178
+ "# Hiển thị ảnh kết quả\n",
179
+ "plt.figure(figsize=(15, 15))\n",
180
+ "plt.imshow(cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB))\n",
181
+ "plt.axis('off')\n",
182
+ "plt.show()"
183
+ ]
184
+ }
185
+ ],
186
+ "metadata": {
187
+ "colab": {
188
+ "name": "Drawings_RT_DETR_Demo.ipynb",
189
+ "provenance": []
190
+ },
191
+ "kernelspec": {
192
+ "display_name": "Python 3",
193
+ "name": "python3"
194
+ },
195
+ "language_info": {
196
+ "name": "python"
197
+ }
198
+ },
199
+ "nbformat": 4,
200
+ "nbformat_minor": 0
201
+ }
app.py CHANGED
@@ -137,7 +137,7 @@ def predict():
137
 
138
  # Run inference
139
  t0 = time.time()
140
- results = model.predict(image, conf=conf, iou=iou, imgsz=640, verbose=False)
141
  inference_time = round((time.time() - t0) * 1000, 1)
142
 
143
  result = results[0]
@@ -154,18 +154,17 @@ def predict():
154
  ocr_text = ""
155
 
156
  # --- Xử lý vẽ khung ---
157
- cls_lower = cls_name.lower()
158
- if cls_lower == 'table':
159
- color = (0, 0, 255) # Đỏ (BGR) cho Table
160
  thickness = 3
161
- elif cls_lower == 'note':
162
- color = (0, 150, 0) # Xanh lá đậm (BGR) cho Note
163
  thickness = 2
164
- elif cls_lower == 'partdrawing':
165
- color = (255, 0, 0) # Xanh biển (BGR) cho PartDrawing
166
  thickness = 2
167
  else:
168
- color = (0, 165, 255) # Cam (BGR) cho class khác
169
  thickness = 2
170
 
171
  crop_filename = ""
@@ -186,8 +185,8 @@ def predict():
186
  crop_b64 = base64.b64encode(buffer).decode('utf-8')
187
 
188
  # --- GỌI EASYOCR ĐỂ ĐỌC CHỮ (CHỈ CHO NOTE VÀ TABLE) ---
189
- if cls_lower in ['table', 'note']:
190
- ocr_text = perform_easyocr_on_crop(cropped_img, is_table=(cls_lower == 'table'))
191
  if ocr_text:
192
  print(f"[OCR SUCCESS] Đã đọc được đoạn: {len(ocr_text)} characters")
193
  else:
 
137
 
138
  # Run inference
139
  t0 = time.time()
140
+ results = model.predict(image, conf=conf, iou=iou, verbose=False)
141
  inference_time = round((time.time() - t0) * 1000, 1)
142
 
143
  result = results[0]
 
154
  ocr_text = ""
155
 
156
  # --- Xử lý vẽ khung ---
157
+ if cls_name == 'Table':
158
+ color = (0, 0, 255)
 
159
  thickness = 3
160
+ elif cls_name == 'Note':
161
+ color = (0, 255, 0)
162
  thickness = 2
163
+ elif cls_name == 'PartDrawing':
164
+ color = (255, 0, 0)
165
  thickness = 2
166
  else:
167
+ color = (0, 255, 255)
168
  thickness = 2
169
 
170
  crop_filename = ""
 
185
  crop_b64 = base64.b64encode(buffer).decode('utf-8')
186
 
187
  # --- GỌI EASYOCR ĐỂ ĐỌC CHỮ (CHỈ CHO NOTE VÀ TABLE) ---
188
+ if cls_name in ['Table', 'Note']:
189
+ ocr_text = perform_easyocr_on_crop(cropped_img, is_table=(cls_name == 'Table'))
190
  if ocr_text:
191
  print(f"[OCR SUCCESS] Đã đọc được đoạn: {len(ocr_text)} characters")
192
  else:
blank_test.jpg ADDED
test_predict.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import sys
3
+
4
+ try:
5
+ with open("uploads/test.jpg", "wb") as f:
6
+ f.write(b"fake image data")
7
+ except Exception:
8
+ pass
9
+
10
+ # We need a proper image to test the API. Let's create a blank image using numpy and cv2
11
+ import cv2
12
+ import numpy as np
13
+ blank_image = np.zeros((500, 500, 3), np.uint8)
14
+ cv2.imwrite("blank_test.jpg", blank_image)
15
+
16
+ url = "http://127.0.0.1:5002/predict"
17
+ files = {'image': open('blank_test.jpg', 'rb')}
18
+ data = {'conf': 0.1, 'iou': 0.1}
19
+
20
+ response = requests.post(url, files=files, data=data)
21
+ print("Status Code:", response.status_code)
22
+ print("Response:", response.text[:500])
uploads/test.jpg ADDED