您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
404 行
15 KiB
404 行
15 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Unity.Simulation;
|
|
using UnityEngine.Perception.GroundTruth.Exporters.PerceptionFormat;
|
|
|
|
namespace UnityEngine.Perception.GroundTruth.Exporters.PerceptionNew
|
|
{
|
|
public class PerceptionNewExporter : IDatasetExporter
|
|
{
|
|
public bool prettyPrint = true;
|
|
|
|
string m_DirectoryName = string.Empty;
|
|
|
|
int m_UnknownFrameCount = 0;
|
|
|
|
public void OnMetricRegistered(Guid metricId, string name, string description)
|
|
{
|
|
Debug.Log("On MetricRegistered");
|
|
}
|
|
|
|
public string GetRgbCaptureFilename(params(string, object)[] additionalSensorValues)
|
|
{
|
|
var frameArray = additionalSensorValues.Where(p => p.Item1 == "frame").Select(p => p.Item2);
|
|
var frame = frameArray.Any() ? (int)frameArray.First() : m_UnknownFrameCount++;
|
|
|
|
return Path.Combine(m_DirectoryName, $"rgb_{frame}.png");
|
|
}
|
|
|
|
public void OnSimulationBegin(string directoryName)
|
|
{
|
|
Debug.Log($"SS - New Perception - OnSimBegin");
|
|
m_Metadata = new Metadata
|
|
{
|
|
version = "0.1.1",
|
|
unity_version = "2019.4.26f1",
|
|
perception_version = "0.8.0-preview.4",
|
|
total_frames = 0,
|
|
total_sequences = 0,
|
|
sequences = null,
|
|
sensors = new []
|
|
{
|
|
new CameraData
|
|
{
|
|
id = "camera",
|
|
modality = "camera",
|
|
resolution = new []{0,0}
|
|
}
|
|
}
|
|
};
|
|
|
|
m_DirectoryName = directoryName + Path.DirectorySeparatorChar + Guid.NewGuid() + Path.DirectorySeparatorChar;
|
|
if (!Directory.Exists(m_DirectoryName))
|
|
Directory.CreateDirectory(m_DirectoryName);
|
|
}
|
|
|
|
[Serializable]
|
|
struct Metadata
|
|
{
|
|
public string version;
|
|
public string unity_version;
|
|
public string perception_version;
|
|
public int total_frames;
|
|
public int total_sequences;
|
|
public SequenceData[] sequences;
|
|
public CameraData[] sensors;
|
|
}
|
|
|
|
[Serializable]
|
|
struct SequenceData
|
|
{
|
|
public string sequence_id;
|
|
public int steps;
|
|
}
|
|
|
|
[Serializable]
|
|
struct CameraData
|
|
{
|
|
public string id;
|
|
public string modality;
|
|
public int[] resolution;
|
|
}
|
|
|
|
Metadata m_Metadata;
|
|
|
|
void CopyDefFile(string contains, string newName)
|
|
{
|
|
var d = m_DirectoryName;
|
|
var up = Directory.GetParent(m_DirectoryName)?.ToString() ?? string.Empty;
|
|
up = Directory.GetParent(up)?.ToString() ?? string.Empty;
|
|
|
|
var files = Directory.EnumerateFiles(up);
|
|
foreach (var file in files)
|
|
{
|
|
if (Path.GetFileName(file).Contains(contains))
|
|
{
|
|
File.Copy(file, Path.Combine(m_DirectoryName, newName));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnSimulationEnd()
|
|
{
|
|
Debug.Log($"SS - New Perception - OnSimEnd");
|
|
|
|
var writePath = Path.Combine(m_DirectoryName, "metadata.json");
|
|
var file = File.CreateText(writePath);
|
|
|
|
Debug.Log("SS - New Perception - writing");
|
|
|
|
var sequences = new Dictionary<int, int>();
|
|
|
|
foreach (var (seq, step) in m_FrameToSequenceMap.Values)
|
|
{
|
|
sequences.TryGetValue(seq, out var max);
|
|
if (step > max) max = step;
|
|
sequences[seq] = max;
|
|
}
|
|
|
|
m_Metadata.total_sequences = sequences.Count;
|
|
m_Metadata.sequences = new SequenceData[sequences.Count];
|
|
for (var i = 0; i < sequences.Count; i++)
|
|
{
|
|
m_Metadata.sequences[i] = new SequenceData
|
|
{
|
|
sequence_id = $"sequence_{i}",
|
|
steps = sequences[i]
|
|
};
|
|
}
|
|
|
|
file.Write(JsonUtility.ToJson(m_Metadata, true));
|
|
file.Close();
|
|
|
|
CopyDefFile("annotation", "annotations.json");
|
|
CopyDefFile("metric_def", "metrics.json");
|
|
CopyDefFile("sensors", "sensors.json");
|
|
|
|
|
|
// Copy image files to the proper path
|
|
|
|
var d = m_DirectoryName;
|
|
var upOne = Path.Combine(m_DirectoryName, "..");
|
|
var upOne2 = Directory.GetParent(m_DirectoryName)?.ToString() ?? string.Empty;
|
|
var upTwo = Directory.GetParent(upOne2)?.ToString() ?? string.Empty;
|
|
var upThree = Directory.GetParent(upTwo)?.ToString() ?? string.Empty;
|
|
|
|
var dirs = Directory.EnumerateDirectories(upThree);
|
|
|
|
foreach (var dir in dirs)
|
|
{
|
|
if (dir.Contains("RGB"))
|
|
{
|
|
foreach (var f in Directory.EnumerateFiles(dir))
|
|
{
|
|
// Get the frame number from the path
|
|
var filename = Path.GetFileName(f);
|
|
var underscore = filename.IndexOf("_") + 1;
|
|
var dot = filename.IndexOf(".");
|
|
var frame = filename.Substring(underscore, dot - underscore);
|
|
var (seq, step) = m_FrameToSequenceMap[int.Parse(frame)];
|
|
var newFilename = $"step.{step}.capture.camera.png";
|
|
|
|
|
|
File.Copy(f, Path.Combine(m_DirectoryName, $"sequence.{seq}", newFilename));
|
|
}
|
|
}
|
|
else if (dir.Contains("Instance"))
|
|
{
|
|
foreach (var f in Directory.EnumerateFiles(dir))
|
|
{
|
|
// Get the frame number from the path
|
|
var filename = Path.GetFileName(f);
|
|
var underscore = filename.IndexOf("_") + 1;
|
|
var dot = filename.IndexOf(".");
|
|
var frame = filename.Substring(underscore, dot - underscore);
|
|
var (seq, step) = m_FrameToSequenceMap[int.Parse(frame)];
|
|
var newFilename = $"step.{step}.annotation.semantic_segmentation.camera.png";
|
|
|
|
|
|
File.Copy(f, Path.Combine(m_DirectoryName, $"sequence.{seq}", newFilename));
|
|
}
|
|
}
|
|
else if (dir.Contains("Semantic"))
|
|
{
|
|
foreach (var f in Directory.EnumerateFiles(dir))
|
|
{
|
|
// Get the frame number from the path
|
|
var filename = Path.GetFileName(f);
|
|
var underscore = filename.IndexOf("_") + 1;
|
|
var dot = filename.IndexOf(".");
|
|
var frame = filename.Substring(underscore, dot - underscore);
|
|
var (seq, step) = m_FrameToSequenceMap[int.Parse(frame)];
|
|
var newFilename = $"step.{step}.annotation.instance_segmentation.camera.png";
|
|
|
|
|
|
File.Copy(f, Path.Combine(m_DirectoryName, $"sequence.{seq}", newFilename));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Go into the RGB directory
|
|
|
|
|
|
Manager.Instance.ConsumerFileProduced(writePath);
|
|
|
|
Task.WhenAll(m_PendingTasks);
|
|
}
|
|
|
|
public void OnAnnotationRegistered<TSpec>(Guid annotationId, TSpec[] values)
|
|
{
|
|
// Right now, do nothing :-)
|
|
}
|
|
|
|
bool GetFilenameForAnnotation(int sequence, int step, object rawData, out string filename, out string id, out string def, out bool reportValues)
|
|
{
|
|
filename = string.Empty;
|
|
id = string.Empty;
|
|
def = string.Empty;
|
|
reportValues = true;
|
|
if (rawData is BoundingBox2DLabeler.BoundingBoxValue bbox)
|
|
{
|
|
m_FrameToSequenceMap[bbox.frame] = (sequence, step);
|
|
var frame = bbox.frame;
|
|
id = "bounding_box";
|
|
def = $"{id}_definition";
|
|
// var fmt = new String('0', 5);
|
|
// var format = "{0,20:" + fmt + "}";
|
|
// filename = $"step.{frame.ToString(format)}.annotation.bounding_box.camera.json";
|
|
filename = $"step.{step}.annotation.{id}.camera.json";
|
|
return true;
|
|
}
|
|
#if false
|
|
if (rawData is InstanceSegmentationLabeler.InstanceColorValue)
|
|
{
|
|
id = "instance_segmentation";
|
|
def = $"{id}_definition";
|
|
// var fmt = new String('0', 5);
|
|
// var format = "{0,20:" + fmt + "}";
|
|
// filename = $"step.{frame.ToString(format)}.annotation.bounding_box.camera.json";
|
|
filename = $"step.{step}.annotation.{id}.camera.json";
|
|
return true;
|
|
}
|
|
#endif
|
|
if (rawData is SemanticSegmentationLabeler.SegmentationValue)
|
|
{
|
|
id = "semantic_segmentation";
|
|
def = $"{id}_definition";
|
|
// var fmt = new String('0', 5);
|
|
// var format = "{0,20:" + fmt + "}";
|
|
// filename = $"step.{frame.ToString(format)}.annotation.bounding_box.camera.json";
|
|
filename = $"step.{step}.annotation.{id}.camera.json";
|
|
reportValues = false;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// TODO - handle the 1000's of file writes we will be doing in a more intelligent fashion. Perhaps create a bg thread
|
|
// that reads json records off of a queue and writes them out
|
|
|
|
List<Task> m_PendingTasks = new List<Task>();
|
|
|
|
int m_CurrentSequence = 0;
|
|
Dictionary<Guid, int> m_SequenceGuidMap = new Dictionary<Guid, int>();
|
|
|
|
Dictionary<int, (int, int)> m_FrameToSequenceMap = new Dictionary<int, (int, int)>();
|
|
|
|
public Task ProcessPendingCaptures(List<SimulationState.PendingCapture> pendingCaptures, SimulationState simState)
|
|
{
|
|
foreach (var cap in pendingCaptures)
|
|
{
|
|
if (!m_SequenceGuidMap.TryGetValue(cap.SequenceId, out var seq))
|
|
{
|
|
seq = m_CurrentSequence++;
|
|
m_SequenceGuidMap[cap.SequenceId] = seq;
|
|
|
|
var seqDir = Path.Combine(m_DirectoryName, $"sequence.{m_SequenceGuidMap[cap.SequenceId]}");
|
|
|
|
// Create a directory
|
|
if (!Directory.Exists(seqDir))
|
|
Directory.CreateDirectory(seqDir);
|
|
}
|
|
|
|
var path = Path.Combine(m_DirectoryName, $"sequence.{m_SequenceGuidMap[cap.SequenceId]}");
|
|
|
|
foreach (var (annotation, annotationData) in cap.Annotations)
|
|
{
|
|
// Create a file for the annotation
|
|
|
|
#if false
|
|
if (annotationData.RawValues.Any())
|
|
{
|
|
var first = annotationData.RawValues.First();
|
|
|
|
if (GetFilenameForAnnotation(first, frame, out var filename))
|
|
{
|
|
var json = new StringBuilder("{");
|
|
json.Append(annotationData.ValuesJson);
|
|
json.Append("}");
|
|
m_PendingTasks.Add(AnnotationHandler.WriteOutJson(m_DirectoryName, filename, json.ToString()));
|
|
#if false
|
|
// Need to revisit this and handle this in a performant way
|
|
var jObject = PerceptionExporter.JObjectFromAnnotation((annotation, annotationData));
|
|
PerceptionExporter.WriteJObjectToFile(jObject, m_DirectoryName, filename);
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
foreach (var rawValue in annotationData.RawValues)
|
|
{
|
|
|
|
if (GetFilenameForAnnotation(seq, cap.Step, rawValue, out var filename, out var id, out var def, out var reportValues))
|
|
{
|
|
#if true
|
|
var sensor = "camera";
|
|
|
|
var json = new StringBuilder();
|
|
json.Append($"{{\"Id\": \"{id}\",");
|
|
json.Append($"\"definition\": \"{def}\",");
|
|
json.Append($"\"sequence\": {seq},");
|
|
json.Append($"\"step\": {cap.Step},");
|
|
json.Append($"\"sensor\": \"{sensor}\"");
|
|
|
|
if (reportValues)
|
|
{
|
|
json.Append(",\"values\":");
|
|
json.Append(annotationData.ValuesJson);
|
|
}
|
|
|
|
json.Append("}");
|
|
|
|
m_PendingTasks.Add(AnnotationHandler.WriteOutJson(path, filename, json.ToString()));
|
|
#else
|
|
// Need to revisit this and handle this in a performant way
|
|
var jObject = PerceptionExporter.JObjectFromAnnotation((annotation, annotationData));
|
|
PerceptionExporter.WriteJObjectToFile(jObject, m_DirectoryName, filename);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
[Serializable]
|
|
struct SensorData
|
|
{
|
|
public string id;
|
|
public int sequence;
|
|
public int step;
|
|
public Vector3 translation;
|
|
public Vector3 rotation;
|
|
public Vector3 velocity;
|
|
public Vector3 acceleration;
|
|
}
|
|
|
|
public Task OnCaptureReported(Guid sequence, int step, int width, int height, string filename, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 acceleration)
|
|
{
|
|
var sensor = new SensorData
|
|
{
|
|
id = "camera",
|
|
sequence = 0,
|
|
step = 0,
|
|
translation = position,
|
|
rotation = rotation.eulerAngles,
|
|
velocity = velocity,
|
|
acceleration = acceleration
|
|
};
|
|
|
|
if (!m_SequenceGuidMap.TryGetValue(sequence, out var seq))
|
|
{
|
|
seq = m_CurrentSequence++;
|
|
m_SequenceGuidMap[sequence] = seq;
|
|
}
|
|
|
|
var path = Path.Combine(m_DirectoryName, $"sequence.{seq}");
|
|
|
|
if (!Directory.Exists(path))
|
|
Directory.CreateDirectory(path);
|
|
|
|
var f = $"step.{step}.camera.json";
|
|
|
|
|
|
var json = JsonUtility.ToJson(sensor, true);
|
|
|
|
m_PendingTasks.Add(AnnotationHandler.WriteOutJson(path, f, json));
|
|
|
|
m_Metadata.total_frames++;
|
|
m_Metadata.sensors[0].resolution = new[] { width, height };
|
|
return null;
|
|
}
|
|
|
|
public Task ProcessPendingMetrics(List<SimulationState.PendingMetric> pendingMetrics, SimulationState simState)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
}
|