Esempio n. 1
0
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))
Esempio n. 2
0
class Sort:
    def __init__(self, max_age=120, min_hits=3, flush_pipe_on_read=False):
        """
        Sets key parameters for SORT
        """
        self.max_age = max_age
        self.min_hits = min_hits
        self.trackers = []
        self.frame_count = 0

        self.__flush_pipe_on_read = flush_pipe_on_read

        self.__thread = None
        self.__in_pipe = Pipe(self.__in_pipe_process)
        self.__outpass_pipe = Pipe(self.__out_pipe_process)

    def __in_pipe_process(self, inference):
        detections = inference.get_boxes_tlbr(normalized=False)
        frame = inference.get_input()
        classes = inference.get_classes()
        person_detections = []
        scores = inference.get_scores()
        for i in range(len(classes)):
            if classes[i] == inference.get_category(
                    'person') and scores[i] > .5:
                person_detections.append([
                    detections[i][1], detections[i][0], detections[i][3],
                    detections[i][2]
                ])
        return (frame, person_detections)

    def __out_pipe_process(self, inference):
        image, f_vecs, bboxes = inference

        if bboxes:
            matched, unmatched_dets, unmatched_trks = Tracker.associate_detections_to_trackers(
                f_vecs, self.trackers)

            # 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 ?!

            # create and initialise new trackers for unmatched detections
            for i in unmatched_dets:
                trk = Tracker(bboxes[i], f_vecs[i])
                self.trackers.append(trk)

        i = len(self.trackers)
        ret = []
        for trk in reversed(self.trackers):
            # if bboxes == []:
            # trk.update([], img)
            d = trk.get_bbox()
            if (trk.get_hit_streak() >= self.min_hits
                    or self.frame_count <= self.min_hits):
                ret.append(np.concatenate((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)
        print(len(self.trackers))
        if (len(ret) > 0):
            return np.concatenate(ret), image
        return np.empty((0, 5)), image

    def get_in_pipe(self):
        return self.__in_pipe

    def get_out_pipe(self):
        return self.__out_pipe

    def use_session_runner(self, model, session_runner):
        self.__session_runner = session_runner
        # K.set_session(session_runner.get_session())
        # self.__tf_sess = K.get_session()
        self.__image_encoder = ImageEncoder(model, session_runner)

    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_tuple = self.__in_pipe.pull(self.__flush_pipe_on_read)
            if ret:
                self.data_tuple = data_tuple
                self.__session_runner.add_job(self.__job())
            else:
                self.__in_pipe.pull_wait()

    def __job(self):
        f_vecs = self.__image_encoder.extract_features(self.data_tuple[0],
                                                       self.data_tuple[1])
        self.__out_pipe.push((self.data_tuple[0], f_vecs, self.data_tuple[1]))

    def update(self, image, bboxes):
        """
Esempio n. 3
0
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))
Esempio n. 4
0
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))
Esempio n. 5
0
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)
Esempio n. 6
0
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 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
Esempio n. 9
0
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))