Esempio n. 1
0
    def test_shape_similarity(self):
        """
        Verify that the shape similarity measure is producing sane outputs.
        """

        # make a dummy scene
        scene = ProjectScene("bounding_box")
        evaluator = BBEvaluator(scene, scene, self.settings)

        obj1 = next(iter(self.submission.elements.values()))

        # ::: Temp only, use copy of obj1 if deep copy can be made to work
        obj2 = next(iter(self.ground_truth.elements.values()))

        # verify no offset gives sim = 1
        sim = evaluator._shape_similarity(obj1, obj2)
        self.assertAlmostEqual(sim, 1)

        # verify small offset gives sim between 0 and 1
        pose_orig = obj2.pose
        obj2.pose = Pose3(t=pose_orig.t + [0.1, 0, 0], R=pose_orig.R)
        sim = evaluator._shape_similarity(obj1, obj2)
        self.assertTrue(sim < 1 and sim > 0)

        # verify large offset gives sim = 0
        obj2.pose = Pose3(t=pose_orig.t + [5, 5, 5], R=pose_orig.R)
        sim = evaluator._shape_similarity(obj1, obj2)
        self.assertAlmostEqual(sim, 0)
Esempio n. 2
0
 def test_compose(self):
     expected = Pose3(self.pose.rotation(), Vector3(1, 5, 1))
     translate = Pose3(t=Vector3(0, 0, 4))  # translate Z axis, which is Y
     actual = self.pose.compose(translate)
     actual.assert_equal(expected)
     actual2 = self.pose * translate
     actual2.assert_equal(expected)
Esempio n. 3
0
    def example(cls):
        """Create a simple ProjectObjectDict."""

        pose1 = Pose3()
        pose2 = Pose3(t=Vector3(2, 2, 0))
        pose3 = Pose3(t=Vector3(4, 2, 0))

        # Be explicit about unicode literal in case this code is called from python 2
        data_path = parutil.get_dir_path(u"sumo/threedee/test_data")

        model1 = GltfModel.load_from_glb(os.path.join(data_path, "bed.glb"))
        model2 = GltfModel.load_from_glb(os.path.join(data_path, "bed.glb"))
        model3 = GltfModel.load_from_glb(os.path.join(data_path, "bed.glb"))

        obj1 = ProjectObject.gen_meshes_object(
            meshes=model1, id="1", pose=pose1, category="bed"
        )
        obj2 = ProjectObject.gen_meshes_object(
            meshes=model2, id="2", pose=pose2, category="chair"
        )
        obj3 = ProjectObject.gen_meshes_object(
            meshes=model3, id="3", pose=pose3, category="bed"
        )

        project_object_dict = ProjectObjectDict()
        project_object_dict[obj1.id] = obj1
        project_object_dict[obj2.id] = obj2
        project_object_dict[obj3.id] = obj3

        return project_object_dict
Esempio n. 4
0
    def test_pose_error(self):
        """
        Test rotation and translation error metric.
        """

        self.ground_truth = ProjectScene.load(self.data_path,
                                              'bounding_box_sample2')
        self.submission = ProjectScene.load(self.data_path,
                                            'bounding_box_sample2')
        self.settings.thresholds = [0.5]

        # verify that correct pose is ok
        evaluator = BBEvaluator(self.submission, self.ground_truth,
                                self.settings)
        rotation_error, translation_error = evaluator.pose_error()
        self.assertAlmostEqual(rotation_error, 0)
        self.assertAlmostEqual(translation_error, 0)

        # verify that rotation by symmetry amount is ok
        pose_orig = self.submission.elements["1069"].pose
        new_pose = Pose3(R=pose_orig.R * Rot3.Ry(math.pi), t=pose_orig.t)
        self.submission.elements["1069"].pose = new_pose
        evaluator = BBEvaluator(self.submission, self.ground_truth,
                                self.settings)
        rotation_error, translation_error = evaluator.pose_error()
        self.assertAlmostEqual(rotation_error, 0)
        self.assertAlmostEqual(translation_error, 0)

        # verify that rotation by non-symmetry amount give correct error
        new_pose = Pose3(R=pose_orig.R * Rot3.Ry(math.radians(10)),
                         t=pose_orig.t)
        self.submission.elements["1069"].pose = new_pose
        evaluator = BBEvaluator(self.submission, self.ground_truth,
                                self.settings)
        rotation_error, translation_error = evaluator.pose_error()
        self.assertAlmostEqual(rotation_error, math.radians(10))
        self.assertAlmostEqual(translation_error, 0)

        # verify that translation gives translation error
        new_pose = Pose3(R=pose_orig.R, t=pose_orig.t + [0.05, 0, 0])
        self.submission.elements["1069"].pose = new_pose
        evaluator = BBEvaluator(self.submission, self.ground_truth,
                                self.settings)
        rotation_error, translation_error = evaluator.pose_error()
        self.assertAlmostEqual(rotation_error, 0)
        self.assertAlmostEqual(translation_error, 0.05)

        # verify that empty sumission gives None, None
        new_pose = Pose3(R=pose_orig.R, t=pose_orig.t + [1, 0, 0])
        self.submission.elements["1069"].pose = new_pose
        evaluator = BBEvaluator(self.submission, self.ground_truth,
                                self.settings)
        rotation_error, translation_error = evaluator.pose_error()
        self.assertEqual(rotation_error, None)
        self.assertEqual(translation_error, None)
