def _evaluate(Gt, Hy, threshold, cost_fun, info=False, debug_info=False): if debug_info: fp, m, mme, c, d, g, FN_pairs, FP_pairs, MME_pairs = MOTM.evaluate( Gt, Hy, threshold, cost_fun, debug_info=True) else: fp, m, mme, c, d, g = MOTM.evaluate(Gt, Hy, threshold, cost_fun) FN = np.sum(m) FP = np.sum(fp) IDSW = np.sum(mme) GT = np.sum(g) mota = 1 - (FN + FP + IDSW) / GT result = [mota] if info: result.append({'FN': FN, 'FP': FP, 'IDSW': IDSW, 'GT': GT}) if debug_info: result.append({"FN": FN_pairs, "FP": FP_pairs, "IDSW": MME_pairs}) if len(result) > 1: return result else: return result[0]
def test_motm_1mme(self): Gt = np.array([ [1, 1, 0, 0], [2, 1, 0, 0] ]) Hy = np.array([ [1, 1, 0, 0], [2, 2, 0, 0] ]) cost = lambda a, b: la.norm(a-b) fp, m, mme, c, d, g = MOTM.evaluate(Gt, Hy, 10, cost) self.assertEqual(len(fp), 2) self.assertEqual(len(m), 2) self.assertEqual(len(mme), 2) self.assertEqual(len(c), 2) self.assertEqual(len(d), 2) self.assertEqual(len(g), 2) self.assertEqual(np.sum(fp), 0) self.assertEqual(np.sum(m), 0) self.assertEqual(np.sum(mme), 1) self.assertEqual(np.sum(d), 0) self.assertEqual(np.sum(g), 2) self.assertEqual(np.sum(c), 2)
def test_delete(self): Data = np.array([ [1, 1, None], [1, 2, None], [1, 3, None], [1, 4, None], ]) data = MOTM.SingleFrameData(Data) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 4) data.remove([1, None]) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 3) data.remove([4, None]) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 2) data.remove([3, None]) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 1) data.remove([2, None]) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 0) self.assertEqual(len(data.as_list()), 0)
def test_basics(self): Data = np.array([(1, 1), (1, 2), (1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2)]) L = MOTM.LocalFrameIdToGlobal(Data) self.assertEqual(L.get_true_idx(1, 0), 0) self.assertEqual(L.get_true_idx(1, 2), 2) self.assertEqual(L.get_true_idx(3, 1), 8)
def test_out_of_order(self): Data = np.array([(2, 3), (1, 2), (3, 1), (1, 4), (1, 3), (2, 2), (1, 1), (3, 2), (2, 1)]) L = MOTM.LocalFrameIdToGlobal(Data) self.assertEqual(L.get_true_idx(2, 0), 0) self.assertEqual(L.get_true_idx(1, 2), 4) self.assertEqual(L.get_true_idx(3, 1), 7)
def test_empty(self): Data = np.array([]) data = MOTM.SingleFrameData(Data) self.assertEqual(data.total_elements, 0) self.assertEqual(data.elements_left, 0) A = data.as_list() self.assertEqual(len(A), 0)
def test_mismatch_inverse(self): M = MOTM.MatchLookup(1, 2) o, h = (1, None), (99, None) M.insert_match(1, o, h) o, h = (2, None), (99, None) M.insert_match(2, o, h) self.assertFalse(M.has_mismatch(1, o, h)) self.assertTrue(M.has_mismatch(2, o, h)) self.assertEqual(M.count_matches(1), 1) self.assertEqual(M.count_matches(2), 1)
def test_setup(self): Data = np.array([ [1, 1, None], [1, 2, None], [1, 3, None], [1, 4, None], ]) data = MOTM.SingleFrameData(Data) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 4)
def test_complex_find(self): cost_fun = lambda a, b: abs(a - b) Data = np.array([ [1, 1, 10], [1, 2, 12], [1, 2, 100], [1, 2, -19], ]) data = MOTM.SingleFrameData(Data) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 4) obj = data.find_best(2, [1, 10], cost_fun) self.assertEqual(obj[0], 2) self.assertEqual(obj[1], 12)
def test_listing(self): Data = np.array([ [1, 1, None], [1, 2, None], [1, 3, None], [1, 4, None], ]) data = MOTM.SingleFrameData(Data) data.remove([3, None]) data.remove([2, None]) A = data.as_list() self.assertEqual(len(A), 2) self.assertEqual(A[0][0], 1) self.assertEqual(A[1][0], 4)
def test_motm_fp_with_debug_info(self): Gt = np.array([ [1, 1, 0, 0], [1, 2, 10, 10], [2, 1, 0, 0] ]) Hy = np.array([ [1, 2, 10, 10], [1, 3, 20, 20], [1, 4, 30, 30], [2, 1, 0, 0], [1, 1, 0, 0], [2, 5, 88, 99] ]) cost = lambda a, b: la.norm(a-b) fp, m, mme, c, d, g, FN_pairs, FP_pairs, MME_pairs =\ MOTM.evaluate(Gt, Hy, 5, cost, debug_info=True) self.assertEqual(len(FN_pairs), 0) self.assertEqual(len(FP_pairs), 3) self.assertEqual(len(MME_pairs), 0) self.assertEqual(FP_pairs[0][0], 1) self.assertEqual(FP_pairs[1][0], 1) self.assertEqual(FP_pairs[2][0], 2) self.assertEqual(FP_pairs[0][2], 20) self.assertEqual(FP_pairs[1][2], 30) self.assertEqual(FP_pairs[2][2], 88) self.assertEqual(len(fp), 2) self.assertEqual(len(m), 2) self.assertEqual(len(mme), 2) self.assertEqual(len(c), 2) self.assertEqual(len(d), 2) self.assertEqual(len(g), 2) self.assertEqual(np.sum(fp), 3) self.assertEqual(np.sum(m), 0) self.assertEqual(np.sum(mme), 0) self.assertEqual(np.sum(d), 0) self.assertEqual(np.sum(g), 3) self.assertEqual(np.sum(c), 3)
def test_multiple_inserts(self): M = MOTM.MatchLookup(1, 2) o, h = (1, None), (95.5, None) M.insert_match(1, o, h) o, h = (2, None), (96, None) M.insert_match(1, o, h) o, h = (3, None), (97, None) M.insert_match(1, o, h) self.assertEqual(len(M.get_matches(1)), 3) o, h = (2, None), (96, None) M.insert_match(2, o, h) o, h = (3, None), (97, None) M.insert_match(2, o, h) self.assertEqual(len(M.get_matches(2)), 2)
def test_counting(self): M = MOTM.MatchLookup(1, 2) o, h = (1, None), (95, None) M.insert_match(1, o, h) o, h = (2, None), (96, None) M.insert_match(1, o, h) o, h = (3, None), (97, None) M.insert_match(1, o, h) o, h = (3, None), (97, None) M.insert_match(2, o, h) self.assertEqual(M.count_matches(1), 3) self.assertEqual(M.count_matches(2), 1)
def test_insert(self): M = MOTM.MatchLookup(1, 2) self.assertEqual(len(M.get_matches(0)), 0) o, h = (1, None), (99, None) M.insert_match(1, o, h) self.assertEqual(len(M.get_matches(1)), 1) self.assertFalse(M.has_mismatch(1, o, h)) o_, h_ = M.get_matches(1)[0] self.assertEqual(o_[0], 1) self.assertEqual(h_[0], 99) o, h = (1, None), (99, None) M.insert_match(2, o, h) self.assertFalse(M.has_mismatch(2, o, h))
def evaluate(Gt, Hy, threshold): """ Ground-truth vs hypothesis for the Multiple Object Tracking Precision Gt: [ (frame, pid, x, y) ] Hy: [ (frame, pid, x, y) ] threshold: after which no correspondence is possible """ cost_fun = lambda a, b: la.norm(a-b) fp, m, mme, c, d, g = MOTM.evaluate(Gt, Hy, threshold, cost_fun) D = np.sum(d) C = np.sum(c) return D/C
def test_multiple_delete(self): Data = np.array([[1, 1, 99], [1, 2, 88], [1, 2, 99], [1, 3, 77], [1, 2, 77]]) data = MOTM.SingleFrameData(Data) self.assertEqual(data.total_elements, 5) self.assertEqual(data.elements_left, 5) data.remove([2, 99]) self.assertEqual(data.elements_left, 4) data.remove([1, 99]) self.assertEqual(data.elements_left, 3) A = data.as_list() self.assertEqual(len(A), 3) self.assertEqual(A[0][0], 2) self.assertEqual(A[0][1], 88) self.assertEqual(A[1][0], 2) self.assertEqual(A[1][1], 77) self.assertEqual(A[2][0], 3) self.assertEqual(A[2][1], 77)
def test_find(self): Data = np.array([ [1, 1, 66], [1, 2, 77], [1, 3, 88], [1, 4, 99], ]) data = MOTM.SingleFrameData(Data) self.assertEqual(data.total_elements, 4) self.assertEqual(data.elements_left, 4) obj = data.find(1) self.assertEqual(obj[0], 1) self.assertEqual(obj[1], 66) obj = data.find(2) self.assertEqual(obj[0], 2) self.assertEqual(obj[1], 77) obj = data.find(88) self.assertEqual(obj, None)
def test_motm_interrupt(self): Gt = np.array([ [1, 1, 0, 0], [2, 1, 0, 0], [5, 1, 0, 0], [6, 1, 0, 0], [7, 1, 0, 0], [8, 1, 0, 0] ]) Hy = np.array([ [1, 1, 0, 0], [2, 1, 0, 0], [5, 1, 0, 0], [6, 1, 0, 0], [7, 1, 0, 0], [8, 1, 0, 0] ]) cost = lambda a, b: la.norm(a-b) fp, m, mme, c, d, g = MOTM.evaluate(Gt, Hy, 10, cost) self.assertEqual(len(fp), 8) self.assertEqual(len(m), 8) self.assertEqual(len(mme), 8) self.assertEqual(len(c), 8) self.assertEqual(len(d), 8) self.assertEqual(len(g), 8) self.assertEqual(np.sum(fp), 0) self.assertEqual(np.sum(m), 0) self.assertEqual(np.sum(mme), 0) self.assertEqual(np.sum(d), 0) self.assertEqual(np.sum(g), 6) self.assertEqual(np.sum(c), 6)