-
Notifications
You must be signed in to change notification settings - Fork 177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Steve/instance aggregation #563
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,6 @@ | ||||||
using System; | ||||||
using System.Collections.Generic; | ||||||
using System.Linq; | ||||||
using Unity.Collections; | ||||||
using UnityEngine; | ||||||
using UnityEngine.Experimental.Rendering; | ||||||
|
@@ -49,6 +50,14 @@ public sealed class InstanceSegmentationLabeler : CameraLabeler, IOverlayPanelPr | |||||
/// </summary> | ||||||
public IdLabelConfig idLabelConfig; | ||||||
|
||||||
/// <summary> | ||||||
/// Should child objects, defined by their label hierarchy be reported as an individual instance, or as | ||||||
/// a part of their parent object. If this value is true, the children will be reported as a part of their | ||||||
/// parent. | ||||||
/// </summary> | ||||||
[Tooltip("Should the instance segmentation capture the single instance of the parent gameobject, or the individual sub-components")] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
public bool aggregateChildren = false; | ||||||
|
||||||
///<inheritdoc/> | ||||||
public override string description => InstanceSegmentationDefinition.labelDescription; | ||||||
|
||||||
|
@@ -115,6 +124,44 @@ protected override void Cleanup() | |||||
} | ||||||
} | ||||||
|
||||||
NativeArray<Color32> GetSegmentationColors(int frame) | ||||||
{ | ||||||
var instanceIndices = LabelManager.singleton.instanceIds; | ||||||
var max = uint.MinValue; | ||||||
foreach (var i in instanceIndices) | ||||||
{ | ||||||
if (i > max) max = i; | ||||||
} | ||||||
|
||||||
var activeColors = new NativeArray<Color32>((int)(max + 1), Allocator.Temp, NativeArrayOptions.ClearMemory); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One little concern that I have here is that the array of instance ids can grow indefinitely in projects that use object caching, because we only remove instance ids when objects are destroyed. With 1000 iterations and 20 labelled objects each iteration, activeColors could be around 80KBs. May not be a big deal, but just something to keep in mind. |
||||||
|
||||||
for (var i = 0; i < max + 1; i++) | ||||||
{ | ||||||
activeColors[i] = InstanceIdToColorMapping.GetColorFromInstanceId((uint)i); | ||||||
} | ||||||
|
||||||
if (!aggregateChildren) return activeColors; | ||||||
|
||||||
if (!PerceptionCamera.savedHierarchies.TryGetValue(frame, out var hierarchyInformation)) | ||||||
{ | ||||||
Debug.LogError($"Could not get the scene hierarchy info for the current frame: {frame}"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
return activeColors; | ||||||
} | ||||||
|
||||||
foreach (var i in instanceIndices) | ||||||
{ | ||||||
if (!hierarchyInformation.hierarchy.TryGetValue(i, out var node)) | ||||||
{ | ||||||
continue; | ||||||
} | ||||||
|
||||||
var idx = (int)(node?.parentInstanceId ?? i); | ||||||
activeColors[(int)i] = activeColors[idx]; | ||||||
} | ||||||
|
||||||
return activeColors; | ||||||
} | ||||||
|
||||||
/// <inheritdoc/> | ||||||
protected override void OnEndRendering(ScriptableRenderContext ctx) | ||||||
{ | ||||||
|
@@ -126,9 +173,10 @@ protected override void OnEndRendering(ScriptableRenderContext ctx) | |||||
|
||||||
// Create a compute buffer that maps instanceIndices to unique instance segmentation colors. | ||||||
var instanceIndices = LabelManager.singleton.instanceIds; | ||||||
var instanceSegmentationColors = LabelManager.singleton.instanceSegmentationColors; | ||||||
var colors = GetSegmentationColors(Time.frameCount); | ||||||
|
||||||
var colorBuffer = new ComputeBuffer(instanceIndices.Length, sizeof(uint)); | ||||||
cmd.SetBufferData(colorBuffer, instanceSegmentationColors.AsArray(), 0, 0, colorBuffer.count); | ||||||
cmd.SetBufferData(colorBuffer, colors, 0, 0, colorBuffer.count); | ||||||
|
||||||
// Use a compute shader to map each pixel instance index to a unique color | ||||||
// to create the instance segmentation color texture. | ||||||
|
@@ -149,6 +197,7 @@ protected override void OnEndRendering(ScriptableRenderContext ctx) | |||||
colorBuffer.Dispose(); | ||||||
}); | ||||||
|
||||||
colors.Dispose(); | ||||||
ctx.ExecuteCommandBuffer(cmd); | ||||||
CommandBufferPool.Release(cmd); | ||||||
} | ||||||
|
@@ -159,23 +208,76 @@ void OnRenderedObjectInfosCalculated( | |||||
SceneHierarchyInformation hierarchyInfo | ||||||
) | ||||||
{ | ||||||
var instances = new List<InstanceSegmentationEntry>(); | ||||||
// In order to support aggregate segmentation, we need to use the parent values, if requested, | ||||||
// of the instances to report the instance type for color | ||||||
|
||||||
var instances = new Dictionary<int, InstanceSegmentationEntry>(); | ||||||
|
||||||
foreach (var objectInfo in renderedObjectInfos) | ||||||
{ | ||||||
if (!idLabelConfig.TryGetLabelEntryFromInstanceId(objectInfo.instanceId, out var labelEntry)) | ||||||
if (!hierarchyInfo.hierarchy.TryGetValue(objectInfo.instanceId, out var node)) | ||||||
{ | ||||||
Debug.LogError($"Could not find hierarchy info for instance id: {objectInfo.instanceId}"); | ||||||
continue; | ||||||
} | ||||||
|
||||||
// If collecting aggregate info, use the parent id, else use the objectInfo.instanceId | ||||||
var idx = aggregateChildren ? node?.parentInstanceId ?? objectInfo.instanceId : objectInfo.instanceId; | ||||||
var intIdx = (int)idx; | ||||||
|
||||||
// Ok, this exists because we have no good way to look up label information at runtime, if a label | ||||||
// is not associated with an object that is captured in objectrenderinfo pass. This is seen routinely | ||||||
// in parent geometry using hierarchical labeling not having geometry of its own, but just aggregating | ||||||
// labeled child objects. To support this we have to create a way to query labels from the id label config. | ||||||
// This is not the most performant way to do this, things that we could do in the future to speed this up | ||||||
// * rework the way we are calculating labeled data | ||||||
// * cache this | ||||||
// Also, this only supports a 1-1 mapping of int id to label and label to int id. Re-using labels will | ||||||
// break this but right now is *probably* supported in perception. We need to revisit that and codify | ||||||
// that label strings need to be unique. | ||||||
var labelMap = new Dictionary<string, int>(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we try to cache this? We don't supporting updating of label configs at runtime any way. |
||||||
var labels = idLabelConfig.GetAnnotationSpecification(); | ||||||
foreach (var l in labels) | ||||||
{ | ||||||
labelMap[l.label_name] = l.label_id; | ||||||
} | ||||||
|
||||||
instances.Add(new InstanceSegmentationEntry | ||||||
if (!instances.ContainsKey(intIdx)) | ||||||
{ | ||||||
instanceId = (int)objectInfo.instanceId, | ||||||
labelId = labelEntry.id, | ||||||
labelName = labelEntry.label, | ||||||
color = objectInfo.instanceColor | ||||||
}); | ||||||
var registeredLabels = LabelManager.singleton.registeredLabels; | ||||||
var targetNodes = registeredLabels.Where(x => x.instanceId == idx).ToList(); | ||||||
|
||||||
if (targetNodes.Count != 1) | ||||||
{ | ||||||
Debug.LogWarning($"Something went wrong when trying to find the node for label {idx}, query came back with {targetNodes.Count} entries"); | ||||||
continue; | ||||||
} | ||||||
|
||||||
var targetNode = targetNodes.First(); | ||||||
|
||||||
if (!InstanceIdToColorMapping.TryGetColorFromInstanceId(idx, out var color)) | ||||||
{ | ||||||
Debug.LogWarning($"Could not find the instance color for ID: {idx}"); | ||||||
color = Color.black; | ||||||
} | ||||||
|
||||||
var labelName = targetNode.labels.First(); | ||||||
if (!labelMap.TryGetValue(labelName, out var labelId)) | ||||||
{ | ||||||
Debug.LogWarning($"Could not find a labelId for the label: {labelName}"); | ||||||
} | ||||||
|
||||||
instances[intIdx] = new InstanceSegmentationEntry | ||||||
{ | ||||||
instanceId = intIdx, | ||||||
labelId = labelId, | ||||||
labelName = labelName, | ||||||
color = color | ||||||
}; | ||||||
} | ||||||
} | ||||||
|
||||||
m_PendingEntries[frame] = instances; | ||||||
m_PendingEntries[frame] = instances.Values.ToList(); | ||||||
|
||||||
ReportFrameIfReady(frame); | ||||||
} | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This gives me an error on 2021.3.x. (official perception supported version). Looking at the api, it looks like
selectionChanged
is only supported on 2023.1 and later, do you happen to be using that one?To make it work, we can change the whole block to
This should make the tests pass too.