Jump to content
Unity Insider Forum
Wattsefakk

Mustererkennung von 3d Vectoren

Recommended Posts

Schönen guten Tag,

 

Ich brauche dringend Hilfestellungen bei einem schwierigen Thema. Und zwar habe ich eine eine beliebige anzahl von Positionsvektoren(3D-Vektor) in einer Liste. Nun möchte ich die irgendwie vergleichen mit einer weiterer Liste von Vektoren um herauszufinden ob die gleiche Bewegung ausgeführt wurde, Ich bekomme die 3D Vektoren von meinen ViveHandTrackern. Das Problem ist jetzt das ich ja nicht einfach Richtungsvektoren bestimmen kann und die Vergleichen kann...

 

Auf dem Bild, als beispiel nur 2D Vektoren, wird hoffentlich ganz gut erklärt was der Algorithmus machen soll und was er als richtig und falsch erkennen können soll. Eine Bestimmte Abweichung soll vorhanden sein zum beispiel muss man die Figur bis zu 10% richtig machen.

 

Ich weiß nur jetzt leider überhaupt nicht wie man da am besten anfängt, meine Überlegung mit den Richtungsvektoren funktioniert leider nicht.

 

Vermutlich ist das Code was man nicht sofort runter schreiben kann daher bin ich auch froh über grundsätzliche Informationen über das Thema.

 

Der ganze Spaß soll dafür sein das man Attacken mit Gestiken ausführen kann und mit der Ausführungsart (z.B. man schlägt mit der Faust nach vorne auch die Richtung mit angeben kann, das heißt wenn ich mit der faust nach oben schlage soll die gleiche Attacke ausgeführt werden).

 

Wäre euch echt hilfreich wenn ihr da was wisst.

 

Mit freundlichen Grüßen

post-5529-0-85631300-1488469639_thumb.jpg

Share this post


Link to post
Share on other sites

Auf deiner Abbildung sind aber immer 2 Vektoren zu sehen. Bei den ersten beiden Vektoren ändert sich der Winkel zwischen beiden Vektoren nicht, nur die Lage um Raum.

 

Kannst du das Problem noch genauer erläutern, also wie viele Vektoren sind beteiligt, geht es dir um die lokale Ausrichtung dieser Vektoren und bei einer Drehung oder Translation im globalen Raum soll die Routine "identisch" liefern?

Share this post


Link to post
Share on other sites

Zum Punkt 1: Genau das soll erkennt werden. Also wenn die Winkel zwischen den Vektoren ca identisch ist soll er dieses erkennen, egal wo sie im Raum sind.

 

Zu Punkt 2: Es sind immer eine untschiedliche Anzahl von Vektoren beteiligt. Ich drücke beim HTC Vive controller eine Taste bewege den Controller durch den Raum und beim Loslassen werden alle Positionen die der Controller in der Zeit durchlaufen hat abgespeichert. Wenn ich also ein "V" nachmache ist es egal wie rum es gedreht ist es soll immer erkannt werden.

Share this post


Link to post
Share on other sites
Am 9.3.2017 um 21:06 schrieb Wattsefakk:

ok hab es hinbekommen, den Code werde ich vllt mal später posten muss den jetzt erstmal noch aufräumen und in einer Klasse auslagern.

Hi,

hast du den Code schon gesäubert? Möchte sowas ähnliches machen wo mir dein Code vielleicht helfen könnte. Danke :)

Share this post


Link to post
Share on other sites

 

 

 

 

Ja hab ich schon, werde aber allerdings das ganze dennoch anders lösen da mir die Möglichkeiten zu gering sind. Das ganze funktioniert soweit echt super, lassen sich allerdings nur sehr "Gradlinige" Bewegungen gut auswerten. Ich stell hier mal die ganze Klasse rein kannst ja schauen was du davon benötigst, wenn du noch fragen hast kannst du die hier stellen oder per PM. 

Das hier ist der Aufruf den ich mache um die Bewegungen zu identifizieren. Die "List<Vektor>" "right" sind die Positions-Koordinaten die man überprüfen möchte.

Zurück bekommen tut man dann einmal den Winkel zwischen 2 Richtungsvektoren und die Richtung als integer wobei die zahlen für 0:rechts;1:hinten;2:links;3:vorne;4:oben;5:unten; stehen. 
 

  Attacke attackeneu = new Attacke();
        Vector2 directionlook2 = new Vector2(directionlook.x, directionlook.z);
        List<Vector3> directionvectorsR = attackeneu.distancecheck(right);

        List<Vector3> vectorsattackdirectionsR = attackeneu.vectorstodirectionnormalized(directionvectorsR);

        List<int> richtungindex = new List<int>();
        foreach (Vector3 vec in vectorsattackdirectionsR)
        {
            int direction = new int();
            direction = attackeneu.returndirection(vec, directionlook2);
            richtungindex.Add(direction);
        }
        List<float> floatwinkelR = new List<float>();
        if (vectorsattackdirectionsR.Count > 1)
        {
            for (int i = 0; i < vectorsattackdirectionsR.Count - 1; i++)
            {
                float winkel = Mathf.Acos(Vector3.Dot(vectorsattackdirectionsR[i], vectorsattackdirectionsR[i + 1]) / (vectorsattackdirectionsR[i].sqrMagnitude + vectorsattackdirectionsR[i + 1].sqrMagnitude));
                floatwinkelR.Add(Mathf.Rad2Deg * winkel);

            }

        }
attackeneu = attackeneu.getAttackefromData(floatwinkelR,richtungindex, element);
        if (attackeneu != null)
        {
            castattack(attackeneu,right[right.Count-1], vectorsattackdirectionsR[vectorsattackdirectionsR.Count - 1]);

        }
public class Attacke
{
    public Attacke getAttackfromserilizable(Attackenserialized attser) {

        Attacke att = new Attacke();
        att.idattacke = attser.idattacke;
       
        att.idelement = attser.idelement;
        att.winkel = attser.winkel;
        return att;

    }
    public int idelement;
    public int idattacke;
    public Vector3 direction;
    public List<int> directions;
    public List<float> winkel;
    public Attacke getAttackefromData(List<float> winkel,List<int> directions, int element)
    {
        foreach (float fl in winkel) { Debug.Log(fl); }
        foreach (Attacke att in spieler.attacken)
        {
            if (att.idelement == element || element ==5)
            {
                if (att.winkel.Count == winkel.Count && att.directions.Count==directions.Count)
                {
                    bool bwinkel = false;
                    bool brichtung = true;
                    for (int i = 0; i < att.winkel.Count; i++)
                    {
                        float min = att.winkel[i] - 10;
                        float max = att.winkel[i] + 10;
                        if (min < winkel[i] && winkel[i] < max)
                        {
                            bwinkel = true;
                        }
                        
                    }
                    for(int i = 0; i < att.directions.Count; i++)
                    {
                        if (brichtung)
                        {
                            if (att.directions[i] != directions[i]) { brichtung = false; }


                        }


                    }
                    if (bwinkel && brichtung) { return att; }
                }
            }
        }
        return null;
    }

    public bool checkvectordirection(Vector3 vectortolist, Vector3 vektorcheck)
    {

        Vector3 vec = vectortolist.normalized - vektorcheck.normalized;

        bool checkx = false;
        bool checky = false;
        bool checkz = false;

        if (vec.x >= 0)
        {
            if (vec.x > 0.95F)
            {
                checkx = true;
            }
        }
        else
        {
            if (vec.x < -0.95F)
            {
                checkx = true;
            }
        }

        if (vec.y >= 0)
        {
            if (vec.y > 0.95F)
            {
                checky = true;
            }
        }
        else
        {
            if (vec.y < -0.95F)
            {
                checky = true;
            }
        }
        if (vec.z >= 0)
        {
            if (vec.z > 0.95F)
            {
                checkz = true;
            }
        }
        else
        {
            if (vec.z < -0.95F)
            {
                checkz = true;
            }
        }

        if (checkx || checky || checkz)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    public List<Vector3> vectorstodirectionnormalized(List<Vector3> directions)
    {

        Attacke att = new Attacke();
        List<Vector3> lvectordirectionpoints = new List<Vector3>();
        Vector3 vectortolist = new Vector3();

        if (directions.Count > 0)
        {
            vectortolist = directions[0];
            for (int i = 1; i < directions.Count; i++)
            {

                if (att.checkvectordirection(vectortolist, directions[i]))
                {
                    vectortolist += directions[i];
                }
                else
                {
                    lvectordirectionpoints.Add(vectortolist);
                    vectortolist = directions[i];
                }
            }
            lvectordirectionpoints.Add(vectortolist);

        }
        return lvectordirectionpoints;
    }

    public int returndirection(Vector3 vec, Vector2 look)
    {
        Vector2 direc = new Vector2(vec.x, vec.z);
        int direction = -1;

        if (direction == -1)
        {
            float max = Mathf.Max(Mathf.Abs(vec.x), Mathf.Abs(vec.y), Mathf.Abs(vec.z));
            if (max == Mathf.Abs(vec.y))
            {
                if (vec.y > 0) { direction = 4; Debug.Log("oben"); }
                else
                {
                    direction = 5; Debug.Log("unten");
                }

            }


        }

        if (direction == -1)
        {

            float winkel = Mathf.Rad2Deg * Mathf.Acos(Vector2.Dot(direc.normalized, look.normalized));
            float orient = direc.x * look.y - direc.y * look.x;

            if (!(orient > 0))
            {

                winkel = winkel + 180;

            }



            if (winkel < 135 && winkel > 45) { direction = 0; Debug.Log("rechts"); }
            //else if (winkel < 225) { direction = 3; Debug.Log(winkel+"vorne"); }
            else if (winkel < 315 && winkel > 225) { direction = 2; Debug.Log("links"); }



        }

        if (direction == -1)
        {

            float winkel = Mathf.Rad2Deg * Mathf.Acos(Vector2.Dot(direc.normalized, look.normalized));
            if (winkel < 45) { direction = 3; Debug.Log("vorne"); }
            if (winkel > 135 && winkel < 225) { direction = 1; Debug.Log("hinten"); }

        }
        // 0:rechts;1:hinten;2:links;3:vorne;4:oben;5:unten;
        return direction;

    }

    public List<Vector3> distancecheck(List<Vector3> pos)
    {


        List<Vector3> listvector = new List<Vector3>();
        int counter = 1;
        for (int i = 0; i < pos.Count;)
        {
            if (counter < pos.Count)
            {
                if (directionvector3(pos[i], pos[counter]).sqrMagnitude < 0.001F)
                {
                    counter++;
                }
                else
                {
                    listvector.Add(directionvector3(pos[i], pos[counter]));
                    i = counter;
                }
            }
            else
            {
                break;
            }
        }

        List<Vector3> listreturn = new List<Vector3>();

        for (int i = 2; i < listvector.Count; i++)
        {
            listreturn.Add(listvector[i]);

        }

        return listvector;
    }
        Vector3 directionvector3(Vector3 from, Vector3 to)
    {
        return to - from;


    }
    public List<Vector3> pointstodirectionVectors(List<Vector3> vectors)
    {
        List<Vector3> vlist = new List<Vector3>();
        for (int i = 0; i < vectors.Count - 1; i++)
        {
            vlist.Add(directionvector3(vectors[i], vectors[i + 1]));

        }
        return vlist;
    }
   
}

Dann habe ich mir noch eine static list gemacht worin alle Attacken drin vorhanden sind. Um nicht jedesmal neue attacken zu schreiben habe ich noch alle Attacken Serialisiert. 
 

    List<Attackenserialized> getAttackenfromFile() {
        List<Attackenserialized> Lattsde = new List<Attackenserialized>();
        BinaryFormatter bf = new BinaryFormatter();
        FileStream fileread = File.Open(Application.persistentDataPath + "/attacks.dat", FileMode.Open);
        Lattsde = (List<Attackenserialized>)bf.Deserialize(fileread);
        fileread.Close();
        return Lattsde;
    }
    void writeAtteckentoFile(List<Attackenserialized> Latts)
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.persistentDataPath + "/attacks.dat");
        bf.Serialize(file, Latts);
        file.Close();

    }

Das sind die beiden Funktionen die ich benutzt habe das ganze zu speichern oder um es auszulesen. 

[System.Serializable]
public class Attackenserialized
{
    public int idelement;
    public int idattacke;
    public List<float> winkel;
    public List<int> directions;
}
 public static List<Attacke> attacken; 
List<Attackenserialized> attackenser = getAttackenfromFile();
        foreach(Attackenserialized att in attackenser)
        {
            Attacke attde = new Attacke();
            attde.winkel = att.winkel;
            attde.idattacke = att.idattacke;
            attde.idelement = att.idelement;
            attde.directions = att.directions;
            attacken.Add(attde);


        }

Einmal die Serialized klasse und da darunter ist einmal der Aufruf um die Datei zu lesen und die Attacken zu der static List attacken hinzu zu fügen um sie später abzufragen. 

Ich weiß ganz viel Code^^ gibt bestimmt auch noch eine einfachere Methode, bin ja auch gerade dabei es komplett anders zu lösen da dieses System zwar funktioniert allerdings halt am besten funktioniert wenn man sehr Gradlinige bewegungen macht. Also zum beispiel nach oben und dann nach vorne schlagen. Das ganze ist halt für meine Vive damit ich Zauber auswählen kann ohne Interface sondern mit Bewegung. Werde das ganze allerdings nun anders machen und zwar in dem ich mir eine 3D Röhre baue die so aussieht wie die bewegung die man mit den Controllern machen muss und diese werde ich dann einfach mit einem Collider ausstatten. Wenn dir das ganze in irgend einer weise nützt kannst du das gerne Benutzen. Falls noch fragen sind kannst du die gerne Stellen, da ich alles selbst geschrieben habe sollte ich ja wissen was der Code so macht^^ 

Die Attacken lade ich in einer Start() methode in die entsprechende Static liste. Beispiel Attacken kommen hier drunter und dann gebe ich dir noch das Auslesen welche Attacke letztendlich ausgeführt werden soll.
 

 void castattack(Attacke attacke,Vector3 pos, Vector3 dir)
    {

        if (attacke.idelement == 0)
        {
            if (attacke.idattacke == 1)
            {
                GameObject obj = Instantiate(Feuer[0], pos, Quaternion.identity);
                ConstantForce force = obj.GetComponent<ConstantForce>();
                force.force = dir.normalized * 5;

            }
        }
        if (attacke.idelement == 1)
        {
            if (attacke.idattacke == 1)
            {
                GameObject obj = Instantiate(Wasser[0], pos, Quaternion.identity);
                ConstantForce force = obj.GetComponent<ConstantForce>();
                force.force = dir.normalized * 5;

            }
        }
        if (attacke.idelement == 2)
        {
            if (attacke.idattacke == 1)
            {
                GameObject obj = Instantiate(Erde[0], pos, Quaternion.identity);
                ConstantForce force = obj.GetComponent<ConstantForce>();
                force.force = dir.normalized * 5;

            }
        }
        if (attacke.idelement == 3)
        {
            if (attacke.idattacke == 1)
            {
                GameObject obj = Instantiate(Luft[0], pos, Quaternion.identity);
                ConstantForce force = obj.GetComponent<ConstantForce>();
                force.force = dir.normalized * 5;

            }
        }

    }

Und hier einmal die Beispiel Daten.

    void writedefaultattacken()
    {// 0:rechts;1:hinten;2:links;3:vorne;4:oben;5:unten;
        Attacke fire = new Attacke();
        fire.idattacke = 1;
        fire.idelement = 0;
        fire.winkel = new List<float>();
        fire.winkel.Add(120F);
        fire.directions = new List<int>();
        fire.directions.Add(1);
        fire.directions.Add(3);
        attacken.Add(fire);
        Attacke earth = new Attacke();
        earth.idattacke = 1;
        earth.idelement = 2;
        earth.winkel = new List<float>();
        earth.winkel.Add(90);
        earth.directions = new List<int>();
        earth.directions.Add(4);
        earth.directions.Add(3);
        attacken.Add(earth);
        Attacke water = new Attacke();
        water.idelement = 1;
        water.idattacke = 1;
        water.directions = new List<int>();
        water.directions.Add(5);
        water.directions.Add(3);
        water.directions.Add(5);
        //water.directions.Add(0);
        water.directions.Add(1);
        water.winkel = new List<float>();
        //water.winkel.Add(120);
        water.winkel.Add(90);
        water.winkel.Add(90);
        attacken.Add(water);

        List<Attackenserialized> Latts = new List<Attackenserialized>();
       
        foreach (Attacke att in attacken)
        {
            Attackenserialized satt = new Attackenserialized();
            satt.idattacke = att.idattacke;
            satt.idelement = att.idelement;
            satt.winkel = att.winkel;
            satt.directions = att.directions;
            Latts.Add(satt);
        }

        writeAtteckentoFile(Latts);

       

    }

So vielleicht hilft dir das wenn du fragen hast gerne stellen.
 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...