예제 #1
0
    def loadFile(self, path):
        try:
            try:
                with open(path, "r") as data_file:
                    data = json.load(data_file)
                    self.loadData(data, path)

            except UnicodeDecodeError:
                with open(path, "rb") as data_file:
                    byte_data = data_file.read()
                    data = msgpack.unpackb(byte_data)
                    self.loadData(data, path)

        except FileNotFoundError:
            LogObject().print("File {} not found".format(path))
            return False

        except json.JSONDecodeError:
            LogObject().print("Invalid JSON file".format(path))
            return False

        #except:
        #	LogObject().print("Unexpected error:", sys.exc_info()[1])
        #	return False

        self.previous_path = path
        self.fast_save_enabled = True
        self.file_loaded_event.emit()
        return True
예제 #2
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
    def saveDetectionsToFile(self, path):
        """
		Writes current detections to a file at path. Values are separated by ';'.
		"""

        # Default formatting
        f1 = "{:.5f}"
        lineBase1 = "{};" + "{};{};{};".format(f1, f1, f1)

        try:
            with open(path, "w") as file:
                file.write(
                    "frame;length;distance;angle;corner1 x;corner1 y;corner2 x;corner2 y;corner3 x;corner3 y;corner4 x;corner4 y\n"
                )
                for frame, dets in enumerate(self.detections):
                    if dets is not None:
                        for d in dets:
                            if d.corners is not None:
                                file.write(
                                    lineBase1.format(frame, d.length,
                                                     d.distance, d.angle))
                                file.write(d.cornersToString(";"))
                                file.write("\n")
                LogObject().print("Detections saved to path:", path)

        except PermissionError as e:
            LogObject().print(
                "Cannot open file {}. Permission denied.".format(path))
예제 #3
0
    def __init__(self, pol_shape, cart_height, radius_limits, beam_angle):
        """
		Initializes the mapping function.

		Parameters:
		pol_shape -- Shape of the polar frame
		cart_height -- Height of the cartesian (output) image.
		radius_limits -- Min and max radius of the beam.
		beam_angle -- Angle covered by the beam (radians).
		"""
        LogObject().print("Init mapping")
        self.pol_shape = pol_shape
        self.setCartShape(cart_height, beam_angle)
        self.radius_limits = radius_limits
        self.angle_limits = (np.pi / 2 - beam_angle / 2,
                             np.pi / 2 + beam_angle / 2)
        self.center = (0, (self.cart_shape[1] - 1) / 2)
        self.metric_cart_shape = (radius_limits[1], self.cart_shape[1] /
                                  self.cart_shape[0] * radius_limits[1])

        self.map_x = np.zeros(self.cart_shape, dtype=np.float32)
        self.map_y = np.zeros(self.cart_shape, dtype=np.float32)

        for j in range(self.cart_shape[0]):
            if j % 100 == 0:
                LogObject().print("Mapping:", j)
            for i in range(self.cart_shape[1]):
                _j = self.cart_shape[0] - j - 1
                self.map_y[j, i], self.map_x[j, i] = self.cart2polImage(_j, i)
        LogObject().print("End mapping")
예제 #4
0
    def track(self):
        """
        Handles the tracking process. Opens file and connects detection and tracking
        calls to the appropriate signals, so that they can be started when the file
        has been loaded.
        """
        if self.testFile:
            self.playback_manager.openTestFile()
        else:
            self.playback_manager.loadFile(self.file)

        LogObject().print("Frame count:",
                          self.playback_manager.getFrameCount())

        if self.display:
            self.playback_manager.frame_available.connect(
                self.forwardImageDisplay)
        else:
            self.playback_manager.frame_available.connect(self.forwardImage)

        self.detector.mog_parameters.nof_bg_frames = 500
        self.detector._show_detections = True
        self.playback_manager.mapping_done.connect(self.startTrackingProcess)
        self.tracker.all_computed_signal.connect(self.onAllComputed)

        if self.display:
            self.figure = TestFigure(self.playback_manager.togglePlay)
            self.main_window.setCentralWidget(self.figure)

        LogObject().print(self.detector.parameters)
        LogObject().print(self.detector.parameters.mog_parameters)
        LogObject().print(self.tracker.parameters)

        if self.display:
            self.main_window.show()