Esempio n. 5
0
 def test_register(self):
     ''' Test registering point clouds in different frames. '''
     t = Vector3(1, 1, 1)
     R = Rot3()
     T = Pose3(R, t).inverse()
     cloud = PointCloud(np.zeros((3, 1)))
     registred_cloud = PointCloud.register([(Pose3(), cloud), (T, cloud)])
     np.testing.assert_array_equal(
         registred_cloud.points(),
         np.column_stack([Vector3(0, 0, 0),
                          Vector3(-1.0, -1.0, -1.0)]))
 def test_xml(self):
     """
     Test conversion to and from xml.  This is just a basic functionality
     test of a round trip from Pose3 to xml and back.
     """
     pose = Pose3(t=Vector3(1.5, 2.6, 3.7),
                  R=np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))
     pose_xml = pose.to_xml()
     self.assertEqual(pose_xml.tag, 'pose')
     pose_rt = Pose3.from_xml(pose_xml)
     pose.assert_almost_equal(pose_rt)
    def test_surreal(self):
        """Read from a Surreal json file."""

        # Expected pose.
        expected_pose = Pose3(t=Vector3(1, 2, 3))

        # Read json file
        path_to_json_linear = os.path.join(PATH, 'pose3_test.json')
        data = json.load(open(path_to_json_linear))
        pose = Pose3.from_surreal(data['T_cr'])

        # Test pose
        pose.assert_almost_equal(expected_pose)
Esempio n. 8
0
    def __init__(self,
                 id,
                 project_type="bounding_box",
                 bounds=None,
                 voxels=None,
                 meshes=None,
                 pose=None,
                 category="unknown",
                 symmetry=None,
                 score=-1,
                 evaluated=True):
        """
        Constructor.  Preferred method of creation is one of the factory methods:
        gen_bounding_box_object, gen_voxels_object, or gen_meshes_object.

        For this constructor, representation is selected based on the <project_type>:
        bounding box track: bounds is used
        voxels track: voxels and bounds are used
        mesh track: meshes and bounds are used

        Inputs:
        id (string) - Unique identifier for the object
        project_type (string) - Specifies the project type to construct (valid
            values are "bounding_box", "voxels", or "meshes")
        bounds (Box3d) - Object bounding box in local coordinates
        voxels (VoxelGrid) - Object voxel shape in local coordinates
        meshes (GltfModel) - Object mesh shape and appearance in local coordinates
        pose (Pose3) - Transforms object from local coordinates to world coordinates
        category (string) - Object category (e.g., chair, bookcase, etc.)
        symmetry (ObjectSymmetry) - Object symmetry description
        score (float) - Detection score
        evaluated (Boolean) - Indicates whether this object will be used in
            evaluation metric.  Only relevant for ground truth scenes.

        Exceptions:
            ValueError - if project_type is not one of the allowed values.
        """
        # ensure id is unicode string, idiom below is python2/3 compatible
        self._id = id.decode('UTF-8') if hasattr(id, 'decode') else id
        self._project_type = project_type
        self.pose = pose if pose is not None else Pose3()
        self.category = category
        self.symmetry = symmetry if symmetry is not None else ObjectSymmetry()
        self.score = score
        self.evaluated = evaluated

        if project_type == "bounding_box":
            self.bounds = bounds
            self.voxels = None
            self.meshes = None
        elif project_type == "voxels":
            self.bounds = bounds
            self.voxels = voxels
            self.meshes = None
        elif project_type == "meshes":
            self.bounds = bounds
            self.voxels = None
            self.meshes = meshes
        else:
            raise ValueError("Invalid project_type: " + project_type)
