File size: 6,703 Bytes
7cd0692
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
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
# from utils.bbox_op import non_max_supression

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

    # this is the iou of the box against all other boxes
    assert boxes.shape[0] == boxes_area.shape[0]

    ymin = np.maximum(box[0], boxes[:, 0])  # bottom
    xmin = np.maximum(box[1], boxes[:, 1])  # left
    ymax = np.minimum(box[2], boxes[:, 2])  # top
    xmax = np.minimum(box[3], boxes[:, 3])  # rifht

    # we ignore areas where the intersection side would be negative
    # this is done by using maxing the side length by 0
    intersections = np.maximum(ymax - ymin, 0) * np.maximum(xmax - xmin, 0)
    # each union is then the box area
    # added to each other box area minusing their intersection calculated above
    unions = box_area + boxes_area - intersections
    # element wise division
    # if the intersection is 0, then their ratio is 0
    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]

    # box coordinate ranges are inclusive-inclusive
    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.

    """
    #    assert boxes.shape[0] == scores.shape[0]
    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 = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)
    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)
    # filter by threshold
    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"
    # load model
    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)
    
        # image_np = np.array(Image.open(image_path))
        preds = predict_yolo_tflite(interpreter, image_np)
        bboxes, classes, scores = postprocess_prediction(preds)
    
        plot_prediction(image_np, bboxes, classes, scores, label_map)