浏览代码

Restructuring of files

/solo_support
Steve Borkman 3 年前
当前提交
5da96a7a
共有 40 个文件被更改,包括 1578 次插入1463 次删除
  1. 8
      com.unity.perception/Editor/GroundTruth/PerceptionCameraEditor.cs
  2. 684
      com.unity.perception/Runtime/GroundTruth/DatasetCapture.cs
  3. 4
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBox3DLabeler.cs
  4. 26
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBoxLabeler.cs
  5. 76
      com.unity.perception/Runtime/GroundTruth/Labelers/InstanceSegmentationLabeler.cs
  6. 4
      com.unity.perception/Runtime/GroundTruth/Labelers/KeypointLabeler.cs
  7. 95
      com.unity.perception/Runtime/GroundTruth/Labelers/ObjectCountLabeler.cs
  8. 6
      com.unity.perception/Runtime/GroundTruth/Labelers/RenderedObjectInfoLabeler.cs
  9. 4
      com.unity.perception/Runtime/GroundTruth/Labelers/SemanticSegmentationLabeler.cs
  10. 52
      com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs
  11. 731
      com.unity.perception/Runtime/GroundTruth/SimulationState.cs
  12. 505
      com.unity.perception/Runtime/GroundTruth/SimulationState_Json.cs
  13. 5
      com.unity.perception/Runtime/Randomization/Scenarios/PerceptionScenario.cs
  14. 2
      com.unity.perception/Runtime/Randomization/Scenarios/UnitySimulationScenario.cs
  15. 4
      com.unity.perception/Tests/Runtime/GroundTruthTests/VisualizationTests.cs
  16. 2
      com.unity.perception/Runtime/GroundTruth/ConsumerEndpoint.cs.meta
  17. 5
      com.unity.perception/Runtime/GroundTruth/IMessageBuilder.cs
  18. 2
      com.unity.perception/Runtime/GroundTruth/IMessageBuilder.cs.meta
  19. 17
      com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionConsumer.cs
  20. 17
      com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionJsonFactory.cs
  21. 7
      com.unity.perception/Runtime/GroundTruth/Consumers/SoloMessageBuilder.cs
  22. 33
      com.unity.perception/Runtime/GroundTruth/ConsumerEndpoint.cs
  23. 8
      com.unity.perception/Runtime/GroundTruth/Consumers.meta
  24. 421
      com.unity.perception/Runtime/GroundTruth/DataModel.cs
  25. 11
      com.unity.perception/Runtime/GroundTruth/DataModel.cs.meta
  26. 296
      com.unity.perception/Runtime/GroundTruth/Consumers/SoloConsumer.cs
  27. 8
      com.unity.perception/Runtime/GroundTruth/Exporters.meta
  28. 8
      com.unity.perception/Runtime/GroundTruth/SoloDesign.meta
  29. 0
      /com.unity.perception/Runtime/GroundTruth/ConsumerEndpoint.cs.meta
  30. 0
      /com.unity.perception/Runtime/GroundTruth/Consumers/SoloConsumer.cs.meta
  31. 0
      /com.unity.perception/Runtime/GroundTruth/IMessageBuilder.cs
  32. 0
      /com.unity.perception/Runtime/GroundTruth/IMessageBuilder.cs.meta
  33. 0
      /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionConsumer.cs.meta
  34. 0
      /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionJsonFactory.cs.meta
  35. 0
      /com.unity.perception/Runtime/GroundTruth/Consumers/SoloMessageBuilder.cs.meta
  36. 0
      /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionConsumer.cs
  37. 0
      /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionJsonFactory.cs
  38. 0
      /com.unity.perception/Runtime/GroundTruth/Consumers/SoloMessageBuilder.cs

8
com.unity.perception/Editor/GroundTruth/PerceptionCameraEditor.cs


s.wordWrap = true;
var defaultColor = s.normal.textColor;
var dir = PlayerPrefs.GetString(SimulationState.latestOutputDirectoryKey, string.Empty);
var dir = PlayerPrefs.GetString(string.Empty, string.Empty);
if (dir != string.Empty)
{
EditorGUILayout.LabelField("Latest Generated Dataset");

GUILayout.Space(10);
var userBaseDir = PlayerPrefs.GetString(SimulationState.userBaseDirectoryKey);
var userBaseDir = PlayerPrefs.GetString(string.Empty, string.Empty);
var folder = PlayerPrefs.GetString(SimulationState.defaultOutputBaseDirectory);
var folder = PlayerPrefs.GetString(string.Empty, string.Empty);
userBaseDir = folder != string.Empty ? folder : Application.persistentDataPath;
}

if (path.Length != 0)
{
Debug.Log($"Chose path: {path}");
PlayerPrefs.SetString(SimulationState.userBaseDirectoryKey, path);
// PlayerPrefs.SetString(SimulationState.userBaseDirectoryKey, path);
}
}

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


using System;
using System.Collections.Generic;
using System.IO;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
using Unity.Collections;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using UnityEngine.Perception.GroundTruth.DataModel;
#pragma warning disable 649
namespace UnityEngine.Perception.GroundTruth

public class DatasetCapture : MonoBehaviour
{
public static DatasetCapture Instance { get; protected set; }
public PerceptionConsumer activeConsumer;
// readonly Guid k_DatasetGuid = Guid.NewGuid();
public ConsumerEndpoint activeConsumer;
SimulationState m_SimulationState;
void Awake()

/// </summary>
public event Action SimulationEnding;
/// <summary>
/// Register a new sensor under the given ego.
/// </summary>
/// <param name="egoHandle">The ego container for the sensor. Sensor orientation will be reported in the context of the given ego.</param>
/// <param name="modality">The kind of the sensor (ex. "camera", "lidar")</param>
/// <param name="description">A human-readable description of the sensor (ex. "front-left rgb camera")</param>
/// <param name="firstCaptureFrame">The offset from the current frame on which this sensor should first be scheduled.</param>
/// <param name="captureTriggerMode">The method of triggering captures for this sensor.</param>
/// <param name="simulationDeltaTime">The simulation frame time (seconds) requested by this sensor.</param>
/// <param name="framesBetweenCaptures">The number of frames to simulate and render between the camera's scheduled captures. Setting this to 0 makes the camera capture every frame.</param>
/// <param name="manualSensorAffectSimulationTiming">Have this unscheduled (manual capture) camera affect simulation timings (similar to a scheduled camera) by requesting a specific frame delta time</param>
/// <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>
#if false
public SensorHandle RegisterSensor(EgoHandle egoHandle, string modality, string description, float firstCaptureFrame, CaptureTriggerMode captureTriggerMode, float simulationDeltaTime, int framesBetweenCaptures, bool manualSensorAffectSimulationTiming = false)
{
var sensor = new SensorHandle(Guid.NewGuid(), this);
simulationState.AddSensor(egoHandle, modality, description, firstCaptureFrame, captureTriggerMode, simulationDeltaTime, framesBetweenCaptures, manualSensorAffectSimulationTiming, sensor);
return sensor;
}
#endif
#if false
/// <summary>
/// Creates a metric type, which can be used to produce metrics during the simulation.
/// See <see cref="ReportMetric{T}(MetricDefinition,T[])"/>, <see cref="SensorHandle.ReportMetricAsync(MetricDefinition)"/>, <see cref="SensorHandle.ReportMetric{T}(MetricDefinition,T[])"/>,
/// <see cref="SensorHandle.ReportMetricAsync(MetricDefinition)"/>, <see cref="Annotation.ReportMetric{T}(MetricDefinition,T[])"/>, <see cref="Annotation.ReportMetricAsync(MetricDefinition)"/>
/// </summary>
/// <param name="name">Human readable annotation spec name (e.g. sementic_segmentation, instance_segmentation, etc.)</param>
/// <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 MetricDefinition RegisterMetricDefinition(string name, string description = null, Guid id = default)
{
return RegisterMetricDefinition<object>(name, null, description, id);
}
/// <summary>
/// Creates a metric type, which can be used to produce metrics during the simulation.
/// See <see cref="ReportMetric{T}(MetricDefinition,T[])"/>, <see cref="SensorHandle.ReportMetricAsync(MetricDefinition)"/>, <see cref="SensorHandle.ReportMetric{T}(MetricDefinition,T[])"/>,
/// <see cref="SensorHandle.ReportMetricAsync(MetricDefinition)"/>, <see cref="Annotation.ReportMetric{T}(MetricDefinition,T[])"/>, <see cref="Annotation.ReportMetricAsync(MetricDefinition)"/>
/// </summary>
/// <param name="name">Human readable annotation spec name (e.g. sementic_segmentation, instance_segmentation, etc.)</param>
/// <param name="description">Description of the annotation.</param>
/// <param name="specValues">Format-specific specification for the metric values. Will be converted to json automatically.</param>
/// <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 MetricDefinition RegisterMetricDefinition<TSpec>(string name, TSpec[] specValues, string description = null, Guid id = default)
public void RegisterMetric(MetricDefinition metricDefinition)
return simulationState.RegisterMetricDefinition(name, specValues, description, id);
}
#endif
public void RegisterMetricDefinition(SoloDesign.MetricDefinition metricDefinition)
{
simulationState.RegisterMetricDefinition(metricDefinition);
simulationState.RegisterMetric(metricDefinition);
public void RegisterAnnotationDefinition(SoloDesign.AnnotationDefinition definition)
public void RegisterAnnotationDefinition(AnnotationDefinition definition)
}
#if false
/// <summary>
/// Creates an annotation type, which can be used to produce annotations during the simulation.
/// See <see cref="SensorHandle.ReportAnnotationFile"/>, <see cref="SensorHandle.ReportAnnotationValues{T}"/> and <see cref="SensorHandle.ReportAnnotationAsync"/>.
/// </summary>
/// <param name="name">Human readable annotation spec name (e.g. sementic_segmentation, instance_segmentation, etc.)</param>
/// <param name="description">Description of the annotation.</param>
/// <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 AnnotationDefinition RegisterAnnotationDefinition(string name, string description = null, string format = "json", Guid id = default)
{
return RegisterAnnotationDefinition<object>(name, null, description, format, id);
/// Creates an annotation type, which can be used to produce annotations during the simulation.
/// See <see cref="SensorHandle.ReportAnnotationFile"/>, <see cref="SensorHandle.ReportAnnotationValues{T}"/> and <see cref="SensorHandle.ReportAnnotationAsync"/>.
/// </summary>
/// <param name="name">Human readable annotation spec name (e.g. sementic_segmentation, instance_segmentation, etc.)</param>
/// <param name="description">Description of the annotation.</param>
/// <param name="format">Optional format name.</param>
/// <param name="specValues">Format-specific specification for the annotation values (ex. label-value mappings for semantic segmentation images)</param>
/// <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 AnnotationDefinition RegisterAnnotationDefinition<TSpec>(string name, TSpec[] specValues, string description = null, string format = "json", Guid id = default)
{
return simulationState.RegisterAnnotationDefinition(name, specValues, description, format, id);
}
#endif
#if false
/// <summary>
/// Report a metric not associated with any sensor or annotation.
/// </summary>
/// <param name="metricDefinition">The MetricDefinition associated with this metric. <see cref="RegisterMetricDefinition"/></param>
/// <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 void ReportMetric<T>(MetricDefinition metricDefinition, T[] values)
{
simulationState.ReportMetric(metricDefinition, values, default, default);
}
/// <summary>
/// Report a metric not associated with any sensor or annotation.
/// </summary>
/// <param name="metricDefinition">The MetricDefinition associated with this metric. <see cref="RegisterMetricDefinition"/></param>
/// <param name="valuesJsonArray">A string-based JSON array to be placed in the "values" field of the metric</param>
public void ReportMetric(MetricDefinition metricDefinition, string valuesJsonArray)
{
simulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), default, default);
}
/// <summary>
/// Report a metric not associated with any sensor or annotation.
/// </summary>
/// <param name="metricDefinition">The metric definition of the metric being reported</param>
/// <returns>An <see cref="AsyncMetric"/> which should be used to report the metric values, potentially in a later frame</returns>
public AsyncMetric ReportMetricAsync(MetricDefinition metricDefinition) => simulationState.CreateAsyncMetric(metricDefinition);
#endif
/// <summary>
/// Starts a new sequence in the capture.
/// </summary>
public void StartNewSequence() => simulationState.StartNewSequence();

Manual
}
public enum FutureType
{
Sensor,
Annotation,
Metric
}
public interface IAsyncFuture<T> where T : SimulationState.IPendingId
{
T GetId();
FutureType GetFutureType();
bool IsPending();
}
public struct AsyncSensorFuture : IAsyncFuture<SimulationState.SPendingSensorId>
{
public AsyncSensorFuture(SimulationState.SPendingSensorId id, SimulationState simulationState)
{
m_Id = id;
m_SimulationState = simulationState;
}
SimulationState.SPendingSensorId m_Id;
SimulationState m_SimulationState;
public SimulationState.SPendingSensorId GetId()
{
return m_Id;
}
public FutureType GetFutureType()
{
return FutureType.Sensor;
}
public bool IsPending()
{
return m_SimulationState.IsPending(this);
}
public void Report(Sensor sensor)
{
m_SimulationState.ReportAsyncResult(this, sensor);
}
}
public struct AsyncAnnotationFuture : IAsyncFuture<SimulationState.SPendingCaptureId>
{
public AsyncAnnotationFuture(SimulationState.SPendingCaptureId id, SimulationState simulationState)
{
m_Id = id;
m_SimulationState = simulationState;
}
SimulationState.SPendingCaptureId m_Id;
SimulationState m_SimulationState;
public SimulationState.SPendingCaptureId GetId()
{
return m_Id;
}
public FutureType GetFutureType()
{
return FutureType.Annotation;
}
public bool IsPending()
{
return m_SimulationState.IsPending(this);
}
public void Report(Annotation annotation)
{
m_SimulationState.ReportAsyncResult(this, annotation);
}
}
public struct AsyncMetricFuture : IAsyncFuture<SimulationState.SPendingCaptureId>
{
public AsyncMetricFuture(SimulationState.SPendingCaptureId id, SimulationState simulationState)
{
m_Id = id;
m_SimulationState = simulationState;
}
SimulationState.SPendingCaptureId m_Id;
SimulationState m_SimulationState;
public SimulationState.SPendingCaptureId GetId()
{
return m_Id;
}
public FutureType GetFutureType()
{
return FutureType.Metric;
}
public bool IsPending()
{
return m_SimulationState.IsPending(this);
}
public void Report(Metric metric)
{
m_SimulationState.ReportAsyncResult(this, metric);
}
}
/// <summary>
/// A handle to a sensor managed by the <see cref="DatasetCapture"/>. It can be used to check whether the sensor
/// is expected to capture this frame and report captures, annotations, and metrics regarding the sensor.

internal DatasetCapture datasetCapture { get; }
internal SensorHandle(string id, DatasetCapture datasetCapture)
internal SensorHandle(string id)
this.datasetCapture = datasetCapture;
}
/// <summary>

