Last active
November 2, 2023 21:39
-
-
Save JarbasAl/68100c890df10d6e03f5df85063d7080 to your computer and use it in GitHub Desktop.
obj detect ssd mobilenet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # adapted from https://github.com/kaka-lin/object-detection | |
| # MIT License | |
| import colorsys | |
| import random | |
| import time | |
| import cv2 | |
| import numpy as np | |
| import tensorflow as tf | |
| class ObjDetect: | |
| def __init__(self, model_path, valid_labels=None): | |
| self.valid_labels = valid_labels or [] | |
| # Load TFLite model and allocate tensors. | |
| self.interpreter = tf.lite.Interpreter(model_path=model_path) | |
| self.interpreter.allocate_tensors() | |
| # Get input and output tensors. | |
| self.input_details = self.interpreter.get_input_details() | |
| self.output_details = self.interpreter.get_output_details() | |
| # label | |
| self.class_names = ['None1', 'person', 'bicycle', 'car', 'motorbike', 'airplane', 'bus', 'train', 'truck', | |
| 'boat', 'traffic light', 'fire hydrant', 'None12', 'stop sign', 'parking meter', 'bench', | |
| 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', | |
| 'None', 'backpack', 'umbrella', 'None29', 'Noe30', 'handbag', 'tie', 'suitcase', 'frisbee', | |
| 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', | |
| 'surfboard', 'tennis racket', 'bottle', 'None45', 'wine glass', 'cup', 'fork', 'knife', | |
| 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', | |
| 'pizza', 'donut', 'cake', 'chair', 'sofa', 'pottedplant', 'bed', 'None66', 'diningtable', | |
| 'None68', 'None69', 'toilet', 'None71', 'tvmonitor', 'laptop', 'mouse', 'remote', | |
| 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'None83', | |
| 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] | |
| # Generate colors for drawing bounding boxes. | |
| self.colors = self.generate_colors(self.class_names) | |
| @staticmethod | |
| def generate_colors(class_names): | |
| hsv_tuples = [(x / len(class_names), 1., 1.) for x in range(len(class_names))] | |
| colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) | |
| colors = list(map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), colors)) | |
| random.seed(10101) # Fixed seed for consistent colors across runs. | |
| random.shuffle(colors) # Shuffle colors to decorrelate adjacent classes. | |
| random.seed(None) # Reset seed to default. | |
| return colors | |
| @staticmethod | |
| def preprocess_image(image, model_image_size=(300, 300)): | |
| image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | |
| # image = cv2.resize(image, tuple(reversed(model_image_size)), interpolation=cv2.INTER_AREA) | |
| image = np.array(image, dtype='float32') | |
| image = np.expand_dims(image, 0) # Add batch dimension. | |
| return image | |
| @staticmethod | |
| def preprocess_image_for_tflite(image, model_image_size=300): | |
| image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | |
| image = cv2.resize(image, (model_image_size, model_image_size)) | |
| image = np.expand_dims(image, axis=0) | |
| image = (2.0 / 255.0) * image - 1.0 | |
| image = image.astype('float32') | |
| return image | |
| @staticmethod | |
| def non_max_suppression(scores, boxes, classes, max_boxes=10, min_score_thresh=0.5): | |
| out_boxes = [] | |
| out_scores = [] | |
| out_classes = [] | |
| if not max_boxes: | |
| max_boxes = boxes.shape[0] | |
| for i in range(min(max_boxes, boxes.shape[0])): | |
| if scores is None or scores[i] > min_score_thresh: | |
| out_boxes.append(boxes[i]) | |
| out_scores.append(scores[i]) | |
| out_classes.append(classes[i]) | |
| out_boxes = np.array(out_boxes) | |
| out_scores = np.array(out_scores) | |
| out_classes = np.array(out_classes) | |
| return out_scores, out_boxes, out_classes | |
| def draw_boxes(self, image, out_scores, out_boxes, out_classes): | |
| h, w, _ = image.shape | |
| for i, c in reversed(list(enumerate(out_classes))): | |
| predicted_class = self.class_names[c] | |
| if self.valid_labels and predicted_class not in self.valid_labels: | |
| continue | |
| box = out_boxes[i] | |
| score = out_scores[i] | |
| label = '{} {:.2f}'.format(predicted_class, score) | |
| ymin, xmin, ymax, xmax = box | |
| left, right, top, bottom = (xmin * w, xmax * w, | |
| ymin * h, ymax * h) | |
| top = max(0, np.floor(top + 0.5).astype('int32')) | |
| left = max(0, np.floor(left + 0.5).astype('int32')) | |
| bottom = min(h, np.floor(bottom + 0.5).astype('int32')) | |
| right = min(w, np.floor(right + 0.5).astype('int32')) | |
| # print(label, (left, top), (right, bottom)) | |
| # colors: RGB, opencv: BGR | |
| cv2.rectangle(image, (left, top), (right, bottom), tuple(reversed(self.colors[c])), 6) | |
| font_face = cv2.FONT_HERSHEY_SIMPLEX | |
| font_scale = 1 | |
| font_thickness = 2 | |
| label_size = cv2.getTextSize(label, font_face, font_scale, font_thickness)[0] | |
| label_rect_left, label_rect_top = int(left - 3), int(top - 3) | |
| label_rect_right, label_rect_bottom = int(left + 3 + label_size[0]), int(top - 5 - label_size[1]) | |
| cv2.rectangle(image, (label_rect_left, label_rect_top), (label_rect_right, label_rect_bottom), | |
| tuple(reversed(self.colors[c])), -1) | |
| cv2.putText(image, label, (left, int(top - 4)), font_face, font_scale, (0, 0, 0), font_thickness, | |
| cv2.LINE_AA) | |
| return image | |
| def run_detection(self, image, interpreter): | |
| # Run model: start to detect | |
| # Sets the value of the input tensor. | |
| interpreter.set_tensor(self.input_details[0]['index'], image) | |
| # Invoke the interpreter. | |
| interpreter.invoke() | |
| # get results | |
| boxes = interpreter.get_tensor(self.output_details[0]['index']) | |
| classes = interpreter.get_tensor(self.output_details[1]['index']) | |
| scores = interpreter.get_tensor(self.output_details[2]['index']) | |
| boxes, scores, classes = np.squeeze(boxes), np.squeeze(scores), np.squeeze(classes + 1).astype(np.int32) | |
| out_scores, out_boxes, out_classes = self.non_max_suppression(scores, boxes, classes) | |
| return out_scores, out_boxes, out_classes | |
| def real_time_object_detection(self, show=True): | |
| camera = cv2.VideoCapture(0) | |
| while camera.isOpened(): | |
| start = time.time() | |
| ret, frame = camera.read() | |
| if ret: | |
| image_data = self.preprocess_image_for_tflite(frame, model_image_size=300) | |
| out_scores, out_boxes, out_classes = self.run_detection(image_data, self.interpreter) | |
| if show: | |
| # Draw bounding boxes on the image file | |
| result = self.draw_boxes(frame, out_scores, out_boxes, out_classes, self.class_names, self.colors) | |
| end = time.time() | |
| # fps | |
| t = end - start | |
| fps = "Fps: {:.2f}".format(1 / t) | |
| cv2.putText(result, fps, (10, 30), | |
| cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA) | |
| cv2.imshow("Object detection - ssdlite_mobilenet_v2", frame) | |
| else: | |
| for i, c in reversed(list(enumerate(out_classes))): | |
| predicted_class = self.class_names[c] | |
| if self.valid_labels and predicted_class not in self.valid_labels: | |
| continue | |
| score = out_scores[i] | |
| print("DETECTED:", predicted_class, score) | |
| if cv2.waitKey(1) & 0xFF == ord('q'): | |
| break | |
| camera.release() | |
| cv2.destroyAllWindows() | |
| if __name__ == '__main__': | |
| # download from https://drive.google.com/file/d/1Ha9yfjkweCatEo6UoZgZyHMeyIBGe5FO/view?usp=sharing | |
| o = ObjDetect(model_path="ssdlite_mobilenet_v2.tflite", | |
| valid_labels=["dog", "person", "cat"]) | |
| o.real_time_object_detection(show=False) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment