47 votes

Vision par ordinateur OpenCV filtrage des coques convexes et des défauts de convexité

Je sais que cette question peut être un peu longue et difficile, mais s'il vous plaît, prenez votre temps pour m'aider, ou au moins votez en haut pour que quelqu'un d'autre, qui connaît bien le sujet, soit en mesure d'aider parce que la question apparaîtra en haut... (c'est vraiment important pour moi et la date limite pour terminer est la semaine prochaine). Merci dans la mendicité.

J'ai un problème de traitement des signaux numériques. J'essaye de détecter le bout des doigts, de manière similaire à la solution qui est présentée ici : Détection des mains et des doigts à l'aide de JavaCV .

Cependant, je n'utilise pas JavaCV mais OpenCV pour Android qui est légèrement différent. J'ai réussi à faire toutes les étapes présentées dans le tutoriel, mais le filtrage des coques convexes et des défauts de convexité. Voici à quoi ressemble mon image :

Resolution 640x480

Voici une image dans une autre résolution :

Resolution 320x240

Comme vous pouvez le voir, il y a trop de points jaunes (coques convexes) et trop de points rouges (effets de convexité). Parfois, entre deux points jaunes, il n'y a pas de point rouge, ce qui est assez étrange (comment sont calculées les coques convexes ?).

Ce dont j'ai besoin est de créer une fonction de filtrage similaire à celle du lien fourni précédemment, mais en utilisant les structures de données d'OpenCV.

Les coques convexes sont de type MatOfInt ... Les défauts de convexité sont de type MatOfInt4 ...

J'ai aussi créé quelques structures de données supplémentaires, parce que stupidement OpenCV utilise différents types de données contenant les mêmes données, dans différentes méthodes...

convexHullMatOfInt = new MatOfInt();
convexHullPointArrayList = new ArrayList<Point>();
convexHullMatOfPoint = new MatOfPoint();
convexHullMatOfPointArrayList = new ArrayList<MatOfPoint>();

Voici ce que j'ai fait jusqu'à présent mais cela ne fonctionne pas bien. Le problème est probablement dû à une mauvaise conversion des données :

Création de coques convexes et de défauts de convexité :

public void calculateConvexHulls()
{
    convexHullMatOfInt = new MatOfInt();
    convexHullPointArrayList = new ArrayList<Point>();
    convexHullMatOfPoint = new MatOfPoint();
    convexHullMatOfPointArrayList = new ArrayList<MatOfPoint>();

    try {
        //Calculate convex hulls
        if(aproximatedContours.size() > 0)
        {
            Imgproc.convexHull( aproximatedContours.get(0), convexHullMatOfInt, false);

            for(int j=0; j < convexHullMatOfInt.toList().size(); j++)
                convexHullPointArrayList.add(aproximatedContours.get(0).toList().get(convexHullMatOfInt.toList().get(j)));
            convexHullMatOfPoint.fromList(convexHullPointArrayList);
            convexHullMatOfPointArrayList.add(convexHullMatOfPoint);    
        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        Log.e("Calculate convex hulls failed.", "Details below");
        e.printStackTrace();
    }
}

public void calculateConvexityDefects()
{
    mConvexityDefectsMatOfInt4 = new MatOfInt4();

    try {
        Imgproc.convexityDefects(aproximatedContours.get(0), convexHullMatOfInt, mConvexityDefectsMatOfInt4);

        if(!mConvexityDefectsMatOfInt4.empty())
        {
            mConvexityDefectsIntArrayList = new int[mConvexityDefectsMatOfInt4.toArray().length];
            mConvexityDefectsIntArrayList = mConvexityDefectsMatOfInt4.toArray();
        }
    } catch (Exception e) {
        Log.e("Calculate convex hulls failed.", "Details below");
        e.printStackTrace();
    }
}

Filtrage :

public void filterCalculatedPoints()
    {
        ArrayList<Point> tipPts = new ArrayList<Point>();
        ArrayList<Point> foldPts = new ArrayList<Point>();
        ArrayList<Integer> depths = new ArrayList<Integer>();

        fingerTips = new ArrayList<Point>();

        for (int i = 0; i < mConvexityDefectsIntArrayList.length/4; i++)
        {
            tipPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i]));
            tipPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i+1]));
            foldPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i+2]));
            depths.add(mConvexityDefectsIntArrayList[4*i+3]);
        }

        int numPoints = foldPts.size();
        for (int i=0; i < numPoints; i++) {
            if ((depths.get(i).intValue()) < MIN_FINGER_DEPTH)
                continue;

            // look at fold points on either side of a tip
            int pdx = (i == 0) ? (numPoints-1) : (i - 1);
            int sdx = (i == numPoints-1) ? 0 : (i + 1);

            int angle = angleBetween(tipPts.get(i), foldPts.get(pdx), foldPts.get(sdx));
            if (angle >= MAX_FINGER_ANGLE)   // angle between finger and folds too wide
                continue; 

            // this point is probably a fingertip, so add to list
            fingerTips.add(tipPts.get(i));
        }
    }

