浏览代码

A lot of changes, now we can partially support old perception and new

/solo_support
Steve Borkman 3 年前
当前提交
e2998b0b
共有 28 个文件被更改,包括 1433 次插入143 次删除
  1. 11
      TestProjects/PerceptionURP/Assets/ExampleScripts/CustomAnnotationAndMetricReporter.cs
  2. 146
      com.unity.perception/Runtime/GroundTruth/DatasetCapture.cs
  3. 7
      com.unity.perception/Runtime/GroundTruth/Ego.cs
  4. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/CameraLabeler.cs
  5. 9
      com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs
  6. 4
      com.unity.perception/Runtime/GroundTruth/PerceptionUpdater.cs
  7. 48
      com.unity.perception/Runtime/GroundTruth/SimulationState.cs
  8. 15
      com.unity.perception/Runtime/GroundTruth/SimulationState_Json.cs
  9. 332
      com.unity.perception/Runtime/GroundTruth/SoloDesign/Frame.cs
  10. 10
      com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloConsumer.cs
  11. 18
      com.unity.perception/Runtime/Randomization/Scenarios/PerceptionScenario.cs
  12. 4
      com.unity.perception/Tests/Editor/DatasetCaptureEditorTests.cs
  13. 5
      com.unity.perception/Tests/Editor/PerceptionCameraEditorTests.cs
  14. 5
      com.unity.perception/Tests/Performance/PerformanceTester.cs
  15. 49
      com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetCaptureSensorSchedulingTests.cs
  16. 34
      com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetCaptureTests.cs
  17. 3
      com.unity.perception/Tests/Runtime/GroundTruthTests/GroundTruthTestBase.cs
  18. 7
      com.unity.perception/Tests/Runtime/GroundTruthTests/PerceptionCameraIntegrationTests.cs
  19. 6
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ScenarioTests.cs
  20. 2
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/TestFixedLengthScenario.cs
  21. 25
      com.unity.perception/Runtime/GroundTruth/SoloDesign/IMessageBuilder.cs
  22. 11
      com.unity.perception/Runtime/GroundTruth/SoloDesign/IMessageBuilder.cs.meta
  23. 405
      com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionConsumer.cs
  24. 11
      com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionConsumer.cs.meta
  25. 178
      com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionJsonFactory.cs
  26. 11
      com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionJsonFactory.cs.meta
  27. 206
      com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloMessageBuilder.cs
  28. 11
      com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloMessageBuilder.cs.meta

11
TestProjects/PerceptionURP/Assets/ExampleScripts/CustomAnnotationAndMetricReporter.cs


[RequireComponent(typeof(PerceptionCamera))]
public class CustomAnnotationAndMetricReporter : MonoBehaviour
{
DatasetCapture _DatasetCapture;
internal DatasetCapture DatasetCapture
{
get
{
if (_DatasetCapture == null) _DatasetCapture = GameObject.Find("DatasetCapture").GetComponent<DatasetCapture>();
return _DatasetCapture;
}
}
public GameObject targetLight;
public GameObject target;

146
com.unity.perception/Runtime/GroundTruth/DatasetCapture.cs


using Unity.Collections;
using Unity.Simulation;
using UnityEngine;
using UnityEngine.Perception.GroundTruth.SoloDesign;
#pragma warning disable 649
namespace UnityEngine.Perception.GroundTruth

/// Data capture follows the schema defined in *TODO: Expose schema publicly*
/// </summary>
public static class DatasetCapture
public class DatasetCapture : MonoBehaviour
static readonly Guid k_DatasetGuid = Guid.NewGuid();
internal static SimulationState SimulationState { get; private set; } = CreateSimulationData();
public static DatasetCapture Instance { get; protected set; }
public PerceptionConsumer activeConsumer;
readonly Guid k_DatasetGuid = Guid.NewGuid();
SimulationState m_SimulationState;
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(this);
Debug.LogError($"The simulation started with more than one instance of DatasetCapture, destroying this one");
}
else
{
Instance = this;
}
}
internal static string OutputDirectory => SimulationState.GetOutputDirectoryNoCreate();
internal SimulationState simulationState
{
get { return m_SimulationState ?? (m_SimulationState = CreateSimulationData()); }
private set => m_SimulationState = value;
}
internal string OutputDirectory => simulationState.GetOutputDirectoryNoCreate();
/// <summary>
/// The json metadata schema version the DatasetCapture's output conforms to.

/// <summary>
/// Called when the simulation ends. The simulation ends on playmode exit, application exit, or when <see cref="ResetSimulation"/> is called.
/// </summary>
public static event Action SimulationEnding;
/// <summary>
/// Register a new ego. Used along with RegisterSensor to organize sensors under a top-level ego container. <seealso cref="RegisterSensor"/>
/// </summary>
/// <param name="description">A human-readable description for the ego</param>
/// <returns>An <see cref="EgoHandle"/>, which can be used to organize sensors under a common ego.</returns>
public static EgoHandle RegisterEgo(string description)
{
var ego = new EgoHandle(Guid.NewGuid(), description);
SimulationState.AddEgo(ego);
return ego;
}
public event Action SimulationEnding;
/// <summary>
/// Register a new sensor under the given ego.

/// <returns>A <see cref="SensorHandle"/>, which should be used to check <see cref="SensorHandle.ShouldCaptureThisFrame"/> each frame to determine whether to capture (or render) that frame.
/// It is also used to report captures, annotations, and metrics on the sensor.</returns>
/// <exception cref="ArgumentException">Thrown if ego is invalid.</exception>
public static SensorHandle RegisterSensor(EgoHandle egoHandle, string modality, string description, float firstCaptureFrame, CaptureTriggerMode captureTriggerMode, float simulationDeltaTime, int framesBetweenCaptures, bool manualSensorAffectSimulationTiming = false)
public SensorHandle RegisterSensor(EgoHandle egoHandle, string modality, string description, float firstCaptureFrame, CaptureTriggerMode captureTriggerMode, float simulationDeltaTime, int framesBetweenCaptures, bool manualSensorAffectSimulationTiming = false)
if (!SimulationState.Contains(egoHandle.Id))
#if false
if (!simulationState.Contains(egoHandle.Id))
var sensor = new SensorHandle(Guid.NewGuid());
SimulationState.AddSensor(egoHandle, modality, description, firstCaptureFrame, captureTriggerMode, simulationDeltaTime, framesBetweenCaptures, manualSensorAffectSimulationTiming, sensor);
#endif
var sensor = new SensorHandle(Guid.NewGuid(), this);
simulationState.AddSensor(egoHandle, modality, description, firstCaptureFrame, captureTriggerMode, simulationDeltaTime, framesBetweenCaptures, manualSensorAffectSimulationTiming, sensor);
return sensor;
}

/// <param name="description">Description of the annotation.</param>
/// <param name="id">The ID for this metric. This allows metric types to be shared across simulations and sequences.</param>
/// <returns>A MetricDefinition, which can be used during this simulation to report metrics.</returns>
public static MetricDefinition RegisterMetricDefinition(string name, string description = null, Guid id = default)
public MetricDefinition RegisterMetricDefinition(string name, string description = null, Guid id = default)
{
return RegisterMetricDefinition<object>(name, null, description, id);
}

/// <param name="id">The ID for this metric. This allows metric types to be shared across simulations and sequences.</param>
/// <typeparam name="TSpec">The type of the <see cref="specValues"/> struct to write.</typeparam>
/// <returns>A MetricDefinition, which can be used during this simulation to report metrics.</returns>
public static MetricDefinition RegisterMetricDefinition<TSpec>(string name, TSpec[] specValues, string description = null, Guid id = default)
public MetricDefinition RegisterMetricDefinition<TSpec>(string name, TSpec[] specValues, string description = null, Guid id = default)
return SimulationState.RegisterMetricDefinition(name, specValues, description, id);
return simulationState.RegisterMetricDefinition(name, specValues, description, id);
}
/// <summary>

/// <param name="format">Optional format name.</param>
/// <param name="id">The ID for this annotation type. This allows annotation types to be shared across simulations and sequences.</param>
/// <returns>An AnnotationDefinition. If the given <see cref="id"/> has already been defined, its AnnotationDefinition is returned.</returns>
public static AnnotationDefinition RegisterAnnotationDefinition(string name, string description = null, string format = "json", Guid id = default)
public AnnotationDefinition RegisterAnnotationDefinition(string name, string description = null, string format = "json", Guid id = default)
{
return RegisterAnnotationDefinition<object>(name, null, description, format, id);
}

