利用RealSense检测到的手指关节信息自定义简单动态手势

英特尔的RealSense深度摄像头可以检测到手的骨骼信息,给出各个关节的相对位置。这里我自己定义了一些简单的动态手势,例如上下左右移动和左右旋转等等。如果有需要,程序可以继续进行扩展,加入更多的手势。

注意,程序基于Unity3D平台实现,在运行中需要读取指尖和手掌中心的模型名称。如果官方的SDK对此有修改,需要在代码中更新。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class test : MonoBehaviour {

    // Use this for initialization
    List<GameObject> objs = new List<GameObject>();
    GameObject handCenter;
    Vector3[] Tips;
   // public GUIText gesStateText;
    public GUIText gesCommandText;
    enum GestureCommand {
        moveLeft ,
        moveRight ,
        moveForward ,
        moveBack ,
        rotationRight,
        rotationLeft,
            none
    }
    enum HandMotion {
        up,
        down,
        left,
        right,
        forward,
        back,
        empty
        
    }
    enum GestureState {
        palm,
        pinch,
        empty
    }
    GestureState currentGestureState= GestureState.empty;
    HandMotion currentHandMotion = HandMotion.empty;
    GestureCommand currentGestureCommand = GestureCommand.none;
    float threshold = 120;
    int frameCountX = 0;
    int frameCountY = 0;
    int frameCountZ = 0;
    int frameCountStay = 0;
    int countThreshold = 5;
    public float stayFlag = 0.1f;
    Vector3 origin = Vector3.zero;
    Vector3 destination = Vector3.zero;


    void Start () {
        Tips = new Vector3[5];
       // gesStateText.text = currentGestureState.ToString();
       // gesStateText.fontSize = 40;

        gesCommandText.text = currentGestureCommand.ToString();
        gesCommandText.fontSize = 50;


    }
	
	// Update is called once per frame
	void Update () {


        if (handCenter = GameObject.Find("PalmCenter(Clone)"))
        {
        

            objs.Clear();
            foreach (GameObject go in GameObject.FindObjectsOfType(typeof(GameObject)))
            {
                if (go.name == "Tip(Clone)")
                {
                    objs.Add(go);
                }
            }
            for (int i = 0; i < objs.Count && i < Tips.Length; i++)
            {
                Tips[i] = objs[i].transform.position;
            }
            //Debug.Log("NUM:"+ objs.Count);

            //float temp = MeanDistanceOfFive(Tips);
            float temp2 = SumOfFiveTipsToOthers(Tips);

            if (temp2 < threshold)
            {
                currentGestureState = GestureState.pinch;
            }
            else
            {
                currentGestureState = GestureState.palm;
            }
           


            //================
            destination = handCenter.transform.position;
            int direction = DetectMotionDirection(origin, destination);
            //when accumulate to the threshold, change the HandMotin state
            switch (direction)
            {
                case 0:
                    frameCountStay++;
                    if (frameCountStay > countThreshold)
                    {
                        ClearFrameCount();
                        currentHandMotion =  HandMotion.empty ;

                    }
                    Debug.Log("empty");
                    break;
                case 1:
                    frameCountX++;
                    if (frameCountX > countThreshold)
                    {
                        ClearFrameCount();
                        currentHandMotion = destination.x - origin.x > 0 ? HandMotion.left : HandMotion.right;

                    }
                    Debug.Log("X");
                    break;
                case 2:
                    frameCountY++;
                    if (frameCountY > countThreshold)
                    {
                        ClearFrameCount();
                        currentHandMotion = destination.y - origin.y > 0 ? HandMotion.up : HandMotion.down;

                    }
                    Debug.Log("Y");
                    break;
                case 3:
                    frameCountZ++;
                    if (frameCountZ > countThreshold)
                    {
                        ClearFrameCount();
                        currentHandMotion = destination.z - origin.z > 0 ? HandMotion.forward : HandMotion.back;

                    }
                    Debug.Log("Z");
                    break;
            }
           
        }
        else
        {
            currentGestureState = GestureState.empty;
            
        }

        //according to  the current HandMotion state, compute the speed in the direction
        Vector3 speed = destination - origin;
        GetFinalCommand(currentGestureState, currentHandMotion, ref currentGestureCommand);

        origin = destination; //prepare data for the next cycle

        //gesStateText.text = currentGestureState.ToString();
        gesCommandText.text = currentGestureCommand.ToString();
    }

    void OnGUI()
    {        
    }

    void GetFinalCommand(GestureState gs, HandMotion hm, ref GestureCommand gc)
    {
        switch (gs)
        {
            case GestureState.palm:
                switch (hm)
                {
                    case HandMotion.left:
                        gc = GestureCommand.moveLeft;
                        break;
                    case HandMotion.right:
                        gc = GestureCommand.moveRight;
                        break;
                    case HandMotion.forward:
                        gc = GestureCommand.moveForward;
                        break;
                    case HandMotion.back:
                        gc = GestureCommand.moveBack;
                        break;
                    case HandMotion.up:
                        gc = GestureCommand.none;
                        break;
                    case HandMotion.down:
                        gc = GestureCommand.none;
                        break;
                    case HandMotion.empty:
                        gc = GestureCommand.none;
                        break;
                }
                break;
            case GestureState.pinch:
                switch (hm)
                {
                    case HandMotion.left:
                        gc = GestureCommand.rotationLeft;
                        break;
                    case HandMotion.right:
                        gc = GestureCommand.rotationRight;
                        break;
                    case HandMotion.forward:
                        gc = GestureCommand.none;
                        break;
                    case HandMotion.back:
                        gc = GestureCommand.none;
                        break;
                    case HandMotion.up:
                        gc = GestureCommand.none;
                        break;
                    case HandMotion.down:
                        gc = GestureCommand.none;
                        break;
                    case HandMotion.empty:
                        gc = GestureCommand.none;
                        break;
                }
                break;
            case GestureState.empty:
                gc = GestureCommand.none;
                break;

        }
        
    }
    void ClearFrameCount()
    {
        frameCountX = 0;
        frameCountY = 0;
        frameCountZ = 0;
        frameCountStay = 0;

    }
    //此处的函数不必要,可用Vector3.Distance()代替
    float TipsDistance(Vector3 a, Vector3 b)
    {
        float dis = 0;
        dis = Mathf.Sqrt(Mathf.Pow(a.x-b.x,2)+ Mathf.Pow(a.y - b.y, 2)+Mathf.Pow(a.z - b.z, 2));

        return dis;
    }
    float MeanDistanceOfFive( Vector3[] v)
    {
        float dis =0;
        Vector3 v_sum = Vector3.zero;
        for (int i = 0; i < v.Length; i++)
        {
            v_sum = v_sum + v[i];
        }
        Vector3 v_mean = v_sum / v.Length;
        for (int i = 0; i < v.Length; i++)
        {
            dis = dis + TipsDistance(v_mean,v[i]);
        }


        return dis/v.Length;
    }

    float SumOfFiveTipsToOthers(Vector3[] v)
    {
        float sumDis = 0;
        for (int i = 0; i < v.Length; i++)
        {
            for (int j = 0; j < v.Length; j++)
            {
                sumDis += TipsDistance(v[i],v[j]);
            }
            
        }
        return sumDis;
    }

    int DetectMotionDirection(Vector3 origin, Vector3 destination)
    {
        Vector3 s = destination - origin;
        Vector3 t = new Vector3(Mathf.Abs(s.x), Mathf.Abs(s.y), Mathf.Abs(s.z));
        if (t.x + t.y + t.z < stayFlag) return 0; // not more than the stayflag, we consider it in a static state

        if (t.x >= t.y && t.x >= t.z)
        {
            return 1;
        }
        else if (t.y >= t.x && t.y >= t.z)
        {
            return 2;
        }
        else if (t.z >= t.x && t.z >= t.y)
        {
            return 3;
        }
        else
        {
            return 0;
        }
    }

    
}


posted @ 2017-09-14 01:08  雁回晴空  阅读(815)  评论(0编辑  收藏  举报