{
get => datasetCapture.simulationState.IsEnabled(this);
get => DatasetCapture.Instance.simulationState.IsEnabled(this);
datasetCapture.simulationState.SetEnabled(this, value);
DatasetCapture.Instance.simulationState.SetEnabled(this, value);
#if false
/// <summary>
/// Report a file-based annotation related to this sensor in this frame.
/// </summary>
/// <param name="annotationDefinition">The AnnotationDefinition of this annotation.</param>
/// <param name="filename">The path to the file containing the annotation data.</param>
/// <returns>A handle to the reported annotation for reporting annotation-based metrics.</returns>
/// <exception cref="InvalidOperationException">Thrown if this method is called during a frame where <see cref="ShouldCaptureThisFrame"/> is false.</exception>
/// <exception cref="ArgumentException">Thrown if the given AnnotationDefinition is invalid.</exception>
public AnnotationHandle ReportAnnotationFile(AnnotationDefinition annotationDefinition, string filename)
{
if (!ShouldCaptureThisFrame)
throw new InvalidOperationException("Annotation reported on SensorHandle in frame when its ShouldCaptureThisFrame is false.");
if (!annotationDefinition.IsValid)
throw new ArgumentException("The given annotationDefinition is invalid", nameof(annotationDefinition));
return datasetCapture.simulationState.ReportAnnotationFile(annotationDefinition, this, filename);
}
#endif
public AnnotationHandle ReportAnnotation(SoloDesign.AnnotationDefinition definition, SoloDesign.Annotation annotation)
public void ReportAnnotation(AnnotationDefinition definition, Annotation annotation)
{
if (!ShouldCaptureThisFrame)
throw new InvalidOperationException("Annotation reported on SensorHandle in frame when its ShouldCaptureThisFrame is false.");

return datasetCapture.simulationState.ReportAnnotation(this, definition, annotation);
DatasetCapture.Instance.simulationState.ReportAnnotation(this, definition, annotation);
#if false
/// Report a value-based annotation related to this sensor in this frame.
/// Creates an async annotation for reporting the values for an annotation during a future frame.
/// <param name="values">The annotation data, which will be automatically converted to json.</param>
/// <typeparam name="T">The type of the values array.</typeparam>
/// <returns>Returns a handle to the reported annotation for reporting annotation-based metrics.</returns>
/// <returns>Returns a handle to the <see cref="AsyncAnnotation"/>, which can be used to report annotation data during a subsequent frame.</returns>
public AnnotationHandle ReportAnnotationValues<T>(AnnotationDefinition annotationDefinition, T[] values)
public AsyncAnnotationFuture ReportAnnotationAsync(AnnotationDefinition annotationDefinition)
if (!annotationDefinition.IsValid)
if (!annotationDefinition.IsValid())
return datasetCapture.simulationState.ReportAnnotationValues(annotationDefinition, this, values);
return DatasetCapture.Instance.simulationState.ReportAnnotationAsync(annotationDefinition, this);
#endif
/// <summary>
/// Creates an async annotation for reporting the values for an annotation during a future frame.
/// </summary>
/// <param name="annotationDefinition">The AnnotationDefinition of this annotation.</param>
/// <returns>Returns a handle to the <see cref="AsyncAnnotation"/>, which can be used to report annotation data during a subsequent frame.</returns>
/// <exception cref="InvalidOperationException">Thrown if this method is called during a frame where <see cref="ShouldCaptureThisFrame"/> is false.</exception>
/// <exception cref="ArgumentException">Thrown if the given AnnotationDefinition is invalid.</exception>
public AsyncAnnotation ReportAnnotationAsync(SoloDesign.AnnotationDefinition annotationDefinition)
public AsyncSensorFuture ReportSensorAsync(SensorDefinition sensorDefinition)
if (!annotationDefinition.IsValid())
throw new ArgumentException("The given annotationDefinition is invalid", nameof(annotationDefinition));
if (!sensorDefinition.IsValid())
throw new ArgumentException("The given annotationDefinition is invalid", nameof(sensorDefinition));
return datasetCapture.simulationState.ReportAnnotationAsync(annotationDefinition, this);
return DatasetCapture.Instance.simulationState.ReportSensorAsync(sensorDefinition);
/// <summary>
/// Report a sensor capture recorded to disk. This should be called on the same frame as the capture is taken, and may be called before the file is written to disk.
/// </summary>
/// <param name="filename">The path to the capture data.</param>
/// <param name="sensorSpatialData">Spatial data describing the sensor and the ego containing it.</param>
/// <param name="additionalSensorValues">Additional values to be emitted as json name/value pairs on the sensor object under the capture.</param>
/// <exception cref="InvalidOperationException">Thrown if ReportCapture is being called when ShouldCaptureThisFrame is false or it has already been called this frame.</exception>
public void ReportCapture(string filename, SensorSpatialData sensorSpatialData, params(string, object)[] additionalSensorValues)
public void ReportSensor(SensorDefinition definition, Sensor sensor)
{
throw new InvalidOperationException("Capture reported in frame when ShouldCaptureThisFrame is false.");
}
throw new InvalidOperationException("Annotation reported on SensorHandle in frame when its ShouldCaptureThisFrame is false.");
if (!definition.IsValid())
throw new ArgumentException("The given annotationDefinition is invalid", nameof(definition));
datasetCapture.simulationState.ReportCapture(this, filename, sensorSpatialData, additionalSensorValues);
DatasetCapture.Instance.simulationState.ReportSensor(definition, sensor);
}
/// <summary>

public bool ShouldCaptureThisFrame => datasetCapture.simulationState.ShouldCaptureThisFrame(this);
public bool ShouldCaptureThisFrame => DatasetCapture.Instance.simulationState.ShouldCaptureThisFrame(this);
/// Requests a capture from this sensor on the next rendered frame. Can only be used with manual capture mode (<see cref="PerceptionCamera.CaptureTriggerMode.Manual"/>).
/// Requests a capture from this sensor on the next rendered frame. Can only be used with manual capture mode (<see cref="CaptureTriggerMode.Manual"/>).
datasetCapture.simulationState.SetNextCaptureTimeToNowForSensor(this);
DatasetCapture.Instance.simulationState.SetNextCaptureTimeToNowForSensor(this);
/// <summary>
/// Report a metric regarding this sensor in the current frame.
/// </summary>
/// <param name="metricDefinition">The <see cref="MetricDefinition"/> of the metric.</param>
/// <param name="values">An array to be converted to json and put in the "values" field of the metric</param>
/// <typeparam name="T">The value type</typeparam>
/// <exception cref="ArgumentNullException">Thrown if values is null</exception>
/// <exception cref="InvalidOperationException">Thrown if <see cref="ShouldCaptureThisFrame"/> is false.</exception>
public void ReportMetric<T>(MetricDefinition metricDefinition, [NotNull] T[] values)
public MetricHandle ReportMetric(MetricDefinition definition, Metric metric)
if (values == null)
throw new ArgumentNullException(nameof(values));
if (!ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
datasetCapture.simulationState.ReportMetric(metricDefinition, values, this, default);
}
if (metric == null)
throw new ArgumentNullException(nameof(metric));
/// <summary>
/// Report a metric regarding this sensor in the current frame.
/// </summary>
/// <param name="metricDefinition">The <see cref="MetricDefinition"/> of the metric.</param>
/// <param name="valuesJsonArray">A string-based JSON array to be placed in the "values" field of the metric</param>
/// <exception cref="ArgumentNullException">Thrown if values is null</exception>
/// <exception cref="InvalidOperationException">Thrown if <see cref="ShouldCaptureThisFrame"/> is false.</exception>
public void ReportMetric(MetricDefinition metricDefinition, [NotNull] string valuesJsonArray)
{
datasetCapture.simulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), this, default);
return DatasetCapture.Instance.simulationState.ReportMetric(this, definition, metric, default);
#endif
/// <summary>
/// Start an async metric for reporting metric values for this frame in a subsequent frame.
/// </summary>

public AsyncMetric ReportMetricAsync(MetricDefinition metricDefinition)
public AsyncMetricFuture ReportMetricAsync(MetricDefinition metricDefinition)
if (!metricDefinition.IsValid())
throw new ArgumentException("The passed in metric definition is invalid", nameof(metricDefinition));
return datasetCapture.simulationState.CreateAsyncMetric(metricDefinition, this);
return DatasetCapture.Instance.simulationState.CreateAsyncMetric(metricDefinition, this);
#endif
/// <summary>
/// Dispose this SensorHandle.
/// </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.Instance.IsValid(this.Id);
/// <summary>
/// Returns true if this SensorHandle was default-instantiated.

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

}
/// <summary>
/// Handle to a metric whose values may be reported in a subsequent frame.
/// A handle to an annotation. Can be used to report metrics on the annotation.
public struct AsyncMetric
public readonly struct AnnotationHandle : IEquatable<AnnotationHandle>
internal readonly int Id;
readonly SimulationState m_SimulationState;
internal AsyncMetric(MetricDefinition metricDefinition, int id, SimulationState simulationState)
{
this.Id = id;
MetricDefinition = metricDefinition;
m_SimulationState = simulationState;
}
/// <summary>
/// The MetricDefinition associated with this AsyncMetric.
/// </summary>
public readonly MetricDefinition MetricDefinition;
/// <summary>
/// True if the simulation is still running.
/// </summary>
public bool IsValid => !IsNil && m_SimulationState.IsRunning;
readonly AnnotationDefinition m_Definition;
/// True if ReportValues has not been called yet.
/// The ID of the annotation which will be used in the json metadata.
// public bool IsPending => !IsNil && m_SimulationState.IsPending(ref this);
public string Id => m_Definition.id;
/// Returns true if the AsyncMetric is its default value.
/// </summary>
public bool IsNil => m_SimulationState == null && Id == default;
/// <summary>
/// Report the values for this AsyncMetric. Calling this method will transition <see cref="IsPending"/> to false.
/// ReportValues may only be called once per AsyncMetric.
/// </summary>
/// <param name="values">The values to report for the metric. These values will be converted to json.</param>
/// <typeparam name="T">The type of the values</typeparam>
/// <exception cref="ArgumentNullException">Thrown if values is null</exception>
public void ReportValues<T>(T[] values)
{
if (values == null)
throw new ArgumentNullException(nameof(values));
// m_SimulationState.ReportAsyncMetricResult(this, values: values);
}
/// <summary>
/// Report the values for this AsyncMetric. Calling this method will transition <see cref="IsPending"/> to false.
/// ReportValues may only be called once per AsyncMetric.
/// </summary>
/// <param name="valuesJsonArray">A JSON array in string form.</param>
/// <exception cref="ArgumentNullException">Thrown if values is null</exception>
public void ReportValues(string valuesJsonArray)
{
if (valuesJsonArray == null)
throw new ArgumentNullException(nameof(valuesJsonArray));
// m_SimulationState.ReportAsyncMetricResult(this, valuesJsonArray);
}
}
/// <summary>
/// A handle to an async annotation, used to report values for an annotation after the frame for the annotation has past.
/// See <see cref="SensorHandle.ReportAnnotationAsync"/>
/// </summary>
public struct AsyncAnnotation
{
internal AsyncAnnotation(AnnotationHandle annotationHandle, SimulationState simulationState)
{
this.annotationHandle = annotationHandle;
m_SimulationState = simulationState;
}
#if false
internal AsyncAnnotation(AnnotationHandle annotationHandle, int step, SensorHandle sensorHandle, SimulationState simulationState)
{
this.annotationHandle = annotationHandle;
m_SimulationState = simulationState;
}
#endif
/// <summary>
/// The annotation associated with this AsyncAnnotation. Can be used to report metrics on the annotation.
/// </summary>
public readonly AnnotationHandle annotationHandle;
readonly SimulationState m_SimulationState;
/// <summary>
/// True if the annotation is nil (was created using default instantiation)
/// </summary>
internal bool IsNil => m_SimulationState == null && annotationHandle.IsNil;
/// <summary>
/// True if the annotation is generated by the currently running simulation.
/// </summary>
public bool IsValid => !IsNil && m_SimulationState.IsRunning;
/// <summary>
/// True if neither <see cref="ReportValues{T}"/> nor <see cref="ReportFile"/> have been called.
/// </summary>
public bool IsPending => !IsNil && m_SimulationState.IsPending(annotationHandle);
public void Report(SoloDesign.Annotation annotation)
{
if (annotation == null)
throw new ArgumentNullException();
m_SimulationState.ReportAsyncAnnotationResult(this, annotation);
}
}
/// <summary>
/// A handle to an annotation. Can be used to report metrics on the annotation.
/// </summary>
public struct AnnotationHandle : IEquatable<AnnotationHandle>
{
/// <summary>
/// The ID of the annotation which will be used in the json metadata.
/// </summary>
public readonly string Id;
/// <summary>
/// The step on which the annotation was reported.
/// </summary>
public readonly int Step;
/// <summary>
SimulationState m_SimulationState;
internal AnnotationHandle(SensorHandle sensorHandle, SimulationState simState, AnnotationDefinition definition, int step)
internal AnnotationHandle(SensorHandle sensorHandle, AnnotationDefinition definition, int sequence, int step)
m_SimulationState = simState;
Id = definition.id;
m_Definition = definition;
Step = step;
}
/// <summary>

#if false
/// <summary>
/// Reports a metric on this annotation. May only be called in the same frame as the annotation was reported.
/// </summary>
/// <param name="metricDefinition"></param>
/// <param name="values"></param>
/// <typeparam name="T"></typeparam>
/// <exception cref="ArgumentNullException">Thrown if values is null</exception>
/// <exception cref="InvalidOperationException">Thrown if <see cref="AnnotationHandle.SensorHandle"/> reports false for <see cref="UnityEngine.Perception.GroundTruth.SensorHandle.ShouldCaptureThisFrame"/>.</exception>
public void ReportMetric<T>(MetricDefinition metricDefinition, [NotNull] T[] values)
{
if (values == null)
throw new ArgumentNullException(nameof(values));
if (!SensorHandle.ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
m_SimulationState.ReportMetric(metricDefinition, values, SensorHandle, this);
}
/// <summary>
/// Reports a metric on this annotation. May only be called in the same frame as the annotation was reported.
/// </summary>
/// <param name="metricDefinition"></param>
/// <param name="valuesJsonArray">A string-based JSON array to be placed in the "values" field of the metric</param>
/// <exception cref="ArgumentNullException">Thrown if values is null</exception>
/// <exception cref="InvalidOperationException">Thrown if <see cref="AnnotationHandle.SensorHandle"/> reports false for
/// <see cref="UnityEngine.Perception.GroundTruth.SensorHandle.ShouldCaptureThisFrame"/>.</exception>
public void ReportMetric(MetricDefinition metricDefinition, [NotNull] string valuesJsonArray)
{
if (valuesJsonArray == null)
throw new ArgumentNullException(nameof(valuesJsonArray));
if (!SensorHandle.ShouldCaptureThisFrame)
throw new InvalidOperationException($"Sensor-based metrics may only be reported when SensorHandle.ShouldCaptureThisFrame is true");
m_SimulationState.ReportMetric(metricDefinition, new JRaw(valuesJsonArray), SensorHandle, this);
}
/// <summary>
/// Report a metric whose values will be supplied in a later frame.
/// </summary>
/// <param name="metricDefinition">The type of the metric.</param>
/// <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) => m_SimulationState.CreateAsyncMetric(metricDefinition, SensorHandle, this);
#endif
return Id.Equals(other.Id);
return SensorHandle.Equals(other.SensorHandle) && m_Definition.Equals(other.m_Definition);
}
/// <inheritdoc/>