/// <param name="id">The ID for this annotation type. This allows annotation types to be shared across simulations and sequences.</param>
/// <typeparam name="TSpec">The type of the values for the spec array in the resulting json.</typeparam>
/// <returns>An AnnotationDefinition. If the given <see cref="id"/> has already been defined, its AnnotationDefinition is returned.</returns>
public static AnnotationDefinition RegisterAnnotationDefinition<TSpec>(string name, TSpec[] specValues, string description = null, string format = "json", Guid id = default)
public AnnotationDefinition RegisterAnnotationDefinition<TSpec>(string name, TSpec[] specValues, string description = null, string format = "json", Guid id = default)
return SimulationState.RegisterAnnotationDefinition(name, specValues, description, format, id);
return simulationState.RegisterAnnotationDefinition(name, specValues, description, format, id);
}
/// <summary>

/// <param name="values">An array to be converted to json and put in the "values" field of the metric</param>
/// <typeparam name="T">The type of the <see cref="values"/> array</typeparam>
public static void ReportMetric<T>(MetricDefinition metricDefinition, T[] values)
public void ReportMetric<T>(MetricDefinition metricDefinition, T[] values)
SimulationState.ReportMetric(metricDefinition, values, default, default);
simulationState.ReportMetric(metricDefinition, values, default, default);
}
/// <summary>

/// <param name="valuesJsonArray">A string-based JSON array to be placed in the "values" field of the metric</param>
public static void ReportMetric(MetricDefinition metricDefinition, string valuesJsonArray)
public void ReportMetric(MetricDefinition metricDefinition, string valuesJsonArray)
SimulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), default, default);
simulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), default, default);
}
/// <summary>

/// <returns>An <see cref="AsyncMetric"/> which should be used to report the metric values, potentially in a later frame</returns>
public static AsyncMetric ReportMetricAsync(MetricDefinition metricDefinition) => SimulationState.CreateAsyncMetric(metricDefinition);
public AsyncMetric ReportMetricAsync(MetricDefinition metricDefinition) => simulationState.CreateAsyncMetric(metricDefinition);
public static void StartNewSequence() => SimulationState.StartNewSequence();
public void StartNewSequence() => simulationState.StartNewSequence();
internal static bool IsValid(Guid id) => SimulationState.Contains(id);
internal bool IsValid(Guid id) => simulationState.Contains(id);
static SimulationState CreateSimulationData()
SimulationState CreateSimulationData()
{
//TODO: Remove the Guid path when we have proper dataset merging in Unity Simulation and Thea
return new SimulationState($"Dataset{k_DatasetGuid}");

static void OnInitializeOnLoad()
void OnInitializeOnLoad()
{
Manager.Instance.ShutdownNotification += ResetSimulation;
}

/// </summary>
public static void ResetSimulation()
public void ResetSimulation()
var oldSimulationState = SimulationState;
SimulationState = CreateSimulationData();
var oldSimulationState = simulationState;
simulationState = CreateSimulationData();
oldSimulationState.End();
}
}

/// </summary>
public struct SensorHandle : IDisposable, IEquatable<SensorHandle>
{
internal DatasetCapture datasetCapture { get; }
internal SensorHandle(Guid id)
internal SensorHandle(Guid id, DatasetCapture datasetCapture)
this.datasetCapture = datasetCapture;
}
/// <summary>

{
get => DatasetCapture.SimulationState.IsEnabled(this);
get => datasetCapture.simulationState.IsEnabled(this);
DatasetCapture.SimulationState.SetEnabled(this, value);
datasetCapture.simulationState.SetEnabled(this, value);
}
}

if (!annotationDefinition.IsValid)
throw new ArgumentException("The given annotationDefinition is invalid", nameof(annotationDefinition));
return DatasetCapture.SimulationState.ReportAnnotationFile(annotationDefinition, this, filename);
return datasetCapture.simulationState.ReportAnnotationFile(annotationDefinition, this, filename);
}
/// <summary>

if (!annotationDefinition.IsValid)
throw new ArgumentException("The given annotationDefinition is invalid", nameof(annotationDefinition));
return DatasetCapture.SimulationState.ReportAnnotationValues(annotationDefinition, this, values);
return datasetCapture.simulationState.ReportAnnotationValues(annotationDefinition, this, values);
}
/// <summary>

if (!annotationDefinition.IsValid)
throw new ArgumentException("The given annotationDefinition is invalid", nameof(annotationDefinition));
return DatasetCapture.SimulationState.ReportAnnotationAsync(annotationDefinition, this);
return datasetCapture.simulationState.ReportAnnotationAsync(annotationDefinition, this);
return DatasetCapture.SimulationState.GetRgbCaptureFilename(defaultFilename, additionalSensorValues);
return datasetCapture.simulationState.GetRgbCaptureFilename(defaultFilename, additionalSensorValues);
}
/// <summary>

throw new InvalidOperationException("Capture reported in frame when ShouldCaptureThisFrame is false.");
}
DatasetCapture.SimulationState.ReportCapture(this, filename, sensorSpatialData, additionalSensorValues);
datasetCapture.simulationState.ReportCapture(this, filename, sensorSpatialData, additionalSensorValues);
}
/// <summary>

public bool ShouldCaptureThisFrame => DatasetCapture.SimulationState.ShouldCaptureThisFrame(this);
public bool ShouldCaptureThisFrame => datasetCapture.simulationState.ShouldCaptureThisFrame(this);
/// <summary>
/// Requests a capture from this sensor on the next rendered frame. Can only be used with manual capture mode (<see cref="PerceptionCamera.CaptureTriggerMode.Manual"/>).

DatasetCapture.SimulationState.SetNextCaptureTimeToNowForSensor(this);
datasetCapture.simulationState.SetNextCaptureTimeToNowForSensor(this);
}
/// <summary>

if (!ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
DatasetCapture.SimulationState.ReportMetric(metricDefinition, values, this, default);
datasetCapture.simulationState.ReportMetric(metricDefinition, values, this, default);
}
/// <summary>

if (!ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
DatasetCapture.SimulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), this, default);
datasetCapture.simulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), this, default);
}
/// <summary>

if (!ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
return DatasetCapture.SimulationState.CreateAsyncMetric(metricDefinition, this);
return datasetCapture.simulationState.CreateAsyncMetric(metricDefinition, this);
}
/// <summary>

/// <summary>
/// Returns whether this SensorHandle is valid in the current simulation. Nil SensorHandles are never valid.
/// </summary>
public bool IsValid => DatasetCapture.IsValid(this.Id);
public bool IsValid => datasetCapture.IsValid(this.Id);
/// <summary>
/// Returns true if this SensorHandle was default-instantiated.
/// </summary>

{
if (!DatasetCapture.IsValid(this.Id))
if (!datasetCapture.IsValid(this.Id))
throw new InvalidOperationException("SensorHandle has been disposed or its simulation has ended");
}

/// </summary>
public readonly SensorHandle SensorHandle;
internal Annotation(SensorHandle sensorHandle, int step)
SimulationState m_SimulationState;
internal Annotation(SensorHandle sensorHandle, SimulationState simState, int step)
m_SimulationState = simState;
Id = Guid.NewGuid();
SensorHandle = sensorHandle;
Step = step;

if (!SensorHandle.ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
DatasetCapture.SimulationState.ReportMetric(metricDefinition, values, SensorHandle, this);
m_SimulationState.ReportMetric(metricDefinition, values, SensorHandle, this);
}
/// <summary>

if (!SensorHandle.ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
DatasetCapture.SimulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), SensorHandle, this);
m_SimulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), SensorHandle, this);
}
/// <summary>

/// <returns>A handle to an AsyncMetric, which can be used to report values for this metric in future frames.</returns>
public AsyncMetric ReportMetricAsync(MetricDefinition metricDefinition) => DatasetCapture.SimulationState.CreateAsyncMetric(metricDefinition, SensorHandle, this);
public AsyncMetric ReportMetricAsync(MetricDefinition metricDefinition) => m_SimulationState.CreateAsyncMetric(metricDefinition, SensorHandle, this);
/// <inheritdoc/>
public bool Equals(Annotation other)

/// The ID of the annotation type. Used in the json metadata to associate anntations with the type.
/// </summary>
public readonly Guid Id;
internal bool IsValid => DatasetCapture.IsValid(Id);
internal bool IsValid => m_SimulationState.IsValid(Id);
SimulationState m_SimulationState;
internal AnnotationDefinition(Guid id)
internal AnnotationDefinition(Guid id, SimulationState simState)
m_SimulationState = simState;
}
}

7
com.unity.perception/Runtime/GroundTruth/Ego.cs


