프로젝트

일반

사용자정보

통계
| 개정판:

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
}