/// <inheritdoc/>
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
#if false
/// <summary>
/// A metric type, used to define a kind of metric. <see cref="DatasetCapture.RegisterMetricDefinition"/>.
/// </summary>
public struct MetricDefinition : IEquatable<MetricDefinition>
{
/// <summary>
/// The ID of the metric
/// </summary>
public readonly Guid Id;
internal MetricDefinition(Guid id)
{
Id = id;
}
/// <inheritdoc />
public bool Equals(MetricDefinition other)
{
return Id.Equals(other.Id);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is MetricDefinition other && Equals(other);
}
/// <inheritdoc />
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
#endif
#if false
/// <summary>
/// A metric type, used to define a kind of annotation. <see cref="DatasetCapture.RegisterAnnotationDefinition"/>.
/// </summary>
public struct AnnotationDefinition : IEquatable<AnnotationDefinition>
{
/// <inheritdoc/>
public bool Equals(AnnotationDefinition other)
{
return Id.Equals(other.Id);
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is AnnotationDefinition other && Equals(other);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return Id.GetHashCode();
}
/// <summary>
/// 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 => m_SimulationState.IsValid(Id);
SimulationState m_SimulationState;
internal AnnotationDefinition(Guid id, SimulationState simState)
{
Id = id;
m_SimulationState = simState;
}
}
#endif
/// <summary>
/// Container holding the poses of the ego and sensor. Also optionally contains the ego velocity and acceleration.
/// </summary>
public struct SensorSpatialData
{
/// <summary>
/// The pose of the ego.
/// </summary>
public Pose EgoPose;
/// <summary>
/// The pose of the sensor relative to the ego.
/// </summary>
public Pose SensorPose;
/// <summary>
/// The velocity of the ego (optional).
/// </summary>
public Vector3? EgoVelocity;
/// <summary>
/// The acceleration of the ego (optional).
/// </summary>
public Vector3? EgoAcceleration;
/// <summary>
/// Create a new SensorSpatialData with the given values.
/// </summary>
/// <param name="egoPose">The pose of the ego.</param>
/// <param name="sensorPose">The pose of the sensor relative to the ego.</param>
/// <param name="egoVelocity">The velocity of the ego.</param>
/// <param name="egoAcceleration">The acceleration of the ego.</param>
public SensorSpatialData(Pose egoPose, Pose sensorPose, Vector3? egoVelocity, Vector3? egoAcceleration)
{
EgoPose = egoPose;
SensorPose = sensorPose;
EgoVelocity = egoVelocity;
EgoAcceleration = egoAcceleration;
}
/// <summary>
/// Create a SensorSpatialData from two <see cref="UnityEngine.GameObject"/>s, one representing the ego and the other representing the sensor.
/// </summary>
/// <param name="ego">The ego GameObject.</param>
/// <param name="sensor">The sensor GameObject.</param>
/// <returns>Returns a SensorSpatialData filled out with EgoPose and SensorPose based on the given objects.</returns>
public static SensorSpatialData FromGameObjects(GameObject ego, GameObject sensor)
{
ego = ego == null ? sensor : ego;
var egoRotation = ego.transform.rotation;
var egoPosition = ego.transform.position;
var sensorSpatialData = new SensorSpatialData()
{
EgoPose = new Pose(egoPosition, egoRotation),
SensorPose = new Pose(sensor.transform.position - egoPosition, sensor.transform.rotation * Quaternion.Inverse(egoRotation))
};
return sensorSpatialData;
var hash = (Id != null ? StringComparer.InvariantCulture.GetHashCode(Id) : 0);
return hash;
}
}
}

4
com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBox3DLabeler.cs


static ProfilerMarker s_BoundingBoxCallback = new ProfilerMarker("OnBoundingBoxes3DReceived");
// AnnotationDefinition m_AnnotationDefinition;
Dictionary<int, AsyncAnnotation> m_AsyncAnnotations;
Dictionary<int, AsyncAnnotationFuture> m_AsyncAnnotations;
Dictionary<int, Dictionary<uint, BoxData>> m_BoundingBoxValues;
List<BoxData> m_ToReport;

#endif
perceptionCamera.RenderedObjectInfosCalculated += OnRenderObjectInfosCalculated;
m_AsyncAnnotations = new Dictionary<int, AsyncAnnotation>();
m_AsyncAnnotations = new Dictionary<int, AsyncAnnotationFuture>();
m_BoundingBoxValues = new Dictionary<int, Dictionary<uint, BoxData>>();
m_ToReport = new List<BoxData>();
}

26
com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBoxLabeler.cs


using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using UnityEngine.Perception.GroundTruth.DataModel;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using UnityEngine.UI;
namespace UnityEngine.Perception.GroundTruth
{

[Serializable]
public sealed class BoundingBox2DLabeler : CameraLabeler
{
public class AnnotationDefinition : SoloDesign.AnnotationDefinition
public class BoundingBoxAnnotationDefinition : AnnotationDefinition
public AnnotationDefinition() : base(k_Id, k_Description, k_AnnotationType) { }
public BoundingBoxAnnotationDefinition() : base(k_Id, k_Description, k_AnnotationType) { }
public AnnotationDefinition(IEnumerable<Entry> spec)
public BoundingBoxAnnotationDefinition(IEnumerable<DefinitionEntry> spec)
: base(k_Id, k_Description, k_AnnotationType)
{
this.spec = spec;

public struct Entry : IMessageProducer
public struct DefinitionEntry : IMessageProducer
public Entry(int id, string name)
public DefinitionEntry(int id, string name)
{
labelId = id;
labelName = name;

}
}
public IEnumerable<Entry> spec;
public IEnumerable<DefinitionEntry> spec;
public override void ToMessage(IMessageBuilder builder)
{

}
}
AnnotationDefinition m_AnnotationDefinition = new AnnotationDefinition();
AnnotationDefinition m_AnnotationDefinition = new BoundingBoxAnnotationDefinition();
public class BoundingBoxAnnotation : SoloDesign.Annotation
public class BoundingBoxAnnotation : Annotation
{
public struct Entry
{

[FormerlySerializedAs("labelingConfiguration")]
public IdLabelConfig idLabelConfig;
Dictionary<int, (AsyncAnnotation annotation, LabelEntryMatchCache labelEntryMatchCache)> m_AsyncData;
Dictionary<int, (AsyncAnnotationFuture annotation, LabelEntryMatchCache labelEntryMatchCache)> m_AsyncData;
List<BoundingBoxAnnotation.Entry> m_BoundingBoxValues;
Vector2 m_OriginalScreenSize = Vector2.zero;

if (idLabelConfig == null)
throw new InvalidOperationException("BoundingBox2DLabeler's idLabelConfig field must be assigned");
m_AsyncData = new Dictionary<int, (AsyncAnnotation annotation, LabelEntryMatchCache labelEntryMatchCache)>();
m_AsyncData = new Dictionary<int, (AsyncAnnotationFuture annotation, LabelEntryMatchCache labelEntryMatchCache)>();
DatasetCapture.RegisterAnnotationDefinition(new AnnotationDefinition());
DatasetCapture.RegisterAnnotationDefinition(m_AnnotationDefinition);
#if false
m_BoundingBoxAnnotationDefinition = DatasetCapture.RegisterAnnotationDefinition("bounding box", idLabelConfig.GetAnnotationSpecification(),
"Bounding box for each labeled object visible to the sensor", id: new Guid(annotationId));

76
com.unity.perception/Runtime/GroundTruth/Labelers/InstanceSegmentationLabeler.cs


using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Unity.Simulation;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using UnityEngine.Profiling;
using UnityEngine.Perception.GroundTruth.DataModel;
using UnityEngine.Perception.GroundTruth.Exporters.Solo;
using UnityEngine.Rendering;
namespace UnityEngine.Perception.GroundTruth

[Serializable]
public sealed class InstanceSegmentationLabeler : CameraLabeler, IOverlayPanelProvider
{
[Serializable]
public class InstanceSegmentationDefinition : AnnotationDefinition
{
static readonly string k_Id = "instance segmentation";
static readonly string k_Description = "You know the deal";
static readonly string k_AnnotationType = "instance segmentation";
public InstanceSegmentationDefinition() : base(k_Id, k_Description, k_AnnotationType) { }
}
/// <summary>
/// The instance segmentation image recorded for a capture. This
/// includes the data that associates a pixel color to an object.
/// </summary>
[Serializable]
public class InstanceSegmentation : Annotation
{
public struct Entry
{
/// <summary>
/// The instance ID associated with a pixel color
/// </summary>
public int instanceId;
/// <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>
/// This instance to pixel map
/// </summary>
public List<Entry> instances;
// The format of the image type
public string imageFormat;
// The dimensions (width, height) of the image
public Vector2 dimension;
// The raw bytes of the image file
public byte[] buffer;
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);
}
}
}
InstanceSegmentationDefinition m_Definition = new InstanceSegmentationDefinition();
///<inheritdoc/>

static ProfilerMarker s_OnObjectInfoReceivedCallback = new ProfilerMarker("OnInstanceSegmentationObjectInformationReceived");
static ProfilerMarker s_OnImageReceivedCallback = new ProfilerMarker("OnInstanceSegmentationImagesReceived");
Dictionary<int, (AsyncAnnotation annotation, byte[] buffer)> m_AsyncData;
Dictionary<int, (AsyncAnnotationFuture future, byte[] buffer)> m_AsyncData;
Texture m_CurrentTexture;
/// <inheritdoc cref="IOverlayPanelProvider"/>

buffer = asyncData.buffer
};
asyncData.annotation.Report(toReport);
asyncData.future.Report(toReport);
}
}

perceptionCamera.InstanceSegmentationImageReadback += OnImageCaptured;
perceptionCamera.RenderedObjectInfosCalculated += OnRenderedObjectInfosCalculated;
m_AsyncData = new Dictionary<int, (AsyncAnnotation, byte[])>();
m_AsyncData = new Dictionary<int, (AsyncAnnotationFuture, byte[])>();
visualizationEnabled = supportsVisualization;
}

4
com.unity.perception/Runtime/GroundTruth/Labelers/KeypointLabeler.cs


// AnnotationDefinition m_AnnotationDefinition;
Texture2D m_MissingTexture;
Dictionary<int, (AsyncAnnotation annotation, Dictionary<uint, KeypointEntry> keypoints)> m_AsyncAnnotations;
Dictionary<int, (AsyncAnnotationFuture annotation, Dictionary<uint, KeypointEntry> keypoints)> m_AsyncAnnotations;
List<KeypointEntry> m_KeypointEntriesToReport;
int m_CurrentFrame;

m_KnownStatus = new Dictionary<uint, CachedData>();
m_AsyncAnnotations = new Dictionary<int, (AsyncAnnotation, Dictionary<uint, KeypointEntry>)>();
m_AsyncAnnotations = new Dictionary<int, (AsyncAnnotationFuture, Dictionary<uint, KeypointEntry>)>();
m_KeypointEntriesToReport = new List<KeypointEntry>();
m_CurrentFrame = 0;

95
com.unity.perception/Runtime/GroundTruth/Labelers/ObjectCountLabeler.cs


using System.Diagnostics.CodeAnalysis;
using Unity.Collections;
using Unity.Profiling;
using UnityEngine.Perception.GroundTruth.DataModel;
using UnityEngine.UI;
namespace UnityEngine.Perception.GroundTruth
{

[Serializable]
public sealed class ObjectCountLabeler : CameraLabeler
{
/// <summary>
/// The object count metric records how many of a particular object are
/// present in a capture.
/// </summary>
[Serializable]
public class ObjectCountMetric : Metric
{
public struct Entry
{
/// <summary>
/// The label of the category
/// </summary>
public string labelName;
/// <summary>
/// The number of instances for a particular category.
/// </summary>
public int count;
}
/// <summary>
/// The object counts
/// </summary>
public IEnumerable<Entry> objectCounts;
}
static readonly string k_Id = "ObjectCount";
static readonly string k_Description = "Produces object counts for each label defined in this labeler's associated label configuration.";
get => "Produces object counts for each label defined in this labeler's associated label configuration.";
get => k_Description;
/// The ID to use for object count annotations in the resulting dataset
/// </summary>
public string objectCountMetricId = "51da3c27-369d-4929-aea6-d01614635ce2";
/// <summary>
/// The <see cref="IdLabelConfig"/> which associates objects with labels.
/// </summary>
public IdLabelConfig labelConfig

static ProfilerMarker s_ClassCountCallback = new ProfilerMarker("OnClassLabelsReceived");
ClassCountValue[] m_ClassCountValues;
ObjectCountMetric.Entry[] m_ClassCountValues;
Dictionary<int, AsyncMetric> m_ObjectCountAsyncMetrics;
MetricDefinition m_ObjectCountMetricDefinition;
Dictionary<int, AsyncMetricFuture> m_AsyncMetrics;
MetricDefinition m_Definition = new MetricDefinition(k_Id, k_Description);
/// <summary>
/// Creates a new ObjectCountLabeler. This constructor should only be used by serialization. For creation from

m_LabelConfig = labelConfig;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
struct ClassCountValue
{
public int label_id;
public string label_name;
public uint count;
}
/// <inheritdoc/>
protected override bool supportsVisualization => true;

if (labelConfig == null)
throw new InvalidOperationException("The ObjectCountLabeler idLabelConfig field must be assigned");
m_ObjectCountAsyncMetrics = new Dictionary<int, AsyncMetric>();
m_AsyncMetrics = new Dictionary<int, AsyncMetricFuture>();
NativeArray<uint> objectCounts = ComputeObjectCounts(objectInfo);
var objectCounts = ComputeObjectCounts(objectInfo);
m_Definition = new MetricDefinition
{
id = k_Id,
description = k_Description
};
DatasetCapture.RegisterMetric(m_Definition);
visualizationEnabled = supportsVisualization;
}

#if true
if (m_ObjectCountMetricDefinition.Equals(default))
{
m_ObjectCountMetricDefinition = DatasetCapture.RegisterMetricDefinition("object count",
m_LabelConfig.GetAnnotationSpecification(),
"Counts of objects for each label in the sensor's view", id: new Guid(objectCountMetricId));
}
m_ObjectCountAsyncMetrics[Time.frameCount] = perceptionCamera.SensorHandle.ReportMetricAsync(m_ObjectCountMetricDefinition);
m_AsyncMetrics[Time.frameCount] = perceptionCamera.SensorHandle.ReportMetricAsync(m_Definition);
#endif
}

