| |
| |
| """ |
| 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) |