import os import numpy as np from requests import get import streamlit as st import cv2 from ultralytics import YOLO import shutil import easyocr import imutils PREDICTION_PATH = os.path.join('.', 'predictions') @st.cache_resource def load_od_model(): finetuned_model = YOLO('cc_detect_best.pt') return finetuned_model @st.cache_resource def load_easyocr(): reader = easyocr.Reader(['en']) return reader def decode_text(type: str): reader = load_easyocr() output_crop_path = os.path.join(PREDICTION_PATH, 'predict', 'crops', type) ocr_txt = '' if os.path.exists(output_crop_path): crop_file = os.listdir(output_crop_path)[0] crop_img_path = os.path.join(output_crop_path, crop_file) crop_img = cv2.imread(crop_img_path) increase = cv2.resize(crop_img, None, fx = 2, fy = 2, interpolation = cv2.INTER_CUBIC) if type == 'card_number': increase = cv2.resize(crop_img, None, fx = 5, fy = 5, interpolation = cv2.INTER_CUBIC) gray = cv2.cvtColor(increase, cv2.COLOR_BGR2GRAY) value, thresh = cv2.threshold(gray,0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2)) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1) # Find contours and remove small noise cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: area = cv2.contourArea(c) if area < 50: cv2.drawContours(opening, [c], -1, 0, -1) # Invert result = 255 - opening cleaned_image = result crop_ocr = reader.readtext(cleaned_image) cleaned_image = cv2.resize(cleaned_image, None, fx = 0.5, fy = 0.5, interpolation = cv2.INTER_CUBIC) if type == 'card_number': cleaned_image = cv2.resize(cleaned_image, None, fx = 0.2, fy = 0.2, interpolation = cv2.INTER_CUBIC) cv2.imwrite(crop_img_path, cleaned_image) ocr_txt = ''.join([t for _, t, _ in crop_ocr]) ocr_txt_conf = np.round(np.mean([p for _, _, p in crop_ocr]), 4) if type == 'card_number': ocr_txt = ocr_txt.replace(' ', '') col1, col2 = st.columns(2, gap='small') with col1: st.markdown(f"
{type.replace('_', ' ').upper()}
", unsafe_allow_html=True) st.text(f"{ocr_txt.upper()} ({str(ocr_txt_conf)})") with col2: st.text(' ') if type == 'card_number': st.text(' ') st.image(crop_img_path) def inference(input_image_path: str): finetuned_model = load_od_model() results = finetuned_model.predict(input_image_path, show=False, save=True, save_crop=True, imgsz=640, conf=0.6, save_txt=True, project= PREDICTION_PATH, show_labels=True, show_conf=True, line_width=2, exist_ok=True) decode_text('card_number') decode_text('holder_name') decode_text('exp_date') st.image(os.path.join(PREDICTION_PATH, 'predict', 'input.jpg')) def files_cleanup(path_: str): if os.path.exists(path_): os.remove(path_) if os.path.exists(PREDICTION_PATH): shutil.rmtree(PREDICTION_PATH) # @st.cache_resource def get_upload_path(): upload_file_path = os.path.join('.', 'uploads') if not os.path.exists(upload_file_path): os.makedirs(upload_file_path) upload_filename = "input.jpg" upload_file_path = os.path.join(upload_file_path, upload_filename) return upload_file_path def process_input_image(img_url): upload_file_path = get_upload_path() headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'} r = get(img_url, headers=headers) arr = np.frombuffer(r.content, np.uint8) input_image = cv2.imdecode(arr, cv2.IMREAD_UNCHANGED) input_image = cv2.cvtColor(input_image, cv2.COLOR_BGR2RGB) input_image = cv2.resize(input_image, (640, 640)) cv2.imwrite(upload_file_path, cv2.cvtColor(input_image, cv2.COLOR_RGB2BGR)) return upload_file_path try: files_cleanup(get_upload_path()) st.markdown("

Credit Card Detection

", unsafe_allow_html=True) desc = '''YOLOv8 is fine-tuned to detect credit card number, holder's name and expiry date. Dataset used to fine-tune YOLOv8 can be found here. The detected objects are cropped, processed and passed as inputs to EasyOCR for text recognition. ''' st.markdown(desc, unsafe_allow_html=True) img_url = st.text_input("Paste the image URL of a credit card:", "") placeholder = st.empty() if img_url: placeholder.empty() img_path = process_input_image(img_url) inference(img_path) files_cleanup(get_upload_path()) except Exception as e: files_cleanup(get_upload_path()) st.error(f'An unexpected error occured: \n{e}')