{
using (s_ClassCountCallback.Auto())
{
if (!m_ObjectCountAsyncMetrics.TryGetValue(frameCount, out var classCountAsyncMetric))
if (!m_AsyncMetrics.TryGetValue(frameCount, out var classCountAsyncMetric))
m_ObjectCountAsyncMetrics.Remove(frameCount);
m_AsyncMetrics.Remove(frameCount);
m_ClassCountValues = new ClassCountValue[entries.Count];
m_ClassCountValues = new ObjectCountMetric.Entry[entries.Count]; //ClassCountValue[entries.Count];
var visualize = visualizationEnabled;

for (var i = 0; i < entries.Count; i++)
{
m_ClassCountValues[i] = new ClassCountValue()
m_ClassCountValues[i] = new ObjectCountMetric.Entry
label_id = entries[i].id,
label_name = entries[i].label,
count = counts[i]
labelName = entries[i].label,
count = (int)counts[i]
};
// Only display entries with a count greater than 0

}
}
classCountAsyncMetric.ReportValues(m_ClassCountValues);
var payload = new ObjectCountMetric
{
sensorId = "",
annotationId = default,
description = m_Definition.description,
metadata = new Dictionary<string, object>(),
objectCounts = m_ClassCountValues
};
classCountAsyncMetric.Report(payload);
}
}

6
com.unity.perception/Runtime/GroundTruth/Labelers/RenderedObjectInfoLabeler.cs


public IdLabelConfig idLabelConfig;
RenderedObjectInfoValue[] m_VisiblePixelsValues;
Dictionary<int, AsyncMetric> m_ObjectInfoAsyncMetrics;
Dictionary<int, AsyncMetricFuture> m_ObjectInfoAsyncMetrics;
// MetricDefinition m_RenderedObjectInfoMetricDefinition;
/// <summary>

if (idLabelConfig == null)
throw new InvalidOperationException("RenderedObjectInfoLabeler's idLabelConfig field must be assigned");
m_ObjectInfoAsyncMetrics = new Dictionary<int, AsyncMetric>();
m_ObjectInfoAsyncMetrics = new Dictionary<int, AsyncMetricFuture>();
perceptionCamera.RenderedObjectInfosCalculated += (frameCount, objectInfo) =>
{

}
}
metric.ReportValues(m_VisiblePixelsValues);
// metric.Report(m_VisiblePixelsValues);
}
}

4
com.unity.perception/Runtime/GroundTruth/Labelers/SemanticSegmentationLabeler.cs


LensDistortionUrpPass m_LensDistortionPass;
#endif
Dictionary<int, AsyncAnnotation> m_AsyncAnnotations;
Dictionary<int, AsyncAnnotationFuture> m_AsyncAnnotations;
/// <summary>
/// Creates a new SemanticSegmentationLabeler. Be sure to assign <see cref="labelConfig"/> before adding to a <see cref="PerceptionCamera"/>.

"SemanticSegmentationLabeler's LabelConfig must be assigned");
}
m_AsyncAnnotations = new Dictionary<int, AsyncAnnotation>();
m_AsyncAnnotations = new Dictionary<int, AsyncAnnotationFuture>();
if (targetTexture != null)
{

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


using Unity.Simulation;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using UnityEngine.Perception.GroundTruth.DataModel;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
#if HDRP_PRESENT

SensorHandle = default;
}
SensorDefinition m_SensorDefinition;
var sensorDef = new SensorDefinition(ID, "camera", description)
m_SensorDefinition = new SensorDefinition(ID, "camera", description)
{
firstCaptureFrame = firstCaptureFrame,
captureTriggerMode = captureTriggerMode.ToString(),

};
SensorHandle = DatasetCapture.Instance.RegisterSensor(sensorDef);
SensorHandle = DatasetCapture.Instance.RegisterSensor(m_SensorDefinition);
}
}

void CaptureRgbData(Camera cam)
{
// TODO - Steve - this could be a place where we override the capture of the RGB image to allow the
// active reporter to determine where we should save RGB images, or even write them out
var width = cam.pixelWidth;
var height = cam.pixelHeight;
var capture = new RgbSensor
{
Id = "perception_camera",
sensorType = "rgb_camera",
description = "you know",
position = transform.position,
rotation = transform.eulerAngles,
velocity = Vector3.zero,
acceleration = Vector3.zero,
imageFormat = ".png",
dimension = new Vector2(cam.pixelWidth, cam.pixelHeight),
buffer = null
};
//var width = cam.pixelWidth;
//var height = cam.pixelHeight;
var captureFilename = $"{Manager.Instance.GetDirectoryFor(rgbDirectory)}/{k_RgbFilePrefix}{frameCount}.png";
//var captureFilename = $"{Manager.Instance.GetDirectoryFor(rgbDirectory)}/{k_RgbFilePrefix}{frameCount}.png";
SetPersistentSensorData("camera_width", width);
SetPersistentSensorData("camera_height", height);
SetPersistentSensorData("full_path", captureFilename);
SetPersistentSensorData("frame", frameCount);
// Record the camera's projection type (orthographic or perspective)
var dxRootPath = $"{rgbDirectory}/{k_RgbFilePrefix}{Time.frameCount}.png";
var asyncSensor = SensorHandle.ReportSensorAsync(m_SensorDefinition);
#if false
#endif
Func<AsyncRequest<CaptureCamera.CaptureState>, AsyncRequest.Result> colorFunctor;
colorFunctor = r =>

using (s_EncodeAndSave.Auto())
{
encodedData = ImageConversion.EncodeArrayToPNG(
dataColorBuffer, GraphicsFormat.R8G8B8A8_UNorm, (uint)width, (uint)height);
dataColorBuffer, GraphicsFormat.R8G8B8A8_UNorm, (uint)capture.dimension.x, (uint)capture.dimension.y);
#if false
#endif
capture.buffer = encodedData;
asyncSensor.Report(capture);
return AsyncRequest.Result.Completed;
}
};

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


using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Unity.Collections;
using Unity.Simulation;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using UnityEngine.Perception.GroundTruth.DataModel;
using UnityEngine.Profiling;
namespace UnityEngine.Perception.GroundTruth

int m_CaptureFileIndex;
List<AdditionalInfoTypeData> m_AdditionalInfoTypeData = new List<AdditionalInfoTypeData>();
List<PendingCapture> m_PendingCaptures = new List<PendingCapture>(k_MinPendingCapturesBeforeWrite + 10);
// List<PendingMetric> m_PendingMetrics = new List<PendingMetric>(k_MinPendingMetricsBeforeWrite + 10);
int m_MetricsFileIndex;
// int m_NextMetricId = 1;
Dictionary<SPendingFrameId, int> m_PendingIdToFrameMap = new Dictionary<SPendingFrameId, int>();
Dictionary<SPendingFrameId, PendingFrame> m_PendingFrames = new Dictionary<SPendingFrameId, PendingFrame>();
CustomSampler m_SerializeCapturesSampler = CustomSampler.Create("SerializeCaptures");
CustomSampler m_SerializeCapturesAsyncSampler = CustomSampler.Create("SerializeCapturesAsync");

CustomSampler m_SerializeMetricsAsyncSampler = CustomSampler.Create("SerializeMetricsAsync");
CustomSampler m_GetOrCreatePendingCaptureForThisFrameSampler = CustomSampler.Create("GetOrCreatePendingCaptureForThisFrame");
float m_LastTimeScale;
string m_OutputDirectoryPath;
public const string userBaseDirectoryKey = "userBaseDirectory";
public const string latestOutputDirectoryKey = "latestOutputDirectory";
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

const float k_SimulationTimingAccuracy = 0.01f;
const int k_MinPendingCapturesBeforeWrite = 150;
const int k_MinPendingMetricsBeforeWrite = 150;
public SimulationState()
{

static PerceptionConsumer GetActiveConsumer()
static ConsumerEndpoint GetActiveConsumer()
/// <summary>
/// A self-sufficient container for all information about a reported capture. Capture writing should not depend on any
/// state outside of this container, as other state may have changed since the capture was reported.
/// </summary>
public class PendingCapture
public interface IPendingId
public SensorHandle SensorHandle;
public SensorData SensorData;
public SensorSpatialData SensorSpatialData;
public int FrameCount;
public int Step;
public float Timestamp;
public int SequenceId;
public (string, object)[] AdditionalSensorValues;
public List<(AnnotationHandle, Annotation)> Annotations = new List<(AnnotationHandle, Annotation)>();
public bool CaptureReported;
SPendingFrameId AsFrameId();
SPendingSensorId AsSensorId();
public (int, int) Id => (SequenceId, Step);
bool IsValid();
}
public PendingCapture(SensorHandle sensorHandle, SensorData sensorData, int sequenceId, int frameCount, int step, float timestamp)
public readonly struct SPendingFrameId : IPendingId, IEquatable<SPendingFrameId>, IEquatable<SPendingSensorId>, IEquatable<SPendingCaptureId>
{
public SPendingFrameId(int sequence, int step)
SensorHandle = sensorHandle;
FrameCount = frameCount;
Sequence = sequence;
SequenceId = sequenceId;
Timestamp = timestamp;
SensorData = sensorData;
}
public bool IsValid()
{
return Sequence >= 0 && Step >= 0;
}
public int Sequence { get; }
public int Step { get; }
public SPendingFrameId AsFrameId()
{
return this;
}
public SPendingSensorId AsSensorId()
{
return new SPendingSensorId(string.Empty,this);
}
public bool Equals(SPendingFrameId other)
{
return Sequence == other.Sequence && Step == other.Step;
}
public bool Equals(SPendingSensorId other)
{
var otherId = other.AsFrameId();
return Sequence == otherId.Sequence && Step == otherId.Step;
}
public bool Equals(SPendingCaptureId other)
{
var otherId = other.AsFrameId();
return Sequence == otherId.Sequence && Step == otherId.Step;
}
public override bool Equals(object obj)
{
return obj is SPendingFrameId other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (Sequence * 397) ^ Step;
}
}
}
public readonly struct SPendingSensorId : IPendingId, IEquatable<SPendingSensorId>, IEquatable<SPendingFrameId>, IEquatable<SPendingCaptureId>
{
public SPendingSensorId(string sensorId, int sequence, int step)
{
SensorId = sensorId;
m_FrameId = new SPendingFrameId(sequence, step);
}
public SPendingSensorId(string sensorId, SPendingFrameId frameId)
{
SensorId = sensorId;
m_FrameId = frameId;
}
public bool IsValid()
{
return m_FrameId.IsValid() && !string.IsNullOrEmpty(SensorId);
}
public string SensorId { get; }
readonly SPendingFrameId m_FrameId;
public SPendingFrameId AsFrameId()
{
return m_FrameId;
}
public SPendingSensorId AsSensorId()
{
return this;
}
public bool Equals(SPendingSensorId other)
{
return SensorId == other.SensorId && m_FrameId.Equals(other.m_FrameId);
}
public bool Equals(SPendingFrameId other)
{
return m_FrameId.Equals(other);
}
public bool Equals(SPendingCaptureId other)
{
return Equals(other.SensorId);
}
public override bool Equals(object obj)
{
return obj is SPendingSensorId other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return ((SensorId != null ? SensorId.GetHashCode() : 0) * 397) ^ m_FrameId.GetHashCode();
}
#if false
public struct PendingMetric
public readonly struct SPendingCaptureId : IPendingId, IEquatable<SPendingCaptureId>, IEquatable<SPendingSensorId>, IEquatable<SPendingFrameId>
public PendingMetric(MetricDefinition metricDefinition, int metricId, SensorHandle sensorHandle, AnnotationHandle annotationHandle, int sequenceId, int step, JToken values = null)
public SPendingCaptureId(string sensorId, string captureId, int sequence, int step)
MetricDefinition = metricDefinition;
MetricId = metricId;
SensorHandle = sensorHandle;
AnnotationHandle = annotationHandle;
SequenceId = sequenceId;
Step = step;
Values = values;
CaptureId = captureId;
SensorId = new SPendingSensorId(sensorId, sequence, step);
}
public SPendingCaptureId(string captureId, SPendingSensorId frameId)
{
CaptureId = captureId;
SensorId = frameId;
}
public string CaptureId { get; }
public SPendingSensorId SensorId { get; }
public SPendingFrameId AsFrameId()
{
return SensorId.AsFrameId();
}
public SPendingSensorId AsSensorId()
{
return SensorId;
}
public bool IsValid()
{
return SensorId.IsValid() && !string.IsNullOrEmpty(CaptureId);
}
public bool Equals(SPendingCaptureId other)
{
return CaptureId == other.CaptureId && SensorId.Equals(other.SensorId);
}
public bool Equals(SPendingSensorId other)
{
return SensorId.Equals(other);
}
public bool Equals(SPendingFrameId other)
{
return SensorId.AsFrameId().Equals(other);
}
public override bool Equals(object obj)
{
return obj is SPendingCaptureId other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return ((CaptureId != null ? CaptureId.GetHashCode() : 0) * 397) ^ SensorId.GetHashCode();
}
}
}
public class PendingSensor
{
public PendingSensor(SPendingSensorId id)
{
m_Id = id;
m_SensorData = null;
Annotations = new Dictionary<SPendingCaptureId, Annotation>();
Metrics = new Dictionary<SPendingCaptureId, Metric>();
}
public PendingSensor(SPendingSensorId id, Sensor sensorData) : this(id)
{
m_SensorData = sensorData;
}
public Sensor ToSensor()
{
if (!IsReadyToReport()) return null;
m_SensorData.annotations = Annotations.Select(kvp => kvp.Value);
m_SensorData.metrics = Metrics.Select(kvp => kvp.Value);
return m_SensorData;
}
SPendingSensorId m_Id;
Sensor m_SensorData;
public Dictionary<SPendingCaptureId, Annotation> Annotations { get; private set; }
public Dictionary<SPendingCaptureId, Metric> Metrics { get; private set; }
public bool IsPending<T>(IAsyncFuture<T> asyncFuture) where T : IPendingId
{
switch (asyncFuture.GetFutureType())
{
case FutureType.Sensor:
return m_SensorData == null;
case FutureType.Annotation:
{
return asyncFuture.GetId() is SPendingCaptureId captureId && Annotations.ContainsKey(captureId) && Annotations[captureId] == null;
}
case FutureType.Metric:
{
return asyncFuture.GetId() is SPendingCaptureId captureId && Annotations.ContainsKey(captureId) && Metrics[captureId] == null;
}
default:
throw new ArgumentOutOfRangeException();
}
}
public bool ReportAsyncResult<T>(IAsyncFuture<T> asyncFuture, object result) where T : IPendingId
{
switch (asyncFuture.GetFutureType())
{
case FutureType.Sensor:
if (result is Sensor sensor)
{
m_SensorData = sensor;
return true;
}
return false;
case FutureType.Annotation:
{
if (result is Annotation annotation && asyncFuture.GetId() is SPendingCaptureId capId)
{
Annotations[capId] = annotation;
return true;
}
return false;
}
case FutureType.Metric:
{
if (result is Metric metric && asyncFuture.GetId() is SPendingCaptureId capId)
{
Metrics[capId] = metric;
return true;
}
return false;
}
default:
throw new ArgumentOutOfRangeException();
}
}
public bool IsReadyToReport()
{
return
m_SensorData != null &&
Metrics.All(i => i.Value != null) &&
Annotations.All(i => i.Value != null);
}
}
public class PendingFrame
{
public SPendingFrameId PendingId { get; }
public float Timestamp { get; set; }
internal Dictionary<SPendingSensorId, PendingSensor> sensors = new Dictionary<SPendingSensorId, PendingSensor>();
public bool CaptureReported { get; set; } = false;
public PendingFrame(SPendingFrameId pendingFrameId, float timestamp)
{
PendingId = pendingFrameId;
Timestamp = timestamp;
}
public bool IsReadyToReport()
{
return sensors.All(sensor => sensor.Value.IsReadyToReport());
}
public PendingSensor GetOrCreatePendingSensor(SPendingSensorId sensorId)
{
return GetOrCreatePendingSensor(sensorId, out var _);
}
public PendingSensor GetOrCreatePendingSensor(SPendingSensorId sensorId, out bool created)
{
created = false;
if (!sensors.TryGetValue(sensorId, out var pendingSensor))
{
pendingSensor = new PendingSensor(sensorId);
sensors[sensorId] = pendingSensor;
created = true;
}
return pendingSensor;
}
public bool IsPending<T>(IAsyncFuture<T> asyncFuture) where T : IPendingId
{
var sensorId = asyncFuture.GetId().AsSensorId();
if (!sensorId.IsValid()) return false;
return
sensors.TryGetValue(sensorId, out var pendingSensor) &&
pendingSensor.IsPending(asyncFuture);
// ReSharper disable NotAccessedField.Local
public readonly SensorHandle SensorHandle;
public readonly MetricDefinition MetricDefinition;
public readonly int MetricId;
public (int, int) CaptureId => (SequenceId, Step);
public readonly AnnotationHandle AnnotationHandle;
public readonly int SequenceId;
public readonly int Step;
public JToken Values;
public bool ReportAsyncResult<T>(IAsyncFuture<T> asyncFuture, object result) where T : IPendingId
{
var sensorId = asyncFuture.GetId().AsSensorId();
if (!sensorId.IsValid()) return false;
public bool IsAssigned => Values != null;
var sensor = GetOrCreatePendingSensor(sensorId);
return sensor.ReportAsyncResult(asyncFuture, result);
}
#endif
public struct SensorData
{
public string modality;

}
}
}
#if false
internal void ReportCapture(SensorHandle sensorHandle, string filename, SensorSpatialData sensorSpatialData, params(string, object)[] additionalSensorValues)
{
var sensorData = m_Sensors[sensorHandle];

var rot = pendingCapture.SensorSpatialData.EgoPose.rotation;
var velocity = pendingCapture.SensorSpatialData.EgoVelocity ?? Vector3.zero;
var accel = pendingCapture.SensorSpatialData.EgoAcceleration ?? Vector3.zero;
#if false
GetActiveReporter()?.OnCaptureReported(m_SequenceId, AcquireStep(), width, height, filename, trans, rot, velocity, accel);
}
}
static string GetFormatFromFilename(string filename)
{
var ext = Path.GetExtension(filename);
if (ext == null)
return null;
if (ext.StartsWith("."))
ext = ext.Substring(1);
return ext.ToUpperInvariant();
}
/// <summary>
/// Use this to get the current step when it is desirable to ensure the step has been allocated for this frame. Steps should only be allocated in frames where a capture or metric is reported.
/// </summary>

