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 | } |