# pylint: disable=invalid-name, redefined-outer-name, missing-docstring, non-parent-init-called, trailing-whitespace, line-too-long import cv2 import numpy as np import tensorflow as tf from tensorflow.python.keras.backend import set_session class Label: def __init__(self, cl=-1, tl=np.array([0., 0.]), br=np.array([0., 0.]), prob=None): self.__tl = tl self.__br = br self.__cl = cl self.__prob = prob def __str__(self): return 'Class: %d, top left(x: %f, y: %f), bottom right(x: %f, y: %f)' % ( self.__cl, self.__tl[0], self.__tl[1], self.__br[0], self.__br[1]) def copy(self): return Label(self.__cl, self.__tl, self.__br) def wh(self): return self.__br - self.__tl def cc(self): return self.__tl + self.wh() / 2 def tl(self): return self.__tl def br(self): return self.__br def tr(self): return np.array([self.__br[0], self.__tl[1]]) def bl(self): return np.array([self.__tl[0], self.__br[1]]) def cl(self): return self.__cl def area(self): return np.prod(self.wh()) def prob(self): return self.__prob def set_class(self, cl): self.__cl = cl def set_tl(self, tl): self.__tl = tl def set_br(self, br): self.__br = br def set_wh(self, wh): cc = self.cc() self.__tl = cc - .5 * wh self.__br = cc + .5 * wh def set_prob(self, prob): self.__prob = prob class DLabel(Label): def __init__(self, cl, pts, prob): self.pts = pts tl = np.amin(pts, axis=1) br = np.amax(pts, axis=1) Label.__init__(self, cl, tl, br, prob) def getWH(shape): return np.array(shape[1::-1]).astype(float) def IOU(tl1, br1, tl2, br2): wh1, wh2 = br1 - tl1, br2 - tl2 assert ((wh1 >= 0).all() and (wh2 >= 0).all()) intersection_wh = np.maximum(np.minimum(br1, br2) - np.maximum(tl1, tl2), 0) intersection_area = np.prod(intersection_wh) area1, area2 = (np.prod(wh1), np.prod(wh2)) union_area = area1 + area2 - intersection_area return intersection_area / union_area def IOU_labels(l1, l2): return IOU(l1.tl(), l1.br(), l2.tl(), l2.br()) def nms(Labels, iou_threshold=0.5): SelectedLabels = [] Labels.sort(key=lambda l: l.prob(), reverse=True) for label in Labels: non_overlap = True for sel_label in SelectedLabels: if IOU_labels(label, sel_label) > iou_threshold: non_overlap = False break if non_overlap: SelectedLabels.append(label) return SelectedLabels def find_T_matrix(pts, t_pts): A = np.zeros((8, 9)) for i in range(0, 4): xi = pts[:, i] xil = t_pts[:, i] xi = xi.T A[i * 2, 3:6] = -xil[2] * xi A[i * 2, 6:] = xil[1] * xi A[i * 2 + 1, :3] = xil[2] * xi A[i * 2 + 1, 6:] = -xil[0] * xi [U, S, V] = np.linalg.svd(A) H = V[-1, :].reshape((3, 3)) return H def getRectPts(tlx, tly, brx, bry): return np.matrix([[tlx, brx, brx, tlx], [tly, tly, bry, bry], [1, 1, 1, 1]], dtype=float) def normal(pts, side, mn, MN): pts_MN_center_mn = pts * side pts_MN = pts_MN_center_mn + mn.reshape((2, 1)) pts_prop = pts_MN / MN.reshape((2, 1)) return pts_prop # Reconstruction function from predict value into plate crpoped from image def reconstruct(I, Iresized, Yr, lp_threshold): # 4 max-pooling layers, stride = 2 net_stride = 2 ** 4 side = ((208 + 40) / 2) / net_stride # one line and two lines license plate size one_line = (470, 110) two_lines = (280, 200) Probs = Yr[..., 0] Affines = Yr[..., 2:] xx, yy = np.where(Probs > lp_threshold) # CNN input image size WH = getWH(Iresized.shape) # output feature map size MN = WH / net_stride vxx = vyy = 0.5 # alpha base = lambda vx, vy: np.matrix([[-vx, -vy, 1], [vx, -vy, 1], [vx, vy, 1], [-vx, vy, 1]]).T labels = [] labels_frontal = [] for i in range(len(xx)): x, y = xx[i], yy[i] affine = Affines[x, y] prob = Probs[x, y] mn = np.array([float(y) + 0.5, float(x) + 0.5]) # affine transformation matrix A = np.reshape(affine, (2, 3)) A[0, 0] = max(A[0, 0], 0) A[1, 1] = max(A[1, 1], 0) # identity transformation B = np.zeros((2, 3)) B[0, 0] = max(A[0, 0], 0) B[1, 1] = max(A[1, 1], 0) pts = np.array(A * base(vxx, vyy)) pts_frontal = np.array(B * base(vxx, vyy)) pts_prop = normal(pts, side, mn, MN) frontal = normal(pts_frontal, side, mn, MN) labels.append(DLabel(0, pts_prop, prob)) labels_frontal.append(DLabel(0, frontal, prob)) final_labels = nms(labels, 0.1) final_labels_frontal = nms(labels_frontal, 0.1) # print(final_labels_frontal) assert final_labels_frontal, "" # "No License plate is founded!" # LP size and type out_size, lp_type = (two_lines, 2) if ( (final_labels_frontal[0].wh()[0] / final_labels_frontal[0].wh()[1]) < 1.7) else (one_line, 1) TLp = [] Cor = [] if len(final_labels): final_labels.sort(key=lambda x: x.prob(), reverse=True) for _, label in enumerate(final_labels): t_ptsh = getRectPts(0, 0, out_size[0], out_size[1]) ptsh = np.concatenate((label.pts * getWH(I.shape).reshape((2, 1)), np.ones((1, 4)))) H = find_T_matrix(ptsh, t_ptsh) Ilp = cv2.warpPerspective(I, H, out_size, borderValue=0) # cv2.imshow("plate", Ilp) # cv2.waitKey(0) TLp.append(Ilp) Cor.append(ptsh) return final_labels, TLp, lp_type, Cor def detect_lp(graph, sess, model, I, max_dim, lp_threshold): min_dim_img = min(I.shape[:2]) factor = float(max_dim) / min_dim_img w, h = (np.array(I.shape[1::-1], dtype=float) * factor).astype(int).tolist() Iresized = cv2.resize(I, (w, h)) T = Iresized.copy() T = T.reshape((1, T.shape[0], T.shape[1], T.shape[2])) with graph.as_default(): set_session(sess) Yr = model.predict(T) # print("1: ",Yr) Yr = np.squeeze(Yr) # print("2: ",Yr) # print(Yr.shape) L, TLp, lp_type, Cor = reconstruct(I, Iresized, Yr, lp_threshold) return L, TLp, lp_type, Cor