sensorData.sequenceTimeOfNextRender = UnscaledSequenceTime;
sensor.id = RegisterId(sensor.id);
var sensorHandle = new SensorHandle(sensor.id, DatasetCapture.Instance);
var sensorHandle = new SensorHandle(sensor.id);
m_ActiveSensors.Add(sensorHandle);
m_Sensors.Add(sensorHandle, sensorData);

return;
WritePendingCaptures(true, true);
if (m_PendingCaptures.Count > 0)
Debug.LogError($"Simulation ended with pending annotations: {string.Join(", ", m_PendingCaptures.Select(c => $"id:{c.SensorHandle.Id} frame:{c.FrameCount}"))}");
if (m_PendingFrames.Count > 0)
Debug.LogError($"Simulation ended with pending annotations: {string.Join(", ", m_PendingFrames.Select(c => $"id:{c.Key}"))}");
#if false
WritePendingMetrics(true);
if (m_PendingMetrics.Count > 0)

}
}
WriteReferences();
// WriteReferences();
// Debug.Log($"Calling SS::OnSimulationEnd");
// GetActiveReporter()?.OnSimulationEnd();
public void RegisterAnnotationDefinition(SoloDesign.AnnotationDefinition definition)
public void RegisterAnnotationDefinition(AnnotationDefinition definition)
definition.id = RegisterId(definition.id);
public void RegisterMetricDefinition(SoloDesign.MetricDefinition definition)
public void RegisterMetric(MetricDefinition definition)
definition.id = RegisterId(definition.id);
#if false
public AnnotationDefinition RegisterAnnotationDefinition<TSpec>(string name, TSpec[] specValues, string description, string format, Guid id)
{
if (id == Guid.Empty)
id = Guid.NewGuid();
RegisterAdditionalInfoType(name, specValues, description, format, id, AdditionalInfoKind.Annotation);
// GetActiveReporter()?.OnAnnotationRegistered(id, specValues); // <- Not sure about this one either
if (name == "bounding box")
{
GetActiveConsumer()?.OnAnnotationRegistered(ToBoundingBoxDef(specValues));
}
return new AnnotationDefinition(id, this);
}
#endif
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);
}
#if false
public MetricDefinition RegisterMetricDefinition<TSpec>(string name, TSpec[] specValues, string description, Guid id)
{
if (id == Guid.Empty)
id = Guid.NewGuid();
RegisterAdditionalInfoType(name, specValues, description, null, id, AdditionalInfoKind.Metric);
// GetActiveReporter()?.OnMetricRegistered(id, name, description); // <- Not sure about this one either
return new MetricDefinition(id);
}
#endif
void RegisterAdditionalInfoType<TSpec>(string name, TSpec[] specValues, string description, string format, Guid id, AdditionalInfoKind additionalInfoKind)
{
CheckDatasetAllowed();

m_AdditionalInfoTypeData.Add(annotationDefinitionInfo);
}
public AnnotationHandle ReportAnnotation(SensorHandle sensor, AnnotationDefinition definition, Annotation annotation)
public SPendingSensorId ReportSensor(SensorDefinition definition, Sensor sensor)
var handle = new AnnotationHandle(sensor, this, definition, AcquireStep());
var pendingCapture = GetOrCreatePendingCaptureForThisFrame(sensor);
pendingCapture.Annotations.Add((handle, null));
return handle;
var step = AcquireStep();
var pendingSensorId = new SPendingSensorId(definition.id, m_SequenceId, step);
var pendingFrame = GetOrCreatePendingFrame(pendingSensorId.AsFrameId());
pendingFrame.sensors[pendingSensorId] = new PendingSensor(pendingSensorId, sensor);
return pendingSensorId;
#if false
public AnnotationHandle ReportAnnotationFile(AnnotationHandle annotationHandle, SensorHandle sensorHandle)
public SPendingCaptureId ReportAnnotation(SensorHandle sensorHandle, AnnotationDefinition definition, Annotation annotation)
var annotation = new AnnotationHandle(sensorHandle, this, AcquireStep());
var pendingCapture = GetOrCreatePendingCaptureForThisFrame(sensorHandle);
pendingCapture.Annotations.Add((annotation, new AnnotationData(annotationHandle, null)));
return annotation;
var step = AcquireStep();
var sensorId = new SPendingCaptureId(sensorHandle.Id, definition.id, m_SequenceId, step);
var pendingFrame = GetOrCreatePendingFrame(sensorId.AsFrameId());
var sensor = pendingFrame.GetOrCreatePendingSensor(sensorId.SensorId);
var annotationId = new SPendingCaptureId(sensorHandle.Id, definition.id, m_SequenceId, step);
sensor.Annotations[annotationId] = annotation;
return annotationId;
public AnnotationHandle ReportAnnotationValues<T>(AnnotationDefinition annotationDefinition, SensorHandle sensorHandle, T[] values)
PendingFrame GetOrCreatePendingFrame(SPendingFrameId pendingId)
var annotation = new AnnotationHandle(sensorHandle, this, AcquireStep());
var pendingCapture = GetOrCreatePendingCaptureForThisFrame(sensorHandle);
var valuesJson = new JArray();
foreach (var value in values)
{
valuesJson.Add(DatasetJsonUtility.ToJToken(value));
}
pendingCapture.Annotations.Add((annotation, new AnnotationData(annotationDefinition, null, valuesJson)));
return annotation;
}
#endif
PendingCapture GetOrCreatePendingCaptureForThisFrame(SensorHandle sensorHandle)
{
return GetOrCreatePendingCaptureForThisFrame(sensorHandle, out var _);
return GetOrCreatePendingFrame(pendingId, out var _);
PendingCapture GetOrCreatePendingCaptureForThisFrame(SensorHandle sensorHandle, out bool created)
PendingFrame GetOrCreatePendingFrame(SPendingFrameId pendingId, out bool created)
//Following is this converted to code: m_PendingCaptures.FirstOrDefault(c => c.SensorHandle == sensorHandle && c.FrameCount == Time.frameCount);
//We also start at the end, since the pending capture list can get long as we await writing to disk
PendingCapture pendingCapture = null;
for (var i = m_PendingCaptures.Count - 1; i >= 0; i--)
if (!m_PendingFrames.TryGetValue(pendingId, out var pendingFrame))
var c = m_PendingCaptures[i];
if (c.SensorHandle == sensorHandle && c.FrameCount == Time.frameCount)
{
pendingCapture = c;
break;
}
}
if (pendingCapture == null)
{
pendingFrame = new PendingFrame(pendingId, SequenceTime);
m_PendingFrames[pendingId] = pendingFrame;
m_PendingIdToFrameMap[pendingId] = Time.frameCount;
pendingCapture = new PendingCapture(sensorHandle, m_Sensors[sensorHandle], m_SequenceId, Time.frameCount, AcquireStep(), SequenceTime);
m_PendingCaptures.Add(pendingCapture);
return pendingCapture;
return pendingFrame;
public AsyncAnnotation ReportAnnotationAsync(AnnotationDefinition annotationDefinition, SensorHandle sensorHandle)
public AsyncAnnotationFuture ReportAnnotationAsync(AnnotationDefinition annotationDefinition, SensorHandle sensorHandle)
return new AsyncAnnotation(ReportAnnotation(sensorHandle, annotationDefinition, null), this);
return new AsyncAnnotationFuture(ReportAnnotation(sensorHandle, annotationDefinition, null), this);
#if false
public AsyncAnnotation ReportAnnotationAsync(AnnotationDefinition annotationDefinition, SensorHandle sensorHandle)
public AsyncSensorFuture ReportSensorAsync(SensorDefinition sensorDefinition)
return new AsyncAnnotation(ReportAnnotationFile(annotationDefinition, sensorHandle, null), this);
return new AsyncSensorFuture(ReportSensor(sensorDefinition, null), this);
#endif
public void ReportAsyncAnnotationResult(AsyncAnnotation asyncAnnotation, SoloDesign.Annotation annotation)
{
if (!asyncAnnotation.IsPending)
throw new InvalidOperationException("AsyncAnnotation has already been reported and cannot be reported again.");
PendingCapture pendingCapture = null;
var annotationIndex = -1;
foreach (var c in m_PendingCaptures)
{
if (c.Step == asyncAnnotation.annotationHandle.Step && c.SensorHandle == asyncAnnotation.annotationHandle.SensorHandle)
{
pendingCapture = c;
annotationIndex = pendingCapture.Annotations.FindIndex(a => a.Item1.Equals(asyncAnnotation.annotationHandle));
if (annotationIndex != -1)
break;
}
}
Debug.Assert(pendingCapture != null && annotationIndex != -1);
var annotationTuple = pendingCapture.Annotations[annotationIndex];
annotationTuple.Item2 = annotation;
pendingCapture.Annotations[annotationIndex] = annotationTuple;
}
#if false
public void ReportAsyncAnnotationResult<T>(AsyncAnnotation asyncAnnotation, string filename = null, NativeSlice<T> values = default) where T : struct
public bool IsPending<T>(IAsyncFuture<T> asyncFuture) where T : IPendingId
var jArray = new JArray();
foreach (var value in values)
jArray.Add(new JRaw(DatasetJsonUtility.ToJToken(value)));
ReportAsyncAnnotationResult(asyncAnnotation, filename, jArray);
return
m_PendingFrames.TryGetValue(asyncFuture.GetId().AsFrameId(), out var pendingFrame) &&
pendingFrame.IsPending(asyncFuture);
public void ReportAsyncAnnotationResult<T>(AsyncAnnotation asyncAnnotation, string filename = null, IEnumerable<T> values = null)
PendingFrame GetPendingFrame<T>(IAsyncFuture<T> future) where T : IPendingId
JArray jArray = null;
if (values != null)
{
jArray = new JArray();
foreach (var value in values)
{
if (value != null)
jArray.Add(new JRaw(DatasetJsonUtility.ToJToken(value)));
}
}
ReportAsyncAnnotationResult(asyncAnnotation, filename, jArray, values?.Cast<object>().ToList() ?? null); //aluesList);
return GetPendingFrame(future.GetId().AsFrameId());
void ReportAsyncAnnotationResult(AsyncAnnotation asyncAnnotation, string filename, JArray jArray, IEnumerable<object> values = null)
PendingFrame GetPendingFrame(SPendingFrameId id)
if (!asyncAnnotation.IsPending)
throw new InvalidOperationException("AsyncAnnotation has already been reported and cannot be reported again.");
return m_PendingFrames[id];
}
PendingCapture pendingCapture = null;
var annotationIndex = -1;
foreach (var c in m_PendingCaptures)
{
if (c.Step == asyncAnnotation.Annotation.Step && c.SensorHandle == asyncAnnotation.Annotation.SensorHandle)
{
pendingCapture = c;
annotationIndex = pendingCapture.Annotations.FindIndex(a => a.Item1.Equals(asyncAnnotation.Annotation));
if (annotationIndex != -1)
break;
}
}
Debug.Assert(pendingCapture != null && annotationIndex != -1);
bool ReportAsyncResultGeneric<T>(IAsyncFuture<T> asyncFuture, object result) where T : IPendingId
{
if (!asyncFuture.IsPending()) return false;
var annotationTuple = pendingCapture.Annotations[annotationIndex];
var annotationData = annotationTuple.Item2;
var pendingFrame = GetPendingFrame(asyncFuture);
annotationData.Path = filename;
annotationData.ValuesJson = jArray;
annotationData.RawValues = values;
if (pendingFrame == null) return false;
annotationTuple.Item2 = annotationData;
pendingCapture.Annotations[annotationIndex] = annotationTuple;
return pendingFrame.ReportAsyncResult(asyncFuture, result);
#endif
public bool IsPending(AnnotationHandle annotationHandle)
public bool ReportAsyncResult(AsyncSensorFuture asyncFuture, Sensor sensor)
foreach (var c in m_PendingCaptures)
{
foreach (var (handle, annotation) in c.Annotations)
{
if (handle.Equals(annotationHandle))
return annotation == null;
}
}
return false;
return ReportAsyncResultGeneric(asyncFuture, sensor);
#if false
public bool IsPending(ref AsyncMetric asyncMetric)
public bool ReportAsyncResult(AsyncAnnotationFuture asyncFuture, Annotation annotation)
foreach (var m in m_PendingMetrics)
{
if (m.MetricId == asyncMetric.Id)
return !m.IsAssigned;
}
return false;
return ReportAsyncResultGeneric(asyncFuture, annotation);
public void ReportAsyncMetricResult<T>(AsyncMetric asyncMetric, T[] values)
public bool ReportAsyncResult(AsyncMetricFuture asyncFuture, Metric metric)
var pendingMetricValues = JArrayFromArray(values);
ReportAsyncMetricResult(asyncMetric, pendingMetricValues);
return ReportAsyncResultGeneric(asyncFuture, metric);
public void ReportAsyncMetricResult(AsyncMetric asyncMetric, string valuesJsonArray)
public AsyncMetricFuture CreateAsyncMetric(MetricDefinition metricDefinition, SensorHandle sensorHandle = default, AnnotationHandle annotationHandle = default)
ReportAsyncMetricResult(asyncMetric, new JRaw(valuesJsonArray));
EnsureStepIncremented();
var pendingId = ReportMetric(sensorHandle, metricDefinition, null, annotationHandle);
return new AsyncMetricFuture(pendingId, this);
void ReportAsyncMetricResult(AsyncMetric asyncMetric, JToken values)
public SPendingCaptureId ReportMetric(SensorHandle sensor, MetricDefinition definition, Metric metric, AnnotationHandle annotation)
var metricIndex = -1;
for (var i = 0; i < m_PendingMetrics.Count; i++)
{
if (m_PendingMetrics[i].MetricId == asyncMetric.Id)
{
metricIndex = i;
break;
}
}
if (definition == null)
throw new ArgumentNullException(nameof(metric));
if (metricIndex == -1)
throw new InvalidOperationException("asyncMetric is invalid or has already been reported");
var pendingId = new SPendingCaptureId(sensor.Id, definition.id, m_SequenceId, AcquireStep());
var pendingFrame = GetOrCreatePendingFrame(pendingId.AsFrameId());
var pendingMetric = m_PendingMetrics[metricIndex];
if (pendingMetric.IsAssigned)
throw new InvalidOperationException("asyncMetric already been reported. ReportAsyncMetricResult may only be called once per AsyncMetric");
if (pendingFrame == null)
throw new InvalidOperationException($"Could not get or create a pending frame for {pendingId}");
pendingMetric.Values = values;
m_PendingMetrics[metricIndex] = pendingMetric;
}
#endif
#if false
public AsyncMetric CreateAsyncMetric(MetricDefinition metricDefinition, SensorHandle sensorHandle = default, AnnotationHandle annotationHandle = default)
{
EnsureStepIncremented();
var id = m_NextMetricId++;
if (sensorHandle != default)
{
var capture = GetOrCreatePendingCaptureForThisFrame(sensorHandle);
}
m_PendingMetrics.Add(new PendingMetric(metricDefinition, id, sensorHandle, annotationHandle, m_SequenceId, AcquireStep()));
return new AsyncMetric(metricDefinition, id, this);
}
public void ReportMetric<T>(MetricDefinition metricDefinition, T[] values, SensorHandle sensorHandle, AnnotationHandle annotationHandle)
{
var jArray = JArrayFromArray(values);
ReportMetric(metricDefinition, jArray, sensorHandle, annotationHandle);
}
var pendingSensor = pendingFrame.GetOrCreatePendingSensor(pendingId.SensorId);
public void ReportMetric(MetricDefinition metricDefinition, JToken values, SensorHandle sensorHandle, AnnotationHandle annotationHandle)
{
if (values == null)
throw new ArgumentNullException(nameof(values));
EnsureStepIncremented();
var captureId = sensorHandle.IsNil ? (-1, -1) : GetOrCreatePendingCaptureForThisFrame(sensorHandle).Id;
m_PendingMetrics.Add(new PendingMetric(metricDefinition, m_NextMetricId++, sensorHandle, annotationHandle, m_SequenceId, AcquireStep(), values));
pendingSensor.Metrics[pendingId] = metric;
return pendingId;
#endif
}
}

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


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Unity.Mathematics;
using UnityEngine.Perception.GroundTruth.SoloDesign;
// ReSharper disable NotAccessedField.Local
// ReSharper disable CoVariantArrayConversion
using UnityEngine.Perception.GroundTruth.DataModel;
const Formatting k_Formatting = Formatting.Indented;
/// <summary>
/// Writes sensors.json, egos.json, metric_definitions.json, and annotation_definitions.json
/// </summary>
public void WriteReferences()
{
var egoReference = new JObject();
egoReference["version"] = DatasetCapture.SchemaVersion;
WriteJObjectToFile(egoReference, "egos.json");
var sensorReferenceDoc = new JObject();
sensorReferenceDoc["version"] = DatasetCapture.SchemaVersion;
sensorReferenceDoc["sensors"] = new JArray(m_Sensors.Select(kvp =>
{
var sensorReference = new JObject();
sensorReference["id"] = kvp.Key.Id.ToString();
sensorReference["modality"] = kvp.Value.modality;
if (kvp.Value.description != null)
sensorReference["description"] = kvp.Value.description;
return sensorReference;
}).ToArray());
WriteJObjectToFile(sensorReferenceDoc, "sensors.json");
if (m_AdditionalInfoTypeData.Count > 0)
{
var annotationDefinitionsJArray = new JArray();
var metricDefinitionsJArray = new JArray();
foreach (var typeInfo in m_AdditionalInfoTypeData)
{
var typeJObject = new JObject();
typeJObject.Add("id", new JValue(typeInfo.id.ToString()));
typeJObject.Add("name", new JValue(typeInfo.name));
if (typeInfo.description != null)
typeJObject.Add("description", new JValue(typeInfo.description));
if (typeInfo.format != null)
typeJObject.Add("format", new JValue(typeInfo.format));
if (typeInfo.specValues != null)
{
var specValues = new JArray();
foreach (var value in typeInfo.specValues)
{
specValues.Add(DatasetJsonUtility.ToJToken(value));
}
typeJObject.Add("spec", specValues);
}
switch (typeInfo.additionalInfoKind)
{
case AdditionalInfoKind.Annotation:
annotationDefinitionsJArray.Add(typeJObject);
break;
case AdditionalInfoKind.Metric:
metricDefinitionsJArray.Add(typeJObject);
break;
default:
throw new NotSupportedException("Unsupported info kind");
}
}
if (annotationDefinitionsJArray.Count > 0)
{
var annotationDefinitionsJObject = new JObject();
annotationDefinitionsJObject.Add("version", DatasetCapture.SchemaVersion);
annotationDefinitionsJObject.Add("annotation_definitions", annotationDefinitionsJArray);
WriteJObjectToFile(annotationDefinitionsJObject, "annotation_definitions.json");
}
if (metricDefinitionsJArray.Count > 0)
{
var metricDefinitionsJObject = new JObject();
metricDefinitionsJObject.Add("version", DatasetCapture.SchemaVersion);
metricDefinitionsJObject.Add("metric_definitions", metricDefinitionsJArray);
WriteJObjectToFile(metricDefinitionsJObject, "metric_definitions.json");
}
}
// Debug.Log($"Dataset written to {Path.GetDirectoryName(OutputDirectory)}");
}
void WriteJObjectToFile(JObject jObject, string filename)
{
#if false
m_JsonToStringSampler.Begin();
var stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
using (var jsonTextWriter = new JsonTextWriter(stringWriter))
{
jsonTextWriter.Formatting = k_Formatting;
jObject.WriteTo(jsonTextWriter);
}
var contents = stringWriter.ToString();
m_JsonToStringSampler.End();
m_WriteToDiskSampler.Begin();
var path = Path.Combine(OutputDirectory, filename);
// Debug.Log($"ss - sensors.json - {path}");
File.WriteAllText(path, contents);
Manager.Instance.ConsumerFileProduced(path);
m_WriteToDiskSampler.End();
#endif
}
int m_currentReportedSequence = 0;
Sensor ToSensor(PendingCapture pendingCapture, SimulationState simulationState, int captureFileIndex)
Sensor ToSensor(PendingFrame pendingFrame, SimulationState simulationState, int captureFileIndex)
{
var sensor = new RgbSensor
{

rotation = Vector3.zero,
velocity = Vector3.zero,
acceleration = Vector3.zero,
// metadata = new Dictionary<string, object>(),
imageFormat = "png",
dimension = Vector2.zero,
buffer = null

}
Frame ToFrame(PendingCapture pendingCapture, SimulationState simulationState, int captureFileIndex)
{
if (!m_SequenceMap.TryGetValue(pendingCapture.SequenceId, out var seqId))
{
seqId = m_currentReportedSequence++;
m_SequenceMap[pendingCapture.SequenceId] = seqId;
}
return new Frame(pendingCapture.FrameCount, seqId, pendingCapture.Step);
}
// TODO rename this to 'WritePendingFrames'
// if (!flush && m_PendingCaptures.Count < k_MinPendingCapturesBeforeWrite)
// return;
var pendingCapturesToWrite = new List<PendingCapture>(m_PendingCaptures.Count);
var frameCountNow = Time.frameCount;
for (var i = 0; i < m_PendingCaptures.Count; i++)
var pendingFramesToWrite = new List<KeyValuePair<SPendingFrameId,PendingFrame>>(m_PendingFrames.Count);
var currentFrame = Time.frameCount;
foreach (var frame in m_PendingFrames)
var pendingCapture = m_PendingCaptures[i];
if ((writeCapturesFromThisFrame || pendingCapture.FrameCount < frameCountNow) &&
pendingCapture.Annotations.All(a => a.Item2 != null))
var recordedFrame = m_PendingIdToFrameMap[frame.Value.PendingId];
if ((writeCapturesFromThisFrame || recordedFrame < currentFrame) &&
frame.Value.IsReadyToReport())
pendingCapturesToWrite.Add(pendingCapture);
m_PendingCaptures.RemoveAt(i);
i--; //decrement i because we removed an element
pendingFramesToWrite.Add(frame);
if (pendingCapturesToWrite.Count == 0)
foreach (var pf in pendingFramesToWrite)
m_SerializeCapturesSampler.End();
return;
m_PendingFrames.Remove(pf.Key);
#if false
BoundingBoxAnnotation ToBoundingBox(Annotation annotation, AnnotationData data)
{
var bbox = new BoundingBoxAnnotation
{
Id = "bounding box",
sensorId = "camera",
description = "Labeled bounding boxes",
annotationType = "bounding box labeler",
// metadata = new Dictionary<string, object>(),
boxes = new List<BoundingBoxAnnotation.Entry>()
};
foreach (var d in data.RawValues)
{
if (d is BoundingBox2DLabeler.BoundingBoxValue e)
{
var entry = new BoundingBoxAnnotation.Entry
{
instanceId = (int)e.instance_id,
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}
};
bbox.boxes.Add(entry);
}
}
return bbox;
}
#endif
#if false
InstanceSegmentation ToInstanceSegmentation(AnnotationHandle annotation, AnnotationData data, params(string,object)[] sensorValues)
IEnumerable<Sensor> ConvertToSensors(PendingFrame frame, SimulationState simulationState)
var seg = new InstanceSegmentation
{
Id = "instance segmentation",
sensorId = "camera",
description = "instance segmentation blah blah blah",
annotationType = "instance segmentation labeler",
// metadata = new Dictionary<string, object>(),
instances = new List<InstanceSegmentation.Entry>(),
dimension = Vector2.zero,
imageFormat = "png"
};
foreach (var sv in sensorValues)
{
switch (sv.Item1)
{
case "camera_width":
seg.dimension.x = (int)sv.Item2;
break;
case "camera_height":
seg.dimension.y = (int)sv.Item2;
break;
}
}
foreach (var d in data.RawValues)
{
if (d is InstanceSegmentationLabeler.InstanceData i)
{
seg.buffer = i.buffer;
foreach (var color in i.colors)
{
var entry = new InstanceSegmentation.Entry
{
instanceId = (int)color.instance_id,
rgba = color.color
};
seg.instances.Add(entry);
}
}
}
return seg;
return frame.sensors.Values.Where(s => s.IsReadyToReport()).Select(s => s.ToSensor());
#endif
#if true
List<Sensor> ConvertToSensors(PendingCapture capture, SimulationState simulationState)
{
var dim = new Vector2();
var buffer = new byte[0];
foreach (var sv in capture.AdditionalSensorValues)
{
switch (sv.Item1)
{
case "camera_width":
dim.x = (int)sv.Item2;
break;
case "camera_height":
dim.y = (int)sv.Item2;
break;
case "buffer":
buffer = (byte[])sv.Item2;
break;
}
}
return new List<Sensor>
{
new RgbSensor
{
Id = "camera",
sensorType = capture.SensorData.modality,
imageFormat = ".png",
dimension = dim,
position = capture.SensorSpatialData.EgoPose.position,
rotation = capture.SensorSpatialData.EgoPose.rotation.eulerAngles,
velocity = capture.SensorSpatialData.EgoVelocity ?? Vector3.zero,
acceleration = capture.SensorSpatialData.EgoAcceleration ?? Vector3.zero,
buffer = buffer,
// metadata = new Dictionary<string, object>()
}
};
}
#endif
#if true
Frame ConvertToFrameData(PendingCapture capture, SimulationState simState, int captureFileIndex)
Frame ConvertToFrameData(PendingFrame pendingFrame, SimulationState simState)
if (!m_SequenceMap.TryGetValue(capture.SequenceId, out var seq))
{
seq = m_currentReportedSequence++;
m_SequenceMap[capture.SequenceId] = seq;
}
var frame = new Frame(capture.FrameCount, seq, capture.Step);
var frameId = m_PendingIdToFrameMap[pendingFrame.PendingId];
var frame = new Frame(frameId, pendingFrame.PendingId.Sequence, pendingFrame.PendingId.Step);
frame.sensors = ConvertToSensors(capture, simState);
foreach (var (handle, annotation) in capture.Annotations)
frame.sensors = ConvertToSensors(pendingFrame, simState);
#if false
foreach (var annotation in pendingFrame.annotations.Values)
#if false
foreach (var (annotation, data) in capture.Annotations)
foreach (var metric in pendingFrame.metrics.Values)
SoloDesign.Annotation soloAnnotation = null;
var supported = false;
switch (data.AnnotationDefinition.Id.ToString())
{
#if false
case "f9f22e05-443f-4602-a422-ebe4ea9b55cb":
soloAnnotation = ToBoundingBox(annotation, data);
supported = true;
break;
#endif
case "1ccebeb4-5886-41ff-8fe0-f911fa8cbcdf":
soloAnnotation = ToInstanceSegmentation(annotation, data, capture.AdditionalSensorValues);
supported = true;
break;
}
if (supported) frame.annotations.Add(soloAnnotation);
frame.metrics.Add(metric);
#endif
void Write(List<PendingCapture> pendingCaptures, SimulationState simulationState, int captureFileIndex)
void Write(List<KeyValuePair<SPendingFrameId, PendingFrame>> frames, SimulationState simulationState)
foreach (var pendingCapture in pendingCaptures)
foreach (var pendingFrame in frames)
var frame = ConvertToFrameData(pendingCapture, simulationState, captureFileIndex);
var frame = ConvertToFrameData(pendingFrame.Value, simulationState);
//GetActiveReporter()?.ProcessPendingCaptures(pendingCaptures, simulationState);
#if false
simulationState.m_SerializeCapturesAsyncSampler.Begin();
//lazily allocate for fast zero-write frames
var capturesJArray = new JArray();
foreach (var pendingCapture in pendingCaptures)
capturesJArray.Add(JObjectFromPendingCapture(pendingCapture));
var capturesJObject = new JObject();
capturesJObject.Add("version", DatasetCapture.SchemaVersion);
capturesJObject.Add("captures", capturesJArray);
simulationState.WriteJObjectToFile(capturesJObject,
$"captures_{captureFileIndex:000}.json");
simulationState.m_SerializeCapturesAsyncSampler.End();
#endif
Write(pendingCapturesToWrite, this, m_CaptureFileIndex);
Write(pendingFramesToWrite, this);
}
else
{

CaptureFileIndex = m_CaptureFileIndex,
PendingCaptures = pendingCapturesToWrite,
PendingFrames = pendingFramesToWrite,
Write(r.data.PendingCaptures, r.data.SimulationState, r.data.CaptureFileIndex);
Write(r.data.PendingFrames, r.data.SimulationState);
return AsyncRequest.Result.Completed;
});
req.Execute(AsyncRequest.ExecutionContext.JobSystem);