/// A human-readable description for this Ego to be included in the dataset.
/// </summary>
public string Description;
EgoHandle m_EgoHandle;
// EgoHandle m_EgoHandle;
/// <summary>
/// The EgoHandle registered with DatasetCapture at runtime.

get
{
EnsureEgoInitialized();
return m_EgoHandle;
//return m_EgoHandle;
return new EgoHandle();
}
}

void EnsureEgoInitialized()
{
#if false
#endif
}
}
}

3
com.unity.perception/Runtime/GroundTruth/Labelers/CameraLabeler.cs


[Serializable]
public abstract class CameraLabeler
{
// TODO protect from null
internal DatasetCapture DatasetCapture => DatasetCapture.Instance;
/// <summary>
/// A human-readable description of the labeler
/// </summary>

9
com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs


SetupVisualizationCamera();
DatasetCapture.SimulationEnding += OnSimulationEnding;
DatasetCapture.Instance.SimulationEnding += OnSimulationEnding;
}
void OnEnable()

void OnDestroy()
{
DatasetCapture.SimulationEnding -= OnSimulationEnding;
DatasetCapture.Instance.SimulationEnding -= OnSimulationEnding;
OnSimulationEnding();
CleanupVisualization();

if (m_SensorHandle.IsNil)
{
m_EgoMarker = GetComponentInParent<Ego>();
var ego = m_EgoMarker == null ? DatasetCapture.RegisterEgo("") : m_EgoMarker.EgoHandle;
SensorHandle = DatasetCapture.RegisterSensor(
// var ego = m_EgoMarker == null ? DatasetCapture.RegisterEgo("") : m_EgoMarker.EgoHandle;
var ego = new EgoHandle();
SensorHandle = DatasetCapture.Instance.RegisterSensor(
ego, "camera", description, firstCaptureFrame, captureTriggerMode,
simulationDeltaTime, framesBetweenCaptures, manualSensorAffectSimulationTiming);
}

4
com.unity.perception/Runtime/GroundTruth/PerceptionUpdater.cs


DontDestroyOnLoad(updaterObject);
}
// TODO - all of this can be rolled into dataset capture
DatasetCapture.SimulationState?.Update();
DatasetCapture.Instance.simulationState?.Update();
}
}
}

48
com.unity.perception/Runtime/GroundTruth/SimulationState.cs


//IDatasetExporter _ActiveReporter = null;
IPerceptionConsumer _ActiveConsumer = null;
// PerceptionConsumer activeConsumer = null;
// Always use the property SequenceTimeMs instead
int m_FrameCountLastUpdatedSequenceTime;

public const string defaultOutputBaseDirectory = "defaultOutputBaseDirectory";
public const string outputFormatMode = "outputFormatMode";
public bool IsValid(Guid guid) => true; // TODO obvs we need to do this for realz
public bool IsRunning { get; private set; }
public string OutputDirectory

public SimulationState(string outputDirectory)
{
#if false
_ActiveConsumer = go.AddComponent<SoloConsumer>();
activeConsumer = go.AddComponent<SoloConsumer>();
_ActiveConsumer = go.GetComponent<SoloConsumer>();
activeConsumer = go.GetComponent<SoloConsumer>();
#endif
PlayerPrefs.SetString(defaultOutputBaseDirectory, Configuration.Instance.GetStorageBasePath());
m_OutputDirectoryName = outputDirectory;
var basePath = PlayerPrefs.GetString(userBaseDirectoryKey, string.Empty);

}
//IDatasetExporter GetActiveReporter()
IPerceptionConsumer GetActiveConsumer()
PerceptionConsumer GetActiveConsumer()
return _ActiveConsumer;
return DatasetCapture.Instance.activeConsumer;
}
public string GetRgbCaptureFilename(string defaultFilename, params(string, object)[] additionalSensorValues)

m_ActiveSensors.Add(sensor);
m_Sensors.Add(sensor, sensorData);
m_Ids.Add(sensor.Id);
GetActiveConsumer()?.OnSensorRegistered(new SensorDefinition("camera", modality, description));
}
float GetSequenceTimeOfNextCapture(SensorData sensorData)

// GetActiveReporter()?.OnAnnotationRegistered(id, specValues); // <- Not sure about this one either
return new AnnotationDefinition(id);
if (name == "bounding box")
{
GetActiveConsumer()?.OnAnnotationRegistered(ToBoundingBoxDef(specValues));
}
return new AnnotationDefinition(id, this);
BoundingBoxAnnotationDefinition ToBoundingBoxDef<TSpec>(TSpec[] specValues)
{
var entries = new List<BoundingBoxAnnotationDefinition.Entry>();
foreach (var spec in specValues)
{
if (spec is IdLabelConfig.LabelEntrySpec label)
{
entries.Add(new BoundingBoxAnnotationDefinition.Entry(label.label_id, label.label_name));
}
}
return new BoundingBoxAnnotationDefinition(entries);
}
public MetricDefinition RegisterMetricDefinition<TSpec>(string name, TSpec[] specValues, string description, Guid id)
{

public Annotation ReportAnnotationFile(AnnotationDefinition annotationDefinition, SensorHandle sensorHandle, string filename)
{
var annotation = new Annotation(sensorHandle, AcquireStep());
var annotation = new Annotation(sensorHandle, this, AcquireStep());
var pendingCapture = GetOrCreatePendingCaptureForThisFrame(sensorHandle);
pendingCapture.Annotations.Add((annotation, new AnnotationData(annotationDefinition, filename, null)));
return annotation;

{
var annotation = new Annotation(sensorHandle, AcquireStep());
var annotation = new Annotation(sensorHandle, this, AcquireStep());
var pendingCapture = GetOrCreatePendingCaptureForThisFrame(sensorHandle);
var valuesJson = new JArray();
foreach (var value in values)

15
com.unity.perception/Runtime/GroundTruth/SimulationState_Json.cs


{
Id = "camera",
sensorType = "camera",
description = "this is the description of the sensor",
metadata = new Dictionary<string, object>(),
// metadata = new Dictionary<string, object>(),
imageFormat = "png",
dimension = Vector2.zero,
buffer = null

return new Frame(pendingCapture.FrameCount, seqId, pendingCapture.Step);
}
void WritePendingCaptures(bool flush = false, bool writeCapturesFromThisFrame = false)
{

sensorId = "camera",
description = "Labeled bounding boxes",
annotationType = "bounding box labeler",
metadata = new Dictionary<string, object>(),
// metadata = new Dictionary<string, object>(),
boxes = new List<BoundingBoxAnnotation.Entry>()
};

var entry = new BoundingBoxAnnotation.Entry
{
instanceId = (int)e.instance_id,
label = e.label_name,
labelId = e.label_id,
labelName = e.label_name,
origin = new Vector2{x = e.x, y = e.y},
dimension = new Vector2{x = e.width, y = e.height}
};

sensorId = "camera",
description = "instance segmentation blah blah blah",
annotationType = "instance segmentation labeler",
metadata = new Dictionary<string, object>(),
// metadata = new Dictionary<string, object>(),
instances = new List<InstanceSegmentation.Entry>(),
dimension = Vector2.zero,
imageFormat = "png"

velocity = capture.SensorSpatialData.EgoVelocity ?? Vector3.zero,
acceleration = capture.SensorSpatialData.EgoAcceleration ?? Vector3.zero,
buffer = buffer,
metadata = new Dictionary<string, object>()
// metadata = new Dictionary<string, object>()
}
};
}

332
com.unity.perception/Runtime/GroundTruth/SoloDesign/Frame.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine.Perception.GroundTruth.Exporters.Solo;
internal static class Utils
{
internal static int[] ToIntVector(Color32 c)
{
return new[] { (int)c.r, (int)c.g, (int)c.b, (int)c.a };
}
internal static float[] ToFloatVector(Vector2 v)
{
return new[] { v.x, v.y };
}
internal static float[] ToFloatVector(Vector3 v)
{
return new[] { v.x, v.y, v.z };
}
}
public interface IPerceptionConsumer
public abstract class PerceptionConsumer : MonoBehaviour
{
/// <summary>
/// Called when the simulation begins. Provides simulation wide metadata to

void OnSimulationStarted(SimulationMetadata metadata);
public abstract void OnSimulationStarted(SimulationMetadata metadata);
public virtual void OnSensorRegistered(SensorDefinition sensor) { }
public virtual void OnAnnotationRegistered(AnnotationDefinition annotationDefinition)
{
}
public virtual void OnMetricRegistered() { }
void OnFrameGenerated(Frame frame);
public abstract void OnFrameGenerated(Frame frame);
void OnSimulationCompleted(CompletionMetadata metadata);
public abstract void OnSimulationCompleted(CompletionMetadata metadata);
}
/// <summary>

