Aditya Rathor commited on
Commit
34ca982
Β·
verified Β·
1 Parent(s): 3464573

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +1095 -0
app.py ADDED
@@ -0,0 +1,1095 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ from paddleocr import PaddleOCR
3
+ import cv2
4
+ import numpy as np
5
+ import pandas as pd
6
+ import os
7
+
8
+ # sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
9
+
10
+
11
+ from doctr.models import ocr_predictor
12
+ from torch.utils.data import DataLoader
13
+ from doctr.io import DocumentFile
14
+
15
+
16
+ import math
17
+ from typing import Tuple, Union
18
+
19
+ import cv2
20
+ import numpy as np
21
+ import os
22
+
23
+ from deskew import determine_skew
24
+
25
+
26
+
27
+
28
+ print(sys.version)
29
+ ocr = PaddleOCR(lang='en')
30
+ model = ocr_predictor(pretrained=True)
31
+
32
+ ocr = PaddleOCR(lang='en')
33
+
34
+
35
+
36
+ def find_surr_keys(unassigned_key, known_keys):
37
+ # Sort known keys
38
+ print(known_keys)
39
+ known_keys = sorted(known_keys)
40
+ # Initialize distances and closest keys
41
+ closest_keys = []
42
+ for k in known_keys:
43
+ closest_keys.append((abs(int(k) - int(unassigned_key)), k))
44
+ # Sort by distance
45
+ closest_keys.sort()
46
+ # Return the two closest known keys
47
+ if(closest_keys[0][1]<unassigned_key and closest_keys[0][1]>unassigned_key):
48
+ return [closest_keys[0][1], closest_keys[1][1]]
49
+ else:
50
+ raise ValueError(f"No closest keys found for unassigned key: {unassigned_key}")
51
+
52
+ def label_text(text):
53
+ # Define the two lists
54
+ list1 = ['t', 'r', 'u', 'T', 'R', 'U']
55
+ list2 = ['f', 'a', 'l', 's', 'F', 'A', 'L', 'S']
56
+
57
+ # Count the matches for each list
58
+ count1 = sum(text.count(char) for char in list1)
59
+ count2 = sum(text.count(char) for char in list2)
60
+
61
+ # Determine the label based on the counts
62
+ if count1 > count2:
63
+ return True
64
+ elif count1!=0 or count2!=0:
65
+ return False
66
+
67
+
68
+ def percentMatch(text1,text2):
69
+ list = ['t', 'r', 'u', 'T', 'R', 'U','f', 'a', 'l', 's', 'F', 'A', 'L', 'S']
70
+
71
+ if(text1):
72
+ count1 = sum(text1.count(char) for char in list)
73
+
74
+
75
+ count2 = sum(text2.count(char) for char in list)
76
+
77
+ if(count1==3 and count2==4 or count1==4 and count2==3 ): #if one says true and other says false then priority given to 2nd
78
+ print("true and false collision so given priority to text2 which is the incoming text")
79
+ return 2
80
+
81
+ if(count1>count2):
82
+ print("text1 i.e the prev text is the winner")
83
+ return 1
84
+ else:
85
+ print("text2 i.e the incoming text is the winner")
86
+ return 2
87
+ else:
88
+ print("text1 not there so text2 is the winner")
89
+ return 2
90
+
91
+ def count_true_false(d): #in a dictionary to check how many T/F are there.
92
+ true_count = sum(1 for v in d.values() if v is True)
93
+ false_count = sum(1 for v in d.values() if v is False)
94
+ return true_count, false_count
95
+
96
+ def merge_dicts(dict1, dict2):
97
+ true_count1, false_count1 = count_true_false(dict1)
98
+ true_count2, false_count2 = count_true_false(dict2)
99
+
100
+ if (true_count1 + false_count1) >= (true_count2 + false_count2):
101
+ final_dict = dict1.copy()
102
+ y_dirn_gap=False
103
+ else:
104
+ final_dict = dict2.copy()
105
+ y_dirn_gap=True
106
+
107
+ return final_dict,y_dirn_gap
108
+
109
+
110
+ def assign_true_false_or_unknown(true_list, false_list, question_dict,total_questions):
111
+ # Initialize the final dictionary
112
+ final_dict = {str(i): 'UNASSIGNED' for i in range(1, total_questions+1)}
113
+ unassigned_keys=[]
114
+ assigned_keys=[]
115
+
116
+ # Iterate over each question and its y-coordinate
117
+ for question, y in question_dict.items():
118
+ # compute diff with true list such that we sub t/f box from s/n box
119
+ # true_differences= [y - ty for ty in true_list]
120
+ # Compute absolute differences with true list
121
+ true_abs_differences = [abs(y - ty) for ty in true_list]
122
+ # Compute absolute differences with false list
123
+ # false_differences= [y - ty for ty in false_list]
124
+ false_abs_differences = [abs(y - fy) for fy in false_list]
125
+
126
+
127
+ # Find the minimum differences
128
+
129
+ # min_true_diff = min((diff for diff in true_differences if diff > 0), default=float('inf'))
130
+ # min_false_diff = min((diff for diff in false_differences if diff > 0), default=float('inf'))
131
+
132
+
133
+ min_true_abs_diff=min(true_abs_differences) if true_abs_differences else float('inf')
134
+ min_false_abs_diff=min(false_abs_differences) if false_abs_differences else float('inf')
135
+
136
+ # Determine the smallest difference
137
+ # min_diff = min(min_true_diff, min_false_diff)
138
+ min_abs_diff=min(min_true_abs_diff,min_false_abs_diff)
139
+
140
+
141
+ # Assign the value based on the smallest difference
142
+ # if min_diff < 360:
143
+ # if min_true_diff < min_false_diff:
144
+ # final_dict[question] = True
145
+ # true_list.pop(true_differences.index(min_true_diff))
146
+ # else:
147
+ # final_dict[question] = False
148
+ # false_list.pop(false_differences.index(min_false_diff))
149
+ # else:
150
+ # checking the abs diff option if nothing can find in positive diff option
151
+ if min_abs_diff < 300:
152
+ if min_true_abs_diff < min_false_abs_diff:
153
+ final_dict[question] = True
154
+ true_list.pop(true_abs_differences.index(min_true_abs_diff))
155
+ else:
156
+ final_dict[question] = False
157
+ false_list.pop(false_abs_differences.index(min_false_abs_diff))
158
+
159
+ else:
160
+ final_dict[question] = 'NULL'
161
+
162
+
163
+
164
+
165
+
166
+
167
+
168
+ return final_dict
169
+
170
+
171
+ def assign_true_false_or_unknown_rotated(true_list,false_list,true_list_x,false_list_x,question_dict,question_dict_x,total_questions):
172
+ final_dict = {str(i): 'UNASSIGNED' for i in range(1, total_questions+1)}
173
+ unassigned_keys=[]
174
+ assigned_keys=[]
175
+ final_dict_y={str(i): 'UNASSIGNED' for i in range(1, total_questions+1)}
176
+ final_dict_x={str(i): 'UNASSIGNED' for i in range(1, total_questions+1)}
177
+
178
+ # Iterate over each question and its y-coordinate
179
+ for question, y in question_dict.items():
180
+ # Compute absolute differences with true list
181
+ true_differences= [y - ty for ty in true_list]
182
+ true_abs_differences = [abs(y - ty) for ty in true_list]
183
+ # Compute absolute differences with false list
184
+ false_differences= [y - fy for fy in false_list]
185
+ false_abs_differences = [abs(y - fy) for fy in false_list]
186
+
187
+
188
+ # Find the minimum differences
189
+
190
+ min_true_diff = min((diff for diff in true_differences if diff > 0), default=float('inf'))
191
+ min_false_diff = min((diff for diff in false_differences if diff > 0), default=float('inf'))
192
+
193
+
194
+ min_true_abs_diff=min(true_abs_differences) if true_abs_differences else float('inf')
195
+ min_false_abs_diff=min(false_abs_differences) if false_abs_differences else float('inf')
196
+
197
+ # Determine the smallest difference
198
+ min_diff = min(min_true_diff, min_false_diff)
199
+ min_abs_diff=min(min_true_abs_diff,min_false_abs_diff)
200
+
201
+ # print("the question number is :",question)
202
+ # print("the min dist is :",min_diff)
203
+ # print("the min abs_diff is :",min_abs_diff)
204
+ # print("the false abs diff",false_abs_differences)
205
+
206
+
207
+
208
+ # Assign the value based on the smallest difference first going with abs diff as for upside down it will favour abs
209
+ if min_abs_diff < 310:
210
+ if min_true_abs_diff < min_false_abs_diff:
211
+ final_dict_y[question] = True
212
+ true_list.pop(true_abs_differences.index(min_true_abs_diff))
213
+ else:
214
+ final_dict_y[question] = False
215
+ false_list.pop(false_abs_differences.index(min_false_abs_diff))
216
+ else:
217
+ # checking the postive diff option if nothing can find in abs diff option
218
+ if min_diff < 310:
219
+ print(question)
220
+ if min_true_diff < min_false_diff:
221
+
222
+ final_dict_y[question] = True
223
+ true_list.pop(true_differences.index(min_true_diff))
224
+ else:
225
+ final_dict_y[question] = False
226
+ false_list.pop(false_differences.index(min_false_diff))
227
+
228
+ else:
229
+ final_dict_y[question] = 'NULL'
230
+
231
+
232
+
233
+
234
+ for question,x in question_dict_x.items():
235
+
236
+ # Compute absolute differences with true list
237
+ true_differences= [x - tx for tx in true_list_x]
238
+ true_abs_differences = [abs(x - tx) for tx in true_list_x]
239
+ # Compute absolute differences with false list
240
+ false_differences= [x - fy for fy in false_list_x]
241
+ false_abs_differences = [abs(x - fy) for fy in false_list_x]
242
+
243
+
244
+ # Find the minimum differences
245
+
246
+ min_true_diff = min((diff for diff in true_differences if diff > 0), default=float('inf'))
247
+ min_false_diff = min((diff for diff in false_differences if diff > 0), default=float('inf'))
248
+
249
+
250
+ min_true_abs_diff=min(true_abs_differences) if true_abs_differences else float('inf')
251
+ min_false_abs_diff=min(false_abs_differences) if false_abs_differences else float('inf')
252
+
253
+ # Determine the smallest difference
254
+ min_diff = min(min_true_diff, min_false_diff)
255
+ min_abs_diff=min(min_true_abs_diff,min_false_abs_diff)
256
+
257
+ if min_diff < 310:
258
+ if min_true_diff < min_false_diff:
259
+ final_dict_x[question] = True
260
+ true_list_x.pop(true_differences.index(min_true_diff))
261
+ else:
262
+ final_dict_x[question] = False
263
+ false_list_x.pop(false_differences.index(min_false_diff))
264
+ else:
265
+ # checking the abs diff option if nothing can find in positive diff option
266
+ if min_abs_diff < 310:
267
+ if min_true_abs_diff < min_false_abs_diff:
268
+ final_dict_x[question] = True
269
+ true_list_x.pop(true_abs_differences.index(min_true_abs_diff))
270
+ else:
271
+ final_dict_x[question] = False
272
+ false_list_x.pop(false_abs_differences.index(min_false_abs_diff))
273
+
274
+ else:
275
+ final_dict_x[question] = 'NULL'
276
+
277
+
278
+ print("the final dict for y is: ")
279
+ print(final_dict_y)
280
+ print("the final dict for x is: ")
281
+ print(final_dict_x)
282
+ final_dict,y_dirn_gap=merge_dicts(final_dict_x,final_dict_y)
283
+
284
+
285
+ if 'L' in final_dict:
286
+ final_dict['7']=final_dict['L']
287
+ del final_dict['L']
288
+
289
+ if 'I' in final_dict:
290
+ final_dict['1']=final_dict['I']
291
+ del final_dict['I']
292
+
293
+ if y_dirn_gap and '6' in final_dict and '9' in final_dict: #means image is inverted and 6 and 9 true and false value needs to swapped out
294
+ temp=final_dict['6']
295
+ final_dict['6']=final_dict['9']
296
+ final_dict['9']=temp
297
+
298
+
299
+ return final_dict
300
+
301
+ def process_using_paddleocr(image_path,output_folder,output_folder1,total_questions):
302
+
303
+ ocr = PaddleOCR(lang='en')
304
+ base_name = os.path.basename(image_path)
305
+ image_cv = cv2.imread(image_path)
306
+ print("!------------------------------start with paddleocr-----------------------------------!")
307
+ print("Started processing of the image :",base_name)
308
+
309
+ output = ocr.ocr(image_path)[0]
310
+
311
+
312
+
313
+ texts = [line[1][0] for line in output]
314
+
315
+
316
+
317
+
318
+
319
+ print("OCR detection done")
320
+
321
+ boxes = [line[0] for line in output]
322
+ # probabilities = [line[1][1] for line in output]
323
+
324
+
325
+
326
+ image_boxes = image_cv.copy()
327
+
328
+
329
+
330
+ # print("!------------------------------all coordinates-----------------------------------!")
331
+
332
+ for box,text in zip(boxes,texts):
333
+ cv2.rectangle(image_boxes,(int(box[0][0]),int(box[0][1])),(int(box[2][0]),int(box[2][1])),(0,0,255),5) #needs top left and bottom right to draw bounding box
334
+ cv2.putText(image_boxes,text,(int(box[0][0]),int(box[0][1])),cv2.FONT_HERSHEY_SIMPLEX,4,(222,0,0),3)
335
+
336
+
337
+
338
+
339
+
340
+
341
+ alldet_file_name = f'detect_{base_name}'
342
+ alldet_file_path = os.path.join(output_folder1, alldet_file_name)
343
+
344
+ # Save the processed image
345
+ cv2.imwrite(alldet_file_path, image_boxes)
346
+
347
+
348
+
349
+ for box, text in zip(boxes, texts):
350
+ if text=="SN" or text=="NS":
351
+ num_l_x1=box[0][0]
352
+ num_r_x1=box[2][0]+140
353
+ num_l_y1=box[0][1]
354
+ num_r_y1=box[2][1]+140
355
+ print("left top x of SN:",num_l_x1)
356
+ print("bottom right x of SN:",num_r_x1)
357
+ print("left top y of SN:",num_l_y1)
358
+ print("bottom right y of SN:",num_r_y1)
359
+
360
+
361
+
362
+
363
+ cons_boxes_image=image_cv.copy()
364
+ true_list=[]
365
+ false_list=[]
366
+
367
+ true_list_x=[]
368
+ false_list_x=[]
369
+
370
+
371
+ numbers_dict={}
372
+ numbers_dict_x={}
373
+ c=0
374
+ prev_x=0
375
+ prev_y=0
376
+
377
+
378
+ # this is for s/n column
379
+ try:
380
+ for box, text in zip(boxes, texts):
381
+ # print(f"the text is : {text}")
382
+
383
+
384
+ box_top_left_x = int(box[0][0])
385
+ box_top_left_y=int(box[0][1])
386
+ box_bottom_right_x = int(box[2][0])
387
+ box_bottom_right_y = int(box[2][1])
388
+ box_width_x = box_bottom_right_x - box_top_left_x
389
+ box_width_y = box_bottom_right_y - box_top_left_y
390
+ if (num_l_x1 <= box_bottom_right_x <= num_r_x1 or num_l_y1<= box_bottom_right_y<=num_r_y1) and box_width_x <= 200 and box_width_y <= 200 and text!="SN" and text!="NS":
391
+ # print("entered in the S/N column ")
392
+ # print(text)
393
+ # print(box)
394
+ numbers_dict[text] = int(box[0][1])
395
+ numbers_dict_x[text]=int(box[0][0])
396
+
397
+ cv2.rectangle(cons_boxes_image, (int(box[0][0]), int(box[0][1])), (int(box[2][0]), int(box[2][1])), (0, 0, 255), 5)
398
+ cv2.putText(cons_boxes_image, text, (int(box[0][0]), int(box[0][1])), cv2.FONT_HERSHEY_SIMPLEX, 4, (222, 0, 0), 1)
399
+
400
+
401
+
402
+
403
+
404
+
405
+
406
+
407
+
408
+
409
+
410
+
411
+ #error in detection of S/N column
412
+ except NameError:
413
+ print("cant detect s/n column also so going with all detection using box width")
414
+ c=0
415
+ for box,text in zip(boxes,texts):
416
+ box_top_left_x = int(box[0][0])
417
+ box_top_left_y=int(box[0][1])
418
+ box_bottom_right_x = int(box[2][0])
419
+ box_bottom_right_y = int(box[2][1])
420
+ box_width_x = box_bottom_right_x - box_top_left_x
421
+ box_width_y = box_bottom_right_y - box_top_left_y
422
+
423
+
424
+ if (box_width_x <= 80 and box_width_y <= 80):
425
+ if text.isdigit():
426
+ number = int(text)
427
+ if 1 <= number <= total_questions+1:
428
+ # Store in dictionaries only if the number is between 1 and 10
429
+ numbers_dict[text] = int(box[0][1])
430
+ numbers_dict_x[text] = int(box[0][0])
431
+
432
+ # Visualize the rectangle and text on the image (optional)
433
+ cv2.rectangle(cons_boxes_image, (int(box[0][0]), int(box[0][1])), (int(box[1][0]), int(box[1][1])), (0, 0, 255), 5)
434
+ cv2.putText(cons_boxes_image, text, (int(box[0][0]), int(box[0][1])), cv2.FONT_HERSHEY_SIMPLEX, 4, (222, 0, 0), 1)
435
+
436
+ if((box_width_x<=300 and box_width_y<=300) and ' ' not in text and label_text(text)==True):
437
+ if(c==0):
438
+ print("first t/f detection")
439
+ print(text)
440
+ print(box)
441
+ prev_y=box[0][1]
442
+ prev_x=box[0][0]
443
+ true_list.append(int(box[0][1]))
444
+ true_list_x.append(int(box[0][0]))
445
+
446
+ else:
447
+
448
+ if((abs(box[0][0]-prev_x)>160) or abs(box[0][1]-prev_y)>160):
449
+ print(text)
450
+ print(box)
451
+ true_list.append(int(box[0][1]))
452
+ true_list_x.append(int(box[0][0]))
453
+ prev_y=box[0][1]
454
+ prev_x=box[0][0]
455
+
456
+ c+=1
457
+
458
+ cv2.rectangle(cons_boxes_image,(int(box[0][0]),int(box[0][1])),(int(box[2][0]),int(box[2][1])),(0,0,255),5)
459
+ cv2.putText(cons_boxes_image,text,(int(box[0][0]),int(box[0][1])),cv2.FONT_HERSHEY_SIMPLEX,4,(222,0,0),1)
460
+
461
+ if((box_width_x<=300 and box_width_y<=300) and ' ' not in text and label_text(text)==False):
462
+ if(c==0):
463
+ print("first t/f detection")
464
+ print(text)
465
+ print(box)
466
+ prev_y=box[0][1]
467
+ prev_x=box[0][0]
468
+
469
+ false_list.append(int(box[0][1]))
470
+ false_list_x.append(int(box[0][0]))
471
+ else:
472
+
473
+ if((abs(box[0][0]-prev_x)>160) or abs(box[0][1]-prev_y)>160):
474
+ print(text)
475
+ print(box)
476
+ false_list.append(int(box[0][1]))
477
+ false_list_x.append(int(box[0][0]))
478
+ prev_y=box[0][1]
479
+ prev_x=box[0][0]
480
+
481
+ c+=1
482
+
483
+ cv2.rectangle(cons_boxes_image,(int(box[0][0]),int(box[0][1])),(int(box[2][0]),int(box[2][1])),(0,0,255),5)
484
+ cv2.putText(cons_boxes_image,text,(int(box[0][0]),int(box[0][1])),cv2.FONT_HERSHEY_SIMPLEX,4,(222,0,0),1)
485
+
486
+ print("the number dict is: ",numbers_dict)
487
+ print("the number dict x is: ",numbers_dict_x)
488
+ print("the true list is ",true_list)
489
+ print("the false list is ",false_list)
490
+ print("the true list for xdirn",true_list_x)
491
+ print("the false list for xdirn",false_list_x)
492
+
493
+ final_dict=assign_true_false_or_unknown_rotated(true_list,false_list,true_list_x,false_list_x,numbers_dict,numbers_dict_x,total_questions)
494
+ # Create a unique output file name
495
+ output_file_name = f'final_tf_{base_name}'
496
+ output_file_path = os.path.join(output_folder, output_file_name)
497
+
498
+ # Save the processed image
499
+ cv2.imwrite(output_file_path, cons_boxes_image)
500
+
501
+
502
+
503
+
504
+ return final_dict
505
+
506
+
507
+
508
+
509
+
510
+ def rotate(
511
+ image: np.ndarray, angle: float, background: Union[int, Tuple[int, int, int]]
512
+ ) -> np.ndarray:
513
+ old_width, old_height = image.shape[:2]
514
+ angle_radian = math.radians(angle)
515
+ width = abs(np.sin(angle_radian) * old_height) + abs(np.cos(angle_radian) * old_width)
516
+ height = abs(np.sin(angle_radian) * old_width) + abs(np.cos(angle_radian) * old_height)
517
+
518
+ image_center = tuple(np.array(image.shape[1::-1]) / 2)
519
+ rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
520
+ rot_mat[1, 2] += (width - old_width) / 2
521
+ rot_mat[0, 2] += (height - old_height) / 2
522
+ return cv2.warpAffine(image, rot_mat, (int(round(height)), int(round(width))), borderValue=background)
523
+
524
+ def process_using_doctr_less_row_gap(boxes,texts,numbers_dict,num_l_x2,num_r_x2,image_path,total_questions):
525
+ print("the number dict in low gap",numbers_dict)
526
+ cons_boxes_image = cv2.imread(image_path)
527
+ true_list=[]
528
+ false_list=[]
529
+ c=0
530
+ print("starting with low row gap")
531
+
532
+ try:
533
+ for box, text in zip(boxes, texts):
534
+ box_bottom_right_x = int(box[1][0])
535
+
536
+
537
+
538
+
539
+ # Draw the adjusted bounding box
540
+ if (num_l_x2 <= box_bottom_right_x <= num_r_x2):
541
+ # print("entered in the t/f column ")
542
+
543
+ if label_text(text)==True and text!='TRUE/FALSE':
544
+ if(c==0):
545
+ print("first t/f detection")
546
+ print(text)
547
+ print(box)
548
+ prev=box[0][1]
549
+ prev_text=text
550
+ true_list.append(int(box[0][1]))
551
+ else:
552
+
553
+ if(abs(box[0][1]-prev)>20): #to avoid boxes in same row to overlap
554
+ print(text)
555
+ print(box)
556
+ true_list.append(int(box[0][1]))
557
+ prev=box[0][1]
558
+ prev_text=text
559
+ else:
560
+ print(f"collision happend with box:{prev} and text:{prev_text} solving on the basis of percent match boxes")
561
+ print("the current box specification are")
562
+ print(text)
563
+ print(box)
564
+ ans=percentMatch(prev_text,text)
565
+ if(ans==2):
566
+
567
+ if(label_text(prev_text)==False):
568
+ false_list.pop()
569
+
570
+ elif(label_text(prev_text)==True):
571
+ true_list.pop()
572
+
573
+
574
+ prev=box[0][1]
575
+ prev_text=text
576
+ true_list.append(int(prev))
577
+
578
+
579
+
580
+
581
+ c+=1
582
+
583
+ elif label_text(text)==False and text!='TRUE/FALSE':
584
+ if(c==0):
585
+ print("first t/f detection")
586
+ print(text)
587
+ print(box)
588
+ prev=box[0][1]
589
+ prev_text=text
590
+ false_list.append(int(box[0][1]))
591
+ else:
592
+ if(abs(box[0][1]-prev)>20):
593
+ print(text)
594
+ print(box)
595
+ false_list.append(int(box[0][1]))
596
+ prev=box[0][1]
597
+ prev_text=text
598
+ else:
599
+ print(f"collision happend with box:{prev} and text:{prev_text} solving on the basis of percent match boxes")
600
+ print("the current box specification are")
601
+ print(text)
602
+ print(box)
603
+ ans=percentMatch(prev_text,text)
604
+
605
+ if(ans==2):
606
+
607
+ if(label_text(prev_text)==False):
608
+ false_list.pop()
609
+
610
+ elif(label_text(prev_text)==True):
611
+ true_list.pop()
612
+
613
+
614
+ prev=box[0][1]
615
+ prev_text=text
616
+ false_list.append(int(prev))
617
+ c+=1
618
+
619
+ cv2.rectangle(cons_boxes_image,(int(box[0][0]),int(box[0][1])),(int(box[1][0]),int(box[1][1])),(0,0,255),5)
620
+ cv2.putText(cons_boxes_image,text,(int(box[0][0]),int(box[0][1])),cv2.FONT_HERSHEY_SIMPLEX,1,(222,0,0),1)
621
+
622
+
623
+
624
+
625
+ final_dict=assign_true_false_or_unknown(true_list,false_list,numbers_dict,total_questions)
626
+
627
+ return cons_boxes_image,final_dict
628
+ except Exception as e:
629
+ print("error occured")
630
+ print(e)
631
+
632
+
633
+ def process_and_save_image(image_path,actual_ans_csv ,output_folder , output_folder1):
634
+
635
+ base_name = os.path.basename(image_path)
636
+ image_cv = cv2.imread(image_path)
637
+ height = image_cv.shape[0]
638
+ width = image_cv.shape[1]
639
+ print("!------------------------------starting detection using doctr-----------------------------------!")
640
+ print("Started processing of the image :",base_name)
641
+ # print(image_width)
642
+ # output = ocr.ocr(image_path)[0]
643
+
644
+ # checking if header is there
645
+ with open(actual_ans_csv, 'r') as file:
646
+ first_line = file.readline().strip()
647
+
648
+
649
+ # Check if the first column of the first line is numeric
650
+ first_column_numeric = False
651
+ try:
652
+ first_value = float(first_line.split(',')[0]) # Assuming comma-separated values
653
+ first_column_numeric = True
654
+ except ValueError:
655
+ pass # If the first column cannot be converted to a float, it's not numeric
656
+
657
+
658
+ # Read the CSV file based on the condition
659
+ if first_column_numeric:
660
+ actualAns_df = pd.read_csv(actual_ans_csv, header=None)
661
+ else:
662
+ actualAns_df = pd.read_csv(actual_ans_csv)
663
+
664
+ total_questions = len(actualAns_df)
665
+
666
+ #checking skewness
667
+ grayscale = cv2.cvtColor(image_cv, cv2.COLOR_BGR2GRAY)
668
+ angle = determine_skew(grayscale)
669
+ image_cv = rotate(image_cv, angle, (0, 0, 0))
670
+ cv2.imwrite(image_path, image_cv)
671
+
672
+
673
+ single_img_doc = DocumentFile.from_images(image_path)
674
+ result = model(single_img_doc)
675
+
676
+
677
+
678
+
679
+
680
+
681
+ texts=[]
682
+
683
+ for page in result.pages:
684
+ for block in page.blocks:
685
+ for line in block.lines:
686
+ for word in line.words:
687
+ text = word.value
688
+ texts.append(text)
689
+
690
+
691
+
692
+
693
+ #checking for rotation
694
+ r_count=0
695
+
696
+ while('TRUE/FALSE' not in texts):
697
+ image_cv = cv2.rotate(image_cv, cv2.ROTATE_90_CLOCKWISE)
698
+ print("rotation started")
699
+
700
+
701
+ # Save the rotated image to a temporary path
702
+ # temp_image_path = 'temp_rotated_image.jpg'
703
+ cv2.imwrite(image_path, image_cv)
704
+
705
+ # output=ocr.ocr(temp_image_path)[0]
706
+ single_img_doc = DocumentFile.from_images(image_path)
707
+ result=model(single_img_doc)
708
+ texts=[]
709
+ for page in result.pages:
710
+ for block in page.blocks:
711
+ for line in block.lines:
712
+ for word in line.words:
713
+ text = word.value
714
+ texts.append(text)
715
+
716
+ print(texts)
717
+ r_count+=1
718
+ if r_count==4: #reaching the same orientation
719
+ break
720
+
721
+
722
+
723
+ if(r_count>0 and r_count!=4):
724
+ # cv2.imwrite(image_path,image_cv)
725
+ print("rotation done for: ",base_name)
726
+ print("Number of times rotation done:",r_count)
727
+
728
+ height = image_cv.shape[0]
729
+ width = image_cv.shape[1]
730
+
731
+ print("OCR detection done with doctr")
732
+ boxes=[]
733
+ # boxes = [line[0] for line in output]4
734
+ for page in result.pages:
735
+ for block in page.blocks:
736
+ for line in block.lines:
737
+ for word in line.words:
738
+
739
+ (x_min, y_min), (x_max, y_max) = word.geometry
740
+
741
+ x_min_px = x_min * width
742
+ y_min_px = y_min * height
743
+ x_max_px = x_max * width
744
+ y_max_px = y_max * height
745
+
746
+ bbox=(x_min_px, y_min_px), (x_max_px, y_max_px)
747
+
748
+
749
+ boxes.append(bbox)
750
+
751
+ image_boxes = image_cv.copy()
752
+
753
+
754
+
755
+ # print("!------------------------------all coordinates-----------------------------------!")
756
+
757
+ for box,text in zip(boxes,texts):
758
+ # print(text)
759
+ # print(box)
760
+ cv2.rectangle(image_boxes,(int(box[0][0]),int(box[0][1])),(int(box[1][0]),int(box[1][1])),(0,0,255),5) #needs top left and bottom right to draw bounding box
761
+ cv2.putText(image_boxes,text,(int(box[0][0]),int(box[0][1])),cv2.FONT_HERSHEY_SIMPLEX,4,(222,0,0),3)
762
+
763
+
764
+ # print("!------------------------------done with all coordinates-----------------------------------!")
765
+
766
+
767
+
768
+ alldet_file_name = f'detect_{base_name}'
769
+ alldet_file_path = os.path.join(output_folder1, alldet_file_name)
770
+
771
+ # Save the processed image
772
+ cv2.imwrite(alldet_file_path, image_boxes)
773
+
774
+
775
+
776
+ for box, text in zip(boxes, texts):
777
+ if text=="SN" or text=="NS":
778
+ num_l_x1=box[0][0]-100
779
+ num_r_x1=box[1][0]+140
780
+
781
+ print("left top x of SN:",num_l_x1)
782
+ print("bottom right x of SN:",num_r_x1)
783
+
784
+
785
+ if text=="TRUE/FALSE":
786
+ num_l_x2=box[0][0]-10
787
+ num_r_x2=box[1][0]+200
788
+
789
+
790
+ print("left top x of T/F:",num_l_x2)
791
+ print("bottom right x of T/F:",num_r_x2)
792
+
793
+
794
+
795
+
796
+
797
+
798
+
799
+ # Draw OCR bounding boxes within the final rectangle
800
+ cons_boxes_image=image_cv.copy()
801
+ true_list=[]
802
+ false_list=[]
803
+
804
+
805
+
806
+ numbers_dict={}
807
+ numbers_dict_x={}
808
+ c=0
809
+
810
+
811
+ no_of_collisions=0
812
+
813
+ try:
814
+
815
+ # this is for s/n column
816
+ for box, text in zip(boxes, texts):
817
+ # print(f"the text is : {text}")
818
+
819
+
820
+ box_top_left_x = int(box[0][0])
821
+ box_top_left_y=int(box[0][1])
822
+ box_bottom_right_x = int(box[1][0])
823
+ box_bottom_right_y = int(box[1][1])
824
+
825
+
826
+
827
+ # print(box_bottom_right_x)
828
+ # print(box_bottom_right_y)
829
+ # print(box_width_x)
830
+ # print(box_width_y)
831
+
832
+
833
+
834
+ if (num_l_x1 <= box_bottom_right_x <= num_r_x1 ):
835
+ if text.isdigit():
836
+ number = int(text)
837
+ if 1 <= number <= total_questions+1:
838
+ # Store in dictionaries only if the number is between 1 and 10
839
+ numbers_dict[text] = int(box[0][1])
840
+ print(text)
841
+ print(box)
842
+ # Visualize the rectangle and text on the image (optional)
843
+ cv2.rectangle(cons_boxes_image, (int(box[0][0]), int(box[0][1])), (int(box[1][0]), int(box[1][1])), (0, 0, 255), 5)
844
+ cv2.putText(cons_boxes_image, text, (int(box[0][0]), int(box[0][1])), cv2.FONT_HERSHEY_SIMPLEX, 1, (222, 0, 0), 1)
845
+
846
+
847
+
848
+
849
+
850
+
851
+
852
+
853
+
854
+
855
+ prev=0
856
+
857
+
858
+
859
+ for box, text in zip(boxes, texts):
860
+
861
+
862
+
863
+ box_bottom_right_x = int(box[1][0])
864
+
865
+ if(no_of_collisions>4):
866
+ break
867
+
868
+ # Draw the adjusted bounding box
869
+ if (num_l_x2 <= box_bottom_right_x <= num_r_x2):
870
+ # print("entered in the t/f column ")
871
+
872
+ if label_text(text)==True and text!='TRUE/FALSE':
873
+ if(c==0):
874
+ print("first t/f detection")
875
+ print(text)
876
+ print(box)
877
+ prev=box[0][1]
878
+ prev_text=text
879
+ true_list.append(int(box[0][1]))
880
+ else:
881
+
882
+ if(abs(box[0][1]-prev)>200): #to avoid boxes in same row to overlap
883
+ print(text)
884
+ print(box)
885
+ true_list.append(int(box[0][1]))
886
+ prev=box[0][1]
887
+ prev_text=text
888
+ else:
889
+ print(f"collision happend with box:{prev} and text:{prev_text} solving on the basis of percent match boxes")
890
+ print("the current box specification are")
891
+ print(text)
892
+ print(box)
893
+ no_of_collisions+=1
894
+ ans=percentMatch(prev_text,text)
895
+ if(ans==2):
896
+
897
+ if(label_text(prev_text)==False):
898
+ false_list.pop()
899
+
900
+ elif(label_text(prev_text)==True):
901
+ true_list.pop()
902
+
903
+
904
+ prev=box[0][1]
905
+ prev_text=text
906
+ true_list.append(int(prev))
907
+
908
+
909
+
910
+
911
+ c+=1
912
+
913
+ elif label_text(text)==False and text!='TRUE/FALSE':
914
+ if(c==0):
915
+ print("first t/f detection")
916
+ print(text)
917
+ print(box)
918
+ prev=box[0][1]
919
+ prev_text=text
920
+ false_list.append(int(box[0][1]))
921
+ else:
922
+ if(abs(box[0][1]-prev)>200):
923
+ print(text)
924
+ print(box)
925
+ false_list.append(int(box[0][1]))
926
+ prev=box[0][1]
927
+ prev_text=text
928
+ else:
929
+ print(f"collision happend with box:{prev} and text:{prev_text} solving on the basis of percent match boxes")
930
+ print("the current box specification are")
931
+ print(text)
932
+ print(box)
933
+ no_of_collisions+=1
934
+ ans=percentMatch(prev_text,text)
935
+
936
+ if(ans==2):
937
+
938
+ if(label_text(prev_text)==False):
939
+ false_list.pop()
940
+
941
+ elif(label_text(prev_text)==True):
942
+ true_list.pop()
943
+
944
+
945
+ prev=box[0][1]
946
+ prev_text=text
947
+ false_list.append(int(prev))
948
+ c+=1
949
+
950
+ cv2.rectangle(cons_boxes_image,(int(box[0][0]),int(box[0][1])),(int(box[1][0]),int(box[1][1])),(0,0,255),5)
951
+ cv2.putText(cons_boxes_image,text,(int(box[0][0]),int(box[0][1])),cv2.FONT_HERSHEY_SIMPLEX,1,(222,0,0),1)
952
+
953
+
954
+ if(no_of_collisions<=4):
955
+ final_dict=assign_true_false_or_unknown(true_list,false_list,numbers_dict,total_questions)
956
+
957
+ else:
958
+ print("going with doctr less gap")
959
+ cons_boxes_image,final_dict=process_using_doctr_less_row_gap(boxes,texts,numbers_dict,num_l_x2,num_r_x2,image_path,total_questions)
960
+
961
+
962
+
963
+ # Create a unique output file name
964
+ output_file_name = f'final_tf_{base_name}'
965
+ output_file_path = os.path.join(output_folder, output_file_name)
966
+
967
+ # Save the processed image
968
+ cv2.imwrite(output_file_path, cons_boxes_image)
969
+
970
+
971
+ print("printing the number dict y_coordinate")
972
+ print(numbers_dict)
973
+
974
+
975
+
976
+
977
+
978
+ except NameError:
979
+
980
+ print("TRUE/FALSE not detected. Skipping this part of processing.")
981
+ print("going with paddleocr")
982
+
983
+ final_dict=process_using_paddleocr(image_path,output_folder,output_folder1,total_questions)
984
+
985
+
986
+
987
+
988
+
989
+
990
+
991
+
992
+
993
+
994
+
995
+
996
+ print("--------- Printing the final dict ------------")
997
+ print(final_dict)
998
+
999
+ df=pd.DataFrame(final_dict.items(),columns=['Q_No.','True/False'])
1000
+
1001
+
1002
+ # predcsv_file_name = f'answers_{base_name}.csv'
1003
+
1004
+ # predcsv_file_path = os.path.join(output_folder, predcsv_file_name)
1005
+ # df.to_csv(predcsv_file_path,index=False)
1006
+
1007
+
1008
+ # print(f'DataFrame saved to {predcsv_file_path}')
1009
+
1010
+
1011
+
1012
+
1013
+
1014
+
1015
+
1016
+
1017
+
1018
+ # predictions_file_path='pred_output.csv'
1019
+ # reading the answers and evaluting
1020
+
1021
+
1022
+ marks=0
1023
+ w_ans=[]
1024
+ m_ans=[]
1025
+
1026
+ for index, row in actualAns_df.iterrows():
1027
+ question_number = str(row.iloc[0]) # Accessing the first column by index
1028
+ answer = row.iloc[1] # Accessing the second column by index
1029
+ # print(answer)
1030
+ if final_dict[question_number]==answer:
1031
+ marks += 1
1032
+ elif final_dict[question_number] not in ("NULL", "UNASSIGNED"):
1033
+ w_ans.append(question_number)
1034
+ else:
1035
+ m_ans.append(question_number)
1036
+
1037
+
1038
+ print("Total Marks:", marks)
1039
+
1040
+ image_name = base_name #Replace this with the actual image name
1041
+ marks_df = pd.DataFrame({"Filename": [image_name], "Marks": [marks]})
1042
+
1043
+ # Append the marks DataFrame to the predictions file
1044
+ # marks_df.to_csv(predictions_file_path, mode='a', header=False, index=False)
1045
+ output_text = f"Marks: {marks} out of {total_questions}"
1046
+
1047
+ if w_ans:
1048
+ output_text += f" and the following were wrong_answers: {w_ans}"
1049
+
1050
+ if m_ans and w_ans:
1051
+ output_text += f" and missed_questions: {m_ans}"
1052
+
1053
+ if m_ans and len(w_ans)==0:
1054
+ output_text += f" and the following were missed_answers: {m_ans}"
1055
+
1056
+ print(output_text)
1057
+
1058
+ return output_text
1059
+
1060
+
1061
+
1062
+ import gradio as gr
1063
+
1064
+
1065
+ output_folder = "test_gradio/output"
1066
+ output_folder1 = "test_gradio/detection"
1067
+
1068
+ # actual_ans_csv = "test_gradio/ModelAnswer.csv"
1069
+
1070
+ demo_image_paths = [
1071
+ "test_gradio/samples/1zHXQVK.jpg",
1072
+ "test_gradio/samples/9X9qVWN.jpg",
1073
+ "test_gradio/samples/LRccyJJ.jpg"
1074
+
1075
+
1076
+ ]
1077
+
1078
+ demo_csv_path = "test_gradio/answerKey.csv"
1079
+
1080
+ # Define the Gradio interface
1081
+ demo = gr.Interface(
1082
+ fn=lambda img_path, csv_path: process_and_save_image(img_path, csv_path, output_folder, output_folder1),
1083
+ inputs=[gr.Image(type='filepath',label="Upload Image of your answer_sheet"),
1084
+ gr.File(type='filepath',label="Upload the Answer Key in csv file")],
1085
+ outputs=[gr.Textbox(label=f"Predicted Marks")],
1086
+ title="AutoEval for True/False AnswerSheet",
1087
+ examples=[
1088
+ [demo_image_paths[0], demo_csv_path],
1089
+ [demo_image_paths[1], demo_csv_path],
1090
+ [demo_image_paths[2], demo_csv_path]
1091
+ ]
1092
+ )
1093
+
1094
+ # Launch the Gradio app
1095
+ demo.launch()