Arnav Raina
commited on
Commit
·
0e28ea3
1
Parent(s):
c59d060
Upload 3 files
Browse files- app.py +35 -0
- predict.py +114 -0
- utils.py +72 -0
app.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from predict import ONNXInference
|
3 |
+
|
4 |
+
PRED = []
|
5 |
+
|
6 |
+
def detect(files):
|
7 |
+
model = ONNXInference(
|
8 |
+
model_path="/home/neo/Downloads/torchFlow/models/torchFlow-ckpt.onnx",
|
9 |
+
files=files,
|
10 |
+
save_image=False,
|
11 |
+
save_path="/home/neo/Downloads/torchFlow/"
|
12 |
+
)
|
13 |
+
res = model.run()
|
14 |
+
img_id = res["IMG_ID"]
|
15 |
+
pred_lab = res["PRED_LAB"],
|
16 |
+
pred_ct = res["PRED_CT"],
|
17 |
+
geo_tag_url = res["GEO_TAG_URL"]
|
18 |
+
PRED.append(pred_ct)
|
19 |
+
return f"Predicted"
|
20 |
+
|
21 |
+
with gr.Blocks() as demo:
|
22 |
+
with gr.Row():
|
23 |
+
output=gr.Image()
|
24 |
+
with gr.Row():
|
25 |
+
btn = gr.UploadButton(
|
26 |
+
label="Upload Image",
|
27 |
+
file_types = ['.jpg','.jpeg'],
|
28 |
+
file_count = "multiple")
|
29 |
+
btn.upload(fn=detect, inputs=btn)
|
30 |
+
with gr.Column(scale=1, min_width=600):
|
31 |
+
gr.Markdown(f"Output here")
|
32 |
+
if PRED is not None:
|
33 |
+
gr.Markdown(f"Predicted: {PRED}")
|
34 |
+
|
35 |
+
demo.launch()
|
predict.py
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Inference script for YOLOv8 ONNX model
|
2 |
+
|
3 |
+
import os
|
4 |
+
import cv2
|
5 |
+
import numpy as np
|
6 |
+
import onnxruntime
|
7 |
+
import pandas as pd
|
8 |
+
from exif import Image
|
9 |
+
from pathlib import Path
|
10 |
+
from utils import load_img, nms, xywh2xyxy
|
11 |
+
|
12 |
+
class ONNXInference():
|
13 |
+
def __init__(self, model_path, files, save_image, save_path='./'):
|
14 |
+
self.model_path = model_path
|
15 |
+
self.files = files
|
16 |
+
self.conf_thres = 0.2 # confidence threshold for onnx model
|
17 |
+
self.iou_thres = 0.7 # intersection-over-union threshold for onnx model
|
18 |
+
self.save_image = save_image
|
19 |
+
self.save_path = save_path
|
20 |
+
|
21 |
+
def run(self):
|
22 |
+
opt_session = onnxruntime.SessionOptions()
|
23 |
+
opt_session.enable_mem_pattern = True # True: memory efficient
|
24 |
+
opt_session.enable_cpu_mem_arena = True # True: memory efficient
|
25 |
+
opt_session.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL # ALL: for optimization
|
26 |
+
|
27 |
+
EP_list = ['CUDAExecutionProvider', 'CPUExecutionProvider'] # providers list
|
28 |
+
ort_session = onnxruntime.InferenceSession(self.model_path, sess_options=opt_session, providers=EP_list)
|
29 |
+
|
30 |
+
model_inputs = ort_session.get_inputs() # List of input nodes for loaded ONNX model
|
31 |
+
input_names = [model_inputs[i].name for i in range(len(model_inputs))] # names of the input nodes
|
32 |
+
input_shape = model_inputs[0].shape # shape of input
|
33 |
+
print(input_shape)
|
34 |
+
model_output = ort_session.get_outputs() # list of output nodes for loaded ONNX model
|
35 |
+
output_names = [model_output[i].name for i in range(len(model_output))] # list of output names
|
36 |
+
|
37 |
+
IMG_ID = []
|
38 |
+
PRED_LAB = []
|
39 |
+
GEO_TAG_URL = []
|
40 |
+
PRED_CT = []
|
41 |
+
file_paths = [file.name for file in self.files]
|
42 |
+
|
43 |
+
for i in file_paths:
|
44 |
+
# Loading images
|
45 |
+
image, image_height, image_width, input_height, input_width, input_tensor = load_img(
|
46 |
+
Path(i).as_posix(),
|
47 |
+
input_shape
|
48 |
+
)
|
49 |
+
|
50 |
+
# Run
|
51 |
+
outputs = ort_session.run(output_names, {input_names[0]: input_tensor})[0] # ONNX output as numpy array
|
52 |
+
|
53 |
+
predictions = np.squeeze(outputs).T
|
54 |
+
CONF_THRESHOLD = self.conf_thres
|
55 |
+
scores = np.max(predictions[:, 4:], axis=1)
|
56 |
+
predictions = predictions[scores > CONF_THRESHOLD, :] # Filter out object confidence scores below threshold
|
57 |
+
scores = scores[scores > CONF_THRESHOLD]
|
58 |
+
class_ids = np.argmax(predictions[:, 4:], axis=1)
|
59 |
+
boxes = predictions[:, :4] # (x,y,w,h)
|
60 |
+
|
61 |
+
#rescale box
|
62 |
+
input_shape = np.array([input_width, input_height, input_width, input_height])
|
63 |
+
boxes = np.divide(boxes, input_shape, dtype=np.float32)
|
64 |
+
boxes *= np.array([image_width, image_height, image_width, image_height])
|
65 |
+
boxes = boxes.astype(np.int32)
|
66 |
+
|
67 |
+
|
68 |
+
# Apply NMS to suppress weak, overlapping bounding boxes
|
69 |
+
IOU_THRESHOLD = self.iou_thres
|
70 |
+
indices = nms(xywh2xyxy(boxes), scores, IOU_THRESHOLD)
|
71 |
+
|
72 |
+
if self.save_image:
|
73 |
+
image_draw = image.copy()
|
74 |
+
for (bbox, score, label) in zip(xywh2xyxy(boxes[indices]), scores[indices], class_ids[indices]):
|
75 |
+
bbox = bbox.round().astype(np.int32).tolist()
|
76 |
+
cls_id = int(label)
|
77 |
+
CLASSES = ["plastic"]
|
78 |
+
cls = CLASSES[cls_id]
|
79 |
+
color = (0,255,0)
|
80 |
+
cv2.rectangle(image_draw, tuple(bbox[:2]), tuple(bbox[2:]), color, 2)
|
81 |
+
cv2.putText(image_draw,
|
82 |
+
f'{cls}:{int(score*100)}', (bbox[0], bbox[1] - 2),
|
83 |
+
cv2.FONT_HERSHEY_SIMPLEX,
|
84 |
+
0.60, [225, 255, 255],
|
85 |
+
thickness=1)
|
86 |
+
cv2.imwrite(f"result_[0].jpg", image_draw)
|
87 |
+
|
88 |
+
# preds
|
89 |
+
boxes = boxes[indices]
|
90 |
+
scores = scores[indices]
|
91 |
+
pred_ct = len(scores)
|
92 |
+
|
93 |
+
# Getting geo-coordinates
|
94 |
+
with open(i, "rb") as image_geo:
|
95 |
+
my_image = Image(image_geo)
|
96 |
+
dd_lat = my_image.gps_latitude[0] + (my_image.gps_latitude[1]/60) + (my_image.gps_latitude[2]/3600)
|
97 |
+
dd_long = my_image.gps_longitude[0] + (my_image.gps_longitude[1]/60) + (my_image.gps_longitude[2]/3600)
|
98 |
+
url = f"https://www.google.com/maps?q={dd_lat:.7f}%2C{dd_long:.7f}"
|
99 |
+
GEO_TAG_URL.append(url)
|
100 |
+
|
101 |
+
if pred_ct is not None:
|
102 |
+
PRED_LAB.append("Yes")
|
103 |
+
IMG_ID.append(str(i))
|
104 |
+
PRED_CT.append(pred_ct)
|
105 |
+
|
106 |
+
|
107 |
+
result = {
|
108 |
+
"IMG_ID": IMG_ID,
|
109 |
+
"PRED_LAB": PRED_LAB,
|
110 |
+
"PRED_CT": PRED_CT,
|
111 |
+
"GEO_TAG_URL": GEO_TAG_URL
|
112 |
+
}
|
113 |
+
|
114 |
+
return result
|
utils.py
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Utilities
|
2 |
+
|
3 |
+
import cv2
|
4 |
+
import numpy as np
|
5 |
+
from PIL import Image
|
6 |
+
|
7 |
+
def load_img(img_path, input_shape):
|
8 |
+
# Loading image
|
9 |
+
image = cv2.imread(img_path)
|
10 |
+
image_height, image_width = image.shape[:2]
|
11 |
+
Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
12 |
+
|
13 |
+
input_height, input_width = input_shape[2:]
|
14 |
+
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
15 |
+
resized = cv2.resize(image_rgb, (input_width, input_height)) # image resized as req by onnx model
|
16 |
+
|
17 |
+
input_image = resized / 255.0 # scaling image
|
18 |
+
input_image = input_image.transpose(2,0,1) # dim rearranged as req by onnx (batch_size, channel, height, width)
|
19 |
+
input_tensor = input_image[np.newaxis, :, :, :].astype(np.float32)
|
20 |
+
|
21 |
+
return image, image_height, image_width, input_height, input_width, input_tensor
|
22 |
+
|
23 |
+
def nms(boxes, scores, iou_threshold):
|
24 |
+
# Sort by score
|
25 |
+
sorted_indices = np.argsort(scores)[::-1]
|
26 |
+
|
27 |
+
keep_boxes = []
|
28 |
+
while sorted_indices.size > 0:
|
29 |
+
# Pick the last box
|
30 |
+
box_id = sorted_indices[0]
|
31 |
+
keep_boxes.append(box_id)
|
32 |
+
|
33 |
+
# Compute IoU of the picked box with the rest
|
34 |
+
ious = compute_iou(boxes[box_id, :], boxes[sorted_indices[1:], :])
|
35 |
+
|
36 |
+
# Remove boxes with IoU over the threshold
|
37 |
+
keep_indices = np.where(ious < iou_threshold)[0]
|
38 |
+
|
39 |
+
# print(keep_indices.shape, sorted_indices.shape)
|
40 |
+
sorted_indices = sorted_indices[keep_indices + 1]
|
41 |
+
|
42 |
+
return keep_boxes
|
43 |
+
|
44 |
+
def compute_iou(box, boxes):
|
45 |
+
# Compute xmin, ymin, xmax, ymax for both boxes
|
46 |
+
xmin = np.maximum(box[0], boxes[:, 0])
|
47 |
+
ymin = np.maximum(box[1], boxes[:, 1])
|
48 |
+
xmax = np.minimum(box[2], boxes[:, 2])
|
49 |
+
ymax = np.minimum(box[3], boxes[:, 3])
|
50 |
+
|
51 |
+
# Compute intersection area
|
52 |
+
intersection_area = np.maximum(0, xmax - xmin) * np.maximum(0, ymax - ymin)
|
53 |
+
|
54 |
+
# Compute union area
|
55 |
+
box_area = (box[2] - box[0]) * (box[3] - box[1])
|
56 |
+
boxes_area = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
57 |
+
union_area = box_area + boxes_area - intersection_area
|
58 |
+
|
59 |
+
# Compute IoU
|
60 |
+
iou = intersection_area / union_area
|
61 |
+
|
62 |
+
return iou
|
63 |
+
|
64 |
+
|
65 |
+
def xywh2xyxy(x):
|
66 |
+
# Convert bounding box (x, y, w, h) to bounding box (x1, y1, x2, y2)
|
67 |
+
y = np.copy(x)
|
68 |
+
y[..., 0] = x[..., 0] - x[..., 2] / 2
|
69 |
+
y[..., 1] = x[..., 1] - x[..., 3] / 2
|
70 |
+
y[..., 2] = x[..., 0] + x[..., 2] / 2
|
71 |
+
y[..., 3] = x[..., 1] + x[..., 3] / 2
|
72 |
+
return y
|