Esempio n. 9
0
 def test_transform_from(self):
     '''Test transform_from.'''
     t = Vector3(1, 1, 1)
     R = Rot3()
     T = Pose3(R, t).inverse()
     cloud = PointCloud(np.zeros((3, 1)))
     new_cloud = cloud.transform_from(T)
     np.testing.assert_array_equal(new_cloud.points(),
                                   [[-1.0], [-1.0], [-1.0]])
Esempio n. 10
0
    def test_semantic_score(self):
        # We cannot test Evaluator directly.  This creates the similarity cache and
        # does data association
        evaluator = BBEvaluator(self.submission, self.ground_truth,
                                self.settings)

        # submission and GT are exactly the same, should get mAP = 1
        semantic_score = evaluator.semantics_score()
        expected = 1
        self.assertEqual(
            semantic_score, expected,
            "Expected semantic score of %.3f, found %.3f.\n" %
            (expected, semantic_score))

        # move the coffee table by a bit to get IoU ~ 0.72.  Should
        # get 0.5 since the average precision in 5 of the 10
        # thresholds is 1 and in the other cases it is 0.
        table = self.submission.elements["1069"]
        settings = self.settings
        settings.categories = ["coffee_table"]
        pose_orig = table.pose
        table.pose = Pose3(t=pose_orig.t + [0.1, 0, 0], R=pose_orig.R)
        evaluator2 = BBEvaluator(self.submission, self.ground_truth, settings)
        semantic_score = evaluator2.semantics_score()
        expected = 0.5
        self.assertAlmostEqual(
            semantic_score, expected, 3,
            "Expected semantic score of %.3f, found %.3f.\n" %
            (expected, semantic_score))

        # move the coffee table by a lot to get IoU < 0.5.
        table = self.submission.elements["1069"]
        settings = self.settings
        settings.categories = ["coffee_table"]
        table.pose = Pose3(t=pose_orig.t + [0.5, 0, 0], R=pose_orig.R)
        evaluator2 = BBEvaluator(self.submission, self.ground_truth, settings)
        semantic_score = evaluator2.semantics_score()
        expected = 0
        self.assertAlmostEqual(
            semantic_score, expected, 3,
            "Expected semantic score of %.3f, found %.3f.\n" %
            (expected, semantic_score))
Esempio n. 11
0
 def example(cls, id="1"):
     """Create a simple ProjectObject of project_type = meshes."""
     meshes = GltfModel.example()
     pose = Pose3(t=Vector3(1, 2, 3))
     symmetry = ObjectSymmetry.example()
     return cls.gen_meshes_object(id=id,
                                  pose=pose,
                                  category="chair",
                                  meshes=meshes,
                                  symmetry=symmetry,
                                  score=0.57)
Esempio n. 12
0
    def _parse_xml(base_elem):
        """
        Parse the xml of an <element> tag, extracting the ProjectObject attributes.

        Inputs:
        base_elem (ET.Element) - An Element with tag "element" and appropriate
            sub-elements.

        Return:
        tuple (id, pose, category, bounds, symmetry, score, evaluated)
        ProjectObject attributes (see constructor for details).

        Exceptions:
        ValueError - If base_elem is not <element> or if none of its children is <id>.
        """
        # verify base_elem tag is 'element'
        if base_elem.tag != "element":
            raise ValueError('Expected tag to be "element"')

        # defaults
        proxy = ProjectObject(1)
        category = proxy.category
        pose = proxy.pose
        symmetry = proxy.symmetry
        score = proxy.score
        evaluated = proxy.evaluated

        for elem in base_elem:
            if elem.tag == "id":
                id = elem.text
            elif elem.tag == "pose":
                pose = Pose3.from_xml(elem)
            elif elem.tag == "category":
                category = elem.text
            elif (elem.tag == "bounds"):
                # Note: Boxe3d.from_xml expects tag to be 'box3d'
                elem_temp = deepcopy(elem)
                elem_temp.tag = "box3d"
                bounds = Box3d.from_xml(elem_temp)
            elif elem.tag == "symmetry":
                symmetry = ObjectSymmetry.from_xml(elem)
            elif elem.tag == "detectionScore":
                score = float(elem.text)
            elif elem.tag == "evaluated":
                evaluated = bool(elem.text)

        if id is None:
            raise ValueError("XML is missing required <id> tag.")

        return (id, pose, category, bounds, symmetry, score, evaluated)