m_CaptureFileIndex++;
}
#if false
struct WritePendingMetricRequestData
{
public List<PendingMetric> PendingMetrics;
public int MetricFileIndex;
}
void WritePendingMetrics(bool flush = false)
{
if (!flush && m_PendingMetrics.Count < k_MinPendingMetricsBeforeWrite)
return;
var pendingMetricsToWrite = new List<PendingMetric>(m_PendingMetrics.Count);
m_SerializeMetricsSampler.Begin();
for (var i = 0; i < m_PendingMetrics.Count; i++)
{
var metric = m_PendingMetrics[i];
if (metric.IsAssigned)
{
pendingMetricsToWrite.Add(metric);
m_PendingMetrics.RemoveAt(i);
i--; //decrement i because we removed an element
}
}
if (pendingMetricsToWrite.Count == 0)
{
m_SerializeMetricsSampler.End();
return;
}
void Write(List<PendingMetric> pendingMetrics, SimulationState simState, int metricsFileIndex)
{
#if false
GetActiveReporter()?.ProcessPendingMetrics(pendingMetrics, simState);
#endif
#if false
m_SerializeMetricsAsyncSampler.Begin();
var jArray = new JArray();
foreach (var pendingMetric in pendingMetrics)
jArray.Add(JObjectFromPendingMetric(pendingMetric));
var metricsJObject = new JObject();
metricsJObject.Add("version", DatasetCapture.SchemaVersion);
metricsJObject.Add("metrics", jArray);
WriteJObjectToFile(metricsJObject, $"metrics_{metricsFileIndex:000}.json");
m_SerializeMetricsAsyncSampler.End();
#endif
}
if (flush)
{
Write(pendingMetricsToWrite, this, m_MetricsFileIndex);
}
else
{
var req = Manager.Instance.CreateRequest<AsyncRequest<WritePendingMetricRequestData>>();
req.data = new WritePendingMetricRequestData()
{
MetricFileIndex = m_MetricsFileIndex,
PendingMetrics = pendingMetricsToWrite
};
req.Enqueue(r =>
{
Write(r.data.PendingMetrics, this, r.data.MetricFileIndex);
return AsyncRequest.Result.Completed;
});
req.Execute();
}
m_MetricsFileIndex++;
m_SerializeMetricsSampler.End();
}
static JObject JObjectFromPendingMetric(PendingMetric metric)
{
var jObject = new JObject();
#if false
jObject["capture_id"] = metric.CaptureId == Guid.Empty ? new JRaw("null") : new JValue(metric.CaptureId.ToString());
jObject["annotation_id"] = metric.annotationHandle.IsNil ? new JRaw("null") : new JValue(metric.annotationHandle.Id.ToString());
jObject["sequence_id"] = metric.SequenceId.ToString();
jObject["step"] = metric.Step;
jObject["metric_definition"] = metric.MetricDefinition.Id.ToString();
jObject["values"] = metric.Values;
#endif
return jObject;
}
#endif
#if false
/// <summary>
/// Creates the json representation of the given PendingCapture. Static because this should not depend on any SimulationState members,
/// which may have changed since the capture was reported.
/// </summary>
static JToken JObjectFromPendingCapture(PendingCapture pendingCapture)
{
var sensorJObject = new JObject();//new SensorCaptureJson
sensorJObject["sensor_id"] = pendingCapture.SensorHandle.Id.ToString();
sensorJObject["modality"] = pendingCapture.SensorData.modality;
sensorJObject["translation"] = DatasetJsonUtility.ToJToken(pendingCapture.SensorSpatialData.SensorPose.position);
sensorJObject["rotation"] = DatasetJsonUtility.ToJToken(pendingCapture.SensorSpatialData.SensorPose.rotation);
if (pendingCapture.AdditionalSensorValues != null)
{
foreach (var(name, value) in pendingCapture.AdditionalSensorValues)
sensorJObject.Add(name, DatasetJsonUtility.ToJToken(value));
}
var egoCaptureJson = new JObject();
egoCaptureJson["translation"] = DatasetJsonUtility.ToJToken(pendingCapture.SensorSpatialData.EgoPose.position);
egoCaptureJson["rotation"] = DatasetJsonUtility.ToJToken(pendingCapture.SensorSpatialData.EgoPose.rotation);
egoCaptureJson["velocity"] = pendingCapture.SensorSpatialData.EgoVelocity.HasValue ? DatasetJsonUtility.ToJToken(pendingCapture.SensorSpatialData.EgoVelocity.Value) : null;
egoCaptureJson["acceleration"] = pendingCapture.SensorSpatialData.EgoAcceleration.HasValue ? DatasetJsonUtility.ToJToken(pendingCapture.SensorSpatialData.EgoAcceleration.Value) : null;
var capture = new JObject();
capture["id"] = pendingCapture.Id.ToString();
capture["sequence_id"] = pendingCapture.SequenceId.ToString();
capture["step"] = pendingCapture.Step;
capture["timestamp"] = pendingCapture.Timestamp;
capture["sensor"] = sensorJObject;
capture["ego"] = egoCaptureJson;
if (pendingCapture.Annotations.Any())
capture["annotations"] = new JArray(pendingCapture.Annotations.Select(JObjectFromAnnotation).ToArray());
return capture;
}
#endif
#if false
static JObject JObjectFromAnnotation((AnnotationHandle, AnnotationData) annotationInfo)
{
var annotationJObject = new JObject();
annotationJObject["id"] = annotationInfo.Item1.Id.ToString();
annotationJObject["annotation_definition"] = annotationInfo.Item2.AnnotationDefinition.Id.ToString();
if (annotationInfo.Item2.Path != null)
annotationJObject["filename"] = annotationInfo.Item2.Path;
if (annotationInfo.Item2.ValuesJson != null)
annotationJObject["values"] = annotationInfo.Item2.ValuesJson;
return annotationJObject;
}
#endif
public List<PendingCapture> PendingCaptures;
public int CaptureFileIndex;
public List<KeyValuePair<SPendingFrameId, PendingFrame>> PendingFrames;
public SimulationState SimulationState;
}
}

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


