|
|
|
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 |
|
|
|
|
|
|
|
def reconstruct(I, Iresized, Yr, lp_threshold): |
|
|
|
net_stride = 2 ** 4 |
|
side = ((208 + 40) / 2) / net_stride |
|
|
|
|
|
one_line = (470, 110) |
|
two_lines = (280, 200) |
|
|
|
Probs = Yr[..., 0] |
|
Affines = Yr[..., 2:] |
|
|
|
xx, yy = np.where(Probs > lp_threshold) |
|
|
|
WH = getWH(Iresized.shape) |
|
|
|
MN = WH / net_stride |
|
|
|
vxx = vyy = 0.5 |
|
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]) |
|
|
|
|
|
A = np.reshape(affine, (2, 3)) |
|
A[0, 0] = max(A[0, 0], 0) |
|
A[1, 1] = max(A[1, 1], 0) |
|
|
|
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) |
|
|
|
|
|
assert final_labels_frontal, "" |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
Yr = np.squeeze(Yr) |
|
|
|
|
|
L, TLp, lp_type, Cor = reconstruct(I, Iresized, Yr, lp_threshold) |
|
return L, TLp, lp_type, Cor |
|
|