def test_quat_grad_exists(self):
     """Quaternion calculations are differentiable."""
     rotation = random_rotation()
     rotation.requires_grad = True
     modified = quaternion_to_matrix(matrix_to_quaternion(rotation))
     [g] = torch.autograd.grad(modified.sum(), rotation)
     self.assertTrue(torch.isfinite(g).all())
Пример #2
0
    def test_box_planar_dir(self):
        device = torch.device("cuda:0")
        box1 = torch.tensor(
            UNIT_BOX,
            dtype=torch.float32,
            device=device,
        )

        n1 = torch.tensor(
            [
                [0.0, 0.0, 1.0],
                [0.0, -1.0, 0.0],
                [0.0, 1.0, 0.0],
                [1.0, 0.0, 0.0],
                [-1.0, 0.0, 0.0],
                [0.0, 0.0, -1.0],
            ],
            device=device,
            dtype=torch.float32,
        )

        RR = random_rotation(dtype=torch.float32, device=device)
        TT = torch.rand((1, 3), dtype=torch.float32, device=device)
        box2 = box1 @ RR.transpose(0, 1) + TT
        n2 = n1 @ RR.transpose(0, 1)

        self.assertClose(box_planar_dir(box1), n1)
        self.assertClose(box_planar_dir(box2), n2)
Пример #3
0
 def test_euler_grad_exists(self):
     """Euler angle calculations are differentiable."""
     rotation = random_rotation(dtype=torch.float64, requires_grad=True)
     for convention in self._all_euler_angle_conventions():
         euler_angles = matrix_to_euler_angles(rotation, convention)
         mdata = euler_angles_to_matrix(euler_angles, convention)
         [g] = torch.autograd.grad(mdata.sum(), rotation)
         self.assertTrue(torch.isfinite(g).all())
Пример #4
0
    def test_box_volume(self):
        device = torch.device("cuda:0")
        box1 = torch.tensor(
            [
                [3.1673, -2.2574, 0.4817],
                [4.6470, 0.2223, 2.4197],
                [5.2200, 1.1844, 0.7510],
                [3.7403, -1.2953, -1.1869],
                [-4.9316, 2.5724, 0.4856],
                [-3.4519, 5.0521, 2.4235],
                [-2.8789, 6.0142, 0.7549],
                [-4.3586, 3.5345, -1.1831],
            ],
            dtype=torch.float32,
            device=device,
        )
        box2 = torch.tensor(
            [
                [0.5623, 4.0647, 3.4334],
                [3.3584, 4.3191, 1.1791],
                [3.0724, -5.9235, -0.3315],
                [0.2763, -6.1779, 1.9229],
                [-2.0773, 4.6121, 0.2213],
                [0.7188, 4.8665, -2.0331],
                [0.4328, -5.3761, -3.5436],
                [-2.3633, -5.6305, -1.2893],
            ],
            dtype=torch.float32,
            device=device,
        )

        box3 = torch.tensor(
            [
                [0, 0, 0],
                [1, 0, 0],
                [1, 1, 0],
                [0, 1, 0],
                [0, 0, 1],
                [1, 0, 1],
                [1, 1, 1],
                [0, 1, 1],
            ],
            dtype=torch.float32,
            device=device,
        )

        RR = random_rotation(dtype=torch.float32, device=device)
        TT = torch.rand((1, 3), dtype=torch.float32, device=device)
        box4 = box3 @ RR.transpose(0, 1) + TT

        self.assertClose(box_volume(box1).cpu(),
                         torch.tensor(65.899010),
                         atol=1e-3)
        self.assertClose(box_volume(box2).cpu(),
                         torch.tensor(156.386719),
                         atol=1e-3)
        self.assertClose(box_volume(box3).cpu(), torch.tensor(1.0), atol=1e-3)
        self.assertClose(box_volume(box4).cpu(), torch.tensor(1.0), atol=1e-3)
    def test_random_rotation_invariant(self):
        """The image of the x-axis isn't biased among quadrants."""
        N = 1000
        base = random_rotation()
        quadrants = list(itertools.product([False, True], repeat=3))

        matrices = random_rotations(N)
        transformed = torch.matmul(base, matrices)
        transformed2 = torch.matmul(matrices, base)

        for k, results in enumerate([matrices, transformed, transformed2]):
            counts = {i: 0 for i in quadrants}
            for j in range(N):
                counts[tuple(i.item() > 0 for i in results[j, 0])] += 1
            average = N / 8.0
            counts_tensor = torch.tensor(list(counts.values()))
            chisquare_statistic = torch.sum(
                (counts_tensor - average) * (counts_tensor - average) / average
            )
            # The 0.1 significance level for chisquare(8-1) is
            # scipy.stats.chi2(7).ppf(0.9) == 12.017.
            self.assertLess(chisquare_statistic, 12, (counts, chisquare_statistic, k))
