Update alpr.py
Browse files
alpr.py
CHANGED
@@ -9,9 +9,6 @@ from os.path import splitext
|
|
9 |
from tensorflow.python.keras.backend import set_session
|
10 |
from tensorflow.keras.models import model_from_json
|
11 |
from tensorflow.compat.v1 import ConfigProto
|
12 |
-
#from tensorflow.compat.v1 import InteractiveSession
|
13 |
-
from vars import models_path
|
14 |
-
|
15 |
|
16 |
|
17 |
class DetectLicensePlate:
|
@@ -25,7 +22,7 @@ class DetectLicensePlate:
|
|
25 |
self.graph = tf.get_default_graph()
|
26 |
set_session(self.sess)
|
27 |
|
28 |
-
self.wpod_net_path =
|
29 |
self.wpod_net = self.load_model(self.wpod_net_path)
|
30 |
|
31 |
def load_model(self, path):
|
@@ -58,218 +55,6 @@ class DetectLicensePlate:
|
|
58 |
return vehicle, plates, cor
|
59 |
|
60 |
|
61 |
-
class Segmentation:
|
62 |
-
# to grab the contour of each digit from left to right
|
63 |
-
def sort_contours(self, cnts, reverse=False):
|
64 |
-
i = 0
|
65 |
-
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
|
66 |
-
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
|
67 |
-
key=lambda b: b[1][i], reverse=False))
|
68 |
-
return cnts
|
69 |
-
|
70 |
-
def find_characters(self, thresh, plate_image):
|
71 |
-
# 2li 3lü gruplama için
|
72 |
-
tmp_space = None
|
73 |
-
short_space = None
|
74 |
-
letter_num = 0
|
75 |
-
state_ = 0
|
76 |
-
|
77 |
-
cont, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
78 |
-
|
79 |
-
# creat a copy version "test_roi" of plat_image to draw bounding box
|
80 |
-
test_roi = thresh.copy()
|
81 |
-
|
82 |
-
# Initialize a list which will be used to append charater image
|
83 |
-
crop_characters = []
|
84 |
-
|
85 |
-
# define standard width and height of character
|
86 |
-
digit_w, digit_h = 32, 32
|
87 |
-
try:
|
88 |
-
conturs = self.sort_contours(cont)
|
89 |
-
except:
|
90 |
-
return
|
91 |
-
for c in conturs:
|
92 |
-
(x, y, w, h) = cv2.boundingRect(c)
|
93 |
-
ratio = h / w
|
94 |
-
if 1 <= ratio <= 5.7: # Only select contour with defined ratio
|
95 |
-
if h / plate_image.shape[0] >= 0.3: # Select contour which has the height larger than 50% of the plate
|
96 |
-
if letter_num == 1:
|
97 |
-
short_space = x - tmp_space
|
98 |
-
if letter_num == 3:
|
99 |
-
space = x - tmp_space
|
100 |
-
if space > short_space + 2:
|
101 |
-
# print("4.karakter sayı")
|
102 |
-
state_ = 2
|
103 |
-
letter_num += 2
|
104 |
-
elif letter_num == 4:
|
105 |
-
space = x - tmp_space
|
106 |
-
if space > short_space + 2:
|
107 |
-
state_ = 3
|
108 |
-
# print("5.karakter sayı")
|
109 |
-
else:
|
110 |
-
state_ = 4
|
111 |
-
# print("5.karakter harf")
|
112 |
-
tmp_space = x + w
|
113 |
-
|
114 |
-
# Draw bounding box arroung digit number
|
115 |
-
cv2.rectangle(test_roi, (x, y), (x + w, y + h), (0, 255, 0), 2)
|
116 |
-
try:
|
117 |
-
# Sperate number and gibe prediction
|
118 |
-
curr_num = thresh[y - 1:y + h + 2, x - 1:x + w + 2]
|
119 |
-
curr_num = cv2.resize(curr_num, dsize=(digit_w, digit_h))
|
120 |
-
crop_characters.append(curr_num)
|
121 |
-
letter_num += 1
|
122 |
-
except Exception as e:
|
123 |
-
print(str(e))
|
124 |
-
return crop_characters, state_
|
125 |
-
|
126 |
-
|
127 |
-
class SVM(object):
|
128 |
-
def __init__(self, C=1.0, gamma=0.5): # def C = 1.0, gamma = 0.5
|
129 |
-
self.model = cv2.ml.SVM_create()
|
130 |
-
self.model.setGamma(gamma)
|
131 |
-
self.model.setC(C)
|
132 |
-
self.model.setKernel(cv2.ml.SVM_RBF)
|
133 |
-
self.model.setType(cv2.ml.SVM_C_SVC)
|
134 |
-
|
135 |
-
def train(self, samples, responses):
|
136 |
-
self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
|
137 |
-
|
138 |
-
def predict(self, samples):
|
139 |
-
return self.model.predict(samples)[1].ravel()
|
140 |
-
|
141 |
-
def load(self, fn):
|
142 |
-
self.model = cv2.ml.SVM_load(fn)
|
143 |
-
|
144 |
-
def save(self, fn):
|
145 |
-
self.model.save(fn)
|
146 |
-
|
147 |
-
|
148 |
-
class Ocr:
|
149 |
-
def __init__(self):
|
150 |
-
|
151 |
-
self.letter_dict = dict()
|
152 |
-
self.letter_dict["0"] = "O"
|
153 |
-
self.letter_dict["1"] = "I"
|
154 |
-
self.letter_dict["2"] = "Z"
|
155 |
-
self.letter_dict["3"] = "3"
|
156 |
-
self.letter_dict["4"] = "L"
|
157 |
-
self.letter_dict["5"] = "S"
|
158 |
-
self.letter_dict["6"] = "G"
|
159 |
-
self.letter_dict["7"] = "7"
|
160 |
-
self.letter_dict["8"] = "B"
|
161 |
-
self.letter_dict["9"] = "9"
|
162 |
-
self.letter_dict["10"] = "A"
|
163 |
-
self.letter_dict["11"] = "B"
|
164 |
-
self.letter_dict["12"] = "C"
|
165 |
-
self.letter_dict["13"] = "D"
|
166 |
-
self.letter_dict["14"] = "E"
|
167 |
-
self.letter_dict["15"] = "F"
|
168 |
-
self.letter_dict["16"] = "G"
|
169 |
-
self.letter_dict["17"] = "H"
|
170 |
-
self.letter_dict["18"] = "I"
|
171 |
-
self.letter_dict["19"] = "J"
|
172 |
-
self.letter_dict["20"] = "K"
|
173 |
-
self.letter_dict["21"] = "L"
|
174 |
-
self.letter_dict["22"] = "M"
|
175 |
-
self.letter_dict["23"] = "N"
|
176 |
-
self.letter_dict["24"] = "O"
|
177 |
-
self.letter_dict["25"] = "P"
|
178 |
-
self.letter_dict["26"] = "R"
|
179 |
-
self.letter_dict["27"] = "S"
|
180 |
-
self.letter_dict["28"] = "T"
|
181 |
-
self.letter_dict["29"] = "U"
|
182 |
-
self.letter_dict["30"] = "V"
|
183 |
-
self.letter_dict["31"] = "Y"
|
184 |
-
self.letter_dict["32"] = "Z"
|
185 |
-
|
186 |
-
self.num_dict = dict()
|
187 |
-
self.num_dict["0"] = "0"
|
188 |
-
self.num_dict["1"] = "1"
|
189 |
-
self.num_dict["2"] = "2"
|
190 |
-
self.num_dict["3"] = "3"
|
191 |
-
self.num_dict["4"] = "4"
|
192 |
-
self.num_dict["5"] = "5"
|
193 |
-
self.num_dict["6"] = "6"
|
194 |
-
self.num_dict["7"] = "7"
|
195 |
-
self.num_dict["8"] = "8"
|
196 |
-
self.num_dict["9"] = "9"
|
197 |
-
self.num_dict["10"] = "A"
|
198 |
-
self.num_dict["11"] = "8"
|
199 |
-
self.num_dict["12"] = "C"
|
200 |
-
self.num_dict["13"] = "0"
|
201 |
-
self.num_dict["14"] = "E"
|
202 |
-
self.num_dict["15"] = "F"
|
203 |
-
self.num_dict["16"] = "6"
|
204 |
-
self.num_dict["17"] = "H"
|
205 |
-
self.num_dict["18"] = "1"
|
206 |
-
self.num_dict["19"] = "3"
|
207 |
-
self.num_dict["20"] = "K"
|
208 |
-
self.num_dict["21"] = "4"
|
209 |
-
self.num_dict["22"] = "M"
|
210 |
-
self.num_dict["23"] = "N"
|
211 |
-
self.num_dict["24"] = "0"
|
212 |
-
self.num_dict["25"] = "P"
|
213 |
-
self.num_dict["26"] = "8"
|
214 |
-
self.num_dict["27"] = "5"
|
215 |
-
self.num_dict["28"] = "T"
|
216 |
-
self.num_dict["29"] = "U"
|
217 |
-
self.num_dict["30"] = "V"
|
218 |
-
self.num_dict["31"] = "Y"
|
219 |
-
self.num_dict["32"] = "2"
|
220 |
-
|
221 |
-
def preprocess_hog(self, digits):
|
222 |
-
samples = []
|
223 |
-
for img in digits:
|
224 |
-
gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
|
225 |
-
gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
|
226 |
-
mag, ang = cv2.cartToPolar(gx, gy)
|
227 |
-
bin_n = 16
|
228 |
-
bin = np.int32(bin_n * ang / (2 * np.pi))
|
229 |
-
bin_cells = bin[:10, :10], bin[10:, :10], bin[:10, 10:], bin[10:, 10:]
|
230 |
-
mag_cells = mag[:10, :10], mag[10:, :10], mag[:10, 10:], mag[10:, 10:]
|
231 |
-
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
|
232 |
-
hist = np.hstack(hists)
|
233 |
-
|
234 |
-
# transform to Hellinger kernel
|
235 |
-
eps = 1e-7
|
236 |
-
hist /= hist.sum() + eps
|
237 |
-
hist = np.sqrt(hist)
|
238 |
-
hist /= norm(hist) + eps
|
239 |
-
samples.append(hist)
|
240 |
-
return np.float32(samples)
|
241 |
-
|
242 |
-
def deskew(self, img):
|
243 |
-
SZ = 32
|
244 |
-
m = cv2.moments(img)
|
245 |
-
if abs(m['mu02']) < 1e-2:
|
246 |
-
return img.copy()
|
247 |
-
skew = m['mu11'] / m['mu02']
|
248 |
-
M = np.float32([[1, skew, -0.5 * SZ * skew], [0, 1, 0]])
|
249 |
-
img = cv2.warpAffine(img, M, (SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)
|
250 |
-
return img
|
251 |
-
|
252 |
-
def find_label(self, character_, model_):
|
253 |
-
arr = [character_]
|
254 |
-
arr = np.array(arr)
|
255 |
-
mapped = list(map(self.deskew, arr))
|
256 |
-
mapped = self.preprocess_hog(mapped)
|
257 |
-
predict = model_.predict(mapped)[0].ravel()
|
258 |
-
return str(predict).split(".")[0].replace("[", "").replace(" ","").replace("]","")
|
259 |
-
|
260 |
-
def recognize_characters(self, characters, model_, state):
|
261 |
-
plate_text = ""
|
262 |
-
num = 0
|
263 |
-
for character in characters:
|
264 |
-
character = cv2.bitwise_not(character)
|
265 |
-
pred = self.find_label(character, model_)
|
266 |
-
if num < 2 or num > state:
|
267 |
-
plate_text += self.num_dict.get(pred)
|
268 |
-
else:
|
269 |
-
plate_text += self.letter_dict.get(pred)
|
270 |
-
num += 1
|
271 |
-
return plate_text
|
272 |
-
|
273 |
|
274 |
|
275 |
|
|
|
9 |
from tensorflow.python.keras.backend import set_session
|
10 |
from tensorflow.keras.models import model_from_json
|
11 |
from tensorflow.compat.v1 import ConfigProto
|
|
|
|
|
|
|
12 |
|
13 |
|
14 |
class DetectLicensePlate:
|
|
|
22 |
self.graph = tf.get_default_graph()
|
23 |
set_session(self.sess)
|
24 |
|
25 |
+
self.wpod_net_path ="wpod-net.json" # model path
|
26 |
self.wpod_net = self.load_model(self.wpod_net_path)
|
27 |
|
28 |
def load_model(self, path):
|
|
|
55 |
return vehicle, plates, cor
|
56 |
|
57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
|
60 |
|