예제 #5
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
    def loadDetectionsFromFile(self, path):
        """
		Loads a file from path. Values are expected to be separated by ';'.
		"""
        try:
            with open(path, 'r') as file:
                self.clearDetections()
                nof_frames = self.image_provider.getFrameCount()
                ignored_dets = 0

                header = file.readline()

                for line in file:
                    split_line = line.split(';')
                    frame = int(split_line[0])

                    if frame >= nof_frames:
                        ignored_dets += 1
                        continue

                    length = float(split_line[1])
                    distance = float(split_line[2])
                    angle = float(split_line[3])

                    c1 = [float(split_line[5]), float(split_line[4])]
                    c2 = [float(split_line[7]), float(split_line[6])]
                    c3 = [float(split_line[9]), float(split_line[8])]
                    c4 = [float(split_line[11]), float(split_line[10])]
                    corners = np.array([c1, c2, c3, c4])

                    det = Detection(0)
                    det.init_from_file(corners, length, distance, angle)

                    if self.detections[frame] is None:
                        self.detections[frame] = [det]
                    else:
                        self.detections[frame].append(det)

                self.updateVerticalDetections()
                self.compute_on_event = False
                if ignored_dets > 0:
                    LogObject().print(
                        "Encountered {} detections that were out of range {}.".
                        format(ignored_dets, nof_frames))

        except PermissionError as e:
            LogObject().print(
                "Cannot open file {}. Permission denied.".format(path))
예제 #6
0
파일: fish_manager.py 프로젝트: MiG-Ui/LUKE
    def data(self, index, role):
        if role == Qt.DisplayRole:
            row = index.row()
            col = index.column()

            if row >= len(self.fish_list):
                LogObject().print("Bad index {}/{}".format(row, len(self.fish_list) - 1))
                return QtCore.QVariant()

            if col == 0:
                return self.fish_list[row].id
            elif col == 1:
                return self.fish_list[row].length
            elif col == 2:
                return self.fish_list[row].direction.name
            elif col == 3:
                return self.fish_list[row].frame_in
            elif col == 4:
                return self.fish_list[row].frame_out
            elif col == 5:
                return self.fish_list[row].duration
            elif col == 6:
                return len(self.fish_list[row].tracks)
            else:
                return QtCore.QVariant()
        else:
            return QtCore.QVariant()
예제 #7
0
파일: batch_track.py 프로젝트: MiG-Ui/LUKE
    def __init__(self,
                 display,
                 files,
                 save_directory,
                 parallel=1,
                 create_directory=True):
        super().__init__()
        LogObject().print("Display: ", display)
        self.files = files
        self.display = display

        if create_directory:
            date_time_directory = "batch_{}".format(
                datetime.now().strftime("%Y-%m-%d-%H%M%S"))
            self.save_directory = os.path.join(save_directory,
                                               date_time_directory)
            if not os.path.exists(self.save_directory):
                os.mkdir(self.save_directory)
        else:
            self.save_directory = save_directory

        self.thread_pool = QtCore.QThreadPool()
        self.thread_pool.setMaxThreadCount(parallel + 1)

        self.processes = []
        self.active_processes = []
        self.state = ProcessState.INITIALIZING
        self.exit_time = time.time()
        self.n_processes = 0
        self.total_processes = len(self.files)
예제 #8
0
파일: batch_track.py 프로젝트: MiG-Ui/LUKE
    def finishTerminated(self):
        """
        Handles the shutdown process initiated by method terminate.
        """
        for proc_info in self.processes:
            try:
                proc_info.connection.send((-1, "Terminate"))
            except BrokenPipeError as e:
                # Process not yet active
                pass

            while True:
                try:
                    id, msg = proc_info.connection.recv()
                    if id == -1:
                        break
                except EOFError:
                    break
                except ValueError:
                    # Received message with no id
                    continue
            LogObject().print("File [{}] terminated.".format(proc_info.id))

        for proc_info in self.processes:
            if proc_info.process is not None:
                proc_info.process.terminate()

        self.exit_signal.emit(False)
예제 #9
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
 def updateVerticalDetections(self):
     LogObject().print("Updated")
     self.vertical_detections = [
         [d.center[0] for d in dets
          if d.center is not None] if dets is not None else []
         for dets in self.detections
     ]
