open-mmlab / mmdetection3d

OpenMMLab's next-generation platform for general 3D object detection.
https://mmdetection3d.readthedocs.io/en/latest/
Apache License 2.0
5k stars 1.49k forks source link

[Docs] python 文件: data_augment_utils.py 函数: box_collision_test 不能充分的判断盒子是否重叠 #2974

Open ALLLLLecy opened 1 month ago

ALLLLLecy commented 1 month ago

Branch

main branch https://mmdetection3d.readthedocs.io/en/latest/

📚 The doc issue

我为这个函数创建了两个测试用以用以判断当盒子位于如下图所示的情况时代码是否能够正常运行: 79F301F181E7058225802D72BBF7B807 黑色代表原始盒子,红色代表需要判断的盒子 对于第二种情况,通过叉乘法代码能够判断出待检测盒子的端点在当前盒子的内部。 但是对于第一种情况,仅通过叉乘法是不够的,因为叉乘法无法判断两条线段共线的情况。 关键代码如下所示:

                    # 如果没有发生碰撞,检查是否完全重叠
                    if not ret[i, j]:
                        # now check complete overlap.
                        # box overlap qbox:
                        # 检查是否完全重叠
                        # 假设待碰撞盒子在当前盒子的内部
                        box_overlap_qbox = True
                        for box_l in range(4):  # 对待避免碰撞盒子的每个点 point l in qboxes
                            for k in range(4):  # 对当前盒子的每个边 corner k in boxes
                                vec = boxes[i, k] - boxes[i, (k + 1) % 4]  # 计算边的向量

                                # 如果顺时针旋转则反向
                                if clockwise:
                                    vec = -vec

                                # 判断待避免碰撞的盒子的顶点是否在当前盒子内部。
                                # 如果叉乘结果大于等于零,则说明待避免碰撞的盒子的顶点共线或在盒子外部如下图所示,
                                # 但是对于共线的情况,这种方法判断是不足的,见上图
                                #        D ________ C
                                #         |        |
                                #         |        |
                                #         |        |
                                #         |_____P__|
                                #       A           B
                                #
                                #                P
                                cross = vec[1] * (boxes[i, k, 0] - qboxes[j, box_l, 0])
                                cross -= vec[0] * (boxes[i, k, 1] - qboxes[j, box_l, 1])

                                # 判断是否在盒子内部
                                if cross >= 0:
                                    box_overlap_qbox = False
                                    break

                            if box_overlap_qbox is False:
                                break

                        # 判断当前盒子是否在待碰撞盒子内部
                        if box_overlap_qbox is False:
                            # qbox overlap box:
                            # 假设当前盒子在待碰撞盒子的内部
                            qbox_overlap_box = True
                            for box_l in range(4):  # 对当前盒子的每个点 point box_l in boxes
                                for k in range(4):  # 对待避免碰撞盒子的每个边 corner k in qboxes
                                    vec = qboxes[j, k] - qboxes[j, (k + 1) % 4]  # 计算边的向量
                                    if clockwise:
                                        vec = -vec  # 如果顺时针旋转则反向
                                    cross = vec[1] * (qboxes[j, k, 0] - boxes[i, box_l, 0])  # 计算叉乘
                                    cross -= vec[0] * (qboxes[j, k, 1] - boxes[i, box_l, 1])  # 计算叉乘
                                    if cross >= 0:  # 判断是否在盒子内部
                                        qbox_overlap_box = False
                                        break
                                if qbox_overlap_box is False:
                                    break
                            if qbox_overlap_box:
                                ret[i, j] = True  # 发生碰撞
                        else:
                            ret[i, j] = True  # 发生碰撞

此外,代码当中还有一个有趣的错误,这个代码的返回结果 ret 是通过 np 创建的 ret = np.zeros((N, K), dtype=np.bool_) 这种创建方式并不会将常量 false 的 id 值复制给 ret,原始代码是通过 is 进行判断的如下所示:

                    if ret[i, j] is False:
                        # now check complete overlap.
                        # box overlap qbox:
                        box_overlap_qbox = True
                        for box_l in range(4):  # point l in qboxes
                            for k in range(4):  # corner k in boxes
                                vec = boxes[i, k] - boxes[i, (k + 1) % 4]
                                if clockwise:
                                    vec = -vec
                                cross = vec[1] * (
                                    boxes[i, k, 0] - qboxes[j, box_l, 0])
                                cross -= vec[0] * (
                                    boxes[i, k, 1] - qboxes[j, box_l, 1])
                                if cross >= 0:
                                    box_overlap_qbox = False
                                    break
                            if box_overlap_qbox is False:
                                break

                        if box_overlap_qbox is False:
                            qbox_overlap_box = True
                            for box_l in range(4):  # point box_l in boxes
                                for k in range(4):  # corner k in qboxes
                                    vec = qboxes[j, k] - qboxes[j, (k + 1) % 4]
                                    if clockwise:
                                        vec = -vec
                                    cross = vec[1] * (
                                        qboxes[j, k, 0] - boxes[i, box_l, 0])
                                    cross -= vec[0] * (
                                        qboxes[j, k, 1] - boxes[i, box_l, 1])
                                    if cross >= 0:  #
                                        qbox_overlap_box = False
                                        break
                                if qbox_overlap_box is False:
                                    break
                            if qbox_overlap_box:
                                ret[i, j] = True  # collision.
                        else:
                            ret[i, j] = True  # collision.

由于 is 语句的作用,这段代码永远也不会执行 o(╥﹏╥)o

Suggest a potential alternative/fix

我建议对于共线的情况需要额外的考虑以避免上述情况出现