# From http://www.pyimagesearch.com/2015/12/21/increasing-webcam-fps-with-python-and-opencv/ import struct import six import collections import cv2 import datetime import subprocess as sp import json import numpy import time from threading import Thread from matplotlib import colors class FPS: def __init__(self): # store the start time, end time, and total number of frames # that were examined between the start and end intervals self._start = None self._end = None self._numFrames = 0 def start(self): # start the timer self._start = datetime.datetime.now() return self def stop(self): # stop the timer self._end = datetime.datetime.now() def update(self): # increment the total number of frames examined during the # start and end intervals self._numFrames += 1 def elapsed(self): # return the total number of seconds between the start and # end interval return (self._end - self._start).total_seconds() def fps(self): # compute the (approximate) frames per second return self._numFrames / self.elapsed() class HLSVideoStream: def __init__(self, src): # initialize the video camera stream and read the first frame # from the stream # initialize the variable used to indicate if the thread should # be stopped self.stopped = False FFMPEG_BIN = "ffmpeg" metadata = {} while "streams" not in metadata.keys(): print('ERROR: Could not access stream. Trying again.') info = sp.Popen(["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", src], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE) out, err = info.communicate(b"ffprobe -v quiet -print_format json -show_format -show_streams http://52.91.28.88:8080/hls/live.m3u8") metadata = json.loads(out.decode('utf-8')) time.sleep(5) print('SUCCESS: Retrieved stream metadata.') self.WIDTH = metadata["streams"][0]["width"] self.HEIGHT = metadata["streams"][0]["height"] self.pipe = sp.Popen([ FFMPEG_BIN, "-i", src, "-loglevel", "quiet", # no text output "-an", # disable audio "-f", "image2pipe", "-pix_fmt", "bgr24", "-vcodec", "rawvideo", "-"], stdin = sp.PIPE, stdout = sp.PIPE) print('WIDTH: ', self.WIDTH) raw_image = self.pipe.stdout.read(self.WIDTH*self.HEIGHT*3) # read 432*240*3 bytes (= 1 frame) self.frame = numpy.fromstring(raw_image, dtype='uint8').reshape((self.HEIGHT,self.WIDTH,3)) self.grabbed = self.frame is not None def start(self): # start the thread to read frames from the video stream Thread(target=self.update, args=()).start() return self def update(self): # keep looping infinitely until the thread is stopped # if the thread indicator variable is set, stop the thread while True: if self.stopped: return raw_image = self.pipe.stdout.read(self.WIDTH*self.HEIGHT*3) # read 432*240*3 bytes (= 1 frame) self.frame = numpy.fromstring(raw_image, dtype='uint8').reshape((self.HEIGHT,self.WIDTH,3)) self.grabbed = self.frame is not None def read(self): # return the frame most recently read return self.frame def stop(self): # indicate that the thread should be stopped self.stopped = True class WebcamVideoStream: def __init__(self, src, width, height): # initialize the video camera stream and read the first frame # from the stream self.stream = cv2.VideoCapture(src) self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, width) self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, height) (self.grabbed, self.frame) = self.stream.read() # initialize the variable used to indicate if the thread should # be stopped self.stopped = False def start(self): # start the thread to read frames from the video stream Thread(target=self.update, args=()).start() return self def update(self): # keep looping infinitely until the thread is stopped while True: # if the thread indicator variable is set, stop the thread if self.stopped: return # otherwise, read the next frame from the stream (self.grabbed, self.frame) = self.stream.read() def read(self): # return the frame most recently read return self.frame def stop(self): # indicate that the thread should be stopped self.stopped = True def standard_colors(): colors = [ 'AliceBlue', 'Chartreuse', 'Aqua', 'Aquamarine', 'Azure', 'Beige', 'Bisque', 'BlanchedAlmond', 'BlueViolet', 'BurlyWood', 'CadetBlue', 'AntiqueWhite', 'Chocolate', 'Coral', 'CornflowerBlue', 'Cornsilk', 'Crimson', 'Cyan', 'DarkCyan', 'DarkGoldenRod', 'DarkGrey', 'DarkKhaki', 'DarkOrange', 'DarkOrchid', 'DarkSalmon', 'DarkSeaGreen', 'DarkTurquoise', 'DarkViolet', 'DeepPink', 'DeepSkyBlue', 'DodgerBlue', 'FireBrick', 'FloralWhite', 'ForestGreen', 'Fuchsia', 'Gainsboro', 'GhostWhite', 'Gold', 'GoldenRod', 'Salmon', 'Tan', 'HoneyDew', 'HotPink', 'IndianRed', 'Ivory', 'Khaki', 'Lavender', 'LavenderBlush', 'LawnGreen', 'LemonChiffon', 'LightBlue', 'LightCoral', 'LightCyan', 'LightGoldenRodYellow', 'LightGray', 'LightGrey', 'LightGreen', 'LightPink', 'LightSalmon', 'LightSeaGreen', 'LightSkyBlue', 'LightSlateGray', 'LightSlateGrey', 'LightSteelBlue', 'LightYellow', 'Lime', 'LimeGreen', 'Linen', 'Magenta', 'MediumAquaMarine', 'MediumOrchid', 'MediumPurple', 'MediumSeaGreen', 'MediumSlateBlue', 'MediumSpringGreen', 'MediumTurquoise', 'MediumVioletRed', 'MintCream', 'MistyRose', 'Moccasin', 'NavajoWhite', 'OldLace', 'Olive', 'OliveDrab', 'Orange', 'OrangeRed', 'Orchid', 'PaleGoldenRod', 'PaleGreen', 'PaleTurquoise', 'PaleVioletRed', 'PapayaWhip', 'PeachPuff', 'Peru', 'Pink', 'Plum', 'PowderBlue', 'Purple', 'Red', 'RosyBrown', 'RoyalBlue', 'SaddleBrown', 'Green', 'SandyBrown', 'SeaGreen', 'SeaShell', 'Sienna', 'Silver', 'SkyBlue', 'SlateBlue', 'SlateGray', 'SlateGrey', 'Snow', 'SpringGreen', 'SteelBlue', 'GreenYellow', 'Teal', 'Thistle', 'Tomato', 'Turquoise', 'Violet', 'Wheat', 'White', 'WhiteSmoke', 'Yellow', 'YellowGreen' ] return colors def color_name_to_rgb(): colors_rgb = [] for key, value in colors.cnames.items(): colors_rgb.append((key, struct.unpack('BBB', bytes.fromhex(value.replace('#', ''))))) return dict(colors_rgb) def draw_boxes_and_labels( boxes, classes, scores, category_index, instance_masks=None, keypoints=None, max_boxes_to_draw=20, min_score_thresh=.5, agnostic_mode=False): """Returns boxes coordinates, class names and colors Args: boxes: a numpy array of shape [N, 4] classes: a numpy array of shape [N] scores: a numpy array of shape [N] or None. If scores=None, then this function assumes that the boxes to be plotted are groundtruth boxes and plot all boxes as black with no classes or scores. category_index: a dict containing category dictionaries (each holding category index `id` and category name `name`) keyed by category indices. instance_masks: a numpy array of shape [N, image_height, image_width], can be None keypoints: a numpy array of shape [N, num_keypoints, 2], can be None max_boxes_to_draw: maximum number of boxes to visualize. If None, draw all boxes. min_score_thresh: minimum score threshold for a box to be visualized agnostic_mode: boolean (default: False) controlling whether to evaluate in class-agnostic mode or not. This mode will display scores but ignore classes. """ # Create a display string (and color) for every box location, group any boxes # that correspond to the same location. box_to_display_str_map = collections.defaultdict(list) box_to_color_map = collections.defaultdict(str) box_to_instance_masks_map = {} box_to_keypoints_map = collections.defaultdict(list) if not max_boxes_to_draw: max_boxes_to_draw = boxes.shape[0] for i in range(min(max_boxes_to_draw, boxes.shape[0])): if scores is None or scores[i] > min_score_thresh: box = tuple(boxes[i].tolist()) if instance_masks is not None: box_to_instance_masks_map[box] = instance_masks[i] if keypoints is not None: box_to_keypoints_map[box].extend(keypoints[i]) if scores is None: box_to_color_map[box] = 'black' else: if not agnostic_mode: if classes[i] in category_index.keys(): class_name = category_index[classes[i]]['name'] else: class_name = 'N/A' display_str = '{}: {}%'.format( class_name, int(100 * scores[i])) else: display_str = 'score: {}%'.format(int(100 * scores[i])) box_to_display_str_map[box].append(display_str) if agnostic_mode: box_to_color_map[box] = 'DarkOrange' else: box_to_color_map[box] = standard_colors()[ classes[i] % len(standard_colors())] # Store all the coordinates of the boxes, class names and colors color_rgb = color_name_to_rgb() rect_points = [] class_names = [] class_colors = [] for box, color in six.iteritems(box_to_color_map): ymin, xmin, ymax, xmax = box rect_points.append(dict(ymin=ymin, xmin=xmin, ymax=ymax, xmax=xmax)) class_names.append(box_to_display_str_map[box]) class_colors.append(color_rgb[color.lower()]) return rect_points, class_names, class_colors