예제 #10
0
파일: fish_manager.py 프로젝트: MiG-Ui/LUKE
    def applySaveDictionary(self, data, dets):
        """
		Load fish entries from data provided by SaveManager.
		"""
        self.clear()
        for id, f_data in data.items():
            f = None
            for frame, det_label, track in f_data:
                if f is None:
                    f = FishEntry(id, frame, frame)

                if det_label is not None:
                    # Goes through detections in the same frame and tries to assign the
                    # corresponding detection based on the label.

                    frame_dets = dets[frame]
                    match_found = False
                    for fd in frame_dets:
                        if fd.label == det_label:
                            # Adds track with a matching detection to the FishEntry

                            f.addTrack(track, fd, frame)
                            match_found = True
                            break

                    if not match_found:
                        LogObject().print("Warning: Match not found in frame {} for label {}".format(frame, det_label))
                else:
                    f.addTrack(track, None, frame)

            self.all_fish[id] = f

        self.trimFishList()
예제 #11
0
파일: batch_track.py 프로젝트: MiG-Ui/LUKE
 def terminate(self):
     """
     Clears the thread pool and sets system state to TERMINATING,
     which leads to clean shutdown of the processes.
     """
     self.thread_pool.clear()
     LogObject().print("Terminating")
     self.state = ProcessState.TERMINATING
예제 #12
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
    def run(self):
        self.showWindow()
        self.detector.initMOG()

        for i in range(self.getFrameCount()):
            self.readParameters()
            images = self.detector.compute(i, self.getFrame(i), True)
            LogObject().print(images)
            self.updateWindows(*images)
예제 #13
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
 def clearDetections(self):
     LogObject().print("Cleared")
     nof_frames = self.image_provider.getFrameCount()
     self.detections = [None] * nof_frames
     self.vertical_detections = []
     #self.detections_clearable = False
     self.applied_parameters = None
     self.compute_on_event = True
     self.state_changed_event()
예제 #14
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
 def setParameterDict(self, dict):
     for key, value in dict.items():
         if hasattr(self, key) and key in PARAMETER_TYPES:
             try:
                 setattr(self, key, PARAMETER_TYPES[key](value))
             except ValueError as e:
                 LogObject().print(
                     "Error: Invalid value in detector parameters file,", e)
         elif hasattr(self.mog_parameters, key) and key in PARAMETER_TYPES:
             try:
                 setattr(self.mog_parameters, key,
                         PARAMETER_TYPES[key](value))
             except ValueError as e:
                 LogObject().print(
                     "Error: Invalid value in detector parameters file,", e)
         else:
             LogObject().print("Error: Invalid parameters: {}: {}".format(
                 key, value))
예제 #15
0
파일: tracker.py 프로젝트: MiG-Ui/LUKE
    def trackAll(self, detection_frames):
        """
        Tracks all detections in the given frames. Updates tracks_by_frame and
        signals when the computation has finished.
        """
        self.tracking = True
        self.stop_tracking = False
        self.state_changed_signal.emit()
        self.init_signal.emit()

        if self.detector.allCalculationAvailable():
            self.detector.computeAll()
            if self.detector.allCalculationAvailable():
                LogObject().print("Stopped before tracking.")
                self.abortComputing(True)
                return

        count = len(detection_frames)
        self.tracks_by_frame = {}
        self.mot_tracker = Sort(max_age=self.parameters.max_age,
                                min_hits=self.parameters.min_hits,
                                search_radius=self.parameters.search_radius)
        KalmanBoxTracker.count = 0
        ten_perc = 0.1 * count
        print_limit = 0
        for i, dets in enumerate(detection_frames):
            if i > print_limit:
                LogObject().print("Tracking:", int(float(i) / count * 100),
                                  "%")
                print_limit += ten_perc
            if self.stop_tracking:
                LogObject().print("Stopped tracking at", i)
                self.abortComputing(False)
                return

            self.tracks_by_frame[i] = self.trackBase(dets, i)

        LogObject().print("Tracking: 100 %")
        self.tracking = False
        self.applied_parameters = self.parameters.copy()
        self.applied_detector_parameters = self.detector.parameters.copy()

        self.state_changed_signal.emit()
        self.all_computed_signal.emit()
