File size: 2,497 Bytes
88b0dcb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
""" 
@author: Zhigang Jiang
@time: 2022/01/28
@description:
Holistic 3D Vision Challenge on General Room Layout Estimation Track Evaluation Package
Reference: https://github.com/bertjiazheng/indoor-layout-evaluation
"""

from scipy.optimize import linear_sum_assignment
import numpy as np
import scipy

HEIGHT, WIDTH = 512, 1024
MAX_DISTANCE = np.sqrt(HEIGHT**2 + WIDTH**2)


def f1_score_2d(gt_corners, dt_corners, thresholds):
    distances = scipy.spatial.distance.cdist(gt_corners, dt_corners)
    return eval_junctions(distances, thresholds=thresholds)


def eval_junctions(distances, thresholds=5):
    thresholds = thresholds if isinstance(thresholds, tuple) or isinstance(
        thresholds, list) else list([thresholds])

    num_gts, num_preds = distances.shape

    # filter the matches between ceiling-wall and floor-wall junctions
    mask = np.zeros_like(distances, dtype=np.bool)
    mask[:num_gts//2, :num_preds//2] = True
    mask[num_gts//2:, num_preds//2:] = True
    distances[~mask] = np.inf

    # F-measure under different thresholds
    Fs = []
    Ps = []
    Rs = []
    for threshold in thresholds:
        distances_temp = distances.copy()

        # filter the mis-matched pairs
        distances_temp[distances_temp > threshold] = np.inf

        # remain the rows and columns that contain non-inf elements
        distances_temp = distances_temp[:, np.any(np.isfinite(distances_temp), axis=0)]

        if np.prod(distances_temp.shape) == 0:
            Fs.append(0)
            Ps.append(0)
            Rs.append(0)
            continue

        distances_temp = distances_temp[np.any(np.isfinite(distances_temp), axis=1), :]

        # solve the bipartite graph matching problem
        row_ind, col_ind = linear_sum_assignment_with_inf(distances_temp)
        true_positive = np.sum(np.isfinite(distances_temp[row_ind, col_ind]))

        # compute precision and recall
        precision = true_positive / num_preds
        recall = true_positive / num_gts

        # compute F measure
        Fs.append(2 * precision * recall / (precision + recall))
        Ps.append(precision)
        Rs.append(recall)

    return Fs, Ps, Rs


def linear_sum_assignment_with_inf(cost_matrix):
    """
    Deal with linear_sum_assignment with inf according to
    https://github.com/scipy/scipy/issues/6900#issuecomment-451735634
    """
    cost_matrix = np.copy(cost_matrix)
    cost_matrix[np.isinf(cost_matrix)] = MAX_DISTANCE
    return linear_sum_assignment(cost_matrix)