[Serializable]
public class CompletionMetadata : SimulationMetadata
{
public CompletionMetadata() : base()
{}
public CompletionMetadata()
: base() { }
public struct Sequence
{

public List<Sequence> sequences;
}
public interface IMessageProducer
{
void ToMessage(IMessageBuilder builder);
}
[Serializable]
public class SensorDefinition : IMessageProducer
{
public SensorDefinition(string id, string modality, string definition)
{
this.id = id;
this.modality = modality;
this.definition = definition;
this.firstCaptureFrame = 0;
this.captureTriggerMode = string.Empty;
this.simulationDeltaTime = 0.0f;
this.framesBetweenCaptures = 0;
this.manualSensorsAffectTiming = false;
}
public string id;
public string modality;
public string definition;
public float firstCaptureFrame;
public string captureTriggerMode;
public float simulationDeltaTime;
public int framesBetweenCaptures;
public bool manualSensorsAffectTiming;
public void ToMessage(IMessageBuilder builder)
{
builder.AddString("id", id);
builder.AddString("modality", modality);
builder.AddString("definition", definition);
builder.AddFloat("first_capture_frame", firstCaptureFrame);
builder.AddString("capture_trigger_mode", captureTriggerMode);
builder.AddFloat("simulation_delta_time", simulationDeltaTime);
builder.AddInt("frames_between_captures", framesBetweenCaptures);
builder.AddBoolean("manual_sensors_affect_timing", manualSensorsAffectTiming);
}
}
[Serializable]
public abstract class AnnotationDefinition : IMessageProducer
{
public string id = string.Empty;
public string description = string.Empty;
public string annotationType = string.Empty;
public AnnotationDefinition() { }
public AnnotationDefinition(string id, string description, string annotationType)
{
this.id = id;
this.description = description;
this.annotationType = annotationType;
}
public virtual void ToMessage(IMessageBuilder builder)
{
builder.AddString("id", id);
builder.AddString("description", description);
builder.AddString("annotation_type", annotationType);
}
}
[Serializable]
public class BoundingBoxAnnotationDefinition : AnnotationDefinition
{
static readonly string k_Id = "bounding box";
static readonly string k_Description = "Bounding box for each labeled object visible to the sensor";
static readonly string k_AnnotationType = "bounding box";
public BoundingBoxAnnotationDefinition() : base(k_Id, k_Description, k_AnnotationType) { }
public BoundingBoxAnnotationDefinition(IEnumerable<Entry> spec)
: base(k_Id, k_Description, k_AnnotationType)
{
this.spec = spec;
}
[Serializable]
public struct Entry : IMessageProducer
{
public Entry(int id, string name)
{
labelId = id;
labelName = name;
}
public int labelId;
public string labelName;
public void ToMessage(IMessageBuilder builder)
{
builder.AddInt("label_id", labelId);
builder.AddString("label_name", labelName);
}
}
public IEnumerable<Entry> spec;
public override void ToMessage(IMessageBuilder builder)
{
base.ToMessage(builder);
foreach (var e in spec)
{
var nested = builder.AddNestedMessageToVector("spec");
e.ToMessage(nested);
}
}
}
public class MetricDefinition : IMessageProducer
{
public void ToMessage(IMessageBuilder builder)
{
throw new NotImplementedException();
}
}
/// <summary>
/// The top level structure that holds all of the artifacts of a simulation
/// frame. This is only reported after all of the captures, annotations, and

public class Frame
public class Frame : IMessageProducer
{
public Frame(int frame, int sequence, int step)
{

sensors = new List<Sensor>();
annotations = new List<Annotation>();
metrics = new List<Metric>();
}

/// The step in the sequence that this record is a part of
/// </summary>
public int step;
public float timestamp;
/// <summary>
/// A list of all of the sensor captures recorded for the frame.
/// </summary>

/// </summary>
public List<Annotation> annotations;
public void ToMessage(IMessageBuilder builder)
{
builder.AddInt("frame", frame);
builder.AddInt("sequence", sequence);
builder.AddInt("step", step);
foreach (var s in sensors)
{
var nested = builder.AddNestedMessageToVector("sensors");
s.ToMessage(nested);
}
foreach (var annotation in annotations)
{
var nested = builder.AddNestedMessageToVector("annotations");
annotation.ToMessage(nested);
}
}
#if false
public class SoloConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
switch (value)
{
case Vector3 v3:
{
writer.WriteStartArray();
writer.WriteValue(v3.x);
writer.WriteValue(v3.y);
writer.WriteValue(v3.z);
writer.WriteEndArray();
break;
}
case Vector2 v2:
{
writer.WriteStartArray();
writer.WriteValue(v2.x);
writer.WriteValue(v2.y);
writer.WriteEndArray();
break;
}
case Color32 rgba:
{
writer.WriteStartArray();
writer.WriteValue(rgba.r);
writer.WriteValue(rgba.g);
writer.WriteValue(rgba.b);
writer.WriteValue(rgba.a);
writer.WriteEndArray();
break;
}
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return null;
}
public override bool CanConvert(Type objectType)
{
if (objectType == typeof(Vector3)) return true;
if (objectType == typeof(Vector2)) return true;
return objectType == typeof(Color32);
}
}
#endif
public abstract class Sensor
public abstract class Sensor : IMessageProducer
{
/// <summary>
/// The unique, human readable ID for the sensor.

/// The type of the sensor.
/// </summary>
public string sensorType;
public string description;
/// <summary>
/// The position (xyz) of the sensor in the world.
/// </summary>

/// The current acceleration (xyz) of the sensor.
/// </summary>
public Vector3 acceleration;
/// <summary>
/// Additional key/value pair metadata that can be associated with
/// the sensor.
/// </summary>
public Dictionary<string, object> metadata;
public virtual void ToMessage(IMessageBuilder builder)
{
builder.AddString("id", Id);
builder.AddString("sensor_id", sensorType);
builder.AddFloatVector("position", Utils.ToFloatVector(position));
builder.AddFloatVector("rotation", Utils.ToFloatVector(rotation));
builder.AddFloatVector("velocity", Utils.ToFloatVector(velocity));
builder.AddFloatVector("acceleration", Utils.ToFloatVector(acceleration));
}
}
/// <summary>

{
// The format of the image type
public string imageFormat;
public override void ToMessage(IMessageBuilder builder)
{
base.ToMessage(builder);
builder.AddString("image_format", imageFormat);
builder.AddFloatVector("dimension", Utils.ToFloatVector(dimension));
builder.AddPngImage("camera", buffer);
}
}
/// <summary>

/// </summary>
[Serializable]
public abstract class Annotation
public abstract class Annotation : IMessageProducer
{
/// <summary>
/// The unique, human readable ID for the annotation.

/// class.
/// </summary>
public string annotationType;
/// <summary>
/// Additional key/value pair metadata that can be associated with
/// any record.
/// </summary>
public Dictionary<string, object> metadata;
public virtual void ToMessage(IMessageBuilder builder)
{
builder.AddString("id", Id);
builder.AddString("sensor_id", sensorId);
builder.AddString("description", description);
builder.AddString("annotation_type", annotationType);
}
}
/// <summary>

{
// The instance ID of the object
public int instanceId;
public int labelId;
public string label;
public string labelName;
/// <summary>
/// (xy) pixel location of the object's bounding box
/// </summary>

/// </summary>
public Vector2 dimension;
public void ToMessage(IMessageBuilder builder)
{
builder.AddInt("instance_id", instanceId);
builder.AddInt("label_id", labelId);
builder.AddString("label_name", labelName);
builder.AddFloatVector("origin", new[] { origin.x, origin.y });
builder.AddFloatVector("dimension", new[] { dimension.x, dimension.y });
}
}
/// <summary>

public override void ToMessage(IMessageBuilder builder)
{
base.ToMessage(builder);
foreach (var e in boxes)
{
var nested = builder.AddNestedMessageToVector("values");
e.ToMessage(nested);
}
}
}
/// <summary>

/// The color (rgba) value
/// </summary>
public Color32 rgba;
internal void ToMessage(IMessageBuilder builder)
{
builder.AddInt("instance_id", instanceId);
builder.AddIntVector("rgba", new[] { (int)rgba.r, (int)rgba.g, (int)rgba.b, (int)rgba.a });
}
}
/// <summary>

public override void ToMessage(IMessageBuilder builder)
{
base.ToMessage(builder);
builder.AddString("image_format", imageFormat);
builder.AddFloatVector("dimension", new[] { dimension.x, dimension.y });
builder.AddPngImage("instance_segmentation", buffer);
foreach (var e in instances)
{
var nested = builder.AddNestedMessageToVector("instances");
e.ToMessage(nested);
}
}
}
/// <summary>

public List<Entry> objectCounts;
}
}

10
com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloConsumer.cs


namespace UnityEngine.Perception.GroundTruth.SoloDesign
{
public class SoloConsumer : MonoBehaviour, IPerceptionConsumer
public class SoloConsumer : PerceptionConsumer
{
public string _baseDirectory = "D:/PerceptionOutput/SoloConsumer";
public string soloDatasetName = "solo";

public void OnSimulationStarted(SimulationMetadata metadata)
public override void OnSimulationStarted(SimulationMetadata metadata)
{
Debug.Log("SC - On Simulation Started");
m_CurrentMetadata = metadata;

File.WriteAllText(filePath, contents);
}
public void OnFrameGenerated(Frame frame)
public override void OnFrameGenerated(Frame frame)
{
var path = GetSequenceDirectoryPath(frame);
path = Path.Combine(path, $"step{frame.step}.frame_data.json");

Debug.Log("SC - On Frame Generated");
}
public void OnSimulationCompleted(CompletionMetadata metadata)
public override void OnSimulationCompleted(CompletionMetadata metadata)
{
Debug.Log("SC - On Simulation Completed");
}

values.Add(new JObject
{
["frame"] = frame.frame,
["label_name"] = box.label,
["label_name"] = box.labelName,
["instance_id"] = box.instanceId,
["origin"] = FromVector2(box.origin),
["dimension"] = FromVector2(box.dimension)

18
com.unity.perception/Runtime/Randomization/Scenarios/PerceptionScenario.cs


}
/// <inheritdoc/>
protected override void OnAwake()
protected override void OnStart()
m_IterationMetricDefinition = DatasetCapture.RegisterMetricDefinition(
m_IterationMetricDefinition = DatasetCapture.Instance.RegisterMetricDefinition(
}
/// <inheritdoc/>
protected override void OnStart()
{
var randomSeedMetricDefinition = DatasetCapture.RegisterMetricDefinition(
var randomSeedMetricDefinition = DatasetCapture.Instance.RegisterMetricDefinition(
DatasetCapture.ReportMetric(randomSeedMetricDefinition, new[] { genericConstants.randomSeed });
DatasetCapture.Instance.ReportMetric(randomSeedMetricDefinition, new[] { genericConstants.randomSeed });
DatasetCapture.StartNewSequence();
DatasetCapture.ReportMetric(m_IterationMetricDefinition, new[]
DatasetCapture.Instance.StartNewSequence();
DatasetCapture.Instance.ReportMetric(m_IterationMetricDefinition, new[]
{
new IterationMetricData { iteration = currentIteration }
});

protected override void OnComplete()
{
DatasetCapture.ResetSimulation();
DatasetCapture.Instance.ResetSimulation();
Manager.Instance.Shutdown();
Quit();
}

4
com.unity.perception/Tests/Editor/DatasetCaptureEditorTests.cs


{
[SerializeField]
string expectedDatasetPath;
#if false
[Test]
public void RegisterEgo_InEditMode_Throws()
{

{
Assert.Throws<InvalidOperationException>(() => DatasetCapture.RegisterMetricDefinition(""));
}
yield return new EnterPlayMode();
DatasetCapture.ResetSimulation();
var ego = DatasetCapture.RegisterEgo("ego");

Assert.True(sensor.ShouldCaptureThisFrame);
yield return new ExitPlayMode();
}
#endif
}
}

5
com.unity.perception/Tests/Editor/PerceptionCameraEditorTests.cs


var expectedLastFrame = Time.frameCount;
yield return null;
DatasetCapture.ResetSimulation();
// DatasetCapture.ResetSimulation();
var capturesPath = Path.Combine(DatasetCapture.OutputDirectory, "captures_000.json");
// var capturesPath = Path.Combine(DatasetCapture.OutputDirectory, "captures_000.json");
var capturesPath = Path.Combine("", "captures_000.json");
var capturesJson = File.ReadAllText(capturesPath);
for (int iFrameCount = expectedFirstFrame; iFrameCount <= expectedLastFrame; iFrameCount++)
{

5
com.unity.perception/Tests/Performance/PerformanceTester.cs


[SetUp]
public void SetUpTest()
{
#if false
#endif
Screen.SetResolution(m_Resolution.Item1, m_Resolution.Item2, true);
(m_Camera, m_IdConfig, m_SsConfig, m_SceneRoot) = TestHelper.CreateThreeBlockScene();

[TearDown]
public void TearDown()
{
#if false
Object.DestroyImmediate(m_Camera.gameObject);
Object.DestroyImmediate(m_SceneRoot.gameObject);

m_ActiveLabelers = null;
m_IdConfig = null;
m_SsConfig = null;
#endif
}
[UnityTest, Performance]

49
com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetCaptureSensorSchedulingTests.cs


// due to protection level - use only when testing protected logic is critical
class SimulationStateTestHelper
{
#if false
#endif
#if false
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
m_SequenceTimeOfNextCaptureMethod = m_State.GetType().GetMethod("GetSequenceTimeOfNextCapture", bindingFlags);
Debug.Assert(m_SequenceTimeOfNextCaptureMethod != null, "Couldn't find sequence time method.");

Debug.Assert(m_SensorsReference != null, "Couldn't cast sensor field to dictionary");
#endif
return (float)m_SequenceTimeOfNextCaptureMethod.Invoke(m_State, new object[] { sensorData });
// return (float)m_SequenceTimeOfNextCaptureMethod.Invoke(m_State, new object[] { sensorData });
return 0;
return m_SensorsReference[sensorHandle];
// return m_SensorsReference[sensorHandle];
return new SimulationState.SensorData();
}
}

public void TearDown()
{
Time.timeScale = 1;
DatasetCapture.ResetSimulation();
// DatasetCapture.ResetSimulation();
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var firstCaptureFrame = 2f;
var simulationDeltaTime = .4f;

Assert.AreEqual(sequenceTimesExpected[i], sequenceTimeActual, 0.0001f);
yield return null;
}
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var firstCaptureFrame = 2;
var simulationDeltaTime = .4f;

yield return null;
}
}
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var firstCaptureFrame = 2f;
var simulationDeltaTime = .4f;

yield return null;
Assert.AreEqual(deltaTimeSamplesExpected[i], Time.deltaTime, 0.0001f);
}
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var firstCaptureFrame = 2f;
var simulationDeltaTime = 1f;

yield return null;
Assert.AreEqual(deltaTimeSamplesExpected[i], Time.deltaTime, 0.0001f);
}
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
DatasetCapture.RegisterSensor(ego, "cam", "", 2f, CaptureTriggerMode.Scheduled, 1, 0);

LogAssert.Expect(LogType.Error, new Regex("Time\\.timeScale may not change mid-sequence.*"));
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
DatasetCapture.RegisterSensor(ego, "cam", "", 2f, CaptureTriggerMode.Scheduled, 1, 0);

yield return null;
#endif
yield return null;
}

{
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var firstCaptureFrame = 2f;
var simulationDeltaTime = 1f;

yield return null;
Assert.AreEqual(deltaTimeSamplesExpected[i], Time.deltaTime, 0.0001f);
}
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
DatasetCapture.RegisterSensor(ego, "cam", "", 0, CaptureTriggerMode.Scheduled, 5, 0);
yield return null;

#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var firstCaptureFrame1 = 2;
var simDeltaTime1 = 4;

}
CollectionAssert.AreEqual(samplesExpected, samplesActual);
#endif
yield return null;
}
[UnityTest]

[TestCase(235, 10, 2350, 2585, 2820, 3055, ExpectedResult = (IEnumerator)null)]
public IEnumerator SequenceTimeOfNextCapture_ReportsCorrectTime_VariedDeltaTimesAndStartFrames(float simulationDeltaTime, int firstCaptureFrame, float firstCaptureTime, float secondCaptureTime, float thirdCaptureTime, float fourthCaptureTime)
{
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var sensorHandle = DatasetCapture.RegisterSensor(ego, "cam", "", firstCaptureFrame, CaptureTriggerMode.Scheduled, simulationDeltaTime, 0);

Assert.AreEqual(sequenceTimesExpected[i], sequenceTimeActual, 0.0001f);
yield return null;
}
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var sensorHandle = DatasetCapture.RegisterSensor(ego, "cam", "", 0, CaptureTriggerMode.Manual, 0, 0, false);

}
Assert.AreEqual(frameIndex, framesToCaptureOn.Count, 0.0001f);
#endif
yield return null;
#if false
var ego = DatasetCapture.RegisterEgo("ego");
var simulationDeltaTime = 0.05f;
var sensorHandle = DatasetCapture.RegisterSensor(ego, "cam", "", 0, CaptureTriggerMode.Manual, simulationDeltaTime, 0, true);

