File size: 6,767 Bytes
6498fe6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | import cv2
import time
import re
from PIL import Image
from DetecInfoBoxes.GetBoxes import Detect
from util import correct_skew
from config import opt
get_dictionary = Detect(opt)
class ReadInfo:
def __init__(self, imgsz, stride, device, half, model, names, ocr_predictor):
self.imgsz = imgsz
self.stride = stride
self.device = device
self.half = half
self.model = model
self.names = names
self.opt = opt
self.ocrPredictor = ocr_predictor
@staticmethod
def get_the_most_confident_bbox(page_boxes: dict):
for key in page_boxes:
value = page_boxes.get(key)
if value:
value = sorted(value, key=lambda item: item[4])
page_boxes.update({key: [value[-1]]})
return page_boxes
@staticmethod
def arrange_info(infos: list):
sorted_infos = sorted(infos, key=lambda item: item[1])
return sorted_infos
def ocr_info(self, img, info: list):
x_min = info[0] - int(int(info[2]) / 2)
y_min = info[1] - int(int(info[3]) / 2)
w = info[2]
h = info[3]
crop_img = img[max(0, y_min):y_min + h, max(0, x_min):x_min + w]
crop_img_rgb = cv2.cvtColor(crop_img, cv2.COLOR_BGR2RGB)
image_pill = Image.fromarray(crop_img_rgb)
text = self.ocrPredictor.predict(image_pill)
return text
def get_all_info(self, img_path):
"""
Đọc MẶT TRƯỚC CCCD sử dụng YOLO cắt ô + VietOCR đọc chữ.
"""
st = time.time()
img = cv2.imread(img_path)
if img is None:
return {}
img = correct_skew(img)
page_boxes = get_dictionary.prediction(img, self.imgsz, self.stride, self.device, self.half, self.model, self.names)
page_boxes = get_dictionary.dict_processing(page_boxes)
print("\n--- [YOLO - MẶT TRƯỚC] TỌA ĐỘ CÁC Ô TÌM THẤY ---")
for key, val in page_boxes.items():
if val:
print(f" > {key}: {len(val)} ô")
fields = ["id", "full_name", "date_of_birth", "sex", "nationality", "place_of_origin", "place_of_residence", "date_of_expiry"]
user_info_dict = {}
print("\n--- [VietOCR - MẶT TRƯỚC] KẾT QUẢ DỊCH CHỮ ---")
for field in fields:
infos = page_boxes.get(field)
if infos:
if len(infos) != 1:
infos = self.arrange_info(infos)
all_text = ''
for info in infos:
text = self.ocr_info(img, info)
all_text += text + ' '
else:
all_text = self.ocr_info(img, infos[0])
extracted_str = all_text.strip()
user_info_dict.update({field: extracted_str})
print(f" [*] {field.upper():<20}: {extracted_str}")
else:
user_info_dict.update({field: ''})
print(f" [!] {field.upper():<20}: (Không tìm thấy ô)")
print("----------------------------------\n")
print(f'[ReadInfo] Total Process Time: {time.time() - st:.2f}s')
return user_info_dict
# ══════════════════════════════════════════════════════════════════
# MẶT SAU: KHÔNG DÙNG YOLO (VÌ CHƯA CÓ MODEL), DÙNG VIETOCR QUÉT FULL
# ══════════════════════════════════════════════════════════════════
def get_back_info(self, img_path):
"""
Đọc MẶT SAU CCCD: Đẩy toàn bộ ảnh vào VietOCR, sau đó dùng Regex
và từ khóa để lọc ra thông tin thay vì dùng YOLO cắt ô.
"""
st = time.time()
img = cv2.imread(img_path)
if img is None:
return {}
# Xoay ảnh cho thẳng
img = correct_skew(img)
print("\n--- [VietOCR - MẶT SAU (Quét toàn ảnh)] KẾT QUẢ DỊCH CHỮ ---")
# Chuyển thẳng toàn bộ ảnh sang RGB và đẩy vào VietOCR
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
full_text = self.ocrPredictor.predict(Image.fromarray(img_rgb))
full_text_upper = full_text.upper()
result = {
"issue_date": "",
"issued_by": "",
"special_features": ""
}
# 1. Tìm Ngày Cấp (Issue Date) bằng Regex
# Tìm chuỗi có dạng dd/mm/yyyy, có thể bị lỗi khoảng trắng hoặc dấu gạch nối
date_match = re.search(r'(\d{2}[\s/\-\.]+\d{2}[\s/\-\.]+\d{4})', full_text)
if date_match:
result["issue_date"] = re.sub(r'[\s\-\.]+', '/', date_match.group(1))
# 2. Tìm Nơi Cấp (Issued By) bằng Từ khóa
# Lấy từ các chức danh người ký trở về sau
keywords = ["CỤC TRƯỞNG", "GIÁM ĐỐC", "NƠI CẤP"]
for kw in keywords:
idx = full_text_upper.find(kw)
if idx != -1:
# Cắt chuỗi từ khóa đó trở về cuối
result["issued_by"] = full_text[idx:].strip()
break
# 3. Tìm Đặc điểm nhận dạng (Special Features)
# Nằm giữa cụm từ "nhận dạng" và cụm "Ngày, tháng, năm" hoặc con dấu
feat_match = re.search(r'(ĐẶC ĐIỂM NHẬN DẠNG|NHẬN DẠNG)[:\s]*(.*?)(?=NGÀY|CỤC|GIÁM|DẤU|$)', full_text_upper, re.DOTALL)
if feat_match:
# Dùng vị trí match ở text thường để giữ nguyên chữ hoa/chữ thường
start_idx = feat_match.start(2)
end_idx = feat_match.end(2)
extracted_feat = full_text[start_idx:end_idx].strip().replace('\n', ' ')
# Lọc bỏ các ký tự rác nếu có
result["special_features"] = extracted_feat
# Log kết quả ra terminal
print(f" [*] ISSUE_DATE : {result['issue_date'] if result['issue_date'] else '(Không tìm thấy)'}")
print(f" [*] ISSUED_BY : {result['issued_by'] if result['issued_by'] else '(Không tìm thấy)'}")
print(f" [*] SPECIAL_FEATURES: {result['special_features'] if result['special_features'] else '(Không tìm thấy)'}")
print("----------------------------------\n")
print(f'[ReadInfo - Back] Total Process Time: {time.time() - st:.2f}s')
return result |