File size: 3,647 Bytes
90ca518
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
79
80
81
82
83
84
85
86
87
88
89
"""点云距离与法向一致性指标(倒角 L1/L2、豪斯多夫、|NC| / NC)。

modules.pipeline 与 scripts.eval 共用同一份实现, 保证推理内打印的指标与离线评测同口径。
"""
import numpy as np
from scipy.spatial import cKDTree


def calculate_distances_numpy(pcd1, pcd2):
    """
    [已修改]
    使用 NumPy 高效计算 L2倒角距离、L1倒角距离 和 豪斯多夫距离。

    参数:
    pcd1: np.ndarray, 形状为 (N, 3),第一个点云。
    pcd2: np.ndarray, 形状为 (M, 3),第二个点云。

    返回:
    (float, float, float): (L2倒角距离, 豪斯多夫距离, L1倒角距离)
    """
    # --- 计算所有点对之间的差异 ---
    pcd1_expanded = pcd1[:, np.newaxis, :]
    pcd2_expanded = pcd2[np.newaxis, :, :]
    diff = pcd1_expanded - pcd2_expanded

    # --- L2 (欧氏) 距离计算 ---
    dist_matrix_sq = np.sum(diff**2, axis=2)

    # --- L2 倒角距离 (Chamfer Distance L2) ---
    min_dists_1_to_2_l2 = np.sqrt(np.min(dist_matrix_sq, axis=1))
    min_dists_2_to_1_l2 = np.sqrt(np.min(dist_matrix_sq, axis=0))
    chamfer_dist_l2 = np.mean(min_dists_1_to_2_l2) + np.mean(min_dists_2_to_1_l2)

    # --- L2 豪斯多夫距离 (Hausdorff Distance) ---
    hausdorff_dist = max(np.max(min_dists_1_to_2_l2), np.max(min_dists_2_to_1_l2))
    
    # --- L1 (曼哈顿) 距离计算 ---
    dist_matrix_l1 = np.sum(np.abs(diff), axis=2)
    
    # --- L1 倒角距离 (Chamfer Distance L1) ---
    min_dists_1_to_2_l1 = np.min(dist_matrix_l1, axis=1)
    min_dists_2_to_1_l1 = np.min(dist_matrix_l1, axis=0)
    chamfer_dist_l1 = np.mean(min_dists_1_to_2_l1) + np.mean(min_dists_2_to_1_l1)

    return chamfer_dist_l2, hausdorff_dist, chamfer_dist_l1


def calculate_normal_consistency_score(pcd_gt, normal_gt, pcd_pred, normal_pred):
    """
    【修改版】根据提供的公式计算法向量一致性得分 (Normal Consistency Score)。
    返回两个值:
    1. |NC| (绝对值 NC): np.mean( |n1·n2| )
    2.  NC  (真实值 NC): np.mean( n1·n2 )
    """

    def _calculate_one_way_score(source_pcd, source_normals, target_pcd, target_normals):
        """
        辅助函数:计算从 source 到 target 的单向 NC 得分。
        返回 (mean_abs_dot, mean_real_dot)
        """
        # 1. 计算 source 到 target 的所有点对的距离矩阵
        diff = source_pcd[:, np.newaxis, :] - target_pcd[np.newaxis, :, :]
        dist_sq = np.sum(diff**2, axis=2)

        # 2. 为每个 source 点找到 target 中的最近邻点的索引
        indices = np.argmin(dist_sq, axis=1)

        # 3. 获取这些最近邻点对应的法向量
        corresponding_normals = target_normals[indices]

        # 4. 计算 source 法向量与对应 target 法向量的点积
        dot_products = np.einsum('ij,ij->i', source_normals, corresponding_normals)
        
        # 5. [修改] 返回点积绝对值的平均值 和 真实点积的平均值
        return np.mean(np.abs(dot_products)), np.mean(dot_products)

    # --- Part 1: 计算从 GT -> Pred 的得分 ---
    score_gt_to_pred_abs, score_gt_to_pred_real = _calculate_one_way_score(pcd_gt, normal_gt, pcd_pred, normal_pred)
    
    # --- Part 2: 计算从 Pred -> GT 的得分 ---
    score_pred_to_gt_abs, score_pred_to_gt_real = _calculate_one_way_score(pcd_pred, normal_pred, pcd_gt, normal_gt)
    
    # --- Final Score: 结合两部分 ---
    final_score_abs = (score_gt_to_pred_abs + score_pred_to_gt_abs) / 2.0
    final_score_real = (score_gt_to_pred_real + score_pred_to_gt_real) / 2.0
    
    # [修改] 返回两个分数
    return final_score_abs, final_score_real