phuochungus commited on
Commit
6907879
1 Parent(s): 36753c2

save change

Browse files
app/detector/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .yolov8.YOLOv8 import YOLOv8
2
+
3
+ model_path = "./model"
4
+ detector = YOLOv8(model_path)
app/detector/yolov8/YOLOv8.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import cv2
3
+ import numpy as np
4
+ import onnxruntime
5
+
6
+ from yolov8.utils import xywh2xyxy, draw_detections, multiclass_nms
7
+
8
+
9
+ class YOLOv8:
10
+ def __init__(self, path, conf_thres=0.7, iou_thres=0.5):
11
+ self.conf_threshold = conf_thres
12
+ self.iou_threshold = iou_thres
13
+
14
+ # Initialize model
15
+ self.initialize_model(path)
16
+
17
+ def __call__(self, image):
18
+ return self.detect_objects(image)
19
+
20
+ def initialize_model(self, path):
21
+ self.session = onnxruntime.InferenceSession(
22
+ path, providers=onnxruntime.get_available_providers()
23
+ )
24
+ # Get model info
25
+ self.get_input_details()
26
+ self.get_output_details()
27
+
28
+ def detect_objects(self, image):
29
+ input_tensor = self.prepare_input(image)
30
+
31
+ # Perform inference on the image
32
+ outputs = self.inference(input_tensor)
33
+
34
+ self.boxes, self.scores, self.class_ids = self.process_output(outputs)
35
+
36
+ return self.boxes, self.scores, self.class_ids
37
+
38
+ def prepare_input(self, image):
39
+ self.img_height, self.img_width = image.shape[:2]
40
+
41
+ input_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
42
+
43
+ # Resize input image
44
+ input_img = cv2.resize(input_img, (self.input_width, self.input_height))
45
+
46
+ # Scale input pixel values to 0 to 1
47
+ input_img = input_img / 255.0
48
+ input_img = input_img.transpose(2, 0, 1)
49
+ input_tensor = input_img[np.newaxis, :, :, :].astype(np.float32)
50
+
51
+ return input_tensor
52
+
53
+ def inference(self, input_tensor):
54
+ start = time.perf_counter()
55
+ outputs = self.session.run(
56
+ self.output_names, {self.input_names[0]: input_tensor}
57
+ )
58
+
59
+ # print(f"Inference time: {(time.perf_counter() - start)*1000:.2f} ms")
60
+ return outputs
61
+
62
+ def process_output(self, output):
63
+ predictions = np.squeeze(output[0]).T
64
+
65
+ # Filter out object confidence scores below threshold
66
+ scores = np.max(predictions[:, 4:], axis=1)
67
+ predictions = predictions[scores > self.conf_threshold, :]
68
+ scores = scores[scores > self.conf_threshold]
69
+
70
+ if len(scores) == 0:
71
+ return [], [], []
72
+
73
+ # Get the class with the highest confidence
74
+ class_ids = np.argmax(predictions[:, 4:], axis=1)
75
+
76
+ # Get bounding boxes for each object
77
+ boxes = self.extract_boxes(predictions)
78
+
79
+ # Apply non-maxima suppression to suppress weak, overlapping bounding boxes
80
+ # indices = nms(boxes, scores, self.iou_threshold)
81
+ indices = multiclass_nms(boxes, scores, class_ids, self.iou_threshold)
82
+
83
+ return boxes[indices], scores[indices], class_ids[indices]
84
+
85
+ def extract_boxes(self, predictions):
86
+ # Extract boxes from predictions
87
+ boxes = predictions[:, :4]
88
+
89
+ # Scale boxes to original image dimensions
90
+ boxes = self.rescale_boxes(boxes)
91
+
92
+ # Convert boxes to xyxy format
93
+ boxes = xywh2xyxy(boxes)
94
+
95
+ return boxes
96
+
97
+ def rescale_boxes(self, boxes):
98
+ # Rescale boxes to original image dimensions
99
+ input_shape = np.array(
100
+ [self.input_width, self.input_height, self.input_width, self.input_height]
101
+ )
102
+ boxes = np.divide(boxes, input_shape, dtype=np.float32)
103
+ boxes *= np.array(
104
+ [self.img_width, self.img_height, self.img_width, self.img_height]
105
+ )
106
+ return boxes
107
+
108
+ def draw_detections(self, image, draw_scores=True, mask_alpha=0.4):
109
+ return draw_detections(
110
+ image, self.boxes, self.scores, self.class_ids, mask_alpha
111
+ )
112
+
113
+ def get_input_details(self):
114
+ model_inputs = self.session.get_inputs()
115
+ self.input_names = [model_inputs[i].name for i in range(len(model_inputs))]
116
+
117
+ self.input_shape = model_inputs[0].shape
118
+ self.input_height = self.input_shape[2]
119
+ self.input_width = self.input_shape[3]
120
+
121
+ def get_output_details(self):
122
+ model_outputs = self.session.get_outputs()
123
+ self.output_names = [model_outputs[i].name for i in range(len(model_outputs))]
app/detector/yolov8/__init__.py ADDED
File without changes
app/detector/yolov8/utils.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Tuple
2
+ import numpy as np
3
+ import cv2
4
+
5
+ class_names = [
6
+ "person",
7
+ "bicycle",
8
+ "car",
9
+ "motorcycle",
10
+ "airplane",
11
+ "bus",
12
+ "train",
13
+ "truck",
14
+ "boat",
15
+ "traffic light",
16
+ "fire hydrant",
17
+ "stop sign",
18
+ "parking meter",
19
+ "bench",
20
+ "bird",
21
+ "cat",
22
+ "dog",
23
+ "horse",
24
+ "sheep",
25
+ "cow",
26
+ "elephant",
27
+ "bear",
28
+ "zebra",
29
+ "giraffe",
30
+ "backpack",
31
+ "umbrella",
32
+ "handbag",
33
+ "tie",
34
+ "suitcase",
35
+ "frisbee",
36
+ "skis",
37
+ "snowboard",
38
+ "sports ball",
39
+ "kite",
40
+ "baseball bat",
41
+ "baseball glove",
42
+ "skateboard",
43
+ "surfboard",
44
+ "tennis racket",
45
+ "bottle",
46
+ "wine glass",
47
+ "cup",
48
+ "fork",
49
+ "knife",
50
+ "spoon",
51
+ "bowl",
52
+ "banana",
53
+ "apple",
54
+ "sandwich",
55
+ "orange",
56
+ "broccoli",
57
+ "carrot",
58
+ "hot dog",
59
+ "pizza",
60
+ "donut",
61
+ "cake",
62
+ "chair",
63
+ "couch",
64
+ "potted plant",
65
+ "bed",
66
+ "dining table",
67
+ "toilet",
68
+ "tv",
69
+ "laptop",
70
+ "mouse",
71
+ "remote",
72
+ "keyboard",
73
+ "cell phone",
74
+ "microwave",
75
+ "oven",
76
+ "toaster",
77
+ "sink",
78
+ "refrigerator",
79
+ "book",
80
+ "clock",
81
+ "vase",
82
+ "scissors",
83
+ "teddy bear",
84
+ "hair drier",
85
+ "toothbrush",
86
+ ]
87
+
88
+ # Create a list of colors for each class where each color is a tuple of 3 integer values
89
+ rng = np.random.default_rng(3)
90
+ colors = rng.uniform(0, 255, size=(len(class_names), 3))
91
+
92
+
93
+ def nms(boxes, scores, iou_threshold):
94
+ # Sort by score
95
+ sorted_indices = np.argsort(scores)[::-1]
96
+
97
+ keep_boxes = []
98
+ while sorted_indices.size > 0:
99
+ # Pick the last box
100
+ box_id = sorted_indices[0]
101
+ keep_boxes.append(box_id)
102
+
103
+ # Compute IoU of the picked box with the rest
104
+ ious = compute_iou(boxes[box_id, :], boxes[sorted_indices[1:], :])
105
+
106
+ # Remove boxes with IoU over the threshold
107
+ keep_indices = np.where(ious < iou_threshold)[0]
108
+
109
+ # print(keep_indices.shape, sorted_indices.shape)
110
+ sorted_indices = sorted_indices[keep_indices + 1]
111
+
112
+ return keep_boxes
113
+
114
+
115
+ def multiclass_nms(boxes, scores, class_ids, iou_threshold):
116
+ unique_class_ids = np.unique(class_ids)
117
+
118
+ keep_boxes = []
119
+ for class_id in unique_class_ids:
120
+ class_indices = np.where(class_ids == class_id)[0]
121
+ class_boxes = boxes[class_indices, :]
122
+ class_scores = scores[class_indices]
123
+
124
+ class_keep_boxes = nms(class_boxes, class_scores, iou_threshold)
125
+ keep_boxes.extend(class_indices[class_keep_boxes])
126
+
127
+ return keep_boxes
128
+
129
+
130
+ def compute_iou(box, boxes):
131
+ # Compute xmin, ymin, xmax, ymax for both boxes
132
+ xmin = np.maximum(box[0], boxes[:, 0])
133
+ ymin = np.maximum(box[1], boxes[:, 1])
134
+ xmax = np.minimum(box[2], boxes[:, 2])
135
+ ymax = np.minimum(box[3], boxes[:, 3])
136
+
137
+ # Compute intersection area
138
+ intersection_area = np.maximum(0, xmax - xmin) * np.maximum(0, ymax - ymin)
139
+
140
+ # Compute union area
141
+ box_area = (box[2] - box[0]) * (box[3] - box[1])
142
+ boxes_area = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
143
+ union_area = box_area + boxes_area - intersection_area
144
+
145
+ # Compute IoU
146
+ iou = intersection_area / union_area
147
+
148
+ return iou
149
+
150
+
151
+ def xywh2xyxy(x):
152
+ # Convert bounding box (x, y, w, h) to bounding box (x1, y1, x2, y2)
153
+ y = np.copy(x)
154
+ y[..., 0] = x[..., 0] - x[..., 2] / 2
155
+ y[..., 1] = x[..., 1] - x[..., 3] / 2
156
+ y[..., 2] = x[..., 0] + x[..., 2] / 2
157
+ y[..., 3] = x[..., 1] + x[..., 3] / 2
158
+ return y
159
+
160
+
161
+ def draw_detections(image, boxes, scores, class_ids, mask_alpha=0.3):
162
+ det_img = image.copy()
163
+
164
+ img_height, img_width = image.shape[:2]
165
+ font_size = min([img_height, img_width]) * 0.0006
166
+ text_thickness = int(min([img_height, img_width]) * 0.001)
167
+
168
+ det_img = draw_masks(det_img, boxes, class_ids, mask_alpha)
169
+
170
+ # Draw bounding boxes and labels of detections
171
+ for class_id, box, score in zip(class_ids, boxes, scores):
172
+ color = colors[class_id]
173
+
174
+ draw_box(det_img, box, color)
175
+
176
+ label = class_names[class_id]
177
+ caption = f"{label} {int(score * 100)}%"
178
+ draw_text(det_img, caption, box, color, font_size, text_thickness)
179
+
180
+ return det_img
181
+
182
+
183
+ def draw_box(
184
+ image: np.ndarray,
185
+ box: np.ndarray,
186
+ color: Tuple[int, int, int] = (0, 0, 255),
187
+ thickness: int = 2,
188
+ ) -> np.ndarray:
189
+ x1, y1, x2, y2 = box.astype(int)
190
+ return cv2.rectangle(image, (x1, y1), (x2, y2), color, thickness)
191
+
192
+
193
+ def draw_text(
194
+ image: np.ndarray,
195
+ text: str,
196
+ box: np.ndarray,
197
+ color: Tuple[int, int, int] = (0, 0, 255),
198
+ font_size: float = 0.001,
199
+ text_thickness: int = 2,
200
+ ) -> np.ndarray:
201
+ x1, y1, x2, y2 = box.astype(int)
202
+ (tw, th), _ = cv2.getTextSize(
203
+ text=text,
204
+ fontFace=cv2.FONT_HERSHEY_SIMPLEX,
205
+ fontScale=font_size,
206
+ thickness=text_thickness,
207
+ )
208
+ th = int(th * 1.2)
209
+
210
+ cv2.rectangle(image, (x1, y1), (x1 + tw, y1 - th), color, -1)
211
+
212
+ return cv2.putText(
213
+ image,
214
+ text,
215
+ (x1, y1),
216
+ cv2.FONT_HERSHEY_SIMPLEX,
217
+ font_size,
218
+ (255, 255, 255),
219
+ text_thickness,
220
+ cv2.LINE_AA,
221
+ )
222
+
223
+
224
+ def draw_masks(
225
+ image: np.ndarray, boxes: np.ndarray, classes: np.ndarray, mask_alpha: float = 0.3
226
+ ) -> np.ndarray:
227
+ mask_img = image.copy()
228
+
229
+ # Draw bounding boxes and labels of detections
230
+ for box, class_id in zip(boxes, classes):
231
+ color = colors[class_id]
232
+
233
+ x1, y1, x2, y2 = box.astype(int)
234
+
235
+ # Draw fill rectangle in mask image
236
+ cv2.rectangle(mask_img, (x1, y1), (x2, y2), color, -1)
237
+
238
+ return cv2.addWeighted(mask_img, mask_alpha, image, 1 - mask_alpha, 0)
app/routers/auth.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Depends
2
+
3
+ from app.dependencies import get_current_user
4
+
5
+
6
+ router = APIRouter(prefix="/auth", tags=["Auth"])
7
+
8
+
9
+ @router.post("/login")
10
+ def login(email: str, password: str):
11
+ pass