CloudAnts commited on
Commit
4fece7c
·
1 Parent(s): a36687f
Files changed (3) hide show
  1. Dockerfile +31 -0
  2. app.py +244 -0
  3. requirements.txt +14 -0
Dockerfile ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.9 as the base image
2
+ FROM python:3.9
3
+
4
+ # Create a user with ID 1000
5
+ RUN useradd -m -u 1000 user
6
+ USER user
7
+ ENV PATH="/home/user/.local/bin:$PATH"
8
+
9
+ # Set the working directory
10
+ WORKDIR /app
11
+
12
+ # Copy the requirements.txt file and install dependencies
13
+ COPY --chown=user ./requirements.txt requirements.txt
14
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
15
+
16
+ # Install system dependencies needed for OpenCV, Tesseract, and other libraries
17
+ USER root
18
+ RUN apt-get update && apt-get install -y \
19
+ libgl1-mesa-glx \
20
+ libglib2.0-0 \
21
+ tesseract-ocr \
22
+ && rm -rf /var/lib/apt/lists/*
23
+
24
+ # Return to the user 'user' for safety
25
+ USER user
26
+
27
+ # Copy the entire app directory to the container
28
+ COPY --chown=user . /app
29
+
30
+ # Set the command to run the app with Gunicorn
31
+ CMD ["gunicorn", "-b", "0.0.0.0:7860", "app:app"]
app.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import csv
3
+ import torch
4
+ import torchvision
5
+ import easyocr
6
+ import shutil
7
+ import random
8
+ import cv2
9
+ from glob import glob
10
+ from ultralytics import YOLOv10
11
+ import random
12
+ from glob import glob
13
+ from ultralytics import YOLOv10
14
+ import supervision as sva
15
+ from ultralytics import YOLOv10
16
+ import supervision as sv
17
+ import supervision as sv
18
+ from flask import Flask, request, jsonify, send_from_directory, render_template
19
+ import pytesseract
20
+ # Set the tesseract_cmd based on the operating system
21
+ if os.name == 'nt': # For Windows
22
+ pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
23
+ elif os.name == 'posix': # For Linux/MacOS
24
+ pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract' # Common location for Tesseract on Linux/MacOS
25
+
26
+ import textwrap
27
+ app = Flask(__name__)
28
+
29
+ def enhance_contrast(image):
30
+ gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
31
+ equalized_image = cv2.equalizeHist(gray_image)
32
+ return equalized_image
33
+
34
+
35
+ def calculate_iou(bbox1, bbox2):
36
+ x1_max = max(bbox1[0], bbox2[0])
37
+ y1_max = max(bbox1[1], bbox2[1])
38
+ x2_min = min(bbox1[2], bbox2[2])
39
+ y2_min = min(bbox1[3], bbox2[3])
40
+
41
+ inter_area = max(0, x2_min - x1_max) * max(0, y2_min - y1_max)
42
+
43
+ bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
44
+ bbox2_area = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])
45
+
46
+ iou = inter_area / float(bbox1_area + bbox2_area - inter_area) if (bbox1_area + bbox2_area - inter_area) > 0 else 0
47
+ return iou
48
+
49
+
50
+ def recreate_directories():
51
+ # Paths for the directories
52
+ cropped_dir = "./app/cropped_images/"
53
+ output_dir1 = "./app/Folder1"
54
+ output_dir2 = "./app/Folder2"
55
+ output_dir3 = "./app/Folder3"
56
+ UPLOAD_FOLDER = "./app/data1"
57
+
58
+ # Remove existing directories
59
+ if os.path.exists(cropped_dir):
60
+ shutil.rmtree(cropped_dir)
61
+ if os.path.exists(output_dir1):
62
+ shutil.rmtree(output_dir1)
63
+ if os.path.exists(output_dir2):
64
+ shutil.rmtree(output_dir2)
65
+ if os.path.exists(output_dir3):
66
+ shutil.rmtree(output_dir3)
67
+ if os.path.exists(UPLOAD_FOLDER):
68
+ shutil.rmtree(UPLOAD_FOLDER)
69
+
70
+ # Recreate directories
71
+ os.makedirs(cropped_dir, exist_ok=True)
72
+ os.makedirs(output_dir1, exist_ok=True)
73
+ os.makedirs(output_dir2, exist_ok=True)
74
+ os.makedirs(output_dir3, exist_ok=True)
75
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
76
+
77
+ @app.route('/')
78
+ def index():
79
+ return render_template('index3.html') # This will serve your HTML page
80
+
81
+ @app.route('/upload', methods=['POST'])
82
+ def upload_file():
83
+ recreate_directories()
84
+ if 'invoice-upload' not in request.files:
85
+ return jsonify({'error': 'No file part'}), 400
86
+ file = request.files['invoice-upload']
87
+ if file.filename == '':
88
+ return jsonify({'error': 'No selected file'}), 400
89
+ if file:
90
+ file_path = os.path.join('./app/data1', file.filename)
91
+ file.save(file_path)
92
+ output_image, output_csv,image_path = process_image()
93
+
94
+ return jsonify({
95
+ 'image_path': output_image,
96
+ 'csv_path': output_csv,
97
+ 'original_image': image_path
98
+ })
99
+ def process_image():
100
+ print("Current working directory:", os.getcwd())
101
+
102
+ # Check contents in the root directory
103
+ print("Current directory contents:", os.listdir('/'))
104
+
105
+ model = YOLOv10(f'./runs/detect/train3/weights/best.pt')
106
+ #device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
107
+ #model.to(device)
108
+
109
+ dataset = sv.DetectionDataset.from_yolo(
110
+ images_directory_path=f"./data/MyNewVersion5.0Dataset/valid/images",
111
+ annotations_directory_path=f"./data/MyNewVersion5.0Dataset/valid/labels",
112
+ data_yaml_path=f"./data/MyNewVersion5.0Dataset/data.yaml"
113
+ )
114
+ bounding_box_annotator = sv.BoundingBoxAnnotator()
115
+ label_annotator = sv.LabelAnnotator()
116
+ image_dir = "./app/data1"
117
+ files = os.listdir('./app/data1')
118
+ files.sort()
119
+ files = files[0:100]
120
+ print(files)
121
+ counter = 0
122
+ for ii in files:
123
+ random_image_data = cv2.imread('./app/data1/' + ii)
124
+ random_image_data1 = cv2.imread('./app/data1/' + ii)
125
+ results = model(source='./app/data1/' + ii, conf=0.07)[0]
126
+ detections = sv.Detections.from_ultralytics(results)
127
+ annotated_image = bounding_box_annotator.annotate(scene=random_image_data, detections=detections)
128
+ annotated_image = label_annotator.annotate(scene=annotated_image, detections=detections)
129
+ save_path = "./app/Folder1/" + "detection" + ii
130
+ cv2.imwrite(save_path, annotated_image)
131
+ print(f"Annotated image saved at {save_path}")
132
+ bounding_boxes = results.boxes.xyxy.cpu().numpy()
133
+ class_ids = results.boxes.cls.cpu().numpy()
134
+ confidences = results.boxes.conf.cpu().numpy()
135
+ bounding_box_save_path = "./bounding_boxes.txt"
136
+ with open(bounding_box_save_path, 'w') as f:
137
+ for i, (bbox, class_id, confidence) in enumerate(zip(bounding_boxes, class_ids, confidences)):
138
+ x1, y1, x2, y2 = map(int, bbox)
139
+ f.write(f"Object {i + 1}: Class {class_id}, Confidence: {confidence:.2f}, "
140
+ f"Bounding box: ({x1}, {y1}, {x2}, {y2})\n")
141
+ cropped_image = random_image_data1[y1:y2, x1:x2]
142
+ cropped_image_path = os.path.join('./app/cropped_images/', f"cropped_object_{i + 1}.jpg")
143
+ cv2.imwrite(cropped_image_path, cropped_image)
144
+ print(f"Enhanced cropped image saved at {cropped_image_path}")
145
+ print(f"Checking contents of /app/data: {bounding_box_save_path}")
146
+ print(f"Directory listing: {os.listdir('./app/Folder1')}")
147
+ print(f"Bounding box coordinates saved at {bounding_box_save_path}")
148
+ import re
149
+ input_file_path = './bounding_boxes.txt'
150
+ cropped_images_folder = './app/cropped_images/'
151
+ output_csv_path = './app/Folder2/' + ii + 'bounding_boxes_with_recognition.csv'
152
+ with open(input_file_path, 'r') as infile:
153
+ lines = infile.readlines()
154
+ with open(output_csv_path, 'w', newline='', encoding='utf-8') as csvfile:
155
+ csv_writer = csv.writer(csvfile)
156
+ csv_writer.writerow(['Object ID', 'Bounding Box', 'Image Name', 'Recognized Text'])
157
+ for i, line in enumerate(lines):
158
+ object_id = f"Object_{i + 1}"
159
+ bounding_box_info = line.strip()
160
+ cropped_image_name = f"cropped_object_{i + 1}.jpg"
161
+ cropped_image_path = os.path.join(cropped_images_folder, cropped_image_name)
162
+ if os.path.exists(cropped_image_path):
163
+ bbox_match = re.search(r"Bounding box: \((\d+), (\d+), (\d+), (\d+)\)", bounding_box_info)
164
+ if bbox_match:
165
+ x1, y1, x2, y2 = map(int, bbox_match.groups())
166
+ detected_boxes = [[x1, x2, y1, y2]]
167
+ else:
168
+ print("No bounding box found in the info.")
169
+ cropped_image = cv2.imread(cropped_image_path, cv2.IMREAD_GRAYSCALE)
170
+ recognized_text = pytesseract.image_to_string(cropped_image,config="--psm 6 -c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-")
171
+ print(f"Recognized Text: {recognized_text}")
172
+
173
+ csv_writer.writerow([object_id, bounding_box_info, cropped_image_name, recognized_text])
174
+ print(f"CSV file with recognition results saved at {output_csv_path}")
175
+
176
+ def calculate_iou(bbox1, bbox2):
177
+ x1_max = max(bbox1[0], bbox2[0])
178
+ y1_max = max(bbox1[1], bbox2[1])
179
+ x2_min = min(bbox1[2], bbox2[2])
180
+ y2_min = min(bbox1[3], bbox2[3])
181
+
182
+ inter_area = max(0, x2_min - x1_max) * max(0, y2_min - y1_max)
183
+
184
+ bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
185
+ bbox2_area = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])
186
+
187
+ iou = inter_area / float(bbox1_area + bbox2_area - inter_area) if (bbox1_area + bbox2_area - inter_area) > 0 else 0
188
+ return iou
189
+
190
+ image_path = "./app/data1/" + ii
191
+ csv_file_path = output_csv_path = './app/Folder2/' + ii + 'bounding_boxes_with_recognition.csv'
192
+ image = cv2.imread(image_path)
193
+ font = cv2.FONT_HERSHEY_SIMPLEX
194
+ font_scale = 1.3
195
+ font_thickness = 2
196
+ color = (255, 0, 255)
197
+ bboxes = []
198
+ recognized_texts = []
199
+ with open(csv_file_path, 'r', encoding='utf-8') as csvfile:
200
+ csv_reader = csv.DictReader(csvfile)
201
+ for row in csv_reader:
202
+ bbox_match = re.search(r'\((\d+), (\d+), (\d+), (\d+)\)', row['Bounding Box'])
203
+ if bbox_match:
204
+ bbox = [int(bbox_match.group(i)) for i in range(1, 5)]
205
+ bboxes.append(bbox)
206
+ recognized_texts.append(row['Recognized Text'])
207
+ filtered_bboxes = []
208
+ filtered_texts = []
209
+ iou_threshold = 0.4
210
+ for i, bbox1 in enumerate(bboxes):
211
+ keep = True
212
+ for j, bbox2 in enumerate(filtered_bboxes):
213
+ if calculate_iou(bbox1, bbox2) > iou_threshold:
214
+ keep = False
215
+ break
216
+ if keep:
217
+ filtered_bboxes.append(bbox1)
218
+ filtered_texts.append(recognized_texts[i])
219
+ for bbox, recognized_text in zip(filtered_bboxes, filtered_texts):
220
+ x1, y1, x2, y2 = bbox
221
+ cv2.rectangle(image, (x1, y1), (x2, y2), color, 2)
222
+ max_chars_per_line = 60
223
+ wrapped_text = textwrap.wrap(recognized_text, width=max_chars_per_line)
224
+ text_y = y1 - 10 if y1 - 10 > 10 else y1 + 10
225
+ for line in wrapped_text:
226
+ cv2.putText(image, line, (x1, text_y), font, font_scale, color, font_thickness)
227
+ text_y += int(font_scale * 20)
228
+ output_image_path = "./app/Folder3/" + "annotated" + ii + ".png"
229
+ cv2.imwrite(output_image_path, image)
230
+ print(f"Annotated image saved at {output_image_path}")
231
+ counter += 1
232
+ return output_image_path, output_csv_path,image_path
233
+
234
+ @app.route('/download_csv/<filename>')
235
+ def download_csv(filename):
236
+ return send_from_directory('./app/Folder2', filename, as_attachment=True)
237
+
238
+ @app.route('/download_image/<filename>')
239
+ def download_image(filename):
240
+ return send_from_directory('./app/Folder3', filename, as_attachment=True)
241
+
242
+ @app.route('/uploads/<filename>')
243
+ def serve_uploaded_file(filename):
244
+ return send_from_directory('./app/data1', filename)
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ flask
2
+ pytesseract
3
+ gunicorn
4
+ easyocr
5
+ psutil
6
+ matplotlib
7
+ tqdm
8
+ requests
9
+ pandas
10
+ huggingface_hub
11
+ supervision
12
+ py-cpuinfo
13
+
14
+