|
|
|
|
|
""" |
|
Created on Wed Oct 4 16:44:12 2023 |
|
|
|
@author: lin |
|
""" |
|
import glob |
|
import sys |
|
sys.path.append('../../..') |
|
import os |
|
import cv2 |
|
import json |
|
import tensorflow as tf |
|
import numpy as np |
|
import matplotlib.pyplot as plt |
|
|
|
|
|
def one_multiple_iou(box, boxes, box_area, boxes_area): |
|
""" |
|
Compute the intersection over union. 1 to multiple |
|
Inputs: |
|
box: numpy array with 1 box, ymin, xmin, ymax, xmax |
|
boxes: numpy array with shape [N, 4] holding N boxes |
|
|
|
Outputs: |
|
a numpy array with shape [N*1] representing box areas |
|
""" |
|
|
|
|
|
assert boxes.shape[0] == boxes_area.shape[0] |
|
|
|
ymin = np.maximum(box[0], boxes[:, 0]) |
|
xmin = np.maximum(box[1], boxes[:, 1]) |
|
ymax = np.minimum(box[2], boxes[:, 2]) |
|
xmax = np.minimum(box[3], boxes[:, 3]) |
|
|
|
|
|
|
|
intersections = np.maximum(ymax - ymin, 0) * np.maximum(xmax - xmin, 0) |
|
|
|
|
|
unions = box_area + boxes_area - intersections |
|
|
|
|
|
ious = intersections / unions |
|
return ious |
|
def select_non_overlapping_bboxes(boxes, scores, iou_th): |
|
ymin = boxes[:, 0] |
|
ymax = boxes[:, 2] |
|
xmin = boxes[:, 1] |
|
xmax = boxes[:, 3] |
|
|
|
|
|
areas = (ymax - ymin) * (xmax - xmin) |
|
scores_indexes = list(np.argsort(scores)) |
|
keep_idx = [] |
|
while len(scores_indexes) > 0: |
|
index = scores_indexes.pop() |
|
keep_idx.append(index) |
|
|
|
ious = one_multiple_iou( |
|
boxes[index], boxes[scores_indexes], areas[index], areas[scores_indexes] |
|
) |
|
filtered_indexes = set((ious > iou_th).nonzero()[0]) |
|
|
|
scores_indexes = [ |
|
v for (i, v) in enumerate(scores_indexes) if i not in filtered_indexes |
|
] |
|
return keep_idx |
|
def non_max_supression(boxes, scores, classes, iou_th): |
|
""" |
|
remover overlaped boundingboxes. Starting by the box with the highest score |
|
if the iou is greater than the threshold, remove it, else keep it. |
|
Inputs: |
|
boxes: numpy array with shape [N, 4] holding N boxes。 [ymin, xmin, ymax, xmax] |
|
scores: numpy array with shape [N, 1] holding the prediction score of each box |
|
classes: numpy array with shape [N, 1] holding the class that each box belongs |
|
iou_th: intersection over union threshold to consider the overlapping boxes have detect 2 objects |
|
Output: |
|
boxes, scores, classes with intersection over union ratio less than the threshold. |
|
|
|
""" |
|
|
|
if len(scores) == 0: |
|
return boxes, scores, classes |
|
keep_idx = select_non_overlapping_bboxes(boxes, scores, iou_th) |
|
|
|
return boxes[keep_idx], scores[keep_idx], classes[keep_idx] |
|
|
|
def preprocess(img_path): |
|
image_np = cv2.imread(img_path) |
|
|
|
image_np = center_crop(image_np) |
|
|
|
image_np = cv2.resize(image_np, (640, 640)) |
|
|
|
image_np = image_np.astype(float) |
|
image_np /= 255.0 |
|
return image_np |
|
|
|
def center_crop(img): |
|
width, height = img.shape[1], img.shape[0] |
|
|
|
crop_size = width if width < height else height |
|
|
|
mid_x, mid_y = int(width/2), int(height/2) |
|
|
|
cs2 = int(crop_size/2) |
|
crop_img = img[mid_y-cs2:mid_y+cs2, mid_x-cs2:mid_x+cs2] |
|
|
|
return crop_img |
|
|
|
def postprocess_prediction(preds): |
|
|
|
bboxes = preds[0][:4] |
|
class_prob = preds[0, 4:] |
|
classes = np.argmax(class_prob, axis=0) |
|
scores = np.max(class_prob, axis=0) |
|
|
|
valid_idx = np.where(scores>=min_th)[0] |
|
bboxes = bboxes[:, valid_idx] |
|
classes = classes[valid_idx] |
|
scores = scores[valid_idx] |
|
bboxes = bboxes.transpose() |
|
bboxes = bboxes*640 |
|
xmin = bboxes[:,0]-bboxes[:,2]//2 |
|
xmax = bboxes[:,0]+bboxes[:,2]//2 |
|
ymin = bboxes[:,1]-bboxes[:,3]//2 |
|
ymax = bboxes[:,1]+bboxes[:,3]//2 |
|
xmin = np.clip(xmin, 0, 640) |
|
ymin = np.clip(ymin, 0, 640) |
|
|
|
bboxes = np.vstack([ymin, xmin, ymax, xmax]) |
|
bboxes = bboxes.transpose() |
|
bboxes = bboxes.astype(int) |
|
|
|
bboxes, scores, classes = non_max_supression(bboxes, scores, classes, iou_th=0.5) |
|
idx = np.argsort(scores)[::-1] |
|
bboxes = bboxes[idx] |
|
classes = classes[idx] |
|
scores = scores[idx] |
|
return bboxes, classes, scores |
|
|
|
def plot_prediction(image_np, bboxes, classes, scores, label_map): |
|
color=(255,0,0) |
|
thickness=5 |
|
font_scale=3 |
|
|
|
for i, box in enumerate(bboxes): |
|
box = bboxes[i, :] |
|
|
|
ymin, xmin, ymax, xmax = box |
|
|
|
image_np = cv2.rectangle(image_np, (xmin, ymin), (xmax, ymax), color=color, thickness=thickness) |
|
text_x = xmin - 10 if xmin > 20 else xmin + 10 |
|
text_y = ymin - 10 if ymin > 20 else ymin + 10 |
|
display_str = label_map[str(classes[i])] |
|
|
|
cv2.putText( |
|
image_np, |
|
display_str, |
|
(text_x, text_y), |
|
cv2.FONT_HERSHEY_SIMPLEX, |
|
font_scale, |
|
color, |
|
thickness, |
|
) |
|
plt.imshow(image_np) |
|
plt.show() |
|
|
|
def predict_yolo_tflite(intenpreter, image_np): |
|
input_tensor = np.expand_dims(image_np, axis=0) |
|
input_tensor = tf.convert_to_tensor(input_tensor, dtype=tf.float32) |
|
|
|
interpreter.set_tensor(input_details[0]['index'], input_tensor.numpy()) |
|
|
|
interpreter.invoke() |
|
preds = interpreter.get_tensor(output_details[0]['index']) |
|
return preds |
|
|
|
if __name__ == "__main__": |
|
min_th = 0.1 |
|
labels_json = "coco_labels.json" |
|
with open(labels_json) as f: |
|
label_map = json.load(f) |
|
img_path = "test_images" |
|
saved_tflite = "tflite_model.tflite" |
|
|
|
interpreter = tf.lite.Interpreter(model_path=saved_tflite) |
|
interpreter.allocate_tensors() |
|
input_details = interpreter.get_input_details() |
|
output_details = interpreter.get_output_details() |
|
print(input_details) |
|
print(output_details) |
|
images = glob.glob(os.path.join(img_path, "*")) |
|
for img in images: |
|
image_np = preprocess(img) |
|
print(image_np.shape) |
|
|
|
|
|
preds = predict_yolo_tflite(interpreter, image_np) |
|
bboxes, classes, scores = postprocess_prediction(preds) |
|
|
|
plot_prediction(image_np, bboxes, classes, scores, label_map) |