예제 #16
0
 def connectToLogObject(self, format=None):
     """
     Connect text_edit field to LogObject signal. A formatting function, which takes a string as input
     and returns the modified string, can be provided for custom formatting, e.g. for adding a time stamp.
     """
     log = LogObject()
     if format:
         log.connect(lambda s: self.appendText(format(s)))
     else:
         log.connect(lambda s: self.appendText(s + "\n"))
     log.disconnectDefault()
예제 #17
0
def update_use_times(author):
    """
    「./user_log/ユーザー名.csv」を読み込み、「date」、「use_times」列で一意のkeyとして
    利用回数をインクリメントして更新する

    Parameters
    ------------------------------
    author : str
        ユーザー名

    Returns
    ------------------------------
    Nothing
    """
    current_date = datetime.date.today().strftime(
        '%Y-%m-%d')  #date型のままだとqueryの条件で型が一致しないため、strに変換する
    user_log_data = pd.read_csv(f'{USER_FILE_PATH}/{author}.csv',
                                encoding='utf-8',
                                engine='python')
    current_user_data = user_log_data.query(
        'user_id == @author and date == @current_date')

    log_obj = LogObject()
    log_obj.user_id = author
    log_obj.date = current_date

    if len(current_user_data) == 0:
        # 今日初めての利用の場合は、行が存在しないので、利用回数1回の行を新規で作成し、DataFrameに追加してcsvを更新する
        log_obj.use_times = 1
        s = pd.Series([log_obj.user_id, log_obj.date, log_obj.use_times],
                      index=user_log_data.columns)
        user_log_data = user_log_data.append(s, ignore_index=True)

    elif current_user_data['use_times'].values[0] != DATE_USE_LIMIT:
        # 今日の今までの利用回数が19回以下の場合は、該当ユーザーのDataFrameの利用回数を+1してcsvを更新する
        use_times = current_user_data['use_times'].values[0] + 1
        user_log_data.loc[(user_log_data['user_id'] == author) &
                          (user_log_data['date'] == current_date),
                          ['use_times']] = use_times

    user_log_data.to_csv(f'{USER_FILE_PATH}/{author}.csv',
                         encoding='utf-8',
                         index=False)
예제 #18
0
파일: fish_manager.py 프로젝트: MiG-Ui/LUKE
    def saveToFile(self, path):
        """
        Tries to save all fish information (from all_fish dictionary) to a file.
        """
        if(self.playback_manager.playback_thread is None):
            LogObject().print("No file open, cannot save.")
            return

        try:
            with open(path, "w") as file:
                file.write("id;frame;length;distance;angle;direction;corner1 x;corner1 y;corner2 x;corner2 y;corner3 x;corner3 y;corner4 x;corner4 y; detection\n")

                lines = self.getSaveLines()
                lines.sort(key = lambda l: (l[0].id, l[1]))
                for _, _, line in lines:
                    file.write(line)

                LogObject().print("Tracks saved to path:", path)
        except PermissionError as e:
            LogObject().print("Cannot open file {}. Permission denied.".format(path))
예제 #19
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
    def init_from_file(self, corners, length, distance, angle):
        """
		Initialize detection parameters from a csv file. Data is not stored when exporting a csv file,
		which means it cannot be recovered here. This mainly affects the visualization of the detection.
		"""
        self.corners = np.array(corners)
        self.center = np.average(self.corners, axis=0)
        LogObject().print(self.center)
        self.length = length
        self.distance = distance
        self.angle = angle
예제 #20
0
파일: batch_dialog.py 프로젝트: MiG-Ui/LUKE
    def onBatchExit(self, finished):
        """
        Called when the system is ready to start a new batch.
        """

        LogObject().print("--- On batch exit ---")

        self.start_btn.setText("Start")
        self.start_btn.setEnabled(True)
        self.batch_track = None
        self.setStatusLabel()
