您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
456 行
17 KiB
456 行
17 KiB
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using NUnit.Framework;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.Perception.GroundTruth;
|
|
using UnityEngine.TestTools;
|
|
|
|
namespace GroundTruthTests
|
|
{
|
|
[TestFixture]
|
|
public class BoundingBox3dTests : GroundTruthTestBase
|
|
{
|
|
const float k_Delta = 0.0001f;
|
|
|
|
static string PrintBox(BoundingBox3DLabeler.BoxData box)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.Append("label id: " + box.label_id + " ");
|
|
sb.Append("label_name: " + box.label_name + " ");
|
|
sb.Append("instance_id: " + box.instance_id + " ");
|
|
sb.Append("translation: (" + box.translation[0] + ", " + box.translation[1] + ", " + box.translation[2] + ") ");
|
|
sb.Append("size: (" + box.size[0] + ", " + box.size[1] + ", " + box.size[2] + ") ");
|
|
sb.Append("rotation: " + box.rotation[0] + ", " + box.rotation[1] + ", " + box.rotation[2] + ", " + box.rotation[3] + ") ");
|
|
sb.Append("velocity: " + box.velocity[0] + ", " + box.velocity[1] + ", " + box.velocity[2]);
|
|
sb.Append("acceleration: (" + box.acceleration[0] + ", " + box.acceleration[1] + ", " + box.acceleration[2] + ")");
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator CameraOffset_ProduceProperTranslationTest()
|
|
{
|
|
var expected = new[]
|
|
{
|
|
new ExpectedResult
|
|
{
|
|
instanceId = 1,
|
|
labelId = 1,
|
|
labelName = "label",
|
|
position = new Vector3(0, 0, 10),
|
|
scale = new Vector3(5, 5, 5),
|
|
rotation = Quaternion.identity
|
|
}
|
|
};
|
|
var target = TestHelper.CreateLabeledCube();
|
|
var cameraPosition = new Vector3(0, 0, -10);
|
|
var cameraRotation = Quaternion.identity;
|
|
return ExecuteTest(target, cameraPosition, cameraRotation, expected);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator CameraOffsetAndRotated_ProduceProperTranslationTest()
|
|
{
|
|
var expected = new[]
|
|
{
|
|
new ExpectedResult
|
|
{
|
|
instanceId = 1,
|
|
labelId = 1,
|
|
labelName = "label",
|
|
position = new Vector3(0, 0, Mathf.Sqrt(200)),
|
|
scale = new Vector3(5, 5, 5),
|
|
rotation = Quaternion.identity
|
|
}
|
|
};
|
|
var target = TestHelper.CreateLabeledCube(x: 10, y: 0, z: 10, yaw: 45);
|
|
var cameraPosition = new Vector3(0, 0, 0);
|
|
var cameraRotation = Quaternion.Euler(0, 45, 0);
|
|
return ExecuteTest(target, cameraPosition, cameraRotation, expected);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator SimpleMultiMesh_ProduceProperTranslationTest()
|
|
{
|
|
var expected = new[]
|
|
{
|
|
new ExpectedResult
|
|
{
|
|
instanceId = 1,
|
|
labelId = 1,
|
|
labelName = "label",
|
|
position = new Vector3(0, 0, 10),
|
|
scale = new Vector3(6.5f, 2.5f, 2.5f),
|
|
rotation = Quaternion.identity
|
|
}
|
|
};
|
|
var target = CreateMultiMeshGameObject();
|
|
target.transform.position = Vector3.zero;
|
|
var cameraPosition = new Vector3(0, 0, -10);
|
|
var cameraRotation = Quaternion.identity;
|
|
return ExecuteTest(target, cameraPosition, cameraRotation, expected);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator MultiInheritedMesh_ProduceProperTranslationTest()
|
|
{
|
|
var expected = new[]
|
|
{
|
|
new ExpectedResult
|
|
{
|
|
instanceId = 1,
|
|
labelId = 2,
|
|
labelName = "car",
|
|
position = new Vector3(0, 0.525f, 20),
|
|
scale = new Vector3(2f, 0.875f, 2.4f),
|
|
rotation = Quaternion.identity
|
|
},
|
|
};
|
|
|
|
var target = CreateTestReallyBadCar(new Vector3(0, 0.35f, 20), Quaternion.identity);
|
|
target.transform.localPosition = new Vector3(0, 0, 20);
|
|
var cameraPosition = new Vector3(0, 0, 0);
|
|
var cameraRotation = Quaternion.identity;
|
|
return ExecuteTest(target, cameraPosition, cameraRotation, expected);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator MultiInheritedMeshDifferentLabels_ProduceProperTranslationTest()
|
|
{
|
|
var wheelScale = new Vector3(0.35f, 1.0f, 0.35f);
|
|
var wheelRot = Quaternion.Euler(0, 0, 90);
|
|
|
|
var expected = new[]
|
|
{
|
|
new ExpectedResult
|
|
{
|
|
instanceId = 1,
|
|
labelId = 2,
|
|
labelName = "car",
|
|
position = new Vector3(0, 1.05f, 20),
|
|
scale = new Vector3(1f, 0.7f, 2.4f),
|
|
rotation = Quaternion.identity
|
|
},
|
|
new ExpectedResult
|
|
{
|
|
instanceId = 2,
|
|
labelId = 3,
|
|
labelName = "wheel",
|
|
position = new Vector3(1, 0.35f, 18.6f),
|
|
scale = wheelScale,
|
|
rotation = wheelRot
|
|
},
|
|
new ExpectedResult
|
|
{
|
|
instanceId = 4,
|
|
labelId = 3,
|
|
labelName = "wheel",
|
|
position = new Vector3(-1, 0.35f, 18.6f),
|
|
scale = wheelScale,
|
|
rotation = wheelRot
|
|
}
|
|
};
|
|
|
|
var target = CreateTestReallyBadCar(new Vector3(0, 0.35f, 20), Quaternion.identity, false);
|
|
var cameraPosition = new Vector3(0, 0, 0);
|
|
var cameraRotation = Quaternion.identity;
|
|
return ExecuteTest(target, cameraPosition, cameraRotation, expected);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator TestOcclusion_Seen()
|
|
{
|
|
var target = TestHelper.CreateLabeledCube(scale: 15f, z: 50f);
|
|
return ExecuteSeenUnseenTest(target, Vector3.zero, quaternion.identity, 1);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator TestOcclusion_Unseen()
|
|
{
|
|
var target = TestHelper.CreateLabeledCube(scale: 15f, z: -50f);
|
|
return ExecuteSeenUnseenTest(target, Vector3.zero, quaternion.identity, 0);
|
|
}
|
|
|
|
|
|
struct ExpectedResult
|
|
{
|
|
public int labelId;
|
|
public string labelName;
|
|
public int instanceId;
|
|
public Vector3 position;
|
|
public Vector3 scale;
|
|
public Quaternion rotation;
|
|
}
|
|
|
|
IEnumerator ExecuteSeenUnseenTest(GameObject target, Vector3 cameraPos, Quaternion cameraRotation, int expectedSeen)
|
|
{
|
|
var receivedResults = new List<(int, List<BoundingBox3DLabeler.BoxData>)>();
|
|
var gameObject = SetupCamera(SetupLabelConfig(), (frame, data) =>
|
|
{
|
|
receivedResults.Add((frame, data));
|
|
});
|
|
|
|
gameObject.transform.position = cameraPos;
|
|
gameObject.transform.rotation = cameraRotation;
|
|
|
|
AddTestObjectForCleanup(gameObject);
|
|
|
|
gameObject.SetActive(false);
|
|
receivedResults.Clear();
|
|
gameObject.SetActive(true);
|
|
|
|
yield return null;
|
|
yield return null;
|
|
|
|
Assert.AreEqual(expectedSeen, receivedResults[0].Item2.Count);
|
|
|
|
DestroyTestObject(gameObject);
|
|
UnityEngine.Object.DestroyImmediate(target);
|
|
}
|
|
|
|
IEnumerator ExecuteTest(GameObject target, Vector3 cameraPos, Quaternion cameraRotation, IList<ExpectedResult> expectations)
|
|
{
|
|
var receivedResults = new List<(int, List<BoundingBox3DLabeler.BoxData>)>();
|
|
var gameObject = SetupCamera(SetupLabelConfig(), (frame, data) =>
|
|
{
|
|
receivedResults.Add((frame, data));
|
|
});
|
|
|
|
gameObject.transform.position = cameraPos;
|
|
gameObject.transform.rotation = cameraRotation;
|
|
|
|
AddTestObjectForCleanup(gameObject);
|
|
|
|
gameObject.SetActive(false);
|
|
receivedResults.Clear();
|
|
gameObject.SetActive(true);
|
|
|
|
yield return null;
|
|
yield return null;
|
|
|
|
Assert.AreEqual(expectations.Count, receivedResults[0].Item2.Count);
|
|
|
|
for (var i = 0; i < receivedResults[0].Item2.Count; i++)
|
|
{
|
|
var b = receivedResults[0].Item2[i];
|
|
|
|
Assert.AreEqual(expectations[i].labelId, b.label_id);
|
|
Assert.AreEqual(expectations[i].labelName, b.label_name);
|
|
Assert.AreEqual(expectations[i].instanceId, b.instance_id);
|
|
TestResults(b, expectations[i]);
|
|
}
|
|
|
|
DestroyTestObject(gameObject);
|
|
UnityEngine.Object.DestroyImmediate(target);
|
|
}
|
|
|
|
static IdLabelConfig SetupLabelConfig()
|
|
{
|
|
var labelConfig = ScriptableObject.CreateInstance<IdLabelConfig>();
|
|
labelConfig.Init(new List<IdLabelEntry>()
|
|
{
|
|
new IdLabelEntry
|
|
{
|
|
id = 1,
|
|
label = "label"
|
|
},
|
|
new IdLabelEntry
|
|
{
|
|
|
|
id = 2,
|
|
label= "car"
|
|
},
|
|
new IdLabelEntry
|
|
{
|
|
id = 3,
|
|
label= "wheel"
|
|
},
|
|
});
|
|
|
|
return labelConfig;
|
|
}
|
|
|
|
static GameObject SetupCamera(IdLabelConfig config, Action<int, List<BoundingBox3DLabeler.BoxData>> computeListener)
|
|
{
|
|
var cameraObject = new GameObject();
|
|
cameraObject.SetActive(false);
|
|
var camera = cameraObject.AddComponent<Camera>();
|
|
camera.orthographic = false;
|
|
camera.fieldOfView = 60;
|
|
camera.nearClipPlane = 0.3f;
|
|
camera.farClipPlane = 1000;
|
|
|
|
var perceptionCamera = cameraObject.AddComponent<PerceptionCamera>();
|
|
perceptionCamera.captureRgbImages = false;
|
|
var bboxLabeler = new BoundingBox3DLabeler(config);
|
|
if (computeListener != null)
|
|
bboxLabeler.BoundingBoxComputed += computeListener;
|
|
|
|
perceptionCamera.AddLabeler(bboxLabeler);
|
|
|
|
return cameraObject;
|
|
}
|
|
|
|
static void TestResults(BoundingBox3DLabeler.BoxData data, ExpectedResult e)
|
|
{
|
|
var scale = e.scale * 2;
|
|
|
|
Assert.IsNotNull(data);
|
|
Assert.AreEqual(e.position[0], data.translation[0], k_Delta);
|
|
Assert.AreEqual(e.position[1], data.translation[1], k_Delta);
|
|
Assert.AreEqual(e.position[2], data.translation[2], k_Delta);
|
|
Assert.AreEqual(scale[0], data.size[0], k_Delta);
|
|
Assert.AreEqual(scale[1], data.size[1], k_Delta);
|
|
Assert.AreEqual(scale[2], data.size[2], k_Delta);
|
|
Assert.AreEqual(e.rotation[0], data.rotation[0], k_Delta);
|
|
Assert.AreEqual(e.rotation[1], data.rotation[1], k_Delta);
|
|
Assert.AreEqual(e.rotation[2], data.rotation[2], k_Delta);
|
|
Assert.AreEqual(e.rotation[3], data.rotation[3], k_Delta);
|
|
Assert.AreEqual(Vector3.zero, data.velocity);
|
|
Assert.AreEqual(Vector3.zero, data.acceleration);
|
|
}
|
|
|
|
static GameObject CreateTestReallyBadCar(Vector3 position, Quaternion rotation, bool underOneLabel = true)
|
|
{
|
|
var badCar = new GameObject("BadCar");
|
|
badCar.transform.position = position;
|
|
badCar.transform.rotation = rotation;
|
|
if (underOneLabel)
|
|
{
|
|
var labeling = badCar.AddComponent<Labeling>();
|
|
labeling.labels.Add("car");
|
|
}
|
|
|
|
var body = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
body.name = "body";
|
|
body.transform.parent = badCar.transform;
|
|
body.transform.localPosition = new Vector3(0, 0.7f, 0);
|
|
body.transform.localScale = new Vector3(2f, 1.4f, 4.8f);
|
|
if (!underOneLabel)
|
|
{
|
|
var labeling = body.AddComponent<Labeling>();
|
|
labeling.labels.Add("car");
|
|
}
|
|
|
|
var wheel = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
wheel.name = "wheel1";
|
|
wheel.transform.parent = badCar.transform;
|
|
wheel.transform.localPosition = new Vector3(1f, 0, -1.4f);
|
|
wheel.transform.localRotation = Quaternion.Euler(0, 0, 90);
|
|
wheel.transform.localScale = new Vector3(0.7f, 1, 0.7f);
|
|
if (!underOneLabel)
|
|
{
|
|
var labeling = wheel.AddComponent<Labeling>();
|
|
labeling.labels.Add("wheel");
|
|
}
|
|
|
|
wheel = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
wheel.name = "wheel2";
|
|
wheel.transform.parent = badCar.transform;
|
|
wheel.transform.localPosition = new Vector3(1f, 0, 1.45f);
|
|
wheel.transform.localRotation = Quaternion.Euler(0, 0, 90);
|
|
wheel.transform.localScale = new Vector3(0.7f, 1, 0.7f);
|
|
if (!underOneLabel)
|
|
{
|
|
var labeling = wheel.AddComponent<Labeling>();
|
|
labeling.labels.Add("wheel");
|
|
}
|
|
|
|
wheel = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
wheel.name = "wheel3";
|
|
wheel.transform.parent = badCar.transform;
|
|
wheel.transform.localPosition = new Vector3(-1f, 0, -1.4f);
|
|
wheel.transform.localRotation = Quaternion.Euler(0, 0, 90);
|
|
wheel.transform.localScale = new Vector3(0.7f, 1, 0.7f);
|
|
if (!underOneLabel)
|
|
{
|
|
var labeling = wheel.AddComponent<Labeling>();
|
|
labeling.labels.Add("wheel");
|
|
}
|
|
|
|
wheel = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
wheel.name = "wheel4";
|
|
wheel.transform.parent = badCar.transform;
|
|
wheel.transform.localPosition = new Vector3(-1f, 0, 1.45f);
|
|
wheel.transform.localRotation = Quaternion.Euler(0, 0, 90);
|
|
wheel.transform.localScale = new Vector3(0.7f, 1, 0.7f);
|
|
if (!underOneLabel)
|
|
{
|
|
var labeling = wheel.AddComponent<Labeling>();
|
|
labeling.labels.Add("wheel");
|
|
}
|
|
|
|
return badCar;
|
|
}
|
|
|
|
static GameObject CreateMultiMeshGameObject()
|
|
{
|
|
var go = new GameObject();
|
|
var labeling = go.AddComponent<Labeling>();
|
|
labeling.labels.Add("label");
|
|
|
|
var left = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
left.transform.parent = go.transform;
|
|
left.transform.localPosition = new Vector3(-4, 0, 0);
|
|
left.transform.localScale = new Vector3(5, 5, 5);
|
|
|
|
var right = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
right.transform.parent = go.transform;
|
|
right.transform.localPosition = new Vector3(4, 0, 0);
|
|
right.transform.localScale = new Vector3(5, 5, 5);
|
|
|
|
var center = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
center.transform.parent = go.transform;
|
|
center.transform.localPosition = Vector3.zero;
|
|
center.transform.localRotation = Quaternion.Euler(0, 0, 90);
|
|
center.transform.localScale = new Vector3(1, 3, 1);
|
|
|
|
return go;
|
|
}
|
|
|
|
class CubeSpinner : MonoBehaviour
|
|
{
|
|
public Quaternion rotationPerFrame = Quaternion.Euler(0, 15, 0);
|
|
|
|
void Update()
|
|
{
|
|
transform.localRotation *= rotationPerFrame;
|
|
}
|
|
}
|
|
|
|
class CubeMover : MonoBehaviour
|
|
{
|
|
public Vector3 distancePerFrame = new Vector3(5, 0 , 0);
|
|
|
|
void Update()
|
|
{
|
|
transform.localPosition += distancePerFrame;
|
|
}
|
|
}
|
|
|
|
static GameObject CreateDynamicBox(bool spinning = false, bool moving = false, Vector3? translation = null, Quaternion? rotation = null)
|
|
{
|
|
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
cube.name = "Cube";
|
|
var labeling = cube.AddComponent<Labeling>();
|
|
labeling.labels.Add("label");
|
|
cube.transform.position = new Vector3(0f, 0f, 10f);
|
|
cube.transform.localScale = new Vector3(30f, 30f, 30f);
|
|
if (spinning)
|
|
{
|
|
var spin = cube.AddComponent<CubeSpinner>();
|
|
spin.rotationPerFrame = rotation ?? spin.rotationPerFrame;
|
|
}
|
|
if (moving)
|
|
{
|
|
var move = cube.AddComponent<CubeMover>();
|
|
move.distancePerFrame = translation ?? move.distancePerFrame;
|
|
}
|
|
return cube;
|
|
}
|
|
}
|
|
}
|