@@ -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 ] ;
0 commit comments