APIMONSTER commited on
Commit
a86d03e
·
verified ·
1 Parent(s): 417de80

Upload 3 files

Browse files
Files changed (4) hide show
  1. .gitattributes +1 -0
  2. app.py +137 -0
  3. models/best.pt +3 -0
  4. models/best_plate_model.pdparams +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ models/best_plate_model.pdparams filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ import numpy as np
4
+ import paddle
5
+ import paddle.nn as nn
6
+ import gradio as gr
7
+ from ultralytics import YOLO
8
+ from PIL import Image
9
+
10
+ # ─── 1) PlateOCR Sınıfı (fine-tuned model mimarinizle birebir aynı) ───
11
+ MAX_SEQ_LEN = 15
12
+ LABEL_MAP = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "
13
+ NUM_CLASSES = len(LABEL_MAP)
14
+
15
+ class OCRHead(nn.Layer):
16
+ def __init__(self, flatten_size):
17
+ super().__init__()
18
+ self.dropout = nn.Dropout(0.5)
19
+ self.fc = nn.Linear(flatten_size, MAX_SEQ_LEN * NUM_CLASSES)
20
+
21
+ def forward(self, x):
22
+ x = self.dropout(x)
23
+ x = self.fc(x)
24
+ return x.reshape([-1, MAX_SEQ_LEN, NUM_CLASSES])
25
+
26
+ class PlateOCR(nn.Layer):
27
+ def __init__(self):
28
+ super().__init__()
29
+ self.backbone = nn.Sequential(
30
+ nn.Conv2D(3, 32, 3, padding=1), nn.BatchNorm2D(32), nn.ReLU(),
31
+ nn.MaxPool2D(2,2),
32
+ nn.Conv2D(32, 64, 3, padding=1), nn.BatchNorm2D(64), nn.ReLU(),
33
+ nn.MaxPool2D(2,2),
34
+ nn.Conv2D(64,128,3, padding=1), nn.BatchNorm2D(128),nn.ReLU(),
35
+ nn.MaxPool2D(2,2), nn.Dropout(0.25)
36
+ )
37
+ # dummy tensor ile flatten boyutunu hesapla
38
+ dummy = paddle.randn([1,3,32,128])
39
+ flat_size = paddle.flatten(self.backbone(dummy),1).shape[1]
40
+ self.head = OCRHead(flat_size)
41
+
42
+ def forward(self, x):
43
+ x = self.backbone(x)
44
+ x = paddle.flatten(x,1)
45
+ return self.head(x)
46
+
47
+ # ─── 2) Greedy Decode ───
48
+ def greedy_decode(logits):
49
+ # logits: [B, T, C]
50
+ preds = logits.numpy().argmax(axis=2) # [B, T]
51
+ texts = []
52
+ for seq in preds:
53
+ prev = -1
54
+ chars = []
55
+ for idx in seq:
56
+ if idx != prev and idx < NUM_CLASSES:
57
+ chars.append(LABEL_MAP[idx])
58
+ prev = idx
59
+ texts.append("".join(chars).strip())
60
+ return texts
61
+
62
+ # ─── 3) Modelleri Yükle ───
63
+ # YOLO
64
+ yolo = YOLO("models/best.pt")
65
+
66
+ # PlateOCR
67
+ plate_ocr = PlateOCR()
68
+ plate_ocr.set_state_dict(paddle.load("models/best_plate_model.pdparams"))
69
+ plate_ocr.eval()
70
+
71
+ # ─── 4) Pipeline Fonksiyonu ───
72
+ def detect_and_read(image, conf_thresh):
73
+ """ YOLO ile plakayı kes, PlateOCR ile oku, görselleştir. """
74
+ if image is None:
75
+ return None, "❌ Upload an image."
76
+
77
+ # 1) BGR→RGB
78
+ img = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
79
+ # 2) YOLO predict
80
+ results = yolo.predict(source=img, conf=conf_thresh)[0]
81
+ boxes = results.boxes.xyxy.cpu().numpy() # [N,4]
82
+ scores = results.boxes.conf.cpu().numpy()
83
+ classes = results.boxes.cls.cpu().numpy()
84
+
85
+ annotated = img.copy()
86
+ ocr_texts = []
87
+
88
+ for (x1,y1,x2,y2), conf in zip(boxes, scores):
89
+ x1,y1,x2,y2 = map(int,(x1,y1,x2,y2))
90
+ crop = annotated[y1:y2, x1:x2]
91
+ if crop.size==0:
92
+ continue
93
+
94
+ # 3) PlateOCR için preprocess
95
+ plate = cv2.resize(crop, (128,32))
96
+ arr = plate.astype("float32")/255.0
97
+ arr = arr.transpose(2,0,1)[None,:,:,:] # [1,3,32,128]
98
+ inp = paddle.to_tensor(arr)
99
+
100
+ # 4) OCR inference
101
+ with paddle.no_grad():
102
+ out = plate_ocr(inp) # [1, T, C]
103
+ text = greedy_decode(out)[0]
104
+
105
+ # 5) Draw box + text + confidences
106
+ label = f"{text} ({conf:.2f})"
107
+ # kutu
108
+ cv2.rectangle(annotated,(x1,y1),(x2,y2),(0,255,0),2)
109
+ # label arka plan
110
+ (tw,th),baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.8,2)
111
+ ty = y1 - 10 if y1 -10 > th+baseline else y1+th+10
112
+ cv2.rectangle(annotated,(x1,ty-th-baseline),(x1+tw,ty+baseline),(0,255,0),cv2.FILLED)
113
+ cv2.putText(annotated,label,(x1,ty),cv2.FONT_HERSHEY_SIMPLEX,0.8,(0,0,0),2)
114
+
115
+ ocr_texts.append(text)
116
+
117
+ # BGR→RGB döndür
118
+ out_img = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
119
+ status = f"Detected {len(boxes)} plates, OCR: {ocr_texts}"
120
+ return out_img, status
121
+
122
+ # ─── 5) Gradio Arayüzü ───
123
+ with gr.Blocks() as demo:
124
+ gr.Markdown("## 🚗 Plate Detection + Recognition")
125
+ with gr.Row():
126
+ with gr.Column():
127
+ inp = gr.Image(type="numpy", label="Upload Image")
128
+ conf = gr.Slider(0,1,0.25,0.01, label="YOLO Confidence")
129
+ btn = gr.Button("Run")
130
+ with gr.Column():
131
+ out_img = gr.Image(type="numpy", label="Annotated")
132
+ out_text = gr.Textbox(label="Status", interactive=False)
133
+ btn.click(detect_and_read, [inp, conf], [out_img, out_text])
134
+ gr.Markdown("---\n**How it works:** YOLO finds plate boxes; your PaddleOCR-fine-tuned PlateOCR reads them.")
135
+
136
+ if __name__=="__main__":
137
+ demo.launch()
models/best.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3f25d12d95518dd762f3365e7c3a1fffd87c9e4a2b7a4c61623384c2ecc84f62
3
+ size 6250979
models/best_plate_model.pdparams ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2eb1aef4e213469bd6d6d62dcfa6a0ddda6ba7b8a1339ef84625b2839cc3b2bc
3
+ size 18566687