Esempio n. 13
0
    def test_shape_similarity(self):
        """
        Verify that the shape similarity measure is producing sane outputs.
        """

        evaluator = BBEvaluator(self.submission, self.ground_truth, self.settings)

        obj1 = self.submission.elements["51"]
        obj2 = self.ground_truth.elements["51"]

        # verify no offset gives sim = 1
        sim = evaluator._shape_similarity(obj1, obj2)
        self.assertAlmostEqual(sim, 1)

        # verify small offset gives sim between 0 and 1
        pose_orig = obj2.pose
        obj2.pose = Pose3(t=pose_orig.t + [0.1, 0, 0], R=pose_orig.R)
        sim = evaluator._shape_similarity(obj1, obj2)
        self.assertTrue(sim < 1 and sim > 0)

        # verify large offset gives sim = 0
        obj2.pose = Pose3(t=pose_orig.t + [5, 5, 5], R=pose_orig.R)
        sim = evaluator._shape_similarity(obj1, obj2)
        self.assertAlmostEqual(sim, 0)
Esempio n. 14
0
    def setUp(self):
        # create sample bounding box, meshes, and voxel grid objects
        self.bounds = Box3d([-1.5, -2.2, 3], [4, 4.1, 6.5])
        textured_mesh = self.bounds.to_textured_mesh()
        self.meshes = GltfModel.from_textured_mesh(textured_mesh)
        points = np.array([[0.1, 0.1, 0.1], [1.1, 1.1, 1.1], [1.3, 1.2, 1.4]])
        self.voxels = VoxelGrid(0.5,
                                min_corner=Vector3f(0, 0, 0),
                                points=points)

        # and pose
        rot = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]], dtype=float)
        trans = Vector3f(1, 1, 1)
        self.pose = Pose3(rot, trans)

        # Create temporary outout directory.
        self.temp_directory = tempfile.mkdtemp()
    def test_constructor(self):
        """
        Test constructor.
        """
        po = ProjectObject(id="1",
                           project_type="bounding_box",
                           bounds=self.bounds)

        self.assertTrue(isinstance(po.pose, Pose3))
        self.assertTrue(isinstance(po.category, "".__class__))
        po.pose.assert_almost_equal(Pose3())
        self.assertTrue(po.bounds.almost_equal(self.bounds))
        self.assertIs(po.meshes, None)
        self.assertIs(po.voxels, None)
        self.assertTrue(po.category == "unknown")
        self.assertEqual(po.id, "1")
        self.assertEqual(po.symmetry, ObjectSymmetry())
        self.assertAlmostEqual(po.score, -1)
Esempio n. 16
0
 def test_surreal_coding(self):
     """Test conversion to/from surreal-style json dict."""
     json_dict = self.pose.to_surreal()
     decoded_pose = Pose3.from_surreal(json_dict)
     decoded_pose.assert_almost_equal(self.pose)
Esempio n. 17
0
 def test_json(self):
     """Test conversion to/from json dict."""
     json_dict = self.pose.to_json()
     decoded_pose = Pose3.from_json(json_dict)
     decoded_pose.assert_almost_equal(self.pose)
Esempio n. 18
0
 def test_inverse(self):
     expected = Pose3()
     actual1 = self.pose.inverse() * self.pose
     actual1.assert_equal(expected)
     actual2 = self.pose * self.pose.inverse()
     actual2.assert_equal(expected)
Esempio n. 19
0
 def setUp(self):
     # Camera with z-axis looking at world y-axis
     wRc = np.transpose(
         np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]], dtype=float))
     t = Vector3(1, 1, 1)
     self.pose = Pose3(wRc, t)
Esempio n. 20
0
 def test_ENU_camera(self):
     Pose3.ENU_camera(position=Vector3(1, 1, 1)).assert_equal(self.pose)
Esempio n. 21
0
 def test_transform_pose(self):
     po = ProjectObject(id="1", bounds=self.bounds, pose=Pose3())
     po2 = po.transform_pose(self.pose)
     self.assertTrue(po2.pose.almost_equal(self.pose))