class ResNet50ExtractorAPI: def __init__(self, graph_prefix='', flush_pipe_on_read=False): self.__flush_pipe_on_read = flush_pipe_on_read self.__feature_dim = (2048) self.__image_shape = (224, 224, 3) self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) if not graph_prefix: self.__graph_prefix = '' else: self.__graph_prefix = graph_prefix + '/' def __preprocess(self, original): preprocessed = cv2.resize(original, tuple(self.__image_shape[:2][::-1])) preprocessed = resnet50.preprocess_input(preprocessed) return preprocessed def __in_pipe_process(self, inference): images = inference.get_input() if type(images) is not list: images = [images] data = [] for img in images: data.append(self.__preprocess(img)) data = np.array(data) inference.set_data(data) return inference def __out_pipe_process(self, result): result, inference = result inference.set_result(result) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def use_session_runner(self, session_runner): self.__session_runner = session_runner K.set_session(session_runner.get_session()) self.__tf_sess = K.get_session() with self.__tf_sess.as_default(): self.__model = resnet50.ResNet50(weights='imagenet', include_top=False, pooling='avg') def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__session_runner.get_in_pipe().push( (self.__job, inference)) else: self.__in_pipe.wait() def __job(self, inference): try: self.__out_pipe.push( (self.__model.predict(inference.get_data()), inference)) except: self.__out_pipe.push((np.zeros((0, self.__feature_dim), np.float32), inference))
class ImageEncoder: @staticmethod def __fetch_model_path(model_name): return "../resources/networks/" + model_name def __init__(self, session_runner, model_name=PRETRAINED_mars_small128, graph_prefix=None): self.__path_to_frozen_graph = self.__fetch_model_path(model_name) if not graph_prefix: self.__graph_prefix = '' else: self.__graph_prefix = graph_prefix + '/' self.__session_runner = session_runner self.__tf_sess = session_runner.get_session() self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) self.init_graph() def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def __in_pipe_process(self, obj): return obj def __out_pipe_process(self, obj): return obj def init_graph(self): with self.__tf_sess.graph.as_default(): od_graph_def = tf.GraphDef() with tf.gfile.GFile(self.__path_to_frozen_graph, 'rb') as fid: serialized_graph = fid.read() od_graph_def.ParseFromString(serialized_graph) tf.import_graph_def(od_graph_def, name=self.__graph_prefix) self.input_var = self.__tf_sess.graph.get_tensor_by_name( self.__graph_prefix + 'images:0') self.output_var = self.__tf_sess.graph.get_tensor_by_name( self.__graph_prefix + 'features:0') assert len(self.output_var.get_shape()) == 2 assert len(self.input_var.get_shape()) == 4 self.feature_dim = self.output_var.get_shape().as_list()[-1] self.image_shape = self.input_var.get_shape().as_list()[1:] def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, data_x = self.__in_pipe.pull() if ret: self.data_x = data_x self.__session_runner.add_job(self.__job()) else: self.__in_pipe.pull_wait() def __job(self): __tracking_features = np.zeros((len(self.data_x), self.feature_dim), np.float32) self._run_in_batches( lambda x: self.__tf_sess.run(self.output_var, feed_dict=x), {self.input_var: self.data_x}, __tracking_features, batch_size=32) self.__out_pipe.push(__tracking_features) def _run_in_batches(self, f, data_dict, out, batch_size): data_len = len(out) num_batches = int(data_len / batch_size) s, e = 0, 0 for i in range(num_batches): s, e = i * batch_size, (i + 1) * batch_size batch_data_dict = {k: v[s:e] for k, v in data_dict.items()} out[s:e] = f(batch_data_dict) if e < len(out): batch_data_dict = {k: v[e:] for k, v in data_dict.items()} out[e:] = f(batch_data_dict)
class MarsExtractorAPI: def __init__(self, graph_prefix='', flush_pipe_on_read=False): self.__flush_pipe_on_read = flush_pipe_on_read self.__model_path = pretrained_path.get() + "/mars-small128.pb" self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) if not graph_prefix: self.__graph_prefix = '' else: self.__graph_prefix = graph_prefix + '/' def get_input_shape(self): return self.__image_shape def __preprocess(self, original): preprocessed = cv2.resize(original, tuple(self.__image_shape[:2][::-1])) # preprocessed = resnet50.preprocess_input(preprocessed) return preprocessed def __in_pipe_process(self, inference): images = inference.get_input() if type(images) is not list: images = [images] data = [] for img in images: data.append(self.__preprocess(img)) # data = np.array(data) inference.set_data(data) return inference def __out_pipe_process(self, result): result, inference = result inference.set_result(result) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def use_session_runner(self, session_runner): self.__session_runner = session_runner self.__tf_sess = session_runner.get_session() with self.__tf_sess.graph.as_default(): od_graph_def = tf.GraphDef() with tf.gfile.GFile(self.__model_path, 'rb') as fid: serialized_graph = fid.read() od_graph_def.ParseFromString(serialized_graph) tf.import_graph_def(od_graph_def, name=self.__graph_prefix) self.__input_var = tf.get_default_graph().get_tensor_by_name( self.__graph_prefix + "images:0") self.__output_var = tf.get_default_graph().get_tensor_by_name( self.__graph_prefix + "features:0") assert len(self.__output_var.get_shape()) == 2 assert len(self.__input_var.get_shape()) == 4 self.__feature_dim = self.__output_var.get_shape().as_list()[-1] self.__image_shape = self.__input_var.get_shape().as_list()[1:] # print(self.__image_shape) def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__session_runner.get_in_pipe().push( SessionRunnable(self.__job, inference)) else: self.__in_pipe.pull_wait() def __job(self, inference): x = inference.get_data() if len(x) > 0: self.__out_pipe.push( (self.__tf_sess.run(self.__output_var, feed_dict={self.__input_var: x}), inference)) else: self.__out_pipe.push((np.zeros((0, self.__feature_dim), np.float32), inference))
class YOLOObjectDetectionAPI(): _defaults = { "model_path": pretrained_path.get() + '/yolo_v3.h5', "anchors_path": data_path.get() + '/yolo_anchors.txt', "classes_path": data_path.get() + '/coco.names', "score": 0.3, "iou": 0.45, "model_image_size": (416, 416), "gpu_num": 1, } @staticmethod def __get_dir_path(): return dirname(realpath(__file__)) @classmethod def get_defaults(cls, n): if n in cls._defaults: return cls._defaults[n] else: return "Unrecognized attribute name '" + n + "'" def __init__(self, graph_prefix=None, flush_pipe_on_read=False): self.__dict__.update(self._defaults) # set up default values # self.__dict__.update(kwargs) # and update with user overrides YOLOObjectDetectionAPI.class_names, self.__category_dict = self._get_class( ) YOLOObjectDetectionAPI.anchors = self._get_anchors() self.__graph_prefix = graph_prefix self.__flush_pipe_on_read = flush_pipe_on_read self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) self.__run_session_on_thread = False def use_threading(self, run_on_thread=True): self.__run_session_on_thread = run_on_thread def use_session_runner(self, session_runner): self.__session_runner = session_runner K.set_session(session_runner.get_session()) self.__tf_sess = K.get_session() self.boxes, self.scores, self.classes = self.generate() def __in_pipe_process(self, inference): image = inference.get_input() pil_image = Image.fromarray(image) if self.model_image_size != (None, None): assert self.model_image_size[ 0] % 32 == 0, 'Multiples of 32 required' assert self.model_image_size[ 1] % 32 == 0, 'Multiples of 32 required' boxed_image = letterbox_image( pil_image, tuple(reversed(self.model_image_size))) else: new_image_size = (pil_image.width - (pil_image.width % 32), pil_image.height - (pil_image.height % 32)) boxed_image = letterbox_image(pil_image, new_image_size) data = np.array(boxed_image, dtype='float32') data /= 255. data = np.expand_dims(data, 0) # Add batch dimension. inference.set_data(data) inference.get_meta_dict()['PIL'] = pil_image return inference # return image def __out_pipe_process(self, result): (out_boxes, out_classes, out_scores), inference = result out_boxes = np.array([[0 if y < 0 else y for y in x] for x in out_boxes]) result = InferedDetections(inference.get_input(), len(out_boxes), out_boxes, out_classes, out_scores, masks=None, is_normalized=False, get_category_fnc=self.get_category, annotator=self.annotate) inference.set_result(result) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def _get_class(self): dir_path = YOLOObjectDetectionAPI.__get_dir_path() classes_path = os.path.expanduser(self.classes_path) with open(classes_path) as f: class_names = f.readlines() class_names = [c.strip() for c in class_names] category_dict = {} for id, name in enumerate(class_names): category_dict[id] = name category_dict[name] = id return class_names, category_dict def _get_anchors(self): dir_path = YOLOObjectDetectionAPI.__get_dir_path() anchors_path = os.path.expanduser(self.anchors_path) with open(anchors_path) as f: anchors = f.readline() anchors = [float(x) for x in anchors.split(',')] return np.array(anchors).reshape(-1, 2) def generate(self): dir_path = YOLOObjectDetectionAPI.__get_dir_path() model_path = os.path.expanduser(self.model_path) assert model_path.endswith( '.h5'), 'Keras model or weights must be a .h5 file.' # Load model, or construct model and load weights. num_anchors = len(self.anchors) num_classes = len(self.class_names) is_tiny_version = num_anchors == 6 # default setting try: self.yolo_model = load_model(model_path, compile=False) except: self.yolo_model = tiny_yolo_body(Input(shape=(None, None, 3)), num_anchors // 2, num_classes) \ if is_tiny_version else yolo_body(Input(shape=(None, None, 3)), num_anchors // 3, num_classes) self.yolo_model.load_weights( self.model_path) # make sure model, anchors and classes match else: assert self.yolo_model.layers[-1].output_shape[-1] == \ num_anchors / len(self.yolo_model.output) * (num_classes + 5), \ 'Mismatch between model and given anchor and class sizes' # print('{} model, anchors, and classes loaded.'.format(model_path)) # Generate colors for drawing bounding boxes. hsv_tuples = [(x / len(self.class_names), 1., 1.) for x in range(len(self.class_names))] YOLOObjectDetectionAPI.colors = list( map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) YOLOObjectDetectionAPI.colors = list( map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), YOLOObjectDetectionAPI.colors)) np.random.seed(10101) # Fixed seed for consistent colors across runs. np.random.shuffle(YOLOObjectDetectionAPI.colors ) # Shuffle colors to decorrelate adjacent classes. np.random.shuffle(YOLOObjectDetectionAPI.colors ) # Shuffle colors to decorrelate adjacent classes. np.random.seed(None) # Reset seed to default. # Generate output tensor targets for filtered bounding boxes. self.input_image_shape = K.placeholder(shape=(2, )) if self.gpu_num >= 2: self.yolo_model = multi_gpu_model(self.yolo_model, gpus=self.gpu_num) boxes, scores, classes = yolo_eval(self.yolo_model.output, self.anchors, len(self.class_names), self.input_image_shape, score_threshold=self.score, iou_threshold=self.iou) return boxes, scores, classes def freeze_session(self, session, keep_var_names=None, output_names=None, clear_devices=True): """ Freezes the state of a session into a pruned computation graph. Creates a new computation graph where variable nodes are replaced by constants taking their current value in the session. The new graph will be pruned so subgraphs that are not necessary to compute the requested outputs are removed. @param session The TensorFlowsion(detected_boxes, confidence_threshold=FLAGS.conf_threshold, iou_threshold=FLAGS.iou_threshold) draw_boxes(filtered_boxes, img, classes, (FLAGS.size, FLAGS.size)) img.save(FLAGS.output_img) session to be frozen. @param keep_var_names A list of variable names that should not be frozen, or None to freeze all the variables in the graph. @param output_names Names of the relevant graph outputs. @param clear_devices Remove the device directives from the graph for better portability. @return The frozen graph definition. """ from tensorflow.python.framework.graph_util import convert_variables_to_constants graph = session.graph with graph.as_default(): freeze_var_names = list( set(v.op.name for v in tf.global_variables()).difference(keep_var_names or [])) output_names = output_names or [] output_names += [v.op.name for v in tf.global_variables()] input_graph_def = graph.as_graph_def() if clear_devices: for node in input_graph_def.node: node.device = "" frozen_graph = convert_variables_to_constants( session, input_graph_def, output_names, freeze_var_names) return frozen_graph def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__session_runner.get_in_pipe().push( SessionRunnable( self.__job, inference, run_on_thread=self.__run_session_on_thread)) else: self.__in_pipe.pull_wait() def __job(self, inference): data = inference.get_data() pil_image = inference.get_meta_dict()['PIL'] # image = inference.get_input() out_boxes, out_scores, out_classes = self.__tf_sess.run( [self.boxes, self.scores, self.classes], feed_dict={ self.yolo_model.input: data, self.input_image_shape: [pil_image.size[1], pil_image.size[0]], }) self.__out_pipe.push(((out_boxes, out_classes, out_scores), inference)) def close_session(self): self.__tf_sess.close() @staticmethod def annotate(inference): annotated = inference.image.copy() image = Image.fromarray(inference.get_image()) font = ImageFont.truetype(font='arial.ttf', size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32')) thickness = 1 #(image.size[0] + image.size[1]) // 300 for i, c in reversed(list(enumerate(inference.get_classes()))): predicted_class = YOLOObjectDetectionAPI.class_names[c] box = inference.get_boxes_tlbr(normalized=False)[i] score = inference.get_scores()[i] label = '{} {:.2f}'.format(predicted_class, score) draw = ImageDraw.Draw(image) label_size = draw.textsize(label, font) top, left, bottom, right = box top = max(0, np.floor(top + 0.5).astype('int32')) left = max(0, np.floor(left + 0.5).astype('int32')) bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32')) right = min(image.size[0], np.floor(right + 0.5).astype('int32')) # print(label, (left, top), (right, bottom)) if top - label_size[1] >= 0: text_origin = np.array([left, top - label_size[1]]) else: text_origin = np.array([left, top + 1]) # My kingdom for a good redistributable image drawing library. for i in range(thickness): draw.rectangle([left + i, top + i, right - i, bottom - i], outline=YOLOObjectDetectionAPI.colors[c]) draw.rectangle( [tuple(text_origin), tuple(text_origin + label_size)], fill=YOLOObjectDetectionAPI.colors[c]) draw.text(text_origin, label, fill=(0, 0, 0), font=font) del draw return np.array(image) def get_category(self, category): return self.__category_dict[category]
class AgeDetection(object): ''' Path to the trained model path for age_detection ''' WRN_WEIGHTS_PATH = age_model_path.get() + '/age_model.h5' def __init__(self, flush_pipe_on_read=False): self.__detector = None self.__face_size = 64 self.__flush_pipe_on_read = flush_pipe_on_read self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) def crop_face(self, imgarray, section, margin=40, size=64): """ :param imgarray: full image :param section: face detected area (x, y, w, h) :param margin: add some margin to the face detected area to include a full head :param size: the result image resolution with be (size x size) :return: resized image in numpy array with shape (size x size x 3) """ img_h, img_w, _ = imgarray.shape if section is None: section = [0, 0, img_w, img_h] (x, y, w, h) = section margin = int(min(w, h) * margin / 100) x_a = x - margin y_a = y - margin x_b = x + w + margin y_b = y + h + margin if x_a < 0: x_b = min(x_b - x_a, img_w - 1) x_a = 0 if y_a < 0: y_b = min(y_b - y_a, img_h - 1) y_a = 0 if x_b > img_w: x_a = max(x_a - (x_b - img_w), 0) x_b = img_w if y_b > img_h: y_a = max(y_a - (y_b - img_h), 0) y_b = img_h cropped = imgarray[y_a:y_b, x_a:x_b] resized_img = cv2.resize(cropped, (size, size), interpolation=cv2.INTER_AREA) resized_img = np.array(resized_img) return resized_img, (x_a, y_a, x_b - x_a, y_b - y_a) def __in_pipe_process(self, inference): ''' :param inference: inference object with input frame :return: inference: inference object with age_inference object containing face bbox details, data condaining np_array of all faces detected ''' frame = inference.get_input() faces = self.__detector.detect_faces(frame) faces = list_filter(faces, 0.90) # print("faces " ,faces) bboxes = [] face_imgs = np.empty( (len(faces), self.__face_size, self.__face_size, 3)) for i, face in enumerate(faces): face_img, cropped = self.crop_face(frame, face[:4], margin=40, size=self.__face_size) (x, y, w, h) = cropped bboxes.append([x, y, x + w, y + h]) # face_img = (face_img/255)-0.5 # cv2.rectangle(self.image_bounding_boxes, (x, y), (x + w, y + h), (255, 200, 0), 2) face_imgs[i, :, :, :] = face_img age_inference = AgeInference(frame, bboxes=bboxes) inference.set_result(age_inference) inference.set_data(face_imgs) return inference def __out_pipe_process(self, inference): ''' :param inference: inference object with faces np array in data, age_inference object with bboxes in result :return: inference: inference object with age_inference object in result after processing face np array from data for age, gender and ethnicity ''' # placeholder for cropped faces results, inference = inference age_inference = inference.get_result() if results is not None: predicted_genders = results[0] ages = np.arange(0, 101).reshape(101, 1) predicted_ages = results[1].dot(ages).flatten() predicted_ethnicity = np.argmax(results[2], axis=1) age_inference.set_ages(predicted_ages) age_inference.set_genders(predicted_genders) age_inference.set_ethnicity(predicted_ethnicity) inference.set_result(age_inference) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def use_threading(self, run_on_thread=True): self.__run_session_on_thread = run_on_thread def use_session_runner(self, session_runner): self.__session_runner = session_runner K.set_session(self.__session_runner.get_session()) self.__tf_sess = K.get_session() self.__detector = MTCNN(session_runner=self.__session_runner) with self.__tf_sess.as_default(): self.__model = WideResNet(self.__face_size)() self.__model.load_weights(AgeDetection.WRN_WEIGHTS_PATH) def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__session_runner.get_in_pipe().push( SessionRunnable(self.__job, inference)) else: self.__in_pipe.pull_wait() def __job(self, inference): ''' :param inference: run the model on data from inference object and push it to out_pipe :return: ''' try: self.__out_pipe.push( (self.__model.predict(inference.get_data()), inference)) except: self.__out_pipe.push((None, inference))
class OFISTObjectTrackingAPI: def __init__(self, max_age=10000, min_hits=5, flush_pipe_on_read=False): self.max_age = max_age self.min_hits = min_hits self.trackers = [] self.frame_count = 0 self.__bg_frame = None self.__bg_gray = None self.__flush_pipe_on_read = flush_pipe_on_read self.__feature_dim = (2048) self.__image_shape = (224, 224, 3) self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) number = 0 def __extract_image_patch(self, image, bbox, patch_shape): sx, sy, ex, ey = np.array(bbox).astype(np.int) # dx = ex-sx # dx = int(.25*dx) # dy = ey-sy # dy = int(.6*dy) dx = 0 dy = 0 image = image[sy:ey - dy, sx + dx:ex - dx] image = cv2.resize(image, tuple(patch_shape[::-1])) # img_yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV) # img_yuv[:, :, 0] = cv2.equalizeHist(img_yuv[:, :, 0]) # image = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR) image[0] = cv2.equalizeHist(image[0]) image[1] = cv2.equalizeHist(image[1]) image[2] = cv2.equalizeHist(image[2]) return image def __in_pipe_process(self, inference): i_dets = inference.get_input() frame = i_dets.get_image() classes = i_dets.get_classes() boxes = i_dets.get_boxes_tlbr(normalized=False) masks = i_dets.get_masks() bboxes = [] scores = i_dets.get_scores() for i in range(len(classes)): if classes[i] == i_dets.get_category('person') and scores[i] > .75: bboxes.append( [boxes[i][1], boxes[i][0], boxes[i][3], boxes[i][2]]) patches = [] # if self.__bg_frame is None: # self.__bg_frame = frame # self.__bg_gray = cv2.cvtColor(self.__bg_frame, cv2.COLOR_BGR2GRAY) # self.__bg_gray = cv2.GaussianBlur(self.__bg_gray, (5, 5), 0) # # gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # gray_frame = cv2.GaussianBlur(gray_frame, (5, 5), 0) # difference = cv2.absdiff(self.__bg_gray, gray_frame) # ret, mask = cv2.threshold(difference, 50, 255, cv2.THRESH_BINARY) # mask = np.stack((mask, mask, mask), axis=2) # # image = np.multiply(frame, mask) # # inference.get_meta_dict()['mask'] = mask # inference.get_meta_dict()['diff_img']=image image = frame # blur = cv2.GaussianBlur(image, (5, 5), 0) # image = cv2.addWeighted(image, 1.5, image, -0.5, 0) # image = cv2.cvtColor(frame, cv2.COLOR_BGR2HLS) for i in range(len(bboxes)): box = bboxes[i] # mask = masks[i] # mask = np.stack((mask, mask, mask), axis=2) # image = np.multiply(frame, mask) patch = self.__extract_image_patch(image, box, self.__image_shape[:2]) if patch is None: print("WARNING: Failed to extract image patch: %s." % str(box)) patch = np.random.uniform(0., 255., self.__image_shape).astype(np.uint8) patches.append(patch) inference.set_data(patches) inference.get_meta_dict()['bboxes'] = bboxes return inference def __out_pipe_process(self, inference): f_vecs = inference.get_result() # print(f_vecs.shape) inference = inference.get_meta_dict()['inference'] bboxes = inference.get_meta_dict()['bboxes'] self.frame_count = min(self.frame_count + 1, 1000) matched, unmatched_dets, unmatched_trks = KNNTracker.associate_detections_to_trackers( f_vecs, self.trackers, bboxes, distance_threshold=0.575) if bboxes: # # update matched trackers with assigned detections # for t, trk in enumerate(self.trackers): # if (t not in unmatched_trks): # d = matched[np.where(matched[:, 1] == t)[0], 0][0] # trk.update(bboxes[d], f_vecs[d]) ## for dlib re-intialize the trackers ?! # update matched trackers with assigned detections for trk in self.trackers: if (trk.get_id() not in unmatched_trks): d = matched[np.where(matched[:, 1] == trk.get_id())[0], 0][0] trk.update( bboxes[d], f_vecs[d]) ## for dlib re-intialize the trackers ?! # create and initialise new trackers for unmatched detections for i in unmatched_dets: trk = KNNTracker(bboxes[i], f_vecs[i]) self.trackers.append(trk) i = len(self.trackers) ret = [] for trk in reversed(self.trackers): d = trk.get_bbox() if (trk.get_hit_streak() >= self.min_hits): # or self.frame_count <= self.min_hits): ret.append( np.concatenate( ([int(i) for i in d], [trk.get_id()])).reshape( 1, -1)) # +1 as MOT benchmark requires positive i -= 1 # remove dead tracklet if (trk.get_time_since_update() > self.max_age): self.trackers.pop(i) if (len(ret) > 0): inference.set_result(np.concatenate(ret)) else: inference.set_result(np.empty((0, 5))) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def use_session_runner(self, session_runner): self.__session_runner = session_runner # self.__encoder = ResNet50ExtractorAPI("", True) self.__encoder = MarsExtractorAPI(flush_pipe_on_read=True) self.__encoder.use_session_runner(session_runner) self.__enc_in_pipe = self.__encoder.get_in_pipe() self.__enc_out_pipe = self.__encoder.get_out_pipe() self.__encoder.run() def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__job(inference) else: self.__in_pipe.wait() def __job(self, inference): self.__enc_in_pipe.push( Inference(inference.get_data(), meta_dict={'inference': inference}, return_pipe=self.__out_pipe))
class TFObjectDetectionAPI: @staticmethod def __get_dir_path(): return dirname(realpath(__file__)) @staticmethod def __download_model(model_path, download_base, model_file): print("downloading model...", model_path) try: os.mkdir(model_path) except: pass opener = urllib.request.URLopener() opener.retrieve(download_base + model_file, model_path + model_file) print("finished downloading. extracting...") tar_file = tarfile.open(model_path + model_file) for file in tar_file.getmembers(): file_name = os.path.basename(file.name) if 'frozen_inference_graph.pb' in file_name: tar_file.extract(file, model_path) print("finished extracting.") @staticmethod def __fetch_model_path(model_name): dir_path = pretrained_path.get() model_path = dir_path + '/' model_file = model_name + '.tar.gz' download_base = 'http://download.tensorflow.org/models/object_detection/' path_to_frozen_graph = model_path + model_name + '/frozen_inference_graph.pb' if not path.exists(path_to_frozen_graph): TFObjectDetectionAPI.__download_model(model_path, download_base, model_file) return path_to_frozen_graph @staticmethod def __fetch_category_indices(): dir_path = TFObjectDetectionAPI.__get_dir_path() path_to_labels = os.path.join(data_path.get(), 'mscoco_label_map.pbtxt') class_count = 90 label_map = label_map_util.load_labelmap(path_to_labels) categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=class_count, use_display_name=True) category_index = label_map_util.create_category_index(categories) category_dict = {} for item in category_index.values(): category_dict[item['id']] = item['name'] category_dict[item['name']] = item['id'] return category_index, category_dict def __init__(self, model_name=PRETRAINED_ssd_mobilenet_v1_coco_2017_11_17, image_shape=None, graph_prefix=None, flush_pipe_on_read=False): self.__category_index, self.__category_dict = self.__fetch_category_indices() self.__path_to_frozen_graph = self.__fetch_model_path(model_name) self.__flush_pipe_on_read = flush_pipe_on_read self.__image_shape = image_shape self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) self.__run_session_on_thread = False if not graph_prefix: self.__graph_prefix = '' else: self.__graph_prefix = graph_prefix + '/' def __in_pipe_process(self, inference): image = inference.get_input() data = np.expand_dims(image, axis=0) inference.set_data(data) return inference def __out_pipe_process(self, result): result, inference = result num_detections = int(result['num_detections'][0]) detection_classes = result['detection_classes'][0][:num_detections].astype(np.uint8) detection_boxes = result['detection_boxes'][0][:num_detections] detection_scores = result['detection_scores'][0][:num_detections] if 'detection_masks' in result: detection_masks = result['detection_masks'][0][:num_detections] else: detection_masks = None result = InferedDetections(inference.get_input(), num_detections, detection_boxes, detection_classes, detection_scores, masks=detection_masks, is_normalized=True, get_category_fnc=self.get_category, annotator=self.annotate) inference.set_result(result) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def use_threading(self, run_on_thread=True): self.__run_session_on_thread = run_on_thread def use_session_runner(self, session_runner): self.__session_runner = session_runner self.__tf_sess = session_runner.get_session() with self.__tf_sess.graph.as_default(): od_graph_def = tf.GraphDef() with tf.gfile.GFile(self.__path_to_frozen_graph, 'rb') as fid: serialized_graph = fid.read() od_graph_def.ParseFromString(serialized_graph) tf.import_graph_def(od_graph_def, name=self.__graph_prefix) tf_default_graph = self.__tf_sess.graph self.__image_tensor = tf_default_graph.get_tensor_by_name(self.__graph_prefix + 'image_tensor:0') tensor_names = {output.name for op in tf_default_graph.get_operations() for output in op.outputs} self.__tensor_dict = {} for key in ['num_detections', 'detection_boxes', 'detection_classes', 'detection_scores', 'detection_masks']: tensor_name = self.__graph_prefix + key + ':0' if tensor_name in tensor_names: self.__tensor_dict[key] = tf_default_graph.get_tensor_by_name( tensor_name) if 'detection_masks' in self.__tensor_dict: # The following processing is only for single image detection_boxes = tf.squeeze(self.__tensor_dict['detection_boxes'], [0]) detection_masks = tf.squeeze(self.__tensor_dict['detection_masks'], [0]) # Reframe is required to translate mask from box coordinates to image coordinates and fit the image size. real_num_detection = tf.cast(self.__tensor_dict['num_detections'][0], tf.int32) detection_boxes = tf.slice(detection_boxes, [0, 0], [real_num_detection, -1]) detection_masks = tf.slice(detection_masks, [0, 0, 0], [real_num_detection, -1, -1]) detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks( detection_masks, detection_boxes, self.__image_shape[0], self.__image_shape[1]) detection_masks_reframed = tf.cast( tf.greater(detection_masks_reframed, 0.5), tf.uint8) # Follow the convention by adding back the batch dimension self.__tensor_dict['detection_masks'] = tf.expand_dims( detection_masks_reframed, 0) def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__session_runner.get_in_pipe().push( SessionRunnable(self.__job, inference, run_on_thread=self.__run_session_on_thread)) else: self.__in_pipe.wait() def __job(self, inference): self.__out_pipe.push( (self.__tf_sess.run(self.__tensor_dict, feed_dict={self.__image_tensor: inference.get_data()}), inference)) def get_category(self, category): return self.__category_dict[category] @staticmethod def annotate(inference): annotated = inference.image.copy() vis_util.visualize_boxes_and_labels_on_image_array( annotated, inference.get_boxes_tlbr(), inference.get_classes().astype(np.int32), inference.get_scores(), TFObjectDetectionAPI.__fetch_category_indices()[0], instance_masks=inference.get_masks(), use_normalized_coordinates=True, line_thickness=1) return annotated
class YOLO(object): def __init__(self, input_size, labels, max_box_per_image, anchors, flush_pipe_on_read=False): self.__flush_pipe_on_read = flush_pipe_on_read self.__model_path = model_path.get() self.__model = None self.__input_size = input_size self.__labels = list(labels) self.__nb_class = len(self.__labels) self.__nb_box = len(anchors) // 2 self.__class_wt = np.ones(self.__nb_class, dtype='float32') self.__anchors = anchors self.__max_box_per_image = max_box_per_image self.__session_runner = None self.__tf_sess = None self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) self.__run_session_on_thread = False def use_threading(self, run_on_thread=True): self.__run_session_on_thread = run_on_thread def __normalize(self, image): return image / 255. def __preprocess(self, original, warp_points): img_shape = original.shape test1 = np.array(warp_points['point_set_1'], dtype="float32") test2 = np.array(warp_points['point_set_2'], dtype="float32") # print(test2) # points = [warp_points['point_set_2'][0],warp_points['point_set_2'][2]] # print(points) # np.array([[0, 0], [img_shape[0], 0], [img_shape[0], img_shape[1]], [0, img_shape[1]]], dtype=np.float32) M = cv2.getPerspectiveTransform(test1, test2) warped_image = cv2.warpPerspective(original, M, (img_shape[1], img_shape[0]), flags=cv2.INTER_LINEAR) # warped_image = warped_image[points[0][1]:points[1][1],points[0][0]:points[1][0],:] return warped_image def __prepare_data(self, image): image_h, image_w, _ = image.shape preprocessed = cv2.resize(image, (self.__input_size, self.__input_size)) preprocessed = self.__normalize(preprocessed) preprocessed = preprocessed[:, :, ::-1] preprocessed = np.expand_dims(preprocessed, 0) return preprocessed def __in_pipe_process(self, inference): image = inference.get_input() warp_points = inference.get_meta_dict()['warp_points'] dummy_array = np.zeros((1, 1, 1, 1, self.__max_box_per_image, 4)) warped_image = self.__preprocess(image, warp_points) data = (self.__prepare_data(warped_image), dummy_array) inference.set_data(data) inference.get_meta_dict()['warped_image'] = warped_image return inference def __out_pipe_process(self, result): result, inference = result image = inference.get_meta_dict()['warped_image'] i_dets = RetailInference(image, self.__labels) i_dets.decode_netout(result, self.__anchors, self.__nb_class) inference.set_result(i_dets) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def use_session_runner(self, session_runner): self.__session_runner = session_runner K.set_session(self.__session_runner.get_session()) self.__tf_sess = K.get_session() with self.__tf_sess.as_default(): with self.__tf_sess.graph.as_default(): self.__model = load_model(self.__model_path + '/check1.h5', custom_objects={"tf": tf}) print("Successful load of yolo") def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__session_runner.get_in_pipe().push( SessionRunnable( self.__job, inference, run_on_thread=self.__run_session_on_thread)) else: self.__in_pipe.pull_wait() def __job(self, inference): data = inference.get_data() self.__out_pipe.push((self.__model.predict([data[0], data[1]])[0], inference))
class OFISTObjectTrackingAPI: def __init__(self, max_age=10000, min_hits=5, flush_pipe_on_read=False, use_detection_mask=False, conf_path=None): self.max_age = max_age self.min_hits = min_hits self.trackers = [] self.frame_count = 0 self.__bg_frame = None self.__bg_gray = None self.__conf_path = conf_path self.__flush_pipe_on_read = flush_pipe_on_read # self.__feature_dim = (128) # self.__image_shape = (128, 64, 3) self.__thread = None self.__in_pipe = Pipe(self.__in_pipe_process) self.__out_pipe = Pipe(self.__out_pipe_process) self.__use_detection_mask = use_detection_mask self.__zones = None if self.__conf_path is not None: self.__zones = Zone.create_zones_from_conf(self.__conf_path) number = 0 def __extract_image_patch(self, image, bbox, patch_shape): sx, sy, ex, ey = np.array(bbox).astype(np.int) dx = ex - sx dy = ey - sy mx = int((sx + ex) / 2) my = int((sy + ey) / 2) dx = int(min(40, dx / 2)) dy = int(min(50, dy / 2)) # image = image[sy:my + dy, mx - dx:mx + dx] # image = ImageEnhancer.gaussian_blurr(image, sigma=1.75) # image = ImageEnhancer.lab_enhancement(image, l=0.75) # image = ImageEnhancer.hsv_enhancement(image, s=10, v=5) # image = ImageEnhancer.hls_enhancement(image, l=2) # image = ImageEnhancer.lab_enhancement(image, l=1.25) # image = ImageEnhancer.gamma_correction(image, gamma=3) # image = ImageEnhancer.gaussian_blurr(image, sigma=1.1) # dx = int(min(60, dx / 2)) # dy = int(min(90, dy / 2)) image = image[sy:my + dy, mx - dx:mx + dx] image = ImageEnhancer.gaussian_blurr(image, sigma=1.75) image = ImageEnhancer.lab_enhancement(image, l=0.125) image = ImageEnhancer.hsv_enhancement(image, s=5, v=5) image = ImageEnhancer.hls_enhancement(image, l=2) # image = ImageEnhancer.lab_enhancement(image, l=1) # image = ImageEnhancer.gamma_correction(image, gamma=3) image = ImageEnhancer.gaussian_blurr(image, sigma=1.25) # image = image[sy:ey, sx:ex] # image = ImageEnhancer.gaussian_blurr(image, sigma=2) # image = ImageEnhancer.lab_enhancement(image, l=0.75) # image = ImageEnhancer.hsv_enhancement(image, s=3, v=2) # image = ImageEnhancer.lab_enhancement(image, l=1.25) # image = ImageEnhancer.gamma_correction(image, gamma=3) # image = ImageEnhancer.preprocess_retinex(image) image = cv2.resize(image, tuple(patch_shape[::-1])) return image def __in_pipe_process(self, inference): i_dets = inference.get_input() frame = i_dets.get_image() classes = i_dets.get_classes() boxes = i_dets.get_boxes_tlbr(normalized=False) masks = i_dets.get_masks() bboxes = [] scores = i_dets.get_scores() for i in range(len(classes)): if classes[i] == i_dets.get_category('person') and scores[i] > .95: bboxes.append([boxes[i][1], boxes[i][0], boxes[i][3], boxes[i][2]]) patches = [0 for x in bboxes] # flips = [0 for x in bboxes] threads = [] for i in range(len(bboxes)): box = bboxes[i] if self.__use_detection_mask: mask = masks[i] mask = np.stack((mask, mask, mask), axis=2) image = np.multiply(frame, mask) else: image = frame def exec(patches, index): index = i patch = self.__extract_image_patch(image, box, self.__image_shape[:2]) if patch is None: print("WARNING: Failed to extract image patch: %s." % str(box)) patch = np.random.uniform(0., 255., self.__image_shape).astype(np.uint8) if bool(random.getrandbits(1)): patches[index] = patch else: patches[index] = cv2.flip(patch,1) threads.append(Thread(target=exec, args=(patches,i, ))) threads[-1].start() for thread in threads: thread.join() inference.set_data(patches) inference.get_meta_dict()['bboxes'] = bboxes return inference def __out_pipe_process(self, inference): f_vecs = inference.get_result() inference = inference.get_meta_dict()['inference'] bboxes = inference.get_meta_dict()['bboxes'] patches = inference.get_data() self.frame_count += 1 matched, unmatched_dets, unmatched_trks = Tracker.associate_detections_to_trackers(f_vecs, self.trackers, bboxes) if bboxes: for trk in self.trackers: if (trk.get_id() not in unmatched_trks): d = matched[np.where(matched[:, 1] == trk.get_id())[0], 0][0] trk.update(bboxes[d], f_vecs[d], patches[d]) for i in unmatched_dets: trk = Tracker(bboxes[i], f_vecs[i], patches[i], self.frame_count, zones=self.__zones) self.trackers.append(trk) i = len(self.trackers) ret = [] trails = {} for trk in reversed(self.trackers): if (trk.get_hit_streak() >= self.min_hits): # or self.frame_count <= self.min_hits): ret.append(trk) i -= 1 if (trk.get_time_since_update() > self.max_age): self.trackers.pop(i) if self.frame_count - trk.get_creation_time() >= 30 and not trk.is_confident(): self.trackers.pop(i) trails[trk.get_id()] = trk.get_trail() # inference.get_meta_dict()['trails'] = trails if (len(ret) > 0): inference.set_result(ret) else: inference.set_result(np.empty((0, 5))) return inference def get_in_pipe(self): return self.__in_pipe def get_out_pipe(self): return self.__out_pipe def get_zones(self): return self.__zones def use_session_runner(self, session_runner): self.__session_runner = session_runner # self.__encoder = ResNet50ExtractorAPI("", True) self.__encoder = MarsExtractorAPI(flush_pipe_on_read=True) self.__encoder.use_session_runner(session_runner) self.__image_shape = self.__encoder.get_input_shape() self.__enc_in_pipe = self.__encoder.get_in_pipe() self.__enc_out_pipe = self.__encoder.get_out_pipe() self.__encoder.run() def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: if self.__in_pipe.is_closed(): self.__enc_in_pipe.close() self.__out_pipe.close() return ret, inference = self.__in_pipe.pull(self.__flush_pipe_on_read) if ret: self.__job(inference) else: self.__in_pipe.wait() def __job(self, inference): self.__enc_in_pipe.push( Inference(inference.get_data(), meta_dict={'inference': inference}, return_pipe=self.__out_pipe))
class FLIRCamera(object): def __init__(self, index=None): if index is None: index = 0 self.__system = PySpin.System.GetInstance() self.__cam_list = self.__system.GetCameras() self.__cam = self.__cam_list.GetByIndex(index) # self.__pixel_format = self.__cam.PixelFormat # print(self.__pixel_format.GetCurrentEntry()) # self.__pixel_format = PySpin.PixelFormat_BGR8 # print(self.__pixel_format) # self.__access_mode = self.__cam.PixelFormat.GetAccessMode self.__cam.Init() self.__nodemap = self.__cam.GetNodeMap() self.configure_custom_image_settings(self.__nodemap) # self.__cam.DeInit() # self.__cam.Init() self.__cam.AcquisitionMode.SetValue(PySpin.AcquisitionMode_Continuous) print(self.__cam.EncoderMode) self.__node_acquisition_framerate = PySpin.CFloatPtr( self.__nodemap.GetNode('AcquisitionFrameRate')) self.__framerate_to_set = self.__node_acquisition_framerate.GetValue() print(self.__framerate_to_set) self.__cam.BeginAcquisition() self.__out_pipe = Pipe(self.__out_pipe_process) self.__thread = None def __del__(self): self.close() def __out_pipe_process(self, image_primary): image_primary = image_primary.Convert(PySpin.PixelFormat_BGR8, PySpin.HQ_LINEAR) image_array = image_primary.GetNDArray() return image_array def close(self): self.__thread = None self.__cam.EndAcquisition() self.__cam.DeInit() del self.__cam del self.__cam_list del self.__system self.__out_pipe.close() def run(self): if self.__thread is None: self.__thread = Thread(target=self.__run) self.__thread.start() def __run(self): while self.__thread: try: self.__job(self.__cam.GetNextImage()) except: self.close() def __job(self, image_primary): self.__out_pipe.push(image_primary) def get_out_pipe(self): return self.__out_pipe def configure_custom_image_settings(self, nodemap): """ Configures a number of settings on the camera including offsets X and Y, width, height, and pixel format. These settings must be applied before BeginAcquisition() is called; otherwise, they will be read only. Also, it is important to note that settings are applied immediately. This means if you plan to reduce the width and move the x offset accordingly, you need to apply such changes in the appropriate order. :param nodemap: GenICam nodemap. :type nodemap: INodeMap :return: True if successful, False otherwise. :rtype: bool """ try: result = True # Apply mono 8 pixel format # # *** NOTES *** # Enumeration nodes are slightly more complicated to set than other # nodes. This is because setting an enumeration node requires working # with two nodes instead of the usual one. # # As such, there are a number of steps to setting an enumeration node: # retrieve the enumeration node from the nodemap, retrieve the desired # entry node from the enumeration node, retrieve the integer value from # the entry node, and set the new value of the enumeration node with # the integer value from the entry node. # # Retrieve the enumeration node from the nodemap node_pixel_format = PySpin.CEnumerationPtr( nodemap.GetNode('PixelFormat')) if PySpin.IsAvailable(node_pixel_format) and PySpin.IsWritable( node_pixel_format): # Retrieve the desired entry node from the enumeration node node_pixel_format_mono8 = PySpin.CEnumEntryPtr( node_pixel_format.GetEntryByName('RGB8')) print(node_pixel_format.GetEntries()) if PySpin.IsAvailable( node_pixel_format_mono8) and PySpin.IsReadable( node_pixel_format_mono8): # Retrieve the integer value from the entry node pixel_format_mono8 = node_pixel_format_mono8.GetValue() # Set integer as new value for enumeration node node_pixel_format.SetIntValue(pixel_format_mono8) print('Pixel format set to %s...' % node_pixel_format.GetCurrentEntry().GetSymbolic()) else: print('Pixel format mono 8 not available...') else: print('Pixel format not available...') # Apply minimum to offset X # # *** NOTES *** # Numeric nodes have both a minimum and maximum. A minimum is retrieved # with the method GetMin(). Sometimes it can be important to check # minimums to ensure that your desired value is within range. node_offset_x = PySpin.CIntegerPtr(nodemap.GetNode('OffsetX')) if PySpin.IsAvailable(node_offset_x) and PySpin.IsWritable( node_offset_x): node_offset_x.SetValue(node_offset_x.GetMin()) print('Offset X set to %i...' % node_offset_x.GetMin()) else: print('Offset X not available...') # Apply minimum to offset Y # # *** NOTES *** # It is often desirable to check the increment as well. The increment # is a number of which a desired value must be a multiple of. Certain # nodes, such as those corresponding to offsets X and Y, have an # increment of 1, which basically means that any value within range # is appropriate. The increment is retrieved with the method GetInc(). node_offset_y = PySpin.CIntegerPtr(nodemap.GetNode('OffsetY')) if PySpin.IsAvailable(node_offset_y) and PySpin.IsWritable( node_offset_y): node_offset_y.SetValue(node_offset_y.GetMin()) print('Offset Y set to %i...' % node_offset_y.GetMin()) else: print('Offset Y not available...') # Set maximum width # # *** NOTES *** # Other nodes, such as those corresponding to image width and height, # might have an increment other than 1. In these cases, it can be # important to check that the desired value is a multiple of the # increment. However, as these values are being set to the maximum, # there is no reason to check against the increment. node_width = PySpin.CIntegerPtr(nodemap.GetNode('Width')) if PySpin.IsAvailable(node_width) and PySpin.IsWritable( node_width): width_to_set = node_width.GetMax() node_width.SetValue(width_to_set) print('Width set to %i...' % node_width.GetValue()) else: print('Width not available...') # Set maximum height # # *** NOTES *** # A maximum is retrieved with the method GetMax(). A node's minimum and # maximum should always be a multiple of its increment. node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) if PySpin.IsAvailable(node_height) and PySpin.IsWritable( node_height): height_to_set = node_height.GetMax() node_height.SetValue(height_to_set) print('Height set to %i...' % node_height.GetValue()) else: print('Height not available...') except PySpin.SpinnakerException as ex: print('Error: %s' % ex) return False return result