import numpy as np
|
import cv2
|
from rknn.api import RKNN
|
import math
|
import PIL.Image as Image
|
import PIL.ImageDraw as ImageDraw
|
import PIL.ImageFont as ImageFont
|
import re
|
|
np.set_printoptions(threshold=np.inf)
|
|
CLASSES = ('__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat',
|
'traffic light', 'fire hydrant', '???', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse',
|
'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', '???', 'backpack', 'umbrella', '???', '???',
|
'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat',
|
'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', '???', 'wine glass', 'cup', 'fork',
|
'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
|
'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', '???', 'dining table', '???', '???', 'toilet',
|
'???', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink',
|
'refrigerator', '???', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush')
|
|
NUM_CLS = 91
|
|
CONF_THRESH = 0.5
|
NMS_THRESH = 0.45
|
TOP_BOXES = 100
|
max_boxes_to_draw = 100
|
|
Y_SCALE = 10.0
|
X_SCALE = 10.0
|
H_SCALE = 5.0
|
W_SCALE = 5.0
|
|
prior_file = './box_priors.txt'
|
|
box_priors_ = []
|
fp = open(prior_file, 'r')
|
ls = fp.readlines()
|
for s in ls:
|
aList = re.findall('([-+]?\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?', s)
|
for ss in aList:
|
aNum = float((ss[0] + ss[2]))
|
box_priors_.append(aNum)
|
fp.close()
|
|
|
def softmax(x):
|
return np.exp(x) / np.sum(np.exp(x), axis=0)
|
|
|
def IntersectBBox(box1, box2):
|
if box1[0] > box2[2] or box1[2] < box2[0] or box1[1] > box2[3] or box1[3] < box2[1]:
|
return 0
|
else:
|
area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
|
area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
|
|
xx1 = max(box1[0], box2[0])
|
yy1 = max(box1[1], box2[1])
|
xx2 = min(box1[2], box2[2])
|
yy2 = min(box1[3], box2[3])
|
|
w = max(0, xx2 - xx1)
|
h = max(0, yy2 - yy1)
|
|
ovr = w * h / (area1 + area2 - w * h + 0.000001)
|
return ovr
|
|
|
def ssd_post_process(conf_data, loc_data, imgpath, output_dir='.'):
|
prior_num = int(len(loc_data) / 4) # num prior boxes
|
|
prior_bboxes = np.array(box_priors_)
|
prior_bboxes = prior_bboxes.reshape(4, prior_num)
|
|
conf_data = conf_data.reshape(-1, NUM_CLS)
|
|
for i in range(prior_num):
|
conf_data[i] = softmax(conf_data[i])
|
|
idx_class_conf = []
|
bboxes = []
|
|
# conf
|
for prior_idx in range(0, prior_num):
|
conf_data[prior_idx][0] = 0
|
max_val = np.max(conf_data[prior_idx])
|
max_idx = np.argmax(conf_data[prior_idx])
|
if max_val > CONF_THRESH:
|
idx_class_conf.append([prior_idx, max_idx, max_val])
|
|
idx_class_conf_sorted = sorted(idx_class_conf, key=lambda x: x[2], reverse=True)
|
|
idx_class_conf = idx_class_conf_sorted[:min(TOP_BOXES, len(idx_class_conf_sorted))]
|
|
# boxes
|
for i in range(0, prior_num):
|
bbox_center_x = loc_data[4 * i + 1] / X_SCALE * prior_bboxes[3][i] + prior_bboxes[1][i]
|
bbox_center_y = loc_data[4 * i + 0] / Y_SCALE * prior_bboxes[2][i] + prior_bboxes[0][i]
|
bbox_w = math.exp(loc_data[4 * i + 3] / W_SCALE) * prior_bboxes[3][i]
|
bbox_h = math.exp(loc_data[4 * i + 2] / H_SCALE) * prior_bboxes[2][i]
|
|
tmp = []
|
tmp.append(max(min(bbox_center_x - bbox_w / 2., 1), 0))
|
tmp.append(max(min(bbox_center_y - bbox_h / 2., 1), 0))
|
tmp.append(max(min(bbox_center_x + bbox_w / 2., 1), 0))
|
tmp.append(max(min(bbox_center_y + bbox_h / 2., 1), 0))
|
bboxes.append(tmp)
|
|
# nms
|
cur_class_num = 0
|
idx_class_conf_ = []
|
for i in range(0, len(idx_class_conf)):
|
keep = True
|
k = 0
|
while k < cur_class_num:
|
if keep:
|
ovr = IntersectBBox(bboxes[idx_class_conf[i][0]], bboxes[idx_class_conf_[k][0]])
|
if idx_class_conf_[k][1] == idx_class_conf[i][1] and ovr > NMS_THRESH:
|
keep = False
|
break
|
k += 1
|
else:
|
break
|
if keep:
|
idx_class_conf_.append(idx_class_conf[i])
|
cur_class_num += 1
|
idx_class_conf_ = idx_class_conf_[:min(len(idx_class_conf_), max_boxes_to_draw)]
|
|
box_class_score = []
|
|
for i in range(0, len(idx_class_conf_)):
|
bboxes[idx_class_conf_[i][0]].append(idx_class_conf_[i][1])
|
bboxes[idx_class_conf_[i][0]].append(idx_class_conf_[i][2])
|
box_class_score.append(bboxes[idx_class_conf_[i][0]])
|
|
img = cv2.imread(imgpath)
|
img_pil = Image.fromarray(img)
|
draw = ImageDraw.Draw(img_pil)
|
|
font = ImageFont.load_default()
|
|
name = imgpath.split("/")[-1][:-4]
|
|
for i in range(0, len(box_class_score)):
|
x1 = box_class_score[i][0] * img.shape[1]
|
y1 = box_class_score[i][1] * img.shape[0]
|
x2 = box_class_score[i][2] * img.shape[1]
|
y2 = box_class_score[i][3] * img.shape[0]
|
|
# draw rect
|
color = (0, int(box_class_score[i][4] / 20.0 * 255), 255)
|
draw.line([(x1, y1), (x1, y2), (x2, y2),
|
(x2, y1), (x1, y1)], width=2, fill=color)
|
|
display_str = CLASSES[box_class_score[i][4]] + ":" + str('%.2f' % box_class_score[i][5])
|
display_str_height = np.ceil((1 + 2 * 0.05) * font.getsize(display_str)[1]) + 1
|
|
if y1 > display_str_height:
|
text_bottom = y1
|
else:
|
text_bottom = y1 + display_str_height
|
|
text_width, text_height = font.getsize(display_str)
|
margin = np.ceil(0.05 * text_height)
|
draw.rectangle([(x1, text_bottom - text_height - 2 * margin), (x1 + text_width, text_bottom)], fill=color)
|
draw.text((x1 + margin, text_bottom - text_height - margin), display_str, fill='black', font=font)
|
|
print('write output image: {}{}_quant.jpg'.format(output_dir, name))
|
np.copyto(img, np.array(img_pil))
|
cv2.imwrite("{}{}_quant.jpg".format(output_dir, name), img)
|
print('write output image finished.')
|