t1 / TFDContents / Assets / KinectDemos / VariousDemos / Scripts / HandObjectChecker.cs @ 3
이력 | 보기 | 이력해설 | 다운로드 (11.9 KB)
1 |
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 |
} |