yield return null;
}
Assert.AreEqual(frameIndex, framesToCaptureOn.Count, 0.0001f);
#endif
yield return null;
}
}
}

34
com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetCaptureTests.cs


}}
]
}}";
var ego = DatasetCapture.RegisterEgo(egoDescription);
#if false
//var ego = DatasetCapture.RegisterEgo(egoDescription);
var ego = new EgoHandle();
var sensorHandle = DatasetCapture.RegisterSensor(ego, modality, sensorDescription, 1, CaptureTriggerMode.Scheduled, 1, 0);
Assert.IsTrue(sensorHandle.IsValid);
DatasetCapture.ResetSimulation();

AssertJsonFileEquals(egoJsonExpected, egosPath);
AssertJsonFileEquals(sensorJsonExpected, sensorsPath);
#endif
}
[Test]

}}
]
}}";
#if false
var ego = DatasetCapture.RegisterEgo("");
var sensorHandle = DatasetCapture.RegisterSensor(ego, "camera", "", 0, CaptureTriggerMode.Scheduled, 1, 0);
var sensorSpatialData = new SensorSpatialData(new Pose(egoPosition, egoRotation), new Pose(position, rotation), egoVelocity, null);

FileAssert.Exists(capturesPath);
AssertJsonFileEquals(capturesJsonExpected, capturesPath);
#endif
}
[UnityTest]

(0, 0, true),
(1, 2, false)
};
#if false
var ego = DatasetCapture.RegisterEgo("");
var sensorHandle = DatasetCapture.RegisterSensor(ego, "", "", 0, CaptureTriggerMode.Scheduled, 2, 0);
var sensorSpatialData = new SensorSpatialData(default, default, null, null);

currentSequenceId = newSequenceId;
}
#endif
yield return null;
}
//Format a float to match Newtonsoft.Json formatting

[Test]
public void ReportAnnotation_AddsProperJsonToCapture()
{
#if false
var filename = "my/file.png";
var annotationDefinitionGuid = Guid.NewGuid();

FileAssert.Exists(capturesPath);
StringAssert.Contains(TestHelper.NormalizeJson(annotationsJsonExpected), EscapeGuids(File.ReadAllText(capturesPath)));
#endif
#if false
var values = new[]
{
new TestValues()

FileAssert.Exists(capturesPath);
StringAssert.Contains(TestHelper.NormalizeJson(expectedAnnotation), EscapeGuids(File.ReadAllText(capturesPath)));
#endif
#if false
#endif
#if false
Assert.Throws<InvalidOperationException>(() => sensorHandle.ReportAnnotationValues(annotationDefinition, new int[0]));
Assert.Thows<InvalidOperationException>(() => sensorHandle.ReportAnnotationValues(annotationDefinition, new int[0]));
#endif
#if false
#endif
#if false
var ego = DatasetCapture.RegisterEgo("");
var annotationDefinition = DatasetCapture.RegisterAnnotationDefinition("");
var sensorHandle = DatasetCapture.RegisterSensor(ego, "", "", 0, CaptureTriggerMode.Scheduled, 1, 0);

#endif
#if false
[Test]
public void ResetSimulation_CallsSimulationEnding()
{

result = TestHelper.NormalizeJson(result);
return result;
}
#endif
}

3
com.unity.perception/Tests/Runtime/GroundTruthTests/GroundTruthTestBase.cs


SceneManager.UnloadSceneAsync(s);
m_ScenesToUnload.Clear();
#if false
#endif
}
public void AddTestObjectForCleanup(Object @object) => m_ObjectsToDestroy.Add(@object);

7
com.unity.perception/Tests/Runtime/GroundTruthTests/PerceptionCameraIntegrationTests.cs


[UnityPlatform(RuntimePlatform.LinuxPlayer, RuntimePlatform.WindowsPlayer)]
public IEnumerator EnableBoundingBoxes_GeneratesCorrectDataset()
{
#if false
//set resolution to ensure we don't have rounding in rendering leading to bounding boxes to change height/width
Screen.SetResolution(400, 400, false);
//give the screen a chance to resize

var capturesPath = Path.Combine(DatasetCapture.OutputDirectory, "captures_000.json");
var capturesJson = File.ReadAllText(capturesPath);
StringAssert.Contains(TestHelper.NormalizeJson(jsonExpected, true), TestHelper.NormalizeJson(capturesJson, true));
#endif
yield return null;
#if false
SemanticSegmentationLabeler semanticSegmentationLabeler = null;
SetupCamera(pc =>
{

});
return labelingConfiguration;
}
#endif
}
}

6
com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ScenarioTests.cs


var perceptionCamera = SetupPerceptionCamera();
yield return CreateNewScenario(2, 2);
Assert.AreEqual(DatasetCapture.SimulationState.SequenceTime, 0);
// Assert.AreEqual(DatasetCapture.SimulationState.SequenceTime, 0);
Assert.AreEqual(DatasetCapture.SimulationState.SequenceTime, perceptionCamera.simulationDeltaTime);
// Assert.AreEqual(DatasetCapture.SimulationState.SequenceTime, perceptionCamera.simulationDeltaTime);
Assert.AreEqual(DatasetCapture.SimulationState.SequenceTime, 0);
// Assert.AreEqual(DatasetCapture.SimulationState.SequenceTime, 0);
}
[UnityTest]

2
com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/TestFixedLengthScenario.cs


{
protected override void OnComplete()
{
DatasetCapture.ResetSimulation();
DatasetCapture.Instance.ResetSimulation();
}
}
}

25
com.unity.perception/Runtime/GroundTruth/SoloDesign/IMessageBuilder.cs


using System.Collections.Generic;
using System.Linq;
namespace UnityEngine.Perception.GroundTruth.Exporters.Solo
{
public interface IMessageBuilder
{
void AddInt(string label, int value);
void AddIntVector(string label, int[] values);
void AddFloat(string label, float value);
void AddFloatVector(string label, float[] value);
void AddString(string label, string value);
void AddStringVector(string label, object[] values);
void AddBoolean(string label, bool value);
void AddBooleanVector(string label, bool[] values);
void AddPngImage(string label, byte[] value);
IMessageBuilder AddNestedMessage(string label);
IMessageBuilder AddNestedMessageToVector(string arrayLabel);
}
}

11
com.unity.perception/Runtime/GroundTruth/SoloDesign/IMessageBuilder.cs.meta


fileFormatVersion: 2
guid: 9b7babd7be7b7934db08409d6f7a9524
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

405
com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionConsumer.cs