예제 #21
0
파일: batch_track.py 프로젝트: MiG-Ui/LUKE
    def beginTrack(self, test=False):
        """
        For each file in files, creates a Worker that runs track and places it in thread_pool.
        Main thread is occupied with a call to communicate method.
        """

        self.state = ProcessState.RUNNING
        id = 0

        worker = Worker(self.communicate)
        self.thread_pool.start(worker)

        if test:
            # If using test file (defined in conf.json)

            parent_conn, child_conn = mp.Pipe()
            file = fh.getTestFilePath()
            proc_info = ProcessInfo(id, file, parent_conn)
            self.processes.append(proc_info)

            worker = Worker(self.track, proc_info, child_conn, True)
            self.thread_pool.start(worker)
            LogObject().print("Created Worker for file " + file)
            self.n_processes = 1
            self.total_processes = 1

        else:
            # Normal use

            for file in self.files:
                parent_conn, child_conn = mp.Pipe()
                proc_info = ProcessInfo(id, file, parent_conn)
                self.processes.append(proc_info)

                worker = Worker(self.track, proc_info, child_conn, False)
                self.thread_pool.start(worker)
                LogObject().print("Created Worker for file " + file)
                id += 1
                self.n_processes += 1

        LogObject().print("Total processes:", self.n_processes)
예제 #22
0
파일: tracker.py 프로젝트: MiG-Ui/LUKE
    def playbackTest():
        """
        Test code to assure tracker works with detector.
        """
        def forwardImage(tuple):
            ind, frame = tuple
            detections = detector.getDetection(ind)

            image = cv2.applyColorMap(frame, cv2.COLORMAP_OCEAN)
            image = tracker.visualize(image, ind)

            figure.displayImage((ind, image))

        def startDetector():
            detector.initMOG()
            detector.computeAll()
            tracker.trackAll(detector.detections)
            playback_manager.play()

        app = QtWidgets.QApplication(sys.argv)
        main_window = QtWidgets.QMainWindow()
        playback_manager = PlaybackManager(app, main_window)
        detector = Detector(playback_manager)
        tracker = Tracker(detector)

        playback_manager.fps = 10
        playback_manager.openTestFile()
        playback_manager.frame_available.connect(forwardImage)
        detector.mog_parameters.nof_bg_frames = 500
        detector._show_detections = True
        playback_manager.mapping_done.connect(startDetector)

        figure = TestFigure(playback_manager.togglePlay)
        main_window.setCentralWidget(figure)

        LogObject().print(detector.parameters)
        LogObject().print(detector.parameters.mog_parameters)
        LogObject().print(tracker.parameters)

        main_window.show()
        sys.exit(app.exec_())
예제 #23
0
    def loadData(self, data, path):
        try:
            file_path = os.path.abspath(data["path"])
            secondary_path = os.path.abspath(
                os.path.join(os.path.dirname(path),
                             os.path.basename(file_path)))
            self.playback_manager.checkLoadedFile(file_path, secondary_path,
                                                  True)
            self.fish_manager.setUpDownInversion(data["inverted upstream"])

            self.detector.parameters.setParameterDict(data["detector"])
            self.tracker.parameters.setParameterDict(data["tracker"])
            self.detector.applySaveDictionary(data["detections"])
            dets = self.detector.detections
            self.fish_manager.applySaveDictionary(data["fish"], dets)

        except ValueError as e:
            LogObject().print("Error: Invalid value(s) in save file,", e)
            self.playback_manager.closeFile()
        except KeyError as e:
            LogObject().print("Error: Invalid key(s) in save file,", e)
            self.playback_manager.closeFile()
예제 #24
0
파일: detector.py 프로젝트: MiG-Ui/LUKE
    def computeAll(self):
        self.computing = True
        self.stop_computing = False
        self.compute_on_event = False
        self.state_changed_event()

        if self.mogParametersDirty():
            self.initMOG()
            if self.mogParametersDirty():
                LogObject().print("Stopped before detecting.")
                self.abortComputing(True)
                return

        count = self.image_provider.getFrameCount()
        ten_perc = 0.1 * count
        print_limit = 0
        for ind in range(count):
            if ind > print_limit:
                LogObject().print("Detecting:", int(float(ind) / count * 100),
                                  "%")
                print_limit += ten_perc

            if self.stop_computing:
                LogObject().print("Stopped detecting at", ind)
                self.abortComputing(False)
                return

            img = self.image_provider.getFrame(ind)
            self.computeBase(ind, img)

        LogObject().print("Detecting: 100 %")
        self.computing = False
        #self.detections_clearable = True
        self.applied_parameters = self.parameters.copy()

        self.updateVerticalDetections()

        self.state_changed_event()
        self.all_computed_event()
