web-dev-qa-db-fra.com

Computer Vision - Filtrage des coques convexes et des défauts de convexité avec OpenCV

J'ai le problème avec le traitement des signaux numériques. J'essaie de détecter le bout des doigts, semblable à la solution présentée ici: Détection des mains et des doigts avec JavaCV .

Cependant, je n'utilise pas JavaCV mais OpenCV pour Android, ce qui est légèrement différent ..__ J'ai réussi à faire toutes les étapes présentées dans le tutoriel, mais en filtrant les coques convexes et les 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 clairement, il existe de nombreux points jaunes (coques convexes) et également de nombreux points rouges (défauts de convexité). Parfois, entre 2 points jaunes, il n’ya pas de point rouge, ce qui est assez étrange (comment sont calculées les coques convexes?)

Ce dont j'ai besoin, c'est de créer une fonction de filtrage simillar comme dans le lien fourni précédemment, mais en utilisant des structures de données OpenCV. 

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

J'ai également créé des structures de données supplémentaires, parce que stupide OpenCV utilise différents types de données contenant les mêmes données, selon des méthodes différentes ...

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 lié à la 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();
    }
}

Filtration:

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 de doigts après filtrage):

enter image description here

Pourriez-vous m'aider à écrire la fonction appropriée pour le filtrage?

MISE À JOUR 14.08.2013

J'utilise la fonction standard openCV pour l'approximation des contours. Je dois changer la valeur approximative avec le changement de résolution et la distance main-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 approximative devrait être amante. Même avec la distance. Si vous le maintenez haut, vous perdrez complètement le doigt. Donc, je pense que l'approximation n'est pas une bonne approche pour résoudre le problème, bien qu'une petite valeur puisse être utile pour accélérer les calculs:

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

Si j'utilise des valeurs élevées, le résultat est similaire à celui de l'image ci-dessous, ce qui ne serait bon que si la distance et la résolution ne changeaient pas. En outre, je suis assez surpris que les méthodes par défaut pour les points de coque et les points de défauts n'aient pas d'arguments utiles à transmettre (angle minimum, distance, etc.) ... 

L'image ci-dessous présente l'effet que je voudrais obtenir toujours, indépendamment de la résolution ou de la distance main-caméra. Aussi, je ne veux pas voir de points jaunes quand je ferme mon Palm ...

Pour tout résumer, 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 connait ou a du matériel (représentation graphique, explication) sur les structures de données utilisées dans OpenCV, je le lirai volontiers. (Mat, MatOfInt, MatOfPoint, MatOfPoint2, MatOfPoint4 etc.) 

enter image description here

46
Marek

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 à haute résolution doit ensuite être appliquée à votre contour approximatif, il est facile d’ignorer les points ne respectant pas les critères de "longueur et d’angle" des deux derniers, bien que vous souhaitiez peut-être utiliser la "moyenne" au lieu de "ignorer entièrement". ".

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

Cette technique de base est très simple et fonctionne donc pour un Palm ouvert. Cependant, il ne comprend pas intrinsèquement une main ou un geste, aussi le réglage des paramètres d'échelle, d'angle et de longueur ne vous mènera jamais "jusqu'à présent".

Références aux techniques: Longueur du filtre et angle "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 le Kit de développement Kinect avec détection de direction du doigt ajoutée http://candescentnui.codeplex.com/http://blog.candescent.ch/2011/11/improving-finger- détection.html

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

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

1
jayprich

Je pense que vous avez manqué ce point:

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

0
weeska