프로젝트

일반

사용자정보

통계
| 개정판:

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
}