예제 #25
0
파일: batch_track.py 프로젝트: MiG-Ui/LUKE
    def processFinished(self, proc_info):
        """
        Reduces n_processes by one and if none are remaining, emits the exit_signal
        """

        LogObject().print("File {} finished.".format(proc_info.file))
        self.n_processes -= 1
        if self.n_processes <= 0:
            # Let main thread (running communicate) know the process is about to quit
            # and emit exit signal.

            if self.state is not ProcessState.TERMINATING:
                self.state = ProcessState.FINISHED
                self.exit_time = time.time()
                self.exit_signal.emit(True)
예제 #26
0
파일: fish_manager.py 프로젝트: MiG-Ui/LUKE
    def removeFish(self, rows, update=True):
        if(len(rows) > 0):
            for row in sorted(rows, reverse=True):
                if row >= len(self.fish_list):
                    continue

                fish_id = self.fish_list[row].id
                try:
                    del_f = self.all_fish.pop(fish_id)
                    del del_f
                except KeyError:
                    LogObject().print("KeyError occured when removing entry with id:", fish_id)

            if update:
                self.trimFishList()
예제 #27
0
파일: batch_track.py 프로젝트: MiG-Ui/LUKE
    def communicate(self):
        """
        Polls through all running processes and forwards all messages to LogObject.
        """

        while self.state is ProcessState.RUNNING or self.state is ProcessState.INITIALIZING or time.time(
        ) < self.exit_time + 1:
            for proc_info in self.processes:
                if (proc_info.process and proc_info.process.is_alive()
                        and proc_info.connection.poll()):
                    LogObject().print(proc_info.id,
                                      proc_info.connection.recv(),
                                      end="")
            time.sleep(0.01)

        if self.state is ProcessState.TERMINATING:
            self.finishTerminated()
예제 #28
0
    def __init__(self,
                 app,
                 display,
                 file,
                 save_directory,
                 connection=None,
                 testFile=False):
        super().__init__()
        self.app = app
        self.display = display
        self.figure = None
        self.file = file
        self.save_directory = os.path.abspath(save_directory)
        self.connection = connection
        self.testFile = testFile
        self.alive = True

        self.save_detections = True
        self.save_tracks = True

        if display:
            self.main_window = QtWidgets.QMainWindow()
        else:
            self.main_window = None

        self.playback_manager = PlaybackManager(self.app, self.main_window)

        self.detector = Detector(self.playback_manager)
        self.tracker = Tracker(self.detector)
        self.fish_manager = FishManager(self.playback_manager, self.tracker)
        self.playback_manager.fps = 100

        self.playback_manager.runInThread(self.listenConnection)

        log = LogObject()
        log.disconnectDefault()
        #log.connect(writeToFile)
        log.connect(self.writeToConnection)
        log.print("Process created for file: ", self.file)
예제 #29
0
 def showFish(self, fishNumber, inputDict):
     ## TODO _
     # ffigure = self.MyFigureWidget
     # ffigure.clear()
     # self.MyFigureWidget.clear()
     counter = 0
     LogObject().print("Fish = ", fishNumber)
     for i in inputDict["frames"]:
         # ffigure.setUpdatesEnabled(False)
         self.UI_FRAME_INDEX = i
         x = int( inputDict["locations"][counter][0])
         y = int( inputDict["locations"][counter][1])
         
         self.marker = str(x)+','+str(y)
         self.FSlider.setValue(self.UI_FRAME_INDEX)
         
         self.marker = None
         self.repaint()
         counter +=1
     self.marker = None
     return
예제 #30
0
파일: tracker.py 프로젝트: MiG-Ui/LUKE
    def trackBase(self, frame, ind):
        """
        Performs tracking step for a single frame.
        Returns (track, detection) if the track was updated this frame, otherwise (track, None).
        """
        if frame is None:
            LogObject().print(
                "Invalid detector results encountered at frame " + str(ind) +
                ". Consider rerunning the detector.")
            return self.mot_tracker.update()

        detections = [d for d in frame if d.corners is not None]
        if len(detections) > 0:
            dets = np.array([
                np.min(d.corners, 0).flatten().tolist() +
                np.max(d.corners, 0).flatten().tolist() for d in detections
            ])
            tracks = self.mot_tracker.update(dets)
        else:
            tracks = self.mot_tracker.update()

        return [(tr, detections[int(tr[7])]) if tr[7] >= 0 else (tr, None)
                for tr in tracks]