Spaces:
Runtime error
Runtime error
| import time | |
| import torch | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import matplotlib.patches as patches | |
| def boxes_iou(box1, box2): | |
| """ | |
| Returns the IOU between `box1` and `box2` (i.e intersection area divided by union area) | |
| """ | |
| # Get the Width and Height of each bounding box | |
| width_box1 = box1[2] | |
| height_box1 = box1[3] | |
| width_box2 = box2[2] | |
| height_box2 = box2[3] | |
| # Calculate the area of the each bounding box | |
| area_box1 = width_box1 * height_box1 | |
| area_box2 = width_box2 * height_box2 | |
| # Find the vertical edges of the union of the two bounding boxes | |
| mx = min(box1[0] - width_box1/2.0, box2[0] - width_box2/2.0) | |
| Mx = max(box1[0] + width_box1/2.0, box2[0] + width_box2/2.0) | |
| # Calculate the width of the union of the two bounding boxes | |
| union_width = Mx - mx | |
| # Find the horizontal edges of the union of the two bounding boxes | |
| my = min(box1[1] - height_box1/2.0, box2[1] - height_box2/2.0) | |
| My = max(box1[1] + height_box1/2.0, box2[1] + height_box2/2.0) | |
| # Calculate the height of the union of the two bounding boxes | |
| union_height = My - my | |
| # Calculate the width and height of the area of intersection of the two bounding boxes | |
| intersection_width = width_box1 + width_box2 - union_width | |
| intersection_height = height_box1 + height_box2 - union_height | |
| # If the the boxes don't overlap then their IOU is zero | |
| if intersection_width <= 0 or intersection_height <= 0: | |
| return 0.0 | |
| # Calculate the area of intersection of the two bounding boxes | |
| intersection_area = intersection_width * intersection_height | |
| # Calculate the area of the union of the two bounding boxes | |
| union_area = area_box1 + area_box2 - intersection_area | |
| # Calculate the IOU | |
| iou = intersection_area/union_area | |
| return iou | |
| def nms(boxes, iou_thresh): | |
| """ | |
| Performs Non maximal suppression technique to `boxes` using `iou_thresh` threshold | |
| """ | |
| # print(boxes.shape) | |
| # If there are no bounding boxes do nothing | |
| if len(boxes) == 0: | |
| return boxes | |
| # Create a PyTorch Tensor to keep track of the detection confidence | |
| # of each predicted bounding box | |
| det_confs = torch.zeros(len(boxes)) | |
| # Get the detection confidence of each predicted bounding box | |
| for i in range(len(boxes)): | |
| det_confs[i] = boxes[i][4] | |
| # Sort the indices of the bounding boxes by detection confidence value in descending order. | |
| # We ignore the first returned element since we are only interested in the sorted indices | |
| _,sortIds = torch.sort(det_confs, descending = True) | |
| # Create an empty list to hold the best bounding boxes after | |
| # Non-Maximal Suppression (NMS) is performed | |
| best_boxes = [] | |
| # Perform Non-Maximal Suppression | |
| for i in range(len(boxes)): | |
| # Get the bounding box with the highest detection confidence first | |
| box_i = boxes[sortIds[i]] | |
| # Check that the detection confidence is not zero | |
| if box_i[4] > 0: | |
| # Save the bounding box | |
| best_boxes.append(box_i) | |
| # Go through the rest of the bounding boxes in the list and calculate their IOU with | |
| # respect to the previous selected box_i. | |
| for j in range(i + 1, len(boxes)): | |
| box_j = boxes[sortIds[j]] | |
| # If the IOU of box_i and box_j is higher than the given IOU threshold set | |
| # box_j's detection confidence to zero. | |
| if boxes_iou(box_i, box_j) > iou_thresh: | |
| box_j[4] = 0 | |
| return best_boxes | |
| def detect_objects(model, img, iou_thresh, nms_thresh): | |
| # Start the time. This is done to calculate how long the detection takes. | |
| start = time.time() | |
| # Set the model to evaluation mode. | |
| model.eval() | |
| # Convert the image from a NumPy ndarray to a PyTorch Tensor of the correct shape. | |
| # The image is transposed, then converted to a FloatTensor of dtype float32, then | |
| # Normalized to values between 0 and 1, and finally unsqueezed to have the correct | |
| # shape of 1 x 3 x 416 x 416 | |
| img = torch.from_numpy(img.transpose(2,0,1)).float().div(255.0).unsqueeze(0) | |
| # Feed the image to the neural network with the corresponding NMS threshold. | |
| # The first step in NMS is to remove all bounding boxes that have a very low | |
| # probability of detection. All predicted bounding boxes with a value less than | |
| # the given NMS threshold will be removed. | |
| list_boxes = model(img, nms_thresh) | |
| # Make a new list with all the bounding boxes returned by the neural network | |
| boxes = list_boxes[0][0] + list_boxes[1][0] + list_boxes[2][0] | |
| # Perform the second step of NMS on the bounding boxes returned by the neural network. | |
| # In this step, we only keep the best bounding boxes by eliminating all the bounding boxes | |
| # whose IOU value is higher than the given IOU threshold | |
| boxes = nms(boxes, iou_thresh) | |
| # Stop the time. | |
| finish = time.time() | |
| # Print the time it took to detect objects | |
| print('\n\nIt took {:.3f}'.format(finish - start), 'seconds to detect the objects in the image.\n') | |
| # Print the number of objects detected | |
| print('Number of Objects Detected:', len(boxes), '\n') | |
| return boxes | |
| def load_class_names(namesfile): | |
| # Create an empty list to hold the object classes | |
| class_names = [] | |
| # Open the file containing the COCO object classes in read-only mode | |
| with open(namesfile, 'r') as fp: | |
| # The coco.names file contains only one object class per line. | |
| # Read the file line by line and save all the lines in a list. | |
| lines = fp.readlines() | |
| # Get the object class names | |
| for line in lines: | |
| # Make a copy of each line with any trailing whitespace removed | |
| line = line.rstrip() | |
| # Save the object class name into class_names | |
| class_names.append(line) | |
| return class_names | |
| def print_objects(boxes, class_names): | |
| print('Objects Found and Confidence Level:\n') | |
| for i in range(len(boxes)): | |
| box = boxes[i] | |
| if len(box) >= 7 and class_names: | |
| cls_conf = box[5] | |
| cls_id = box[6] | |
| print('%i. %s: %f' % (i + 1, class_names[cls_id], cls_conf)) | |
| def plot_boxes(img, boxes, class_names, plot_labels, color = None): | |
| # Define a tensor used to set the colors of the bounding boxes | |
| colors = torch.FloatTensor([[1,0,1],[0,0,1],[0,1,1],[0,1,0],[1,1,0],[1,0,0]]) | |
| # Define a function to set the colors of the bounding boxes | |
| def get_color(c, x, max_val): | |
| ratio = float(x) / max_val * 5 | |
| i = int(np.floor(ratio)) | |
| j = int(np.ceil(ratio)) | |
| ratio = ratio - i | |
| r = (1 - ratio) * colors[i][c] + ratio * colors[j][c] | |
| return int(r * 255) | |
| # Get the width and height of the image | |
| width = img.shape[1] | |
| height = img.shape[0] | |
| # Create a figure and plot the image | |
| fig, a = plt.subplots(1,1) | |
| a.imshow(img) | |
| # Plot the bounding boxes and corresponding labels on top of the image | |
| for i in range(len(boxes)): | |
| # Get the ith bounding box | |
| box = boxes[i] | |
| # Get the (x,y) pixel coordinates of the lower-left and lower-right corners | |
| # of the bounding box relative to the size of the image. | |
| x1 = int(np.around((box[0] - box[2]/2.0) * width)) | |
| y1 = int(np.around((box[1] - box[3]/2.0) * height)) | |
| x2 = int(np.around((box[0] + box[2]/2.0) * width)) | |
| y2 = int(np.around((box[1] + box[3]/2.0) * height)) | |
| # Set the default rgb value to red | |
| rgb = (1, 0, 0) | |
| # Use the same color to plot the bounding boxes of the same object class | |
| if len(box) >= 7 and class_names: | |
| cls_conf = box[5] | |
| cls_id = box[6] | |
| classes = len(class_names) | |
| offset = cls_id * 123457 % classes | |
| red = get_color(2, offset, classes) / 255 | |
| green = get_color(1, offset, classes) / 255 | |
| blue = get_color(0, offset, classes) / 255 | |
| # If a color is given then set rgb to the given color instead | |
| if color is None: | |
| rgb = (red, green, blue) | |
| else: | |
| rgb = color | |
| # Calculate the width and height of the bounding box relative to the size of the image. | |
| width_x = x2 - x1 | |
| width_y = y1 - y2 | |
| # Set the postion and size of the bounding box. (x1, y2) is the pixel coordinate of the | |
| # lower-left corner of the bounding box relative to the size of the image. | |
| rect = patches.Rectangle((x1, y2), | |
| width_x, width_y, | |
| linewidth = 2, | |
| edgecolor = rgb, | |
| facecolor = 'none') | |
| # Draw the bounding box on top of the image | |
| a.add_patch(rect) | |
| # If plot_labels = True then plot the corresponding label | |
| if plot_labels: | |
| # Create a string with the object class name and the corresponding object class probability | |
| conf_tx = class_names[cls_id] + ': {:.1f}'.format(cls_conf) | |
| # Define x and y offsets for the labels | |
| lxc = (img.shape[1] * 0.266) / 100 | |
| lyc = (img.shape[0] * 1.180) / 100 | |
| # Draw the labels on top of the image | |
| a.text(x1 + lxc, y1 - lyc, conf_tx, fontsize = 12, color = 'k', | |
| bbox = dict(facecolor = rgb, edgecolor = rgb, alpha = 0.6)) | |
| plt.axis("off") | |
| plt.savefig("output.jpg") | |
| plt.show() | |