PlateDetection / app.py
SatriyaTama's picture
Update app.py
7ea6535 verified
import gradio as gr
import cv2
import numpy as np
from PIL import Image
from ultralytics import YOLO
from paddleocr import PaddleOCR
import re
import os
# --- Inisialisasi Model ---
print("Mulai inisialisasi model...")
# Inisialisasi YOLO
try:
print("Memuat model YOLOv8 ('best2.pt')...")
yolo_model = YOLO('best2.pt') # Ganti path jika modelmu di folder lain
print("Model YOLOv8 berhasil dimuat.")
except Exception as e:
print(f"Error saat memuat model kustom 'best2.pt': {e}")
print("Mencoba memuat model YOLOv8 standar ('yolov8n-obb.pt')...")
yolo_model = YOLO('yolov8n-obb.pt')
print("Model YOLOv8 standar berhasil dimuat.")
# Inisialisasi PaddleOCR
ocr_engine = None
try:
print("Memuat model PaddleOCR...")
ocr_engine = PaddleOCR(
use_angle_cls=True,
lang='en',
det_db_box_thresh=0.3,
show_log=False
)
print("Model PaddleOCR berhasil dimuat.")
except Exception as e:
print("!!! Gagal memuat PaddleOCR:", e)
def find_plate_in_text(text):
cleaned = re.sub(r'[^A-Z0-9]', '', text.upper())
match = re.match(r'^([A-Z]{1,2})(\d{1,4})([A-Z]{1,3})', cleaned)
if match:
return f"{match.group(1)} {match.group(2)} {match.group(3)}"
return f"[Tidak Valid]: {cleaned}"
def detect_crop_and_ocr(image, yolo, ocr, margin=10):
print("-> Mulai deteksi...")
image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) if isinstance(image, Image.Image) else image
if image_cv is None or image_cv.size == 0:
return None, None, "Gambar tidak valid."
results = yolo(image_cv, task='obb')[0]
img_annotated_rgb = cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB)
crop_rgb = None
ocr_text = "Plat tidak terdeteksi."
if len(results.obb.xyxyxyxy) > 0:
obb = results.obb.xyxyxyxy[0].cpu().numpy().reshape((4, 2))
xs, ys = obb[:, 0], obb[:, 1]
x1, x2 = int(xs.min()), int(xs.max())
y1, y2 = int(ys.min()), int(ys.max())
h, w = image_cv.shape[:2]
x1m, y1m = max(0, x1 - margin), max(0, y1 - margin)
x2m, y2m = min(w, x2 + margin), min(h, y2 + margin)
cv2.rectangle(img_annotated_rgb, (x1m, y1m), (x2m, y2m), (0, 255, 0), 3)
crop_cv = image_cv[y1m:y2m, x1m:x2m]
if crop_cv.size > 0 and ocr is not None:
h, w = crop_cv.shape[:2]
crop_resized = cv2.resize(crop_cv, (w * 2, h * 2), interpolation=cv2.INTER_CUBIC)
blurred = cv2.GaussianBlur(crop_resized, (0, 0), 3)
sharpened = cv2.addWeighted(crop_resized, 1.5, blurred, -0.5, 0)
crop_rgb = cv2.cvtColor(sharpened, cv2.COLOR_BGR2RGB)
try:
ocr_results = ocr.ocr(crop_rgb, cls=True)
if ocr_results and ocr_results[0]:
texts = [line[1][0] for line in ocr_results[0] if line and line[1]]
raw_text = "".join(texts)
ocr_text = find_plate_in_text(raw_text)
else:
ocr_text = "OCR tidak dapat membaca teks."
except Exception as e:
ocr_text = f"Error OCR: {e}"
else:
print("-> Tidak ada plat yang terdeteksi.")
status_text = "Plat Terdeteksi" if crop_rgb is not None else "Plat Tidak Terdeteksi"
cv2.putText(img_annotated_rgb, status_text, (15, 40), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 0, 0), 3)
return img_annotated_rgb, crop_rgb, ocr_text
def process_image_for_gradio(uploaded_image):
print("\n==============================")
print("Request baru diterima...")
if ocr_engine is None:
placeholder_img = np.zeros((300, 500, 3), dtype=np.uint8)
cv2.putText(placeholder_img, "OCR Engine Gagal", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
return placeholder_img, None, "ERROR: OCR Engine gagal dimuat."
if uploaded_image is None:
return None, None, "Mohon unggah gambar terlebih dahulu."
try:
full_img, crop_img, text = detect_crop_and_ocr(uploaded_image, yolo_model, ocr_engine)
if crop_img is None:
crop_img = np.zeros((100, 300, 3), dtype=np.uint8)
cv2.putText(crop_img, "Tidak ada plat", (40, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
return full_img, crop_img, text
except Exception as e:
error_msg = f"Terjadi kesalahan: {e}"
placeholder_img = np.zeros((300, 500, 3), dtype=np.uint8)
return placeholder_img, None, error_msg
# === INTERFACE GRADIO ===
example_img_path = "AB2638XU.jpg"
example_img = None
if os.path.exists(example_img_path):
example_img = Image.open(example_img_path)
with gr.Blocks(theme=gr.themes.Soft()) as iface:
gr.Markdown("""
# 🚗 Deteksi & OCR Plat Nomor Kendaraan Indonesia
Unggah gambar kendaraan, deteksi plat dengan YOLOv8 OBB, dan baca teks dengan PaddleOCR.
""")
with gr.Row():
with gr.Column(scale=2):
image_input = gr.Image(type="pil", label="Unggah Gambar", value=example_img)
submit_button = gr.Button("Proses", variant="primary")
with gr.Column(scale=3):
image_output = gr.Image(type="numpy", label="Hasil Deteksi")
with gr.Row():
crop_output = gr.Image(type="numpy", label="Plat Terpotong")
text_output = gr.Textbox(label="Teks Plat Nomor")
submit_button.click(
fn=process_image_for_gradio,
inputs=image_input,
outputs=[image_output, crop_output, text_output]
)
if __name__ == '__main__':
iface.launch(debug=True)