shrudhit's picture
Update app.py
e878bbc verified
Raw History Blame Contribute Delete
10.3 kB
import os
import re
import cv2
import pandas as pd
import gradio as gr
import pytesseract
import spaces
from PIL import Image
# =========================================================
# ZERO GPU STARTUP CHECK
# =========================================================
@spaces.GPU
def zerogpu_probe():
return "OK"
# =========================================================
# OCR CORRECTION
# =========================================================
def correct_ocr_mistakes(text):
if not text:
return ""
text = text.upper()
replacements = {
"O": "0",
"I": "1",
"L": "1",
"S": "5",
"B": "8",
"G": "6",
"Z": "2"
}
for k, v in replacements.items():
text = text.replace(k, v)
return text
# =========================================================
# EXTRACT LAST 3 DIGITS
# =========================================================
def extract_last_3_digits(val):
if not val:
return ""
val = correct_ocr_mistakes(val)
digits = re.findall(r"\d", val)
if len(digits) >= 3:
return "".join(digits[-3:])
return ""
# =========================================================
# PARSE OCR TEXT
# =========================================================
def parse_ocr_text(text):
awb_val = ""
packet_val = ""
ship_to_val = ""
if not text:
return "", "", ""
lines = [
line.strip()
for line in text.split("\n")
if line.strip()
]
for i, line in enumerate(lines):
# -------------------------------------------------
# AWB
# -------------------------------------------------
if (
re.search(r"AW[B8]\s*[:\-]", line, re.IGNORECASE)
or "AWB" in line.upper()
):
m = re.search(
r"AW[B8]\s*[:\-]?\s*([A-Z0-9_]+)",
line,
re.IGNORECASE
)
if m and len(m.group(1)) > 4:
awb_val = m.group(1)
elif i + 1 < len(lines):
awb_val = lines[i + 1]
# -------------------------------------------------
# PACKET ID
# -------------------------------------------------
if re.search(
r"Packet\s*[I1][D0]",
line,
re.IGNORECASE
):
m = re.search(
r"Packet\s*[I1][D0]\s*[:\-]?\s*([A-Z0-9_]+)",
line,
re.IGNORECASE
)
if m and len(m.group(1)) > 4:
packet_val = m.group(1)
elif i + 1 < len(lines):
packet_val = lines[i + 1]
# -------------------------------------------------
# SHIP TO
# -------------------------------------------------
if re.search(
r"Ship\s*T[o0]",
line,
re.IGNORECASE
):
m = re.search(
r"Ship\s*T[o0]\s*[:\-]?\s*(.+)",
line,
re.IGNORECASE
)
if m and m.group(1).strip():
ship_to_val = m.group(1).strip()
elif i + 1 < len(lines):
ship_to_val = lines[i + 1].strip()
return (
extract_last_3_digits(awb_val),
extract_last_3_digits(packet_val),
ship_to_val
)
# =========================================================
# IMAGE PREPROCESSING
# =========================================================
def preprocess_image(image_path):
img = cv2.imread(image_path)
if img is None:
return []
# Grayscale
gray = cv2.cvtColor(
img,
cv2.COLOR_BGR2GRAY
)
# Resize
gray = cv2.resize(
gray,
None,
fx=2,
fy=2,
interpolation=cv2.INTER_CUBIC
)
# Denoise
denoised = cv2.fastNlMeansDenoising(
gray,
None,
h=10,
templateWindowSize=7,
searchWindowSize=21
)
# Adaptive threshold
adaptive_thresh = cv2.adaptiveThreshold(
denoised,
255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
31,
2
)
return [
Image.fromarray(adaptive_thresh),
Image.fromarray(gray)
]
# =========================================================
# PROCESS IMAGES
# =========================================================
def process_images(files, progress=gr.Progress()):
if not files:
return (
pd.DataFrame(
columns=[
"AWB",
"Packet ID",
"Ship To"
]
),
None
)
results = []
# OCR configurations
ocr_configs = [
"--psm 6",
"--psm 11"
]
total_files = len(files)
# =====================================================
# LOOP THROUGH FILES
# =====================================================
for index, file_obj in enumerate(files):
progress(
(index + 1) / total_files,
desc=f"Processing {index + 1}/{total_files}"
)
# -------------------------------------------------
# GET FILE PATH
# -------------------------------------------------
if isinstance(file_obj, str):
filepath = file_obj
elif hasattr(file_obj, "name"):
filepath = file_obj.name
else:
filepath = str(file_obj)
# -------------------------------------------------
# PREPROCESS IMAGE
# -------------------------------------------------
preprocessed_imgs = preprocess_image(
filepath
)
final_awb = ""
final_packet = ""
final_ship = ""
found_all = False
# =================================================
# OCR
# =================================================
for img in preprocessed_imgs:
if found_all:
break
for config in ocr_configs:
try:
text = pytesseract.image_to_string(
img,
config=config
)
except Exception:
continue
# Parse OCR
awb, packet, ship = parse_ocr_text(
text
)
# Save AWB
if not final_awb and awb:
final_awb = awb
# Save Packet ID
if not final_packet and packet:
final_packet = packet
# Save Ship To
if not final_ship and ship:
final_ship = ship
# Stop if everything found
if (
final_awb
and final_packet
and final_ship
):
found_all = True
break
# =================================================
# ADD RESULT
# =================================================
results.append({
"AWB": final_awb,
"Packet ID": final_packet,
"Ship To": final_ship
})
# =====================================================
# CREATE DATAFRAME
# =====================================================
df = pd.DataFrame(
results,
columns=[
"AWB",
"Packet ID",
"Ship To"
]
)
# =====================================================
# CREATE EXCEL
# =====================================================
output_excel = os.path.abspath(
"RVP_Data.xlsx"
)
df.to_excel(
output_excel,
index=False
)
return df, output_excel
# =========================================================
# GRADIO INTERFACE
# =========================================================
with gr.Blocks(
title="RVP Label OCR Extractor"
) as interface:
# -----------------------------------------------------
# TITLE
# -----------------------------------------------------
gr.Markdown(
"# 📦 RVP Label OCR Extractor"
)
gr.Markdown(
"Upload RVP label images to extract "
"the last 3 digits of AWB, "
"last 3 digits of Packet ID, "
"and Ship To."
)
# -----------------------------------------------------
# FILE UPLOAD
# -----------------------------------------------------
file_input = gr.File(
file_count="multiple",
file_types=[
".jpg",
".jpeg",
".png"
],
label="Upload RVP Photos",
type="filepath"
)
# -----------------------------------------------------
# EXTRACT BUTTON
# -----------------------------------------------------
extract_btn = gr.Button(
"Extract Data",
variant="primary"
)
# -----------------------------------------------------
# RESULTS
# -----------------------------------------------------
output_df = gr.Dataframe(
headers=[
"AWB",
"Packet ID",
"Ship To"
],
datatype=[
"str",
"str",
"str"
],
label="Results",
interactive=False
)
# -----------------------------------------------------
# EXCEL DOWNLOAD
# -----------------------------------------------------
output_file = gr.File(
label="Download Excel File"
)
# -----------------------------------------------------
# BUTTON EVENT
# -----------------------------------------------------
extract_btn.click(
fn=process_images,
inputs=file_input,
outputs=[
output_df,
output_file
]
)
# =========================================================
# LAUNCH
# =========================================================
if __name__ == "__main__":
interface.launch(
server_name="0.0.0.0",
server_port=7860,
ssr_mode=False
)