Пример #6
0
    def _test_iou(self, overlap_fn, device):

        box1 = torch.tensor(
            UNIT_BOX,
            dtype=torch.float32,
            device=device,
        )

        # 1st test: same box, iou = 1.0
        vol, iou = overlap_fn(box1[None], box1[None])
        self.assertClose(
            vol, torch.tensor([[1.0]], device=vol.device, dtype=vol.dtype))
        self.assertClose(
            iou, torch.tensor([[1.0]], device=vol.device, dtype=vol.dtype))

        # 2nd test
        dd = random.random()
        box2 = box1 + torch.tensor([[0.0, dd, 0.0]], device=device)
        vol, iou = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol, torch.tensor([[1 - dd]], device=vol.device, dtype=vol.dtype))
        # symmetry
        vol, iou = overlap_fn(box2[None], box1[None])
        self.assertClose(
            vol, torch.tensor([[1 - dd]], device=vol.device, dtype=vol.dtype))

        # 3rd test
        dd = random.random()
        box2 = box1 + torch.tensor([[dd, 0.0, 0.0]], device=device)
        vol, _ = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol, torch.tensor([[1 - dd]], device=vol.device, dtype=vol.dtype))
        # symmetry
        vol, _ = overlap_fn(box2[None], box1[None])
        self.assertClose(
            vol, torch.tensor([[1 - dd]], device=vol.device, dtype=vol.dtype))

        # 4th test
        ddx, ddy, ddz = random.random(), random.random(), random.random()
        box2 = box1 + torch.tensor([[ddx, ddy, ddz]], device=device)
        vol, _ = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
        )
        # symmetry
        vol, _ = overlap_fn(box2[None], box1[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
        )

        # Also check IoU is 1 when computing overlap with the same shifted box
        vol, iou = overlap_fn(box2[None], box2[None])
        self.assertClose(
            iou, torch.tensor([[1.0]], device=vol.device, dtype=vol.dtype))

        # 5th test
        ddx, ddy, ddz = random.random(), random.random(), random.random()
        box2 = box1 + torch.tensor([[ddx, ddy, ddz]], device=device)
        RR = random_rotation(dtype=torch.float32, device=device)
        box1r = box1 @ RR.transpose(0, 1)
        box2r = box2 @ RR.transpose(0, 1)
        vol, _ = overlap_fn(box1r[None], box2r[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
        )
        # symmetry
        vol, _ = overlap_fn(box2r[None], box1r[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
        )

        # 6th test
        ddx, ddy, ddz = random.random(), random.random(), random.random()
        box2 = box1 + torch.tensor([[ddx, ddy, ddz]], device=device)
        RR = random_rotation(dtype=torch.float32, device=device)
        TT = torch.rand((1, 3), dtype=torch.float32, device=device)
        box1r = box1 @ RR.transpose(0, 1) + TT
        box2r = box2 @ RR.transpose(0, 1) + TT
        vol, _ = overlap_fn(box1r[None], box2r[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
            atol=1e-7,
        )
        # symmetry
        vol, _ = overlap_fn(box2r[None], box1r[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
            atol=1e-7,
        )

        # 7th test: hand coded example and test with meshlab output

        # Meshlab procedure to compute volumes of shapes
        # 1. Load a shape, then Filters
        #       -> Remeshing, Simplification, Reconstruction -> Convex Hull
        # 2. Select the convex hull shape (This is important!)
        # 3. Then Filters -> Quality Measure and Computation -> Compute Geometric Measures
        # 3. Check for "Mesh Volume" in the stdout
        box1r = torch.tensor(
            [
                [3.1673, -2.2574, 0.4817],
                [4.6470, 0.2223, 2.4197],
                [5.2200, 1.1844, 0.7510],
                [3.7403, -1.2953, -1.1869],
                [-4.9316, 2.5724, 0.4856],
                [-3.4519, 5.0521, 2.4235],
                [-2.8789, 6.0142, 0.7549],
                [-4.3586, 3.5345, -1.1831],
            ],
            device=device,
        )
        box2r = torch.tensor(
            [
                [0.5623, 4.0647, 3.4334],
                [3.3584, 4.3191, 1.1791],
                [3.0724, -5.9235, -0.3315],
                [0.2763, -6.1779, 1.9229],
                [-2.0773, 4.6121, 0.2213],
                [0.7188, 4.8665, -2.0331],
                [0.4328, -5.3761, -3.5436],
                [-2.3633, -5.6305, -1.2893],
            ],
            device=device,
        )
        # from Meshlab:
        vol_inters = 33.558529
        vol_box1 = 65.899010
        vol_box2 = 156.386719
        iou_mesh = vol_inters / (vol_box1 + vol_box2 - vol_inters)

        vol, iou = overlap_fn(box1r[None], box2r[None])
        self.assertClose(vol,
                         torch.tensor([[vol_inters]], device=device),
                         atol=1e-1)
        self.assertClose(iou,
                         torch.tensor([[iou_mesh]], device=device),
                         atol=1e-1)
        # symmetry
        vol, iou = overlap_fn(box2r[None], box1r[None])
        self.assertClose(vol,
                         torch.tensor([[vol_inters]], device=device),
                         atol=1e-1)
        self.assertClose(iou,
                         torch.tensor([[iou_mesh]], device=device),
                         atol=1e-1)

        # 8th test: compare with sampling
        # create box1
        ctrs = torch.rand((2, 3), device=device)
        whl = torch.rand((2, 3), device=device) * 10.0 + 1.0
        # box8a & box8b
        box8a = self.create_box(ctrs[0], whl[0])
        box8b = self.create_box(ctrs[1], whl[1])
        RR1 = random_rotation(dtype=torch.float32, device=device)
        TT1 = torch.rand((1, 3), dtype=torch.float32, device=device)
        RR2 = random_rotation(dtype=torch.float32, device=device)
        TT2 = torch.rand((1, 3), dtype=torch.float32, device=device)
        box1r = box8a @ RR1.transpose(0, 1) + TT1
        box2r = box8b @ RR2.transpose(0, 1) + TT2
        vol, iou = overlap_fn(box1r[None], box2r[None])
        iou_sampling = self._box3d_overlap_sampling_batched(box1r[None],
                                                            box2r[None],
                                                            num_samples=10000)
        self.assertClose(iou, iou_sampling, atol=1e-2)
        # symmetry
        vol, iou = overlap_fn(box2r[None], box1r[None])
        self.assertClose(iou, iou_sampling, atol=1e-2)

        # 9th test: non overlapping boxes, iou = 0.0
        box2 = box1 + torch.tensor([[0.0, 100.0, 0.0]], device=device)
        vol, iou = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol, torch.tensor([[0.0]], device=vol.device, dtype=vol.dtype))
        self.assertClose(
            iou, torch.tensor([[0.0]], device=vol.device, dtype=vol.dtype))
        # symmetry
        vol, iou = overlap_fn(box2[None], box1[None])
        self.assertClose(
            vol, torch.tensor([[0.0]], device=vol.device, dtype=vol.dtype))
        self.assertClose(
            iou, torch.tensor([[0.0]], device=vol.device, dtype=vol.dtype))

        # 10th test: Non coplanar verts in a plane
        box10 = box1 + torch.rand((8, 3), dtype=torch.float32, device=device)
        msg = "Plane vertices are not coplanar"
        with self.assertRaisesRegex(ValueError, msg):
            overlap_fn(box10[None], box10[None])

        # 11th test: Skewed bounding boxes but all verts are coplanar
        box_skew_1 = torch.tensor(
            [
                [0, 0, 0],
                [1, 0, 0],
                [1, 1, 0],
                [0, 1, 0],
                [-2, -2, 2],
                [2, -2, 2],
                [2, 2, 2],
                [-2, 2, 2],
            ],
            dtype=torch.float32,
            device=device,
        )
        box_skew_2 = torch.tensor(
            [
                [2.015995, 0.695233, 2.152806],
                [2.832533, 0.663448, 1.576389],
                [2.675445, -0.309592, 1.407520],
                [1.858907, -0.277806, 1.983936],
                [-0.413922, 3.161758, 2.044343],
                [2.852230, 3.034615, -0.261321],
                [2.223878, -0.857545, -0.936800],
                [-1.042273, -0.730402, 1.368864],
            ],
            dtype=torch.float32,
            device=device,
        )
        vol1 = 14.000
        vol2 = 14.000005
        vol_inters = 5.431122
        iou = vol_inters / (vol1 + vol2 - vol_inters)

        vols, ious = overlap_fn(box_skew_1[None], box_skew_2[None])
        self.assertClose(vols,
                         torch.tensor([[vol_inters]], device=device),
                         atol=1e-1)
        self.assertClose(ious, torch.tensor([[iou]], device=device), atol=1e-1)
        # symmetry
        vols, ious = overlap_fn(box_skew_2[None], box_skew_1[None])
        self.assertClose(vols,
                         torch.tensor([[vol_inters]], device=device),
                         atol=1e-1)
        self.assertClose(ious, torch.tensor([[iou]], device=device), atol=1e-1)

        # 12th test: Zero area bounding box (from GH issue #992)
        box12a = torch.tensor(
            [
                [-1.0000, -1.0000, -0.5000],
                [1.0000, -1.0000, -0.5000],
                [1.0000, 1.0000, -0.5000],
                [-1.0000, 1.0000, -0.5000],
                [-1.0000, -1.0000, 0.5000],
                [1.0000, -1.0000, 0.5000],
                [1.0000, 1.0000, 0.5000],
                [-1.0000, 1.0000, 0.5000],
            ],
            device=device,
            dtype=torch.float32,
        )

        box12b = torch.tensor(
            [
                [0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
            ],
            device=device,
            dtype=torch.float32,
        )
        msg = "Planes have zero areas"
        with self.assertRaisesRegex(ValueError, msg):
            overlap_fn(box12a[None], box12b[None])
        # symmetry
        with self.assertRaisesRegex(ValueError, msg):
            overlap_fn(box12b[None], box12a[None])

        # 13th test: From GH issue #992
        # Zero area coplanar face after intersection
        ctrs = torch.tensor([[0.0, 0.0, 0.0], [-1.0, 1.0, 0.0]])
        whl = torch.tensor([[2.0, 2.0, 2.0], [2.0, 2, 2]])
        box13a = TestIoU3D.create_box(ctrs[0], whl[0])
        box13b = TestIoU3D.create_box(ctrs[1], whl[1])
        vol, iou = overlap_fn(box13a[None], box13b[None])
        self.assertClose(
            vol, torch.tensor([[2.0]], device=vol.device, dtype=vol.dtype))

        # 14th test: From GH issue #992
        # Random rotation, same boxes, iou should be 1.0
        corners = (torch.tensor(
            [
                [-1.0, -1.0, -1.0],
                [1.0, -1.0, -1.0],
                [1.0, 1.0, -1.0],
                [-1.0, 1.0, -1.0],
                [-1.0, -1.0, 1.0],
                [1.0, -1.0, 1.0],
                [1.0, 1.0, 1.0],
                [-1.0, 1.0, 1.0],
            ],
            device=device,
            dtype=torch.float32,
        ) * 0.5)
        yaw = torch.tensor(0.185)
        Rot = torch.tensor(
            [
                [torch.cos(yaw), 0.0, torch.sin(yaw)],
                [0.0, 1.0, 0.0],
                [-torch.sin(yaw), 0.0, torch.cos(yaw)],
            ],
            dtype=torch.float32,
            device=device,
        )
        corners = (Rot.mm(corners.t())).t()
        vol, iou = overlap_fn(corners[None], corners[None])
        self.assertClose(iou,
                         torch.tensor([[1.0]],
                                      device=vol.device,
                                      dtype=vol.dtype),
                         atol=1e-2)

        # 15th test: From GH issue #1082
        box15a = torch.tensor(
            [
                [-2.5629019, 4.13995749, -1.76344576],
                [1.92329434, 4.28127117, -1.86155124],
                [1.86994571, 5.97489644, -1.86155124],
                [-2.61625053, 5.83358276, -1.76344576],
                [-2.53123587, 4.14095496, -0.31397536],
                [1.95496037, 4.28226864, -0.41208084],
                [1.90161174, 5.97589391, -0.41208084],
                [-2.5845845, 5.83458023, -0.31397536],
            ],
            device=device,
            dtype=torch.float32,
        )

        box15b = torch.tensor(
            [
                [-2.6256125, 4.13036357, -1.82893437],
                [1.87201008, 4.25296695, -1.82893437],
                [1.82562476, 5.95458116, -1.82893437],
                [-2.67199782, 5.83197777, -1.82893437],
                [-2.6256125, 4.13036357, -0.40095884],
                [1.87201008, 4.25296695, -0.40095884],
                [1.82562476, 5.95458116, -0.40095884],
                [-2.67199782, 5.83197777, -0.40095884],
            ],
            device=device,
            dtype=torch.float32,
        )
        vol, iou = overlap_fn(box15a[None], box15b[None])
        self.assertClose(iou,
                         torch.tensor([[0.91]],
                                      device=vol.device,
                                      dtype=vol.dtype),
                         atol=1e-2)
Пример #7
0
    def _test_iou(self, overlap_fn, device):

        box1 = torch.tensor(
            UNIT_BOX,
            dtype=torch.float32,
            device=device,
        )

        # 1st test: same box, iou = 1.0
        vol, iou = overlap_fn(box1[None], box1[None])
        self.assertClose(
            vol, torch.tensor([[1.0]], device=vol.device, dtype=vol.dtype))
        self.assertClose(
            iou, torch.tensor([[1.0]], device=vol.device, dtype=vol.dtype))

        # 2nd test
        dd = random.random()
        box2 = box1 + torch.tensor([[0.0, dd, 0.0]], device=device)
        vol, iou = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol, torch.tensor([[1 - dd]], device=vol.device, dtype=vol.dtype))

        # 3rd test
        dd = random.random()
        box2 = box1 + torch.tensor([[dd, 0.0, 0.0]], device=device)
        vol, _ = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol, torch.tensor([[1 - dd]], device=vol.device, dtype=vol.dtype))

        # 4th test
        ddx, ddy, ddz = random.random(), random.random(), random.random()
        box2 = box1 + torch.tensor([[ddx, ddy, ddz]], device=device)
        vol, _ = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
        )

        # Also check IoU is 1 when computing overlap with the same shifted box
        vol, iou = overlap_fn(box2[None], box2[None])
        self.assertClose(
            iou, torch.tensor([[1.0]], device=vol.device, dtype=vol.dtype))

        # 5th test
        ddx, ddy, ddz = random.random(), random.random(), random.random()
        box2 = box1 + torch.tensor([[ddx, ddy, ddz]], device=device)
        RR = random_rotation(dtype=torch.float32, device=device)
        box1r = box1 @ RR.transpose(0, 1)
        box2r = box2 @ RR.transpose(0, 1)
        vol, _ = overlap_fn(box1r[None], box2r[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
        )

        # 6th test
        ddx, ddy, ddz = random.random(), random.random(), random.random()
        box2 = box1 + torch.tensor([[ddx, ddy, ddz]], device=device)
        RR = random_rotation(dtype=torch.float32, device=device)
        TT = torch.rand((1, 3), dtype=torch.float32, device=device)
        box1r = box1 @ RR.transpose(0, 1) + TT
        box2r = box2 @ RR.transpose(0, 1) + TT
        vol, _ = overlap_fn(box1r[None], box2r[None])
        self.assertClose(
            vol,
            torch.tensor(
                [[(1 - ddx) * (1 - ddy) * (1 - ddz)]],
                device=vol.device,
                dtype=vol.dtype,
            ),
            atol=1e-7,
        )

        # 7th test: hand coded example and test with meshlab output

        # Meshlab procedure to compute volumes of shapes
        # 1. Load a shape, then Filters
        #       -> Remeshing, Simplification, Reconstruction -> Convex Hull
        # 2. Select the convex hull shape (This is important!)
        # 3. Then Filters -> Quality Measure and Computation -> Compute Geometric Measures
        # 3. Check for "Mesh Volume" in the stdout
        box1r = torch.tensor(
            [
                [3.1673, -2.2574, 0.4817],
                [4.6470, 0.2223, 2.4197],
                [5.2200, 1.1844, 0.7510],
                [3.7403, -1.2953, -1.1869],
                [-4.9316, 2.5724, 0.4856],
                [-3.4519, 5.0521, 2.4235],
                [-2.8789, 6.0142, 0.7549],
                [-4.3586, 3.5345, -1.1831],
            ],
            device=device,
        )
        box2r = torch.tensor(
            [
                [0.5623, 4.0647, 3.4334],
                [3.3584, 4.3191, 1.1791],
                [3.0724, -5.9235, -0.3315],
                [0.2763, -6.1779, 1.9229],
                [-2.0773, 4.6121, 0.2213],
                [0.7188, 4.8665, -2.0331],
                [0.4328, -5.3761, -3.5436],
                [-2.3633, -5.6305, -1.2893],
            ],
            device=device,
        )
        # from Meshlab:
        vol_inters = 33.558529
        vol_box1 = 65.899010
        vol_box2 = 156.386719
        iou_mesh = vol_inters / (vol_box1 + vol_box2 - vol_inters)

        vol, iou = overlap_fn(box1r[None], box2r[None])
        self.assertClose(vol,
                         torch.tensor([[vol_inters]], device=device),
                         atol=1e-1)
        self.assertClose(iou,
                         torch.tensor([[iou_mesh]], device=device),
                         atol=1e-1)

        # 8th test: compare with sampling
        # create box1
        ctrs = torch.rand((2, 3), device=device)
        whl = torch.rand((2, 3), device=device) * 10.0 + 1.0
        # box8a & box8b
        box8a = self.create_box(ctrs[0], whl[0])
        box8b = self.create_box(ctrs[1], whl[1])
        RR1 = random_rotation(dtype=torch.float32, device=device)
        TT1 = torch.rand((1, 3), dtype=torch.float32, device=device)
        RR2 = random_rotation(dtype=torch.float32, device=device)
        TT2 = torch.rand((1, 3), dtype=torch.float32, device=device)
        box1r = box8a @ RR1.transpose(0, 1) + TT1
        box2r = box8b @ RR2.transpose(0, 1) + TT2
        vol, iou = overlap_fn(box1r[None], box2r[None])
        iou_sampling = self._box3d_overlap_sampling_batched(box1r[None],
                                                            box2r[None],
                                                            num_samples=10000)

        self.assertClose(iou, iou_sampling, atol=1e-2)

        # 9th test: non overlapping boxes, iou = 0.0
        box2 = box1 + torch.tensor([[0.0, 100.0, 0.0]], device=device)
        vol, iou = overlap_fn(box1[None], box2[None])
        self.assertClose(
            vol, torch.tensor([[0.0]], device=vol.device, dtype=vol.dtype))
        self.assertClose(
            iou, torch.tensor([[0.0]], device=vol.device, dtype=vol.dtype))

        # 10th test: Non coplanar verts in a plane
        box10 = box1 + torch.rand((8, 3), dtype=torch.float32, device=device)
        msg = "Plane vertices are not coplanar"
        with self.assertRaisesRegex(ValueError, msg):
            overlap_fn(box10[None], box10[None])

        # 11th test: Skewed bounding boxes but all verts are coplanar
        box_skew_1 = torch.tensor(
            [
                [0, 0, 0],
                [1, 0, 0],
                [1, 1, 0],
                [0, 1, 0],
                [-2, -2, 2],
                [2, -2, 2],
                [2, 2, 2],
                [-2, 2, 2],
            ],
            dtype=torch.float32,
            device=device,
        )
        box_skew_2 = torch.tensor(
            [
                [2.015995, 0.695233, 2.152806],
                [2.832533, 0.663448, 1.576389],
                [2.675445, -0.309592, 1.407520],
                [1.858907, -0.277806, 1.983936],
                [-0.413922, 3.161758, 2.044343],
                [2.852230, 3.034615, -0.261321],
                [2.223878, -0.857545, -0.936800],
                [-1.042273, -0.730402, 1.368864],
            ],
            dtype=torch.float32,
            device=device,
        )
        vol1 = 14.000
        vol2 = 14.000005
        vol_inters = 5.431122
        iou = vol_inters / (vol1 + vol2 - vol_inters)

        vols, ious = overlap_fn(box_skew_1[None], box_skew_2[None])
        self.assertClose(vols,
                         torch.tensor([[vol_inters]], device=device),
                         atol=1e-1)
        self.assertClose(ious, torch.tensor([[iou]], device=device), atol=1e-1)