Spaces:
Sleeping
Sleeping
pawandev
commited on
Commit
·
6368900
1
Parent(s):
37c2aa4
Added PanOCR refined code to do Pan Card ocr
Browse files- .gitignore +3 -1
- app/__init__.py +1 -1
- app/routes/panApi.py +3 -1
- app/services/panServices/panDataExtractor.py +11 -10
- app/services/panServices/panOcr.py +27 -13
.gitignore
CHANGED
@@ -1,2 +1,4 @@
|
|
1 |
env
|
2 |
-
.env
|
|
|
|
|
|
1 |
env
|
2 |
+
.env
|
3 |
+
*.pyc
|
4 |
+
*.DS_Store
|
app/__init__.py
CHANGED
@@ -10,7 +10,7 @@ def create_app():
|
|
10 |
# Load model once
|
11 |
app.models = {
|
12 |
'adhaarModel': YOLO('models/aadhaarYolov8.pt'),
|
13 |
-
'panModel': YOLO('models/
|
14 |
}
|
15 |
|
16 |
return app
|
|
|
10 |
# Load model once
|
11 |
app.models = {
|
12 |
'adhaarModel': YOLO('models/aadhaarYolov8.pt'),
|
13 |
+
'panModel': YOLO('models/PanModal_v3.pt') # Load additional models as needed
|
14 |
}
|
15 |
|
16 |
return app
|
app/routes/panApi.py
CHANGED
@@ -55,7 +55,9 @@ def ocrPan(mode, session):
|
|
55 |
# Run detection
|
56 |
model = current_app.models.get('panModel')
|
57 |
results = model.predict(source=img, save=False)
|
|
|
58 |
extracted_data = process_results(results, img)
|
|
|
59 |
|
60 |
if extracted_data.get('statusCode') == 400:
|
61 |
return jsonify(extracted_data), 400
|
@@ -67,4 +69,4 @@ def ocrPan(mode, session):
|
|
67 |
return jsonify({"error": "Unable to identify image format."}), 400
|
68 |
except Exception as e:
|
69 |
current_app.logger.error(f"Unexpected error: {str(e)}")
|
70 |
-
return jsonify({"error": "An unexpected error occurred."}), 500
|
|
|
55 |
# Run detection
|
56 |
model = current_app.models.get('panModel')
|
57 |
results = model.predict(source=img, save=False)
|
58 |
+
# print(results,"model result")
|
59 |
extracted_data = process_results(results, img)
|
60 |
+
# print(extracted_data, "extracted data")
|
61 |
|
62 |
if extracted_data.get('statusCode') == 400:
|
63 |
return jsonify(extracted_data), 400
|
|
|
69 |
return jsonify({"error": "Unable to identify image format."}), 400
|
70 |
except Exception as e:
|
71 |
current_app.logger.error(f"Unexpected error: {str(e)}")
|
72 |
+
return jsonify({"error": "An unexpected error occurred on api call."}), 500
|
app/services/panServices/panDataExtractor.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
import re
|
2 |
|
3 |
def extract_panData(data):
|
4 |
-
unwanted_words = ["Name","/Name",
|
|
|
5 |
|
6 |
# Clean the array by removing unwanted words and invalid entries
|
7 |
cleaned_data = []
|
@@ -24,30 +25,30 @@ def extract_panData(data):
|
|
24 |
}
|
25 |
|
26 |
# Check and extract PAN number
|
27 |
-
print(cleaned_data)
|
28 |
pan_pattern = re.compile(r'^[A-Z]{5}[0-9]{4}[A-Z]$')
|
29 |
-
if len(cleaned_data) > 0 and pan_pattern.match(cleaned_data[
|
30 |
-
result["data"]["panNo"] = cleaned_data[
|
31 |
else:
|
32 |
result["data"]["panNo"] = ''
|
33 |
|
34 |
# Check and extract name
|
35 |
name_pattern = re.compile(r'^[A-Za-z .]+$')
|
36 |
-
if len(cleaned_data) > 1 and name_pattern.match(cleaned_data[
|
37 |
-
result["data"]["name"] = cleaned_data[
|
38 |
else:
|
39 |
result["data"]["name"] = ''
|
40 |
|
41 |
# Check and extract father's name
|
42 |
-
if len(cleaned_data) > 2 and name_pattern.match(cleaned_data[
|
43 |
-
result["data"]["fatherName"] = cleaned_data[
|
44 |
else:
|
45 |
result["data"]["fatherName"] = ''
|
46 |
|
47 |
# Check and extract date of birth
|
48 |
dob_pattern = re.compile(r'^\d{2}[-/]\d{2}[-/]\d{4}$')
|
49 |
-
if len(cleaned_data) > 3 and dob_pattern.match(cleaned_data[
|
50 |
-
result["data"]["dob"] = cleaned_data[
|
51 |
else:
|
52 |
result["data"]["dob"] = ''
|
53 |
|
|
|
1 |
import re
|
2 |
|
3 |
def extract_panData(data):
|
4 |
+
unwanted_words = ["Name","/Name",'Permanent', 'Account', 'Number', 'Card', 'नाम', '/Name',
|
5 |
+
"पिता का नाम",'नाम / Name', "पिता का नाम/ Father's Name", 'नाम /Name',"पिता का नाम / Father's Name", 'जन्म का वाराज़', 'Date of Birth', 'Permanent Account Number Card', "Date of Birth", "/Date of Birth", "Permanent Account Number", "Father's Name", "14 /Name", "/Father's Name"]
|
6 |
|
7 |
# Clean the array by removing unwanted words and invalid entries
|
8 |
cleaned_data = []
|
|
|
25 |
}
|
26 |
|
27 |
# Check and extract PAN number
|
28 |
+
print(cleaned_data, "cleaned data")
|
29 |
pan_pattern = re.compile(r'^[A-Z]{5}[0-9]{4}[A-Z]$')
|
30 |
+
if len(cleaned_data) > 0 and pan_pattern.match(cleaned_data[0]):
|
31 |
+
result["data"]["panNo"] = cleaned_data[0]
|
32 |
else:
|
33 |
result["data"]["panNo"] = ''
|
34 |
|
35 |
# Check and extract name
|
36 |
name_pattern = re.compile(r'^[A-Za-z .]+$')
|
37 |
+
if len(cleaned_data) > 1 and name_pattern.match(cleaned_data[1]):
|
38 |
+
result["data"]["name"] = cleaned_data[1]
|
39 |
else:
|
40 |
result["data"]["name"] = ''
|
41 |
|
42 |
# Check and extract father's name
|
43 |
+
if len(cleaned_data) > 2 and name_pattern.match(cleaned_data[2]):
|
44 |
+
result["data"]["fatherName"] = cleaned_data[2]
|
45 |
else:
|
46 |
result["data"]["fatherName"] = ''
|
47 |
|
48 |
# Check and extract date of birth
|
49 |
dob_pattern = re.compile(r'^\d{2}[-/]\d{2}[-/]\d{4}$')
|
50 |
+
if len(cleaned_data) > 3 and dob_pattern.match(cleaned_data[3]):
|
51 |
+
result["data"]["dob"] = cleaned_data[3]
|
52 |
else:
|
53 |
result["data"]["dob"] = ''
|
54 |
|
app/services/panServices/panOcr.py
CHANGED
@@ -2,41 +2,55 @@ from io import BytesIO
|
|
2 |
from ...utils.azureOCR import analyze_image
|
3 |
from ...utils.imageUtils import resize_if_needed, all_cropped_images_to_one_image
|
4 |
from .panDataExtractor import extract_panData
|
|
|
5 |
|
6 |
def process_results(results, img):
|
7 |
-
label_indices = {"
|
8 |
confidence_threshold = 0.3
|
9 |
input_image_format = img.format if img.format else "PNG"
|
10 |
valid_formats = ["JPEG", "PNG", "BMP", "GIF", "TIFF"]
|
11 |
input_image_format = input_image_format if input_image_format in valid_formats else "PNG"
|
12 |
|
13 |
-
|
|
|
14 |
precision_data = {label: {"correct": 0, "total": 0} for label in label_indices.keys()}
|
15 |
-
# extracted_data = {"pan_num": "", "name": "", "father": "", "dob": ""}
|
16 |
|
17 |
for result in results:
|
18 |
for bbox, cls, conf in zip(result.boxes.xyxy, result.boxes.cls, result.boxes.conf):
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
20 |
print(label, conf)
|
21 |
if conf < confidence_threshold:
|
22 |
continue
|
23 |
-
|
24 |
x1, y1, x2, y2 = map(int, bbox.tolist())
|
25 |
crop_img = img.crop((x1, y1, x2, y2))
|
26 |
crop_img = resize_if_needed(crop_img)
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
# Sort the images by their label indices in ascending order
|
33 |
cropped_images_with_labels.sort(key=lambda x: x[1])
|
34 |
print(cropped_images_with_labels, "cropped images with labels")
|
|
|
|
|
|
|
|
|
35 |
# Extract only the images for concatenation
|
36 |
cropped_images = [img for img, _, _ in cropped_images_with_labels]
|
37 |
-
# print(cropped_images, "cropped images")
|
38 |
-
if not cropped_images:
|
39 |
-
raise ValueError("No images were cropped.")
|
40 |
|
41 |
final_image = all_cropped_images_to_one_image(cropped_images, separator_image_path='app/utils/seprator3.png')
|
42 |
buffer = BytesIO()
|
@@ -49,4 +63,4 @@ def process_results(results, img):
|
|
49 |
texts = [line['text'] for line in lines]
|
50 |
print(texts, "text after microsoft ocr")
|
51 |
extracted_data = extract_panData(texts)
|
52 |
-
return extracted_data
|
|
|
2 |
from ...utils.azureOCR import analyze_image
|
3 |
from ...utils.imageUtils import resize_if_needed, all_cropped_images_to_one_image
|
4 |
from .panDataExtractor import extract_panData
|
5 |
+
from collections import defaultdict
|
6 |
|
7 |
def process_results(results, img):
|
8 |
+
label_indices = {"pan_num": 0, "name": 1, "father": 2, "dob": 3}
|
9 |
confidence_threshold = 0.3
|
10 |
input_image_format = img.format if img.format else "PNG"
|
11 |
valid_formats = ["JPEG", "PNG", "BMP", "GIF", "TIFF"]
|
12 |
input_image_format = input_image_format if input_image_format in valid_formats else "PNG"
|
13 |
|
14 |
+
best_crops = {label: (None, -1) for label in label_indices.keys()} # Store best (image, confidence) pairs
|
15 |
+
|
16 |
precision_data = {label: {"correct": 0, "total": 0} for label in label_indices.keys()}
|
|
|
17 |
|
18 |
for result in results:
|
19 |
for bbox, cls, conf in zip(result.boxes.xyxy, result.boxes.cls, result.boxes.conf):
|
20 |
+
# Ensure the class index is within the bounds of the label list
|
21 |
+
if int(cls) >= len(label_indices):
|
22 |
+
print(f"Warning: Class index {cls} is out of range. Skipping this bbox.")
|
23 |
+
continue
|
24 |
+
|
25 |
+
label = list(label_indices.keys())[int(cls)]
|
26 |
print(label, conf)
|
27 |
if conf < confidence_threshold:
|
28 |
continue
|
29 |
+
|
30 |
x1, y1, x2, y2 = map(int, bbox.tolist())
|
31 |
crop_img = img.crop((x1, y1, x2, y2))
|
32 |
crop_img = resize_if_needed(crop_img)
|
33 |
+
crop_img.save(f"temp_{label}.png")
|
34 |
+
|
35 |
+
# Replace old crop if new one has higher confidence
|
36 |
+
_, best_conf = best_crops[label]
|
37 |
+
if conf > best_conf:
|
38 |
+
best_crops[label] = (crop_img, conf)
|
39 |
+
precision_data[label]["total"] += 1
|
40 |
+
precision_data[label]["correct"] += 1 # Replace with actual OCR validation check
|
41 |
+
|
42 |
+
# Extract the images for final processing
|
43 |
+
cropped_images_with_labels = [(img, label_indices[label], conf) for label, (img, conf) in best_crops.items() if img is not None]
|
44 |
|
45 |
# Sort the images by their label indices in ascending order
|
46 |
cropped_images_with_labels.sort(key=lambda x: x[1])
|
47 |
print(cropped_images_with_labels, "cropped images with labels")
|
48 |
+
|
49 |
+
if not cropped_images_with_labels:
|
50 |
+
raise ValueError("No images were cropped.")
|
51 |
+
|
52 |
# Extract only the images for concatenation
|
53 |
cropped_images = [img for img, _, _ in cropped_images_with_labels]
|
|
|
|
|
|
|
54 |
|
55 |
final_image = all_cropped_images_to_one_image(cropped_images, separator_image_path='app/utils/seprator3.png')
|
56 |
buffer = BytesIO()
|
|
|
63 |
texts = [line['text'] for line in lines]
|
64 |
print(texts, "text after microsoft ocr")
|
65 |
extracted_data = extract_panData(texts)
|
66 |
+
return extracted_data
|