using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using UnityEngine;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using Formatting = Newtonsoft.Json.Formatting;
namespace GroundTruth.SoloDesign
{
public class PerceptionResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
if (objectType == typeof(Vector3) ||
objectType == typeof(Vector2) ||
objectType == typeof(Color32))
{
contract.Converter = PerceptionConverter.Instance;
}
return contract;
}
}
public class PerceptionConverter : JsonConverter
{
public static PerceptionConverter Instance = new PerceptionConverter();
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
switch (value)
{
case Vector3 v3:
{
writer.WriteStartArray();
writer.WriteValue(v3.x);
writer.WriteValue(v3.y);
writer.WriteValue(v3.z);
writer.WriteEndArray();
break;
}
case Vector2 v2:
{
writer.WriteStartArray();
writer.WriteValue(v2.x);
writer.WriteValue(v2.y);
writer.WriteEndArray();
break;
}
case Color32 rgba:
{
writer.WriteStartObject();
writer.WritePropertyName("r");
writer.WriteValue(rgba.r);
writer.WritePropertyName("g");
writer.WriteValue(rgba.g);
writer.WritePropertyName("b");
writer.WriteValue(rgba.b);
writer.WritePropertyName("a");
writer.WriteValue(rgba.a);
writer.WriteEndObject();
break;
}
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return null;
}
public override bool CanConvert(Type objectType)
{
if (objectType == typeof(Vector3)) return true;
if (objectType == typeof(Vector2)) return true;
return objectType == typeof(Color32);
}
}
public class OldPerceptionConsumer : PerceptionConsumer
{
static readonly string version = "0.1.1";
public string baseDirectory = "D:/PerceptionOutput/KickinItOldSchool";
public int capturesPerFile = 20;
internal JsonSerializer Serializer { get; }= new JsonSerializer { ContractResolver = new PerceptionResolver()};
//JsonSerializer m_JsonSerializer = new JsonSerializer();
string m_CurrentPath;
string m_DatasetPath;
string m_RgbPath;
string m_LogsPath;
[Serializable]
struct SensorInfo
{
public Guid id;
public string modality;
public string description;
}
Dictionary<string, SensorInfo> m_SensorMap = new Dictionary<string, SensorInfo>();
Dictionary<string, (Guid, AnnotationDefinition)> m_RegisteredAnnotations = new Dictionary<string, (Guid, AnnotationDefinition)>();
Dictionary<int, Guid> m_SequenceToGuidMap = new Dictionary<int, Guid>();
List<PerceptionCapture> m_CurrentCaptures = new List<PerceptionCapture>();
internal string VerifyDirectoryWithGuidExists(string directoryPrefix, bool appendGuid = true)
{
var dirs = Directory.GetDirectories(m_CurrentPath);
var found = string.Empty;
foreach (var dir in dirs)
{
var dirName = new DirectoryInfo(dir).Name;
if (dirName.StartsWith(directoryPrefix))
{
found = dir;
break;
}
}
if (found == string.Empty)
{
var dirName = appendGuid ? $"{directoryPrefix}{Guid.NewGuid().ToString()}" : directoryPrefix;
found = Path.Combine(m_CurrentPath, dirName);
Directory.CreateDirectory(found);
}
return found;
}
public override void OnAnnotationRegistered(AnnotationDefinition annotationDefinition)
{
if (m_RegisteredAnnotations.ContainsKey(annotationDefinition.id))
{
Debug.LogError("Tried to register an annotation twice");
return;
}
m_RegisteredAnnotations[annotationDefinition.id] = (Guid.NewGuid(), annotationDefinition);
}
public override void OnSensorRegistered(SensorDefinition sensor)
{
if (m_SensorMap.ContainsKey(sensor.id))
{
Debug.LogError("Tried to register a sensor twice");
return;
}
m_SensorMap[sensor.id] = new SensorInfo
{
id = Guid.NewGuid(),
modality = sensor.modality,
description = sensor.definition
};
}
public override void OnSimulationStarted(SimulationMetadata metadata)
{
// Create a directory guid...
var path = Guid.NewGuid().ToString();
m_CurrentPath = Path.Combine(baseDirectory, path);
Directory.CreateDirectory(m_CurrentPath);
m_DatasetPath = VerifyDirectoryWithGuidExists("Dataset");
m_RgbPath = VerifyDirectoryWithGuidExists("RGB");
m_LogsPath = VerifyDirectoryWithGuidExists("Logs", false);
}
public override void OnFrameGenerated(Frame frame)
{
if (!m_SequenceToGuidMap.TryGetValue(frame.sequence, out var seqId))
{
seqId = Guid.NewGuid();
m_SequenceToGuidMap[frame.sequence] = seqId;
}
// Only support one image file right now
var path = "";
RgbSensor rgbSensor = null;
if (frame.sensors.Count == 1)
{
var sensor = frame.sensors[0];
if (sensor is RgbSensor rgb)
{
rgbSensor = rgb;
path = WriteOutImageFile(frame.frame, rgb);
}
}
var annotations = new JArray();
foreach (var annotation in frame.annotations)
{
var labelerId = Guid.NewGuid(); // TODO - we need to get this figured out
if (!m_RegisteredAnnotations.TryGetValue(annotation.Id, out var def))
{
def.Item1 = Guid.Empty;
}
var defId = def.Item1;
var json = OldPerceptionJsonFactory.Convert(this, frame, labelerId, defId, annotation);
if (json != null) annotations.Add(json);
}
var capture = new PerceptionCapture
{
id = Guid.NewGuid(),
filename = path,
format = "PNG",
sequence_id = seqId,
step = frame.step,
timestamp = frame.timestamp,
sensor = PerceptionRgbSensor.Convert(this, rgbSensor, path),
annotations = annotations
};
m_CurrentCaptures.Add(capture);
if (m_CurrentCaptures.Count >= capturesPerFile)
{
var toRemove = m_CurrentCaptures;
m_CurrentCaptures = new List<PerceptionCapture>();
// Write out a capture file
WriteCaptureFile(m_CurrentCaptureIndex++, toRemove);
toRemove.Clear();
}
}
public override void OnSimulationCompleted(CompletionMetadata metadata)
{
WriteSensorsFile();
WriteEgosFile();
WriteAnnotationsDefinitionsFile();
WriteMetricsDefinitionsFile();
}
int m_CurrentCaptureIndex = 1;
string WriteOutImageFile(int frame, RgbSensor rgb)
{
var path = Path.Combine(m_RgbPath, $"{rgb.sensorType}_{frame}.png");
var file = File.Create(path, 4096);
file.Write(rgb.buffer, 0, rgb.buffer.Length);
file.Close();
return path;
}
void WriteJTokenToFile(string filePath, PerceptionJson json)
{
WriteJTokenToFile(filePath, JToken.FromObject(json, Serializer));
}
static void WriteJTokenToFile(string filePath, JToken json)
{
var stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
using (var jsonTextWriter = new JsonTextWriter(stringWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
json.WriteTo(jsonTextWriter);
}
var contents = stringWriter.ToString();
File.WriteAllText(filePath, contents);
}
void WriteAnnotationsDefinitionsFile()
{
var defs = new JArray();
foreach (var (id, def) in m_RegisteredAnnotations.Values)
{
defs.Add(OldPerceptionJsonFactory.Convert(this, id, def));
}
var top = new JObject
{
["version"] = version,
["annotation_definitions"] = defs
};
var path = Path.Combine(m_DatasetPath, "annotation_definitions.json");
WriteJTokenToFile(path, top);
}
void WriteMetricsDefinitionsFile()
{
var top = new JObject
{
["version"] = version,
["metric_definitions"] = new JArray()
};
var path = Path.Combine(m_DatasetPath, "metric_definitions.json");
WriteJTokenToFile(path, top);
}
void WriteEgosFile()
{
var top = new JObject
{
["version"] = version,
["egos"] = new JArray()
};
var path = Path.Combine(m_DatasetPath, "egos.json");
WriteJTokenToFile(path, top);
}
void WriteSensorsFile()
{
var sub = new JArray();
foreach (var sensor in m_SensorMap)
{
sub.Add(JToken.FromObject(sensor.Value, Serializer));
}
var top = new JObject
{
["version"] = version,
["sensors"] = sub
};
var path = Path.Combine(m_DatasetPath, "sensors.json");
WriteJTokenToFile(path, top);
}
void WriteCaptureFile(int index, IEnumerable<PerceptionCapture> captures)
{
var top = new PerceptionJson
{
version = version,
captures = captures
};
var path = Path.Combine(m_DatasetPath, $"captures_{index}.json");
WriteJTokenToFile(path, top);
}
public Guid GetIdForSensor(Sensor inSensor)
{
if (!m_SensorMap.TryGetValue(inSensor.Id, out var info))
{
Debug.LogError("Sensor Id was not available, it should have already been registered");
return Guid.Empty;
}
return info.id;
}
[Serializable]
struct PerceptionJson
{
public string version;
public IEnumerable<PerceptionCapture> captures;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[Serializable]
struct PerceptionCapture
{
public Guid id;
public Guid sequence_id;
public int step;
public float timestamp;
public string filename;
public string format;
public PerceptionRgbSensor sensor;
public JArray annotations;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[Serializable]
struct PerceptionRgbSensor
{
public Guid sensor_id;
public string modality;
public Vector3 translation;
public Vector3 rotation;
public Vector3 velocity;
public Vector3 acceleration;
public static PerceptionRgbSensor Convert(OldPerceptionConsumer consumer, RgbSensor inRgb, string path)
{
return new PerceptionRgbSensor
{
sensor_id = consumer.GetIdForSensor(inRgb),
modality = inRgb.sensorType,
translation = inRgb.position,
rotation = inRgb.rotation,
velocity = inRgb.velocity,
acceleration = inRgb.acceleration
};
}
}
}
}

11
com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionConsumer.cs.meta


fileFormatVersion: 2
guid: 263154e84a4500e4494724de402f1162
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

178
com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionJsonFactory.cs


using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Perception.GroundTruth.SoloDesign;
namespace GroundTruth.SoloDesign
{
public static class OldPerceptionJsonFactory
{
public static JToken Convert(OldPerceptionConsumer consumer, Guid id, AnnotationDefinition def)
{
switch (def)
{
case BoundingBoxAnnotationDefinition b:
return JToken.FromObject(PerceptionBoundingBoxAnnotationDefinition.Convert(id, b));
}
return null;
}
public static JToken Convert(OldPerceptionConsumer consumer, Frame frame, Guid labelerId, Guid defId, Annotation annotation)
{
switch (annotation)
{
case InstanceSegmentation i:
{
return JToken.FromObject(PerceptionInstanceSegmentationValue.Convert(consumer, frame.frame, i), consumer.Serializer);
}
case BoundingBoxAnnotation b:
{
return JToken.FromObject(PerceptionBoundingBoxAnnotationValue.Convert(consumer, labelerId, defId, b), consumer.Serializer);
}
}
return null;
}
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[Serializable]
struct PerceptionInstanceSegmentationValue
{
[Serializable]
internal struct Entry
{
public int instance_id;
public Color32 color;
internal static Entry Convert(InstanceSegmentation.Entry entry)
{
return new Entry
{
instance_id = entry.instanceId,
color = entry.rgba
};
}
}
public Guid id;
public Guid annotation_definition;
public string filename;
public List<Entry> values;
static string CreateFile(OldPerceptionConsumer consumer, int frame, InstanceSegmentation annotation)
{
var path = consumer.VerifyDirectoryWithGuidExists("InstanceSegmentation");
path = Path.Combine(path, $"Instance_{frame}.png");
var file = File.Create(path, 4096);
file.Write(annotation.buffer, 0, annotation.buffer.Length);
file.Close();
return path;
}
public static PerceptionInstanceSegmentationValue Convert(OldPerceptionConsumer consumer, int frame, InstanceSegmentation annotation)
{
return new PerceptionInstanceSegmentationValue
{
id = Guid.NewGuid(),
annotation_definition = Guid.NewGuid(),
filename = CreateFile(consumer, frame, annotation),
values = annotation.instances.Select(Entry.Convert).ToList()
};
}
}
[Serializable]
struct LabelDefinitionEntry
{
public int label_id;
public string label_name;
}
[Serializable]
struct PerceptionBoundingBoxAnnotationDefinition
{
public Guid id;
public string name;
public string description;
public string format;
public LabelDefinitionEntry[] spec;
public static PerceptionBoundingBoxAnnotationDefinition Convert(Guid inId, BoundingBoxAnnotationDefinition box)
{
var specs = new LabelDefinitionEntry[box.spec.Count()];
var i = 0;
foreach (var e in box.spec)
{
specs[i++] = new LabelDefinitionEntry
{
label_id = e.labelId,
label_name = e.labelName
};
}
return new PerceptionBoundingBoxAnnotationDefinition
{
id = inId,
name = box.id,
description = box.description,
format = "json",
spec = specs
};
}
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[Serializable]
struct PerceptionBoundingBoxAnnotationValue
{
[Serializable]
internal struct Entry
{
public int label_id;
public int frame;
public string label_name;
public uint instance_id;
public float x;
public float y;
public float width;
public float height;
internal static Entry Convert(BoundingBoxAnnotation.Entry entry)
{
return new Entry
{
label_id = entry.labelId, // TODO
frame = -1, // TODO
label_name = entry.labelName,
instance_id = (uint)entry.instanceId,
x = entry.origin.x,
y = entry.origin.y,
width = entry.dimension.x,
height = entry.dimension.y
};
}
}
public Guid id;
public Guid annotation_definition;
public List<Entry> values;
public static PerceptionBoundingBoxAnnotationValue Convert(OldPerceptionConsumer consumer, Guid labelerId, Guid defId, BoundingBoxAnnotation annotation)
{
return new PerceptionBoundingBoxAnnotationValue
{
id = labelerId,
annotation_definition = defId,
values = annotation.boxes.Select(Entry.Convert).ToList()
};
}
}
}

11
com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionJsonFactory.cs.meta


fileFormatVersion: 2
guid: 41c6d077f1a3a704e91176dc0b675ac7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

206
com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloMessageBuilder.cs


using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Perception.GroundTruth.Exporters.Solo;
using UnityEngine.Perception.GroundTruth.SoloDesign;
namespace GroundTruth.SoloDesign
{
public class SoloMessageBuilder : PerceptionConsumer
{
public string _baseDirectory = "D:/PerceptionOutput/SoloMessageBuilder";
public string soloDatasetName = "solo_mb";
static string currentDirectory = "";
SimulationMetadata m_CurrentMetadata;
public override void OnSimulationStarted(SimulationMetadata metadata)
{
Debug.Log("SC - On Simulation Started");
m_CurrentMetadata = metadata;
if (!Directory.Exists((_baseDirectory)))
Directory.CreateDirectory(_baseDirectory);
var i = 0;
while (true)
{
var n = $"{soloDatasetName}_{i++}";
n = Path.Combine(_baseDirectory, n);
if (!Directory.Exists(n))
{
Directory.CreateDirectory(n);
currentDirectory = n;
break;
}
}
}
static string GetSequenceDirectoryPath(Frame frame)
{
var path = $"sequence.{frame.sequence}";
// verify that a directory already exists for a sequence,
// if not, create it.
path = Path.Combine(currentDirectory, path);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return path;
}
JToken m_FrameToken = null;
Stack<JToken> m_Tokens = new Stack<JToken>();
public override void OnFrameGenerated(Frame frame)
{
if (m_FrameToken == null)
{
m_FrameToken = new JObject();
m_Tokens.Push(m_FrameToken);
}
else
{
// do something here to write out previous frame
}
var msg = new FrameMessageBuilder();
FrameMessageBuilder.currentFrame = frame;
frame.ToMessage(msg);
// write out current
var path = GetSequenceDirectoryPath(frame);
path = Path.Combine(path, $"step{frame.step}.frame_data.json");
WriteJTokenToFile(path, msg.ToJson());
}
static void WriteJTokenToFile(string filePath, JToken jToken)
{
var stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
using (var jsonTextWriter = new JsonTextWriter(stringWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
jToken.WriteTo(jsonTextWriter);
}
var contents = stringWriter.ToString();
File.WriteAllText(filePath, contents);
}
public override void OnSimulationCompleted(CompletionMetadata metadata)
{
Debug.Log("SC - On Simulation Completed");
}
class FrameMessageBuilder : IMessageBuilder
{
JToken m_Current = new JObject();
Dictionary<string, FrameMessageBuilder> m_NestedValue = new Dictionary<string, FrameMessageBuilder>();
Dictionary<string, List<FrameMessageBuilder>> m_NestedArrays = new Dictionary<string, List<FrameMessageBuilder>>();
public static Frame currentFrame = null;
public JToken ToJson()
{
foreach (var n in m_NestedValue)
{
m_Current[n.Key] = n.Value.ToJson();
}
foreach (var n in m_NestedArrays)
{
var jArray = new JArray();
foreach (var o in n.Value)
{
jArray.Add(o.ToJson());
}
m_Current[n.Key] = jArray;
}
return m_Current;
}
public void AddInt(string label, int value)
{
m_Current[label] = value;
}
public void AddIntVector(string label, int[] values)
{
m_Current[label] = new JArray(values);
}
public void AddFloat(string label, float value)
{
m_Current[label] = value;
}
public void AddFloatVector(string label, float[] values)
{
m_Current[label] = new JArray(values);
}
public void AddString(string label, string value)
{
m_Current[label] = value;
}
public void AddStringVector(string label, object[] values)
{
m_Current[label] = new JArray(values);
}
public void AddBoolean(string label, bool value)
{
m_Current[label] = value;
}
public void AddBooleanVector(string label, bool[] values)
{
m_Current[label] = new JArray(values);
}
// Right now, just for png images
public void AddPngImage(string label, byte[] value)
{
// write out the file
var path = GetSequenceDirectoryPath(currentFrame);
path = Path.Combine(path, $"step{currentFrame.step}.{label}.png");
var file = File.Create(path, 4096);
file.Write(value, 0, value.Length);
file.Close();
// Add the filename to the json
m_Current["filename"] = path;
}
public IMessageBuilder AddNestedMessage(string label)
{
var nested = new FrameMessageBuilder();
m_NestedValue[label] = nested;
return nested;
}
public IMessageBuilder AddNestedMessageToVector(string arrayLabel)
{
if (!m_NestedArrays.TryGetValue(arrayLabel, out var nestedList))
{
nestedList = new List<FrameMessageBuilder>();
m_NestedArrays[arrayLabel] = nestedList;
}
var nested = new FrameMessageBuilder();
nestedList.Add(nested);
return nested;
}
}
}
}

11
com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloMessageBuilder.cs.meta


fileFormatVersion: 2
guid: 8de61169fea9df74b99d779c0d38b8a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存