t1 / TFDContents / Assets / KinectDemos / VariousDemos / Scripts / HandObjectChecker.cs @ 3
이력 | 보기 | 이력해설 | 다운로드 (11.9 KB)
1 | 3 | KTH | using UnityEngine; |
---|---|---|---|
2 | using System.Collections; |
||
3 | using System.Text; |
||
4 | |||
5 | public class HandObjectChecker : MonoBehaviour |
||
6 | { |
||
7 | [Tooltip("Index of the player, tracked by this component. 0 means the 1st player, 1 - the 2nd one, 2 - the 3rd one, etc.")] |
||
8 | public int playerIndex = 0; |
||
9 | |||
10 | [Tooltip("Maximum distance in horizontal & vertical directions from the hand center, in meters, to be tracked for an object.")] |
||
11 | public float maxHvDistanceToHand = 0.1f; |
||
12 | |||
13 | [Tooltip("Maximum distance in depth from the hand center, in meters, to be tracked for an object.")] |
||
14 | public float maxZDistanceToJoint = 0.05f; |
||
15 | |||
16 | [Tooltip("Minimum fill ratio of the tracked depth area, to be considered as a valid object.")] |
||
17 | public float fillThreshold = 0.5f; |
||
18 | |||
19 | [Tooltip("GUI-Text to display status messages.")] |
||
20 | public GUIText statusText; |
||
21 | |||
22 | private long trackedUserId; |
||
23 | private byte userBodyIndex; |
||
24 | |||
25 | private KinectManager manager; |
||
26 | private KinectInterop.SensorData sensorData; |
||
27 | private long lastDepthFrameTime; |
||
28 | |||
29 | private Vector2 dposHandLeft = Vector2.zero; |
||
30 | private Vector2 dposHandRight = Vector2.zero; |
||
31 | |||
32 | private Vector2 depthMinMaxHL = Vector2.zero; |
||
33 | private Vector2 depthMinMaxHR = Vector2.zero; |
||
34 | |||
35 | private Rect rectObjectHandLeft = new Rect(); |
||
36 | private Rect rectObjectHandRight = new Rect(); |
||
37 | |||
38 | private float fillRatioLeftHand = 0f; |
||
39 | private float fillRatioRightHand = 0f; |
||
40 | |||
41 | // private Vector3 sizeObjectHandLeft = Vector3.zero; |
||
42 | // private Vector3 sizeObjectHandRight = Vector3.zero; |
||
43 | |||
44 | |||
45 | void Start () |
||
46 | { |
||
47 | manager = KinectManager.Instance; |
||
48 | sensorData = manager ? manager.GetSensorData() : null; |
||
49 | } |
||
50 | |||
51 | void Update () |
||
52 | { |
||
53 | if(!manager || !manager.IsInitialized()) |
||
54 | return; |
||
55 | |||
56 | // get required player |
||
57 | long userId = manager.GetUserIdByIndex (playerIndex); |
||
58 | |||
59 | if (trackedUserId != userId) |
||
60 | { |
||
61 | // user lost |
||
62 | trackedUserId = 0; |
||
63 | } |
||
64 | |||
65 | if(trackedUserId == 0 && userId != 0) |
||
66 | { |
||
67 | // new user found |
||
68 | trackedUserId = userId; |
||
69 | } |
||
70 | |||
71 | if (trackedUserId != 0 && sensorData.bodyIndexImage != null && sensorData.depthImage != null && |
||
72 | sensorData.lastDepthFrameTime != lastDepthFrameTime) |
||
73 | { |
||
74 | lastDepthFrameTime = sensorData.lastDepthFrameTime; |
||
75 | userBodyIndex = (byte)manager.GetBodyIndexByUserId(trackedUserId); |
||
76 | |||
77 | TrackDepthAroundJoint((int)KinectInterop.JointType.HandLeft, ref dposHandLeft, ref rectObjectHandLeft, ref depthMinMaxHL, ref fillRatioLeftHand); |
||
78 | TrackDepthAroundJoint((int)KinectInterop.JointType.HandRight, ref dposHandRight, ref rectObjectHandRight, ref depthMinMaxHR, ref fillRatioRightHand); |
||
79 | |||
80 | // CalculateObjectSize(dposHandLeft, rectObjectHandLeft, depthMinMaxHL, ref sizeObjectHandLeft); |
||
81 | // CalculateObjectSize(dposHandRight, rectObjectHandRight, depthMinMaxHR, ref sizeObjectHandRight); |
||
82 | |||
83 | Texture2D texDepth = manager.GetUsersLblTex(); |
||
84 | |||
85 | bool bRectDrawn = false; |
||
86 | if (rectObjectHandLeft.width != 0f && rectObjectHandLeft.height != 0f && dposHandLeft != Vector2.zero) |
||
87 | { |
||
88 | KinectInterop.DrawRect(texDepth, rectObjectHandLeft, fillRatioLeftHand > fillThreshold ? Color.green : Color.yellow); |
||
89 | bRectDrawn = true; |
||
90 | } |
||
91 | |||
92 | if (rectObjectHandRight.width != 0f && rectObjectHandRight.height != 0f && dposHandRight != Vector2.zero) |
||
93 | { |
||
94 | KinectInterop.DrawRect(texDepth, rectObjectHandRight, fillRatioRightHand > fillThreshold ? Color.green : Color.yellow); |
||
95 | bRectDrawn = true; |
||
96 | } |
||
97 | |||
98 | if (bRectDrawn) |
||
99 | { |
||
100 | texDepth.Apply(); |
||
101 | } |
||
102 | |||
103 | StringBuilder sbStatusText = new StringBuilder(); |
||
104 | |||
105 | sbStatusText.AppendFormat("LH-Fill: {0:F1}%", fillRatioLeftHand * 100f); |
||
106 | if (fillRatioLeftHand > fillThreshold) |
||
107 | sbStatusText.Append(" - Object Found"); |
||
108 | sbStatusText.AppendLine(); |
||
109 | |||
110 | sbStatusText.AppendFormat("RF-Fill: {0:F1}%", fillRatioRightHand * 100f); |
||
111 | if (fillRatioRightHand > fillThreshold) |
||
112 | sbStatusText.Append(" - Object Found"); |
||
113 | sbStatusText.AppendLine(); |
||
114 | |||
115 | // if (!float.IsNaN(sizeObjectHandLeft.x) && !float.IsNaN(sizeObjectHandLeft.y) && !float.IsNaN(sizeObjectHandLeft.z)) |
||
116 | // { |
||
117 | // sbStatusText.AppendFormat("L: ({0:F2}, {1:F2}, {2:F2}), {3:F1}%\n", sizeObjectHandLeft.x, sizeObjectHandLeft.y, sizeObjectHandLeft.z, fillRatioLeftHand * 100f); |
||
118 | // } |
||
119 | // |
||
120 | // if (!float.IsNaN(sizeObjectHandRight.x) && !float.IsNaN(sizeObjectHandRight.y) && !float.IsNaN(sizeObjectHandRight.z)) |
||
121 | // { |
||
122 | // sbStatusText.AppendFormat("R: ({0:F2}, {1:F2}, {2:F2}), {3:F1}%\n", sizeObjectHandRight.x, sizeObjectHandRight.y, sizeObjectHandRight.z, fillRatioRightHand * 100f); |
||
123 | // } |
||
124 | // |
||
125 | // if (fillRatioLeftHand > fillThreshold) |
||
126 | // sbStatusText.Append("Found object in the left hand.\n"); |
||
127 | // if (fillRatioRightHand > fillThreshold) |
||
128 | // sbStatusText.Append("Found object in the right hand.\n"); |
||
129 | |||
130 | if (statusText) |
||
131 | { |
||
132 | statusText.text = sbStatusText.ToString(); |
||
133 | } |
||
134 | } |
||
135 | |||
136 | } |
||
137 | |||
138 | |||
139 | // checks for object around the joint, according to the given threshold values |
||
140 | private bool TrackDepthAroundJoint(int iJoint, ref Vector2 dposJoint, ref Rect rectObject, ref Vector2 depthMinMax, ref float fillRatio) |
||
141 | { |
||
142 | // clear results |
||
143 | dposJoint = Vector2.zero; |
||
144 | rectObject.width = 0f; |
||
145 | rectObject.height = 0f; |
||
146 | fillRatio = 0f; |
||
147 | |||
148 | if(!manager.IsJointTracked(trackedUserId, iJoint)) |
||
149 | return false; |
||
150 | |||
151 | // space & depth pos |
||
152 | Vector3 jointSpacePos = manager.GetJointKinectPosition(trackedUserId, iJoint); |
||
153 | Vector2 jointDepthPos = manager.MapSpacePointToDepthCoords(jointSpacePos); |
||
154 | dposJoint = jointDepthPos; |
||
155 | |||
156 | if(jointSpacePos == Vector3.zero || jointDepthPos == Vector2.zero) |
||
157 | return false; |
||
158 | |||
159 | // depth width and height |
||
160 | int depthWidth = sensorData.depthImageWidth; |
||
161 | int depthHeight = sensorData.depthImageHeight; |
||
162 | |||
163 | // left & right |
||
164 | Vector3 spaceLeft = jointSpacePos - new Vector3(maxHvDistanceToHand, 0f, 0f); |
||
165 | Vector3 spaceRight = jointSpacePos + new Vector3(maxHvDistanceToHand, 0f, 0f); |
||
166 | |||
167 | Vector2 depthLeft = manager.MapSpacePointToDepthCoords(spaceLeft); |
||
168 | if (depthLeft == Vector2.zero) depthLeft = new Vector2(0f, jointDepthPos.y); |
||
169 | |||
170 | Vector2 depthRight = manager.MapSpacePointToDepthCoords(spaceRight); |
||
171 | if (depthRight == Vector2.zero) depthRight = new Vector2(depthWidth, jointDepthPos.y); |
||
172 | |||
173 | // up and down |
||
174 | Vector3 spaceTop = jointSpacePos + new Vector3(0f, maxHvDistanceToHand, 0f); |
||
175 | Vector3 spaceBottom = jointSpacePos - new Vector3(0f, maxHvDistanceToHand, 0f); |
||
176 | |||
177 | Vector2 depthTop = manager.MapSpacePointToDepthCoords(spaceTop); |
||
178 | if (depthTop == Vector2.zero) depthTop = new Vector2(jointDepthPos.x, 0f); |
||
179 | |||
180 | Vector2 depthBottom = manager.MapSpacePointToDepthCoords(spaceBottom); |
||
181 | if (depthBottom == Vector2.zero) depthBottom = new Vector2(jointDepthPos.x, depthHeight); |
||
182 | |||
183 | // depth |
||
184 | //ushort jointDepth = manager.GetDepthForPixel((int)jointDepthPos.x, (int)jointDepthPos.y); |
||
185 | ushort depthMin = (ushort)((jointSpacePos.z - maxZDistanceToJoint) * 1000f); |
||
186 | ushort depthMax = (ushort)((jointSpacePos.z + maxZDistanceToJoint) * 1000f); |
||
187 | |||
188 | // calculate the depth rectangle around joint |
||
189 | FindJointDepthRect((int)depthLeft.x, (int)depthTop.y, (int)depthRight.x, (int)depthBottom.y, depthMin, depthMax, |
||
190 | userBodyIndex, ref rectObject, ref depthMinMax, ref fillRatio); |
||
191 | |||
192 | return true; |
||
193 | } |
||
194 | |||
195 | // calculates depth rectangle around the joint belonging to the user, as well as near and far depth |
||
196 | private void FindJointDepthRect(int minX, int minY, int maxX, int maxY, ushort minDepth, ushort maxDepth, |
||
197 | byte userIndex, ref Rect rectResult, ref Vector2 depthMinMax, ref float fillRatio) |
||
198 | { |
||
199 | rectResult.x = rectResult.y = rectResult.width = rectResult.height = 0; |
||
200 | |||
201 | int rectX1 = maxX; |
||
202 | int rectX2 = minX; |
||
203 | int rectY1 = maxY; |
||
204 | int rectY2 = minY; |
||
205 | |||
206 | ushort nearDepth = maxDepth; |
||
207 | ushort farDepth = minDepth; |
||
208 | |||
209 | // start index |
||
210 | int depthWidth = sensorData.depthImageWidth; |
||
211 | int depthLength = sensorData.depthImageWidth * sensorData.depthImageHeight; |
||
212 | |||
213 | int rowIndex = minY * depthWidth + minX; |
||
214 | int fillCount = 0; |
||
215 | |||
216 | for (int y = minY; y < maxY; y++) |
||
217 | { |
||
218 | int index = rowIndex; |
||
219 | |||
220 | for (int x = minX; x < maxX; x++) |
||
221 | { |
||
222 | byte bodyIndex = index >= 0 && index < depthLength ? sensorData.bodyIndexImage[index] : (byte)0; |
||
223 | ushort depth = index >= 0 && index < depthLength ? sensorData.depthImage[index] : (ushort)0; |
||
224 | |||
225 | if(bodyIndex == userIndex && depth != 0 && (depth >= minDepth && depth <= maxDepth)) |
||
226 | { |
||
227 | fillCount++; |
||
228 | |||
229 | if (rectX1 > x) |
||
230 | rectX1 = x; |
||
231 | if (rectX2 < x) |
||
232 | rectX2 = x; |
||
233 | |||
234 | if (rectY1 > y) |
||
235 | rectY1 = y; |
||
236 | if (rectY2 < y) |
||
237 | rectY2 = y; |
||
238 | |||
239 | if (nearDepth > depth) |
||
240 | nearDepth = depth; |
||
241 | if (farDepth < depth) |
||
242 | farDepth = depth; |
||
243 | } |
||
244 | |||
245 | index++; |
||
246 | } |
||
247 | |||
248 | rowIndex += depthWidth; |
||
249 | } |
||
250 | |||
251 | if (rectX1 < rectX2 && rectY1 < rectY2) |
||
252 | { |
||
253 | rectResult.x = rectX1; |
||
254 | rectResult.y = rectY1; |
||
255 | rectResult.width = rectX2 - rectX1; |
||
256 | rectResult.height = rectY2 - rectY1; |
||
257 | |||
258 | depthMinMax.x = (float)nearDepth; // min |
||
259 | depthMinMax.y = (float)farDepth; // max |
||
260 | |||
261 | int totalCount = (maxX - minX) * (maxY - minY); |
||
262 | fillRatio = totalCount > 0 ? (float)fillCount / (float)totalCount : 0f; |
||
263 | } |
||
264 | } |
||
265 | |||
266 | // // tracks the depth in the given direction |
||
267 | // private int TrackDepthInDirection(int index, int stepIndex, int minIndex, int maxIndex, byte userIndex, |
||
268 | // ushort minDepth, ushort maxDepth, ref Vector2 depthMinMax) |
||
269 | // { |
||
270 | // int indexDiff = 0; |
||
271 | // int validIndexDiff = 0; |
||
272 | // |
||
273 | // ushort nearDepth = (ushort)depthMinMax.x; |
||
274 | // ushort farDepth = (ushort)depthMinMax.y; |
||
275 | // |
||
276 | // index += stepIndex; |
||
277 | // while(index >= minIndex && index < maxIndex) |
||
278 | // { |
||
279 | // ushort depth = sensorData.depthImage[index]; |
||
280 | // |
||
281 | // if(sensorData.bodyIndexImage[index] == userIndex && depth != 0 && |
||
282 | // (depth >= minDepth && depth <= maxDepth)) |
||
283 | // { |
||
284 | // validIndexDiff = indexDiff; |
||
285 | // |
||
286 | // if (nearDepth > depth) |
||
287 | // nearDepth = depth; |
||
288 | // if (farDepth < depth) |
||
289 | // farDepth = depth; |
||
290 | // } |
||
291 | // |
||
292 | // index += stepIndex; |
||
293 | // indexDiff++; |
||
294 | // } |
||
295 | // |
||
296 | // depthMinMax.x = (float)nearDepth; // min |
||
297 | // depthMinMax.y = (float)farDepth; // max |
||
298 | // |
||
299 | // return validIndexDiff; |
||
300 | // } |
||
301 | |||
302 | // // calculates real object size from joint depth position and object rectangle |
||
303 | // private bool CalculateObjectSize(Vector2 dposJoint, Rect drectObject, Vector2 depthMinMax, ref Vector3 sizeObject) |
||
304 | // { |
||
305 | // if (dposJoint == Vector2.zero || drectObject.width <= 1f || drectObject.height <= 1f) |
||
306 | // return false; |
||
307 | // |
||
308 | // // left |
||
309 | // Vector2 dposLeft = new Vector2(drectObject.x, dposJoint.y); |
||
310 | // ushort depthLeft = manager.GetDepthForPixel((int)dposLeft.x, (int)dposLeft.y); |
||
311 | // Vector3 spaceLeft = manager.MapDepthPointToSpaceCoords(dposLeft, depthLeft, true); |
||
312 | // |
||
313 | // // right |
||
314 | // Vector2 dposRight = new Vector2(drectObject.x + drectObject.width - 1f, dposJoint.y); |
||
315 | // ushort depthRight = manager.GetDepthForPixel((int)dposRight.x, (int)dposRight.y); |
||
316 | // Vector3 spaceRight = manager.MapDepthPointToSpaceCoords(dposRight, depthRight, true); |
||
317 | // |
||
318 | // // top |
||
319 | // Vector2 dposTop = new Vector2(dposJoint.x, drectObject.y); |
||
320 | // ushort depthTop = manager.GetDepthForPixel((int)dposTop.x, (int)dposTop.y); |
||
321 | // Vector3 spaceTop = manager.MapDepthPointToSpaceCoords(dposTop, depthTop, true); |
||
322 | // |
||
323 | // // bottom |
||
324 | // Vector2 dposBottom = new Vector2(dposJoint.x, drectObject.y + drectObject.height - 1f); |
||
325 | // ushort depthBottom = manager.GetDepthForPixel((int)dposBottom.x, (int)dposBottom.y); |
||
326 | // Vector3 spaceBottom = manager.MapDepthPointToSpaceCoords(dposBottom, depthBottom, true); |
||
327 | // |
||
328 | // // calculate size |
||
329 | // sizeObject.x = spaceRight.x - spaceLeft.x; |
||
330 | // sizeObject.y = spaceTop.y - spaceBottom.y; |
||
331 | // sizeObject.z = depthMinMax.y > depthMinMax.x ? (depthMinMax.y - depthMinMax.x) / 1000f : 0f; |
||
332 | // |
||
333 | // return true; |
||
334 | // } |
||
335 | |||
336 | // // calculates and draws the given depth rectangle on color camera texture |
||
337 | // private void DrawColorRectAroundObject(Vector2 dposJoint, Rect drectObject) |
||
338 | // { |
||
339 | // if (manager && dposJoint != Vector2.zero && drectObject.width > 0 && drectObject.height > 0) |
||
340 | // { |
||
341 | // } |
||
342 | // } |
||
343 | |||
344 | } |