using System;
using Unity.Simulation;
using UnityEngine.Perception.GroundTruth;
using UnityEngine.Perception.GroundTruth.DataModel;
namespace UnityEngine.Perception.Randomization.Scenarios
{

/// <inheritdoc/>
protected override void OnStart()
{
var md = new GroundTruth.SoloDesign.MetricDefinition();
DatasetCapture.Instance.RegisterMetricDefinition(md);
var md = new MetricDefinition();
DatasetCapture.Instance.RegisterMetric(md);
#if false
m_IterationMetricDefinition = DatasetCapture.Instance.RegisterMetricDefinition(

2
com.unity.perception/Runtime/Randomization/Scenarios/UnitySimulationScenario.cs


{
var filePath = new Uri(Configuration.Instance.SimulationConfig.app_param_uri).LocalPath;
LoadConfigurationFromFile(filePath);
PlayerPrefs.SetString(SimulationState.outputFormatMode, constants.outputFormat);
// PlayerPrefs.SetString(SimulationState.outputFormatMode, constants.outputFormat);
}
else
{

4
com.unity.perception/Tests/Runtime/GroundTruthTests/VisualizationTests.cs


});
var labeler1 = new ObjectCountLabeler(cfg);
labeler1.objectCountMetricId = "a1da3c27-369d-4929-aea6-d01614635ce2";
// labeler1.objectCountMetricId = "a1da3c27-369d-4929-aea6-d01614635ce2";
labeler2.objectCountMetricId = "b1da3c27-369d-4929-aea6-d01614635ce2";
// labeler2.objectCountMetricId = "b1da3c27-369d-4929-aea6-d01614635ce2";
perceptionCamera.AddLabeler(labeler1);
perceptionCamera.AddLabeler(labeler2);

2
com.unity.perception/Runtime/GroundTruth/ConsumerEndpoint.cs.meta


fileFormatVersion: 2
guid: 80d31589331913b40b3fa915181ee631
guid: 779eff09909f87249b75122620de01a7
MonoImporter:
externalObjects: {}
serializedVersion: 2

5
com.unity.perception/Runtime/GroundTruth/IMessageBuilder.cs


using System.Collections.Generic;
using System.Linq;
namespace UnityEngine.Perception.GroundTruth.Exporters.Solo
namespace UnityEngine.Perception.GroundTruth.Exporters.Solo
{
public interface IMessageBuilder
{

2
com.unity.perception/Runtime/GroundTruth/IMessageBuilder.cs.meta


fileFormatVersion: 2
guid: 9b7babd7be7b7934db08409d6f7a9524
guid: 2a7e1af431de0d04683f7a4743f4d4da
MonoImporter:
externalObjects: {}
serializedVersion: 2

17
com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionConsumer.cs


using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using UnityEngine.Perception.GroundTruth.DataModel;
namespace GroundTruth.SoloDesign
namespace UnityEngine.Perception.GroundTruth.Consumers
{
public class PerceptionResolver : DefaultContractResolver
{

}
}
public class OldPerceptionConsumer : PerceptionConsumer
public class OldPerceptionConsumer : ConsumerEndpoint
{
static readonly string version = "0.1.1";

var path = "";
RgbSensor rgbSensor = null;
if (frame.sensors.Count == 1)
if (frame.sensors.Count() == 1)
var sensor = frame.sensors[0];
var sensor = frame.sensors.First();
if (sensor is RgbSensor rgb)
{
rgbSensor = rgb;

#if false // TODO bring back annotations....
var annotations = new JArray();
foreach (var annotation in frame.annotations)
{

var json = OldPerceptionJsonFactory.Convert(this, frame, labelerId, defId, annotation);
if (json != null) annotations.Add(json);
}
#endif
var capture = new PerceptionCapture
{
id = Guid.NewGuid(),

step = frame.step,
timestamp = frame.timestamp,
sensor = PerceptionRgbSensor.Convert(this, rgbSensor, path),
annotations = annotations
// annotations = annotations
};
m_CurrentCaptures.Add(capture);

17
com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionJsonFactory.cs


using System.Linq;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Perception.GroundTruth;
using UnityEngine.Perception.GroundTruth.SoloDesign;
using UnityEngine.Perception.GroundTruth.DataModel;
namespace GroundTruth.SoloDesign
namespace UnityEngine.Perception.GroundTruth.Consumers
{
public static class OldPerceptionJsonFactory
{

{
case BoundingBoxAnnotationDefinition b:
case BoundingBox2DLabeler.BoundingBoxAnnotationDefinition b:
return JToken.FromObject(PerceptionBoundingBoxAnnotationDefinition.Convert(id, b));
}

{
switch (annotation)
{
case InstanceSegmentation i:
case InstanceSegmentationLabeler.InstanceSegmentation i:
{
return JToken.FromObject(PerceptionInstanceSegmentationValue.Convert(consumer, frame.frame, i), consumer.Serializer);
}

public int instance_id;
public Color32 color;
internal static Entry Convert(InstanceSegmentation.Entry entry)
internal static Entry Convert(InstanceSegmentationLabeler.InstanceSegmentation.Entry entry)
{
return new Entry
{

public string filename;
public List<Entry> values;
static string CreateFile(OldPerceptionConsumer consumer, int frame, InstanceSegmentation annotation)
static string CreateFile(OldPerceptionConsumer consumer, int frame, InstanceSegmentationLabeler.InstanceSegmentation annotation)
{
var path = consumer.VerifyDirectoryWithGuidExists("InstanceSegmentation");
path = Path.Combine(path, $"Instance_{frame}.png");

return path;
}
public static PerceptionInstanceSegmentationValue Convert(OldPerceptionConsumer consumer, int frame, InstanceSegmentation annotation)
public static PerceptionInstanceSegmentationValue Convert(OldPerceptionConsumer consumer, int frame, InstanceSegmentationLabeler.InstanceSegmentation annotation)
{
return new PerceptionInstanceSegmentationValue
{

public string format;
public LabelDefinitionEntry[] spec;
public static PerceptionBoundingBoxAnnotationDefinition Convert(Guid inId, BoundingBoxAnnotationDefinition box)
public static PerceptionBoundingBoxAnnotationDefinition Convert(Guid inId, BoundingBox2DLabeler.BoundingBoxAnnotationDefinition box)
{
var specs = new LabelDefinitionEntry[box.spec.Count()];
var i = 0;

7
com.unity.perception/Runtime/GroundTruth/Consumers/SoloMessageBuilder.cs


using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using UnityEngine.Perception.GroundTruth.DataModel;
using UnityEngine.Perception.GroundTruth.SoloDesign;
namespace GroundTruth.SoloDesign
namespace UnityEngine.Perception.GroundTruth.Consumers
public class SoloMessageBuilder : PerceptionConsumer
public class SoloMessageBuilder : ConsumerEndpoint
{
public string _baseDirectory = "D:/PerceptionOutput/SoloMessageBuilder";
public string soloDatasetName = "solo_mb";

33
com.unity.perception/Runtime/GroundTruth/ConsumerEndpoint.cs


using UnityEngine.Perception.GroundTruth.DataModel;
namespace UnityEngine.Perception.GroundTruth
{
public abstract class ConsumerEndpoint : MonoBehaviour
{
/// <summary>
/// Called when the simulation begins. Provides simulation wide metadata to
/// the consumer.
/// </summary>
/// <param name="metadata">Metadata describing the active simulation</param>
public abstract void OnSimulationStarted(SimulationMetadata metadata);
public virtual void OnSensorRegistered(SensorDefinition sensor) { }
public virtual void OnAnnotationRegistered(AnnotationDefinition annotationDefinition) { }
public virtual void OnMetricRegistered(MetricDefinition metricDefinition) { }
/// <summary>
/// Called at the end of each frame. Contains all of the generated data for the
/// frame. This method is called after the frame has entirely finished processing.
/// </summary>
/// <param name="frame">The frame data.</param>
public abstract void OnFrameGenerated(Frame frame);
/// <summary>
/// Called at the end of the simulation. Contains metadata describing the entire
/// simulation process.
/// </summary>
/// <param name="metadata">Metadata describing the entire simulation process</param>
public abstract void OnSimulationCompleted(CompletionMetadata metadata);
}
}

8
com.unity.perception/Runtime/GroundTruth/Consumers.meta


fileFormatVersion: 2
guid: e818e37774a99724e8f5cfbeeba26b22
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

421
com.unity.perception/Runtime/GroundTruth/DataModel.cs


using System;
using System.Collections.Generic;
using UnityEngine.Perception.GroundTruth.Exporters.Solo;
namespace UnityEngine.Perception.GroundTruth.DataModel
{
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 virtual bool IsValid()
{
return id != string.Empty && definition != string.Empty;
}
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 bool IsValid()
{
return id != string.Empty && description != string.Empty && annotationType != string.Empty;
}
public virtual void ToMessage(IMessageBuilder builder)
{
builder.AddString("id", id);
builder.AddString("description", description);
builder.AddString("annotation_type", annotationType);
}
}
[Serializable]
public class MetricDefinition : IMessageProducer
{
public string id = string.Empty;
public string description = string.Empty;
bool isRegistered { get; set; }= false;
public MetricDefinition() { }
public MetricDefinition(string id, string description)
{
this.id = id;
this.description = description;
}
public virtual bool IsValid()
{
return id != string.Empty && description != string.Empty;
}
public virtual void ToMessage(IMessageBuilder builder)
{
builder.AddString("id", id);
builder.AddString("description", description);
}
}
/// <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
/// metrics are ready to report for a single frame.
/// </summary>
[Serializable]
public class Frame : IMessageProducer
{
public Frame(int frame, int sequence, int step)
{
this.frame = frame;
this.sequence = sequence;
this.step = step;
sensors = new List<Sensor>();
}
/// <summary>
/// The perception frame number of this record
/// </summary>
public int frame;
/// <summary>
/// The sequence that this record is a part of
/// </summary>
public int sequence;
/// <summary>
/// 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>
public IEnumerable<Sensor> sensors;
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);
}
}
}
/// <summary>
/// Abstract sensor class that holds all of the common information for a sensor.
/// </summary>
[Serializable]
public abstract class Sensor : IMessageProducer
{
/// <summary>
/// The unique, human readable ID for the sensor.
/// </summary>
public string Id;
/// <summary>
/// The type of the sensor.
/// </summary>
public string sensorType;
public string description;
/// <summary>
/// The position (xyz) of the sensor in the world.
/// </summary>
public Vector3 position;
/// <summary>
/// The rotation in euler angles.
/// </summary>
public Vector3 rotation;
/// <summary>
/// The current velocity (xyz) of the sensor.
/// </summary>
public Vector3 velocity;
/// <summary>
/// The current acceleration (xyz) of the sensor.
/// </summary>
public Vector3 acceleration;
// TODO put in camera intrinsic
// TODO put in projection
/// <summary>
/// A list of all of the annotations recorded recorded for the frame.
/// </summary>
public IEnumerable<Annotation> annotations = new List<Annotation>();
/// <summary>
/// A list of all of the metrics recorded recorded for the frame.
/// </summary>
public IEnumerable<Metric> metrics = new List<Metric>();
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));
foreach (var annotation in annotations)
{
var nested = builder.AddNestedMessageToVector("annotations");
annotation.ToMessage(nested);
}
foreach (var metric in metrics)
{
var nested = builder.AddNestedMessageToVector("metrics");
metric.ToMessage(nested);
}
}
}
/// <summary>
/// The concrete class for an RGB sensor.
/// </summary>
[Serializable]
public class RgbSensor : Sensor
{
// The format of the image type
public string imageFormat;
// The dimensions (width, height) of the image
public Vector2 dimension;
// The raw bytes of the image file
public byte[] buffer;
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>
/// Abstract class that holds the common data found in all
/// annotations. Concrete instances of this class will add
/// data for their specific annotation type.
/// </summary>
[Serializable]
public abstract class Annotation : IMessageProducer
{
/// <summary>
/// The unique, human readable ID for the annotation.
/// </summary>
public string Id;
/// <summary>
/// The sensor that this annotation is associated with.
/// </summary>
public string sensorId;
/// <summary>
/// The description of the annotation.
/// </summary>
public string description;
/// <summary>
/// The type of the annotation, this will map directly to one of the
/// annotation subclasses that are concrete implementations of this abstract
/// class.
/// </summary>
public string annotationType;
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>
/// Abstract class that holds the common data found in all
/// metrics. Concrete instances of this class will add
/// data for their specific metric type.
/// </summary>
[Serializable]
public abstract class Metric : IMessageProducer
{
public string Id;
/// <summary>
/// The sensor ID that this metric is associated with
/// </summary>
public string sensorId;
/// <summary>
/// The annotation ID that this metric is associated with. If the value is none ("")
/// then the metric is capture wide, and not associated with a specific annotation.
/// </summary>
public string annotationId;
/// <summary>
/// A human readable description of what this metric is for.
/// </summary>
public string description;
/// <summary>
/// Additional key/value pair metadata that can be associated with
/// any metric.
/// </summary>
public Dictionary<string, object> metadata;
public virtual void ToMessage(IMessageBuilder builder)
{
builder.AddString("id", Id);
builder.AddString("sensor_id", sensorId);
builder.AddString("annotation_id", annotationId);
builder.AddString("description", description);
}
}
/// <summary>
/// Metadata describing the simulation.
/// </summary>
[Serializable]
public class SimulationMetadata
{
public SimulationMetadata()
{
unityVersion = "figure out how to do unity version";
perceptionVersion = "0.8.0-preview.4";
#if HDRP_PRESENT
renderPipeline = "HDRP";
#elif URP_PRESENT
renderPipeline = "URP";
#else
renderPipeline = "built-in";
#endif
metadata = new Dictionary<string, object>();
}
/// <summary>
/// The version of the Unity editor executing the simulation.
/// </summary>
public string unityVersion;
/// <summary>
/// The version of the perception package used to generate the data.
/// </summary>
public string perceptionVersion;
/// <summary>
/// The render pipeline used to create the data. Currently either URP or HDRP.
/// </summary>
public string renderPipeline;
/// <summary>
/// Additional key/value pair metadata that can be associated with
/// the simulation.
/// </summary>
public Dictionary<string, object> metadata;
// We could probably list all of the randomizers here...
}
/// <summary>
/// Metadata describing the final metrics of the simulation.
/// </summary>
[Serializable]
public class CompletionMetadata : SimulationMetadata
{
public CompletionMetadata()
: base() { }
public struct Sequence
{
/// <summary>
/// The ID of the sequence
/// </summary>
public int id;
/// <summary>
/// The number of steps in the sequence.
/// </summary>
public int numberOfSteps;
}
/// <summary>
/// Total frames processed in the simulation. These frames are distributed
/// over sequence and steps.
/// </summary>
public int totalFrames;
/// <summary>
/// A list of all of the sequences and the number of steps in the sequence for
/// a simulation.
/// </summary>
public List<Sequence> sequences;
}
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 };
}
}
}

11
com.unity.perception/Runtime/GroundTruth/DataModel.cs.meta


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

296
com.unity.perception/Runtime/GroundTruth/Consumers/SoloConsumer.cs


using System;
using System.Globalization;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine.Perception.GroundTruth.DataModel;
namespace UnityEngine.Perception.GroundTruth.Consumers
{
public class SoloConsumer : ConsumerEndpoint
{
public string _baseDirectory = "D:/PerceptionOutput/SoloConsumer";
public string soloDatasetName = "solo";
static string currentDirectory = "";
SimulationMetadata m_CurrentMetadata;
void Start()
{
// Only here to get the check mark to show up in Unity Editor
}
public override void OnSimulationStarted(SimulationMetadata metadata)
{
Debug.Log("SC - On Simulation Started");
m_CurrentMetadata = metadata;
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;
}
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 OnFrameGenerated(Frame frame)
{
var path = GetSequenceDirectoryPath(frame);
path = Path.Combine(path, $"step{frame.step}.frame_data.json");
WriteJTokenToFile(path, ToFrame(frame));
Debug.Log("SC - On Frame Generated");
}
public override void OnSimulationCompleted(CompletionMetadata metadata)
{
Debug.Log("SC - On Simulation Completed");
}
static JToken ToFrame(Frame frame)
{
var frameJson = new JObject
{
["frame"] = frame.frame,
["sequence"] = frame.sequence,
["step"] = frame.step
};
var captures = new JArray();
foreach (var sensor in frame.sensors)
{
switch (sensor)
{
case RgbSensor rgb:
captures.Add(ConvertSensor(frame, rgb));
break;
}
}
frameJson["captures"] = captures;
return frameJson;
}
static JArray FromVector3(Vector3 vector3)
{
return new JArray
{
vector3.x, vector3.y, vector3.z
};
}
static JArray FromVector2(Vector2 vector2)
{
return new JArray
{
vector2.x, vector2.y
};
}
static JArray FromColor32(Color32 color)
{
return new JArray
{
color.r, color.g, color.b, color.a
};
}
static JToken ToSensorHeader(Frame frame, Sensor sensor)
{
var token = new JObject
{
["Id"] = sensor.Id,
["sensorType"] = sensor.sensorType,
["position"] = FromVector3(sensor.position),
["rotation"] = FromVector3(sensor.rotation),
["velocity"] = FromVector3(sensor.velocity),
["acceleration"] = FromVector3(sensor.acceleration)
};
return token;
}
static JToken ConvertSensor(Frame frame, RgbSensor sensor)
{
// write out the png data
var path = GetSequenceDirectoryPath(frame);
path = Path.Combine(path, $"step{frame.step}.{sensor.sensorType}.{sensor.imageFormat}");
var file = File.Create(path, 4096);
file.Write(sensor.buffer, 0, sensor.buffer.Length);
file.Close();
var outRgb = ToSensorHeader(frame, sensor);
outRgb["fileName"] = path;
outRgb["imageFormat"] = sensor.imageFormat;
outRgb["dimension"] = FromVector2(sensor.dimension);
var annotations = new JArray();
var metrics = new JArray();
foreach (var annotation in sensor.annotations)
{
switch (annotation)
{
case BoundingBox2DLabeler.BoundingBoxAnnotation bbox:
annotations.Add(ConvertAnnotation(frame, bbox));
break;
case InstanceSegmentationLabeler.InstanceSegmentation seg:
annotations.Add(ConvertAnnotation(frame, seg));
break;
}
}
foreach (var metric in sensor.metrics)
{
switch (metric)
{
case ObjectCountLabeler.ObjectCountMetric objCount:
metrics.Add(ConvertMetric(frame, objCount));
break;
}
}
outRgb["annotations"] = annotations;
outRgb["metrics"] = metrics;
return outRgb;
}
static JToken ToAnnotationHeader(Frame frame, Annotation annotation)
{
return new JObject
{
["Id"] = annotation.Id,
["definition"] = annotation.description,
["sequence"] = frame.sequence,
["step"] = frame.step,
["sensor"] = annotation.sensorId
};
}
static JToken ToMetricHeader(Frame frame, Metric metric)
{
return new JObject
{
["sensorId"] = metric.sensorId,
["annotationId"] = metric.annotationId,
["description"] = metric.description
};
}
static JToken ConvertAnnotation(Frame frame, BoundingBox2DLabeler.BoundingBoxAnnotation bbox)
{
var outBox = ToAnnotationHeader(frame, bbox);
var values = new JArray();
foreach (var box in bbox.boxes)
{
values.Add(new JObject
{
["frame"] = frame.frame,
["label_name"] = box.labelName,
["instance_id"] = box.instanceId,
["origin"] = FromVector2(box.origin),
["dimension"] = FromVector2(box.dimension)
});
}
outBox["values"] = values;
return outBox;
}
static JToken ConvertMetric(Frame frame, ObjectCountLabeler.ObjectCountMetric count)
{
var outCount = ToMetricHeader(frame, count);
var values = new JArray();
foreach (var i in count.objectCounts)
{
values.Add(new JObject
{
["label_name"] = i.labelName,
["count"] = i.count
});
}
outCount["object_counts"] = values;
return outCount;
}
static JToken ConvertAnnotation(Frame frame, InstanceSegmentationLabeler.InstanceSegmentation segmentation)
{
// write out the png data
var path = GetSequenceDirectoryPath(frame);
path = Path.Combine(path,$"step{frame.step}.segmentation.{segmentation.imageFormat}");
var file = File.Create(path, 4096);
file.Write(segmentation.buffer, 0, segmentation.buffer.Length);
file.Close();
var outSeg = ToAnnotationHeader(frame, segmentation);
var values = new JArray();
foreach (var i in segmentation.instances)
{
values.Add(new JObject
{
["instance_id"] = i.instanceId,
["rgba"] = FromColor32(i.rgba)
});
}
outSeg["imageFormat"] = segmentation.imageFormat;
outSeg["dimension"] = FromVector2(segmentation.dimension);
outSeg["imagePath"] = path;
outSeg["instances"] = values;
return outSeg;
}
}
}

8
com.unity.perception/Runtime/GroundTruth/Exporters.meta


fileFormatVersion: 2
guid: 5353392e887128948bc94b5e0dd9ff73
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Runtime/GroundTruth/SoloDesign.meta


fileFormatVersion: 2
guid: 3dbded9ae1438d344bc799a283ac4ea2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

/com.unity.perception/Runtime/GroundTruth/SoloDesign/Frame.cs.meta → /com.unity.perception/Runtime/GroundTruth/ConsumerEndpoint.cs.meta

/com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloConsumer.cs.meta → /com.unity.perception/Runtime/GroundTruth/Consumers/SoloConsumer.cs.meta

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

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

/com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionConsumer.cs.meta → /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionConsumer.cs.meta

/com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionJsonFactory.cs.meta → /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionJsonFactory.cs.meta

/com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloMessageBuilder.cs.meta → /com.unity.perception/Runtime/GroundTruth/Consumers/SoloMessageBuilder.cs.meta

/com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionConsumer.cs → /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionConsumer.cs

/com.unity.perception/Runtime/GroundTruth/SoloDesign/OldPerceptionJsonFactory.cs → /com.unity.perception/Runtime/GroundTruth/Consumers/OldPerceptionJsonFactory.cs

/com.unity.perception/Runtime/GroundTruth/SoloDesign/SoloMessageBuilder.cs → /com.unity.perception/Runtime/GroundTruth/Consumers/SoloMessageBuilder.cs

正在加载...
取消
保存