Skip to content

Commit 1a824cf

Browse files
Keypoint tolerance (#235)
* Added tolerance to test to see if entity contains keypoint * Revert "Added tolerance to test to see if entity contains keypoint" This reverts commit ad94806. * Added tolerance to keypoint on instance check * Updates to address PR comments * Removed Using.Entities that accidentally got brought back in
1 parent 9572d4c commit 1a824cf

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

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

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,63 @@ bool AreEqual(Color32 lhs, Color32 rhs)
103103
return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a;
104104
}
105105

106+
bool PixelOnScreen(int x, int y, (int x, int y) dimensions)
107+
{
108+
return x >= 0 && x < dimensions.x && y >= 0 && y < dimensions.y;
109+
}
110+
111+
bool PixelsMatch(int x, int y, Color32 idColor, (int x, int y) dimensions, NativeArray<Color32> data)
112+
{
113+
var h = dimensions.y - y;
114+
var pixelColor = data[h * dimensions.x + x];
115+
return AreEqual(pixelColor, idColor);
116+
}
117+
118+
static int s_PixelTolerance = 1;
119+
120+
// Determine the state of a keypoint. A keypoint is considered visible (state = 2) if it is on screen and not occluded
121+
// by another object. The way that we determine if a point is occluded is by checking the pixel location of the keypoint
122+
// against the instance segmentation mask for the frame. The instance segmentation mask provides the instance id of the
123+
// visible object at a pixel location. Which means, if the keypoint does not match the visible pixel, then another
124+
// object is in front of the keypoint occluding it from view. An important note here is that the keypoint is an infintely small
125+
// point in space, which can lead to false negatives due to rounding issues if the keypoint is on the edge of an object or very
126+
// close to the edge of the screen. Because of this we will test not only the keypoint pixel, but also the immediate surrounding
127+
// pixels to determine if the pixel is really visible. This method returns 1 if the pixel is not visible but on screen, and 0
128+
// if the pixel is off of the screen (taken the tolerance into account).
129+
int DetermineKeypointState(Keypoint keypoint, Color32 instanceIdColor, (int x, int y) dimensions, NativeArray<Color32> data)
130+
{
131+
if (keypoint.state == 0) return 0;
132+
133+
var centerX = Mathf.RoundToInt(keypoint.x);
134+
var centerY = Mathf.RoundToInt(keypoint.y);
135+
136+
var pixelOnScreen = false;
137+
138+
for (var y = centerY - s_PixelTolerance; y <= centerY + s_PixelTolerance; y++)
139+
{
140+
for (var x = centerX - s_PixelTolerance; x <= centerX + s_PixelTolerance; x++)
141+
{
142+
if (!PixelOnScreen(x, y, dimensions)) continue;
143+
144+
pixelOnScreen = true;
145+
if (PixelsMatch(x, y, instanceIdColor, dimensions, data))
146+
{
147+
return 2;
148+
}
149+
}
150+
}
151+
152+
return pixelOnScreen ? 1 : 0;
153+
}
154+
106155
void OnInstanceSegmentationImageReadback(int frameCount, NativeArray<Color32> data, RenderTexture renderTexture)
107156
{
108157
if (!m_AsyncAnnotations.TryGetValue(frameCount, out var asyncAnnotation))
109158
return;
110159

111160
m_AsyncAnnotations.Remove(frameCount);
112161

113-
var width = renderTexture.width;
162+
var dimensions = (renderTexture.width, renderTexture.height);
114163

115164
m_ToReport.Clear();
116165

@@ -122,22 +171,15 @@ void OnInstanceSegmentationImageReadback(int frameCount, NativeArray<Color32> da
122171

123172
foreach (var keypoint in keypointSet.Value.keypoints)
124173
{
125-
// If the keypoint isn't mapped to a body part keep it at 0
126-
if (keypoint.state == 0) continue;
174+
keypoint.state = DetermineKeypointState(keypoint, idColor, dimensions, data);
127175

128-
if (keypoint.x < 0 || keypoint.x > width || keypoint.y < 0 || keypoint.y > renderTexture.height)
176+
if (keypoint.state == 0)
129177
{
130-
keypoint.state = 0;
131178
keypoint.x = 0;
132179
keypoint.y = 0;
133180
}
134181
else
135182
{
136-
// Get the pixel color at the keypoints location
137-
var height = renderTexture.height - (int)keypoint.y;
138-
var pixel = data[height * width + (int)keypoint.x];
139-
140-
keypoint.state = AreEqual(pixel, idColor) ? 2 : 1;
141183
shouldReport = true;
142184
}
143185
}
@@ -228,8 +270,9 @@ public class Keypoint
228270

229271
float GetCaptureHeight()
230272
{
231-
return perceptionCamera.attachedCamera.targetTexture != null ?
232-
perceptionCamera.attachedCamera.targetTexture.height : Screen.height;
273+
var targetTexture = perceptionCamera.attachedCamera.targetTexture;
274+
return targetTexture != null ?
275+
targetTexture.height : Screen.height;
233276
}
234277

235278
// Converts a coordinate from world space into pixel space
@@ -305,7 +348,7 @@ void ProcessLabel(Labeling labeledEntity)
305348

306349
cached.keypoints.instance_id = labeledEntity.instanceId;
307350
cached.keypoints.label_id = labelEntry.id;
308-
cached.keypoints.template_guid = activeTemplate.templateID.ToString();
351+
cached.keypoints.template_guid = activeTemplate.templateID;
309352

310353
cached.keypoints.keypoints = new Keypoint[activeTemplate.keypoints.Length];
311354
for (var i = 0; i < cached.keypoints.keypoints.Length; i++)
@@ -470,7 +513,7 @@ struct KeypointJson
470513
KeypointJson TemplateToJson(KeypointTemplate input)
471514
{
472515
var json = new KeypointJson();
473-
json.template_id = input.templateID.ToString();
516+
json.template_id = input.templateID;
474517
json.template_name = input.templateName;
475518
json.key_points = new JointJson[input.keypoints.Length];
476519
json.skeleton = new SkeletonJson[input.skeleton.Length];

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,15 @@ static void SetupCubeJoint(GameObject cube, KeypointTemplate template, string la
271271

272272
static void SetupCubeJoints(GameObject cube, KeypointTemplate template)
273273
{
274-
SetupCubeJoint(cube, template, "FrontLowerLeft", -0.495f, -0.495f, -0.495f);
275-
SetupCubeJoint(cube, template, "FrontUpperLeft", -0.495f, 0.495f, -0.495f);
276-
SetupCubeJoint(cube, template, "FrontUpperRight", 0.495f, 0.495f, -0.495f);
277-
SetupCubeJoint(cube, template, "FrontLowerRight", 0.495f, -0.495f, -0.495f);
278-
SetupCubeJoint(cube, template, "BackLowerLeft", -0.495f, -0.495f, 0.495f);
279-
SetupCubeJoint(cube, template, "BackUpperLeft", -0.495f, 0.495f, 0.495f);
280-
SetupCubeJoint(cube, template, "BackUpperRight", 0.495f, 0.495f, 0.495f);
281-
SetupCubeJoint(cube, template, "BackLowerRight", 0.495f, -0.495f, 0.495f);
274+
const float dim = 0.5f;
275+
SetupCubeJoint(cube, template, "FrontLowerLeft", -dim, -dim, -dim);
276+
SetupCubeJoint(cube, template, "FrontUpperLeft", -dim, dim, -dim);
277+
SetupCubeJoint(cube, template, "FrontUpperRight", dim, dim, -dim);
278+
SetupCubeJoint(cube, template, "FrontLowerRight", dim, -dim, -dim);
279+
SetupCubeJoint(cube, template, "BackLowerLeft", -dim, -dim, dim);
280+
SetupCubeJoint(cube, template, "BackUpperLeft", -dim, dim, dim);
281+
SetupCubeJoint(cube, template, "BackUpperRight", dim, dim, dim);
282+
SetupCubeJoint(cube, template, "BackLowerRight", dim, -dim, dim);
282283
}
283284

284285
[UnityTest]

0 commit comments

Comments
 (0)