Résultats (points blancs - bouts des doigts après filtrage) :

enter image description here

Pouvez-vous m'aider à écrire une fonction appropriée pour le filtrage ?

MISE À JOUR 14.08.2013

J'utilise une fonction openCV standard pour l'approximation des contours. Je dois changer la valeur de l'approximation en fonction de la résolution et de la distance entre la main et la caméra, ce qui est assez difficile à faire. Si la résolution est plus petite, alors le doigt est composé de moins de pixels, donc la valeur d'approximation devrait être plus petite. De même pour la distance. Si on la garde élevée, on perd complètement le doigt. Je pense donc que l'approximation n'est pas une bonne approche pour résoudre le problème, mais une petite valeur pourrait être utile pour accélérer les calculs :

Imgproc.approxPolyDP(frame, frame, 2 , true); 

Si j'utilise des valeurs élevées, alors le résultat est comme sur l'image ci-dessous, ce qui serait bon seulement si la distance et la résolution ne changeaient pas. De plus, je suis assez surpris que les méthodes par défaut pour les points de coques et les points de défauts n'aient pas d'arguments utiles à passer (angle min, distance etc.)...

L'image ci-dessous présente l'effet que j'aimerais obtenir en permanence, indépendamment de la résolution ou de la distance main-caméra. Je ne veux pas non plus voir de points jaunes lorsque je ferme ma paume...

Pour résumer le tout, j'aimerais savoir :

  • comment filtrer les points
  • comment puis-je faire une approximation indépendante de la résolution et de la distance qui fonctionnera toujours ?
  • Si quelqu'un connaît ou a du matériel (représentation graphique, explication) sur ces structures de données utilisées dans OpenCV, je serais heureux de le lire. (Mat, MatOfInt, MatOfPoint, MatOfPoint2, MatOfPoint4 etc.)

enter image description here

1voto

jayprich Points 91

La coque convexe à basse résolution peut être utilisée pour identifier la position de la main dans son ensemble, elle n'est pas utile pour les doigts mais fournit une région d'intérêt et une échelle appropriée.

L'analyse à plus haute résolution doit ensuite être appliquée à votre contour approximatif. Il est facile d'ignorer tous les points qui ne répondent pas aux critères de "longueur et d'angle" des deux dernières étapes, bien que vous puissiez souhaiter faire une "moyenne" au lieu d'ignorer entièrement.

Votre exemple de code consiste à calculer en une seule fois les défauts de convexité puis à les supprimer c'est une erreur de logique vous devez supprimer les points au fur et à mesure (a) il est plus rapide et plus simple de tout faire en une seule fois (b) cela évite de supprimer des points lors d'une première passe et de devoir les rajouter plus tard car toute suppression modifie les calculs précédents.

Cette technique de base est très simple et fonctionne donc pour une paume ouverte de base. Elle ne comprend pas intrinsèquement une main ou un geste, donc régler les paramètres d'échelle, d'angle et de longueur ne vous mènera jamais plus loin.

Références aux techniques : Longueur et angle de filtrage "Défaut de convexité Blog de Simen Andresen http://simena86.github.io/blog/2013/08/12/hand-tracking-and-recognition-with-opencv/

Bibliothèque C# basée sur Kinect SDK avec détection de la direction du doigt ajoutée http://candescentnui.codeplex.com/ http://blog.candescent.ch/2011/11/improving-finger-detection.html

"Gaz neurologique auto-croissant et organisé" (SGONG) Prof. Nikos Papamarkos http://www.papamarkos.gr/uploaded-files/Hand%20gesture%20recognition%20using%20a%20neural%20network%20shape%20fitting%20technique.pdf

Produit commercial David Holz et Michael Buckwald, fondateurs de "Leap Motion". http://www.engadget.com/2013/03/11/leap-motion-michael-buckwald-interview/

0voto

weeska Points 145

Je pense que vous avez manqué ce point :

La création de coques et l'analyse des défauts sont accélérées par l'utilisation d'une approximation à faible polygone du contour plutôt que de l'original.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X