Skip to content

Commit 07ea8c1

Browse files
authored
Merge pull request #248 from Unity-Technologies/ability_to_disable_labeling
Added ability to disable labeling on an object by disabling its Labeling component
2 parents 3502511 + 3d110c4 commit 07ea8c1

File tree

10 files changed

+174
-76
lines changed

10 files changed

+174
-76
lines changed

com.unity.perception/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ The newly added `LabelManager` class now enables custom Labelers to access the l
5151

5252
Improved UI for `KeypointTemplate` and added useful default colors for keypoint and skeleton definitions.
5353

54+
Added the ability to switch ground-truth labeling on or off for an object at runtime by enabling or disabling its `Labeling` component.
55+
5456
### Changed
5557

5658
Renamed all appearances of the term `KeyPoint` within types and names to `Keypoint`.

com.unity.perception/Runtime/GroundTruth/InstanceIdToColorMapping.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static class InstanceIdToColorMapping
2626
const uint k_HslCount = 64;
2727
const uint k_ColorsPerAlpha = 256 * 256 * 256;
2828
const uint k_InvalidPackedColor = 255; // packed uint for color (0, 0, 0, 255);
29-
static readonly Color32 k_InvalidColor = new Color(0, 0, 0, 255);
29+
public static readonly Color32 invalidColor = new Color(0, 0, 0, 255);
3030
static readonly float k_GoldenRatio = (1 + Mathf.Sqrt(5)) / 2;
3131
const int k_HuesInEachValue = 30;
3232

@@ -143,7 +143,7 @@ public static Color32 GetColorFromPackedColor(uint color)
143143
/// <returns>Returns true if the ID was mapped to a non-black color, otherwise returns false</returns>
144144
public static bool TryGetColorFromInstanceId(uint id, out Color32 color)
145145
{
146-
color = k_InvalidColor;
146+
color = invalidColor;
147147
if (id > maxId) return false;
148148

149149
var packed = GetColorForId(id);

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

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -332,20 +332,21 @@ bool DoesTemplateContainJoint(JointLabel jointLabel)
332332

333333
void ProcessLabel(Labeling labeledEntity)
334334
{
335-
// Cache out the data of a labeled game object the first time we see it, this will
336-
// save performance each frame. Also checks to see if a labeled game object can be annotated.
337-
if (!m_KnownStatus.ContainsKey(labeledEntity.instanceId))
335+
if (idLabelConfig.TryGetLabelEntryFromInstanceId(labeledEntity.instanceId, out var labelEntry))
338336
{
339-
var cached = new CachedData()
337+
// Cache out the data of a labeled game object the first time we see it, this will
338+
// save performance each frame. Also checks to see if a labeled game object can be annotated.
339+
if (!m_KnownStatus.ContainsKey(labeledEntity.instanceId))
340340
{
341-
status = false,
342-
animator = null,
343-
keypoints = new KeypointEntry(),
344-
overrides = new List<(JointLabel, int)>()
345-
};
341+
var cached = new CachedData()
342+
{
343+
status = false,
344+
animator = null,
345+
keypoints = new KeypointEntry(),
346+
overrides = new List<(JointLabel, int)>()
347+
};
348+
346349

347-
if (idLabelConfig.TryGetLabelEntryFromInstanceId(labeledEntity.instanceId, out var labelEntry))
348-
{
349350
var entityGameObject = labeledEntity.gameObject;
350351

351352
cached.keypoints.instance_id = labeledEntity.instanceId;
@@ -373,55 +374,55 @@ void ProcessLabel(Labeling labeledEntity)
373374
cached.status = true;
374375
}
375376
}
376-
}
377377

378-
m_KnownStatus[labeledEntity.instanceId] = cached;
379-
}
378+
m_KnownStatus[labeledEntity.instanceId] = cached;
379+
}
380380

381-
var cachedData = m_KnownStatus[labeledEntity.instanceId];
381+
var cachedData = m_KnownStatus[labeledEntity.instanceId];
382382

383-
if (cachedData.status)
384-
{
385-
var animator = cachedData.animator;
386-
var keypoints = cachedData.keypoints.keypoints;
387-
388-
// Go through all of the rig keypoints and get their location
389-
for (var i = 0; i < activeTemplate.keypoints.Length; i++)
383+
if (cachedData.status)
390384
{
391-
var pt = activeTemplate.keypoints[i];
392-
if (pt.associateToRig)
385+
var animator = cachedData.animator;
386+
var keypoints = cachedData.keypoints.keypoints;
387+
388+
// Go through all of the rig keypoints and get their location
389+
for (var i = 0; i < activeTemplate.keypoints.Length; i++)
393390
{
394-
var bone = animator.GetBoneTransform(pt.rigLabel);
395-
if (bone != null)
391+
var pt = activeTemplate.keypoints[i];
392+
if (pt.associateToRig)
396393
{
397-
var loc = ConvertToScreenSpace(bone.position);
398-
keypoints[i].index = i;
399-
keypoints[i].x = loc.x;
400-
keypoints[i].y = loc.y;
401-
keypoints[i].state = 2;
394+
var bone = animator.GetBoneTransform(pt.rigLabel);
395+
if (bone != null)
396+
{
397+
var loc = ConvertToScreenSpace(bone.position);
398+
keypoints[i].index = i;
399+
keypoints[i].x = loc.x;
400+
keypoints[i].y = loc.y;
401+
keypoints[i].state = 2;
402+
}
402403
}
403404
}
404-
}
405405

406-
// Go through all of the additional or override points defined by joint labels and get
407-
// their locations
408-
foreach (var (joint, idx) in cachedData.overrides)
409-
{
410-
var loc = ConvertToScreenSpace(joint.transform.position);
411-
keypoints[idx].index = idx;
412-
keypoints[idx].x = loc.x;
413-
keypoints[idx].y = loc.y;
414-
keypoints[idx].state = 2;
415-
}
406+
// Go through all of the additional or override points defined by joint labels and get
407+
// their locations
408+
foreach (var (joint, idx) in cachedData.overrides)
409+
{
410+
var loc = ConvertToScreenSpace(joint.transform.position);
411+
keypoints[idx].index = idx;
412+
keypoints[idx].x = loc.x;
413+
keypoints[idx].y = loc.y;
414+
keypoints[idx].state = 2;
415+
}
416416

417-
cachedData.keypoints.pose = "unset";
417+
cachedData.keypoints.pose = "unset";
418418

419-
if (cachedData.animator != null)
420-
{
421-
cachedData.keypoints.pose = GetPose(cachedData.animator);
422-
}
419+
if (cachedData.animator != null)
420+
{
421+
cachedData.keypoints.pose = GetPose(cachedData.animator);
422+
}
423423

424-
m_AsyncAnnotations[m_CurrentFrame].keypoints[labeledEntity.instanceId] = cachedData.keypoints;
424+
m_AsyncAnnotations[m_CurrentFrame].keypoints[labeledEntity.instanceId] = cachedData.keypoints;
425+
}
425426
}
426427
}
427428

com.unity.perception/Runtime/GroundTruth/Labeling/LabelEntryMatchCache.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,24 @@ void IGroundTruthGenerator.SetupMaterialProperties(MaterialPropertyBlock mpb, Re
5858
if (m_IdLabelConfig.TryGetMatchingConfigurationEntry(labeling, out _, out var index))
5959
{
6060
Debug.Assert(index < k_DefaultValue, "Too many entries in the label config");
61-
if (m_InstanceIdToLabelEntryIndexLookup.Length <= instanceId)
61+
if (labeling.enabled)
6262
{
63-
var oldLength = m_InstanceIdToLabelEntryIndexLookup.Length;
64-
m_InstanceIdToLabelEntryIndexLookup.Resize((int)instanceId + 1, NativeArrayOptions.ClearMemory);
63+
if (m_InstanceIdToLabelEntryIndexLookup.Length <= instanceId)
64+
{
65+
var oldLength = m_InstanceIdToLabelEntryIndexLookup.Length;
66+
m_InstanceIdToLabelEntryIndexLookup.Resize((int)instanceId + 1, NativeArrayOptions.ClearMemory);
6567

66-
for (var i = oldLength; i < instanceId; i++)
67-
m_InstanceIdToLabelEntryIndexLookup[i] = k_DefaultValue;
68+
for (var i = oldLength; i < instanceId; i++)
69+
m_InstanceIdToLabelEntryIndexLookup[i] = k_DefaultValue;
70+
}
71+
m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = (ushort)index;
72+
}
73+
else if (m_InstanceIdToLabelEntryIndexLookup.Length > instanceId)
74+
{
75+
m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = k_DefaultValue;
6876
}
69-
m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = (ushort)index;
7077
}
71-
else if (m_InstanceIdToLabelEntryIndexLookup.Length > (int)instanceId)
78+
else if (m_InstanceIdToLabelEntryIndexLookup.Length > instanceId)
7279
{
7380
m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = k_DefaultValue;
7481
}

com.unity.perception/Runtime/GroundTruth/Labeling/LabelManager.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,6 @@ public bool Deactivate(IGroundTruthGenerator generator)
8181
return m_ActiveGenerators.Remove(generator);
8282
}
8383

84-
/// <summary>
85-
/// Registers a labeling component
86-
/// </summary>
87-
/// <param name="labeling">the component to register</param>
88-
internal void Register(Labeling labeling)
89-
{
90-
m_LabelsPendingRegistration.Add(labeling);
91-
}
92-
9384
/// <summary>
9485
/// Unregisters a labeling component
9586
/// </summary>

com.unity.perception/Runtime/GroundTruth/Labeling/Labeling.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using UnityEditor;
34
using UnityEngine.Serialization;
@@ -34,14 +35,19 @@ public class Labeling : MonoBehaviour
3435
/// </summary>
3536
public uint instanceId { get; private set; }
3637

37-
void Awake()
38+
void OnDestroy()
3839
{
39-
labelManager.Register(this);
40+
labelManager.Unregister(this);
4041
}
4142

42-
void OnDestroy()
43+
void OnEnable()
4344
{
44-
labelManager.Unregister(this);
45+
RefreshLabeling();
46+
}
47+
48+
void OnDisable()
49+
{
50+
RefreshLabeling();
4551
}
4652

4753
void Reset()

com.unity.perception/Runtime/GroundTruth/RenderPasses/CrossPipelinePasses/InstanceSegmentationCrossPipelinePass.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ public override void SetupMaterialProperties(
6969
if (!found)
7070
Debug.LogError($"Could not get a unique color for {instanceId}");
7171

72-
mpb.SetVector(k_SegmentationIdProperty, (Color)color);
72+
if (labeling.enabled)
73+
mpb.SetVector(k_SegmentationIdProperty, (Color)color);
74+
else
75+
mpb.SetVector(k_SegmentationIdProperty, (Color) InstanceIdToColorMapping.invalidColor);
7376
#if PERCEPTION_DEBUG
7477
Debug.Log($"Assigning id. Frame {Time.frameCount} id {id}");
7578
#endif

com.unity.perception/Runtime/GroundTruth/RenderPasses/CrossPipelinePasses/SemanticSegmentationCrossPipelinePass.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,25 @@ public override void SetupMaterialProperties(
6565
{
6666
var entry = new SemanticSegmentationLabelEntry();
6767
var found = false;
68-
foreach (var l in m_LabelConfig.labelEntries)
68+
if (labeling.enabled)
6969
{
70-
if (labeling.labels.Contains(l.label))
70+
foreach (var l in m_LabelConfig.labelEntries)
7171
{
72-
entry = l;
73-
found = true;
74-
break;
72+
if (labeling.labels.Contains(l.label))
73+
{
74+
entry = l;
75+
found = true;
76+
break;
77+
}
7578
}
7679
}
7780

7881
// Set the labeling ID so that it can be accessed in ClassSemanticSegmentationPass.shader
7982
if (found)
8083
mpb.SetVector(k_LabelingId, entry.color);
84+
else
85+
mpb.SetVector(k_LabelingId, Color.black);
86+
8187
}
8288
}
8389
}

com.unity.perception/Tests/Runtime/GroundTruthTests/LabelEntryMatchCacheTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,43 @@ public IEnumerator TryGet_ReturnsFalse_ForNonMatchingLabel_WhenAllObjectsAreDest
131131
}
132132
}
133133

134+
[UnityTest]
135+
public IEnumerator TryGet_ReturnsFalse_ForMatchingLabelWithDisabledLabelingComponent()
136+
{
137+
var label = "label";
138+
var labeledPlane = TestHelper.CreateLabeledPlane(label: label);
139+
AddTestObjectForCleanup(labeledPlane);
140+
var config = ScriptableObject.CreateInstance<IdLabelConfig>();
141+
var labeling = labeledPlane.GetComponent<Labeling>();
142+
143+
config.Init(new[]
144+
{
145+
new IdLabelEntry()
146+
{
147+
id = 1,
148+
label = label
149+
},
150+
});
151+
using (var cache = new LabelEntryMatchCache(config, Allocator.Persistent))
152+
{
153+
labeling.enabled = false;
154+
//allow label to be registered
155+
yield return null;
156+
Assert.IsFalse(cache.TryGetLabelEntryFromInstanceId(labeledPlane.GetComponent<Labeling>().instanceId, out var labelEntry, out var index));
157+
Assert.AreEqual(-1, index);
158+
159+
labeling.enabled = true;
160+
yield return null;
161+
Assert.IsTrue(cache.TryGetLabelEntryFromInstanceId(labeledPlane.GetComponent<Labeling>().instanceId, out labelEntry, out index));
162+
Assert.AreEqual(0, index);
163+
Assert.AreEqual(config.labelEntries[0], labelEntry);
164+
165+
labeling.enabled = false;
166+
yield return null;
167+
Assert.IsFalse(cache.TryGetLabelEntryFromInstanceId(labeledPlane.GetComponent<Labeling>().instanceId, out labelEntry, out index));
168+
Assert.AreEqual(-1, index);
169+
}
170+
}
171+
134172
}
135173
}

com.unity.perception/Tests/Runtime/GroundTruthTests/SegmentationGroundTruthTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,50 @@ void OnSegmentationImageReceived(NativeArray<Color32> data)
256256
Assert.AreEqual(1, timesSegmentationImageReceived);
257257
}
258258

259+
[UnityTest]
260+
public IEnumerator SemanticSegmentationPass_WithMatchingButDisabledLabel_ProducesBlack()
261+
{
262+
int timesSegmentationImageReceived = 0;
263+
var expectedPixelValue = new Color32(0, 0, 0, 255);
264+
void OnSegmentationImageReceived(NativeArray<Color32> data)
265+
{
266+
timesSegmentationImageReceived++;
267+
CollectionAssert.AreEqual(Enumerable.Repeat(expectedPixelValue, data.Length), data.ToArray());
268+
}
269+
270+
var cameraObject = SetupCameraSemanticSegmentation(a => OnSegmentationImageReceived(a.data), false);
271+
272+
var gameObject = TestHelper.CreateLabeledPlane();
273+
gameObject.GetComponent<Labeling>().enabled = false;
274+
AddTestObjectForCleanup(gameObject);
275+
yield return null;
276+
//destroy the object to force all pending segmented image readbacks to finish and events to be fired.
277+
DestroyTestObject(cameraObject);
278+
Assert.AreEqual(1, timesSegmentationImageReceived);
279+
}
280+
281+
[UnityTest]
282+
public IEnumerator InstanceSegmentationPass_WithMatchingButDisabledLabel_ProducesBlack()
283+
{
284+
int timesSegmentationImageReceived = 0;
285+
var expectedPixelValue = new Color32(0, 0, 0, 255);
286+
void OnSegmentationImageReceived(NativeArray<Color32> data)
287+
{
288+
CollectionAssert.AreEqual(Enumerable.Repeat(expectedPixelValue, data.Length), data);
289+
timesSegmentationImageReceived++;
290+
}
291+
292+
var cameraObject = SetupCameraInstanceSegmentation((frame, data, renderTexture) => OnSegmentationImageReceived(data));
293+
294+
var gameObject = TestHelper.CreateLabeledPlane();
295+
gameObject.GetComponent<Labeling>().enabled = false;
296+
AddTestObjectForCleanup(gameObject);
297+
yield return null;
298+
//destroy the object to force all pending segmented image readbacks to finish and events to be fired.
299+
DestroyTestObject(cameraObject);
300+
Assert.AreEqual(1, timesSegmentationImageReceived);
301+
}
302+
259303
[UnityTest]
260304
public IEnumerator SemanticSegmentationPass_WithEmptyFrame_ProducesBlack([Values(false, true)] bool showVisualizations)
261305
{

0 commit comments

Comments
 (0)