web-dev-qa-db-fra.com

Algorithme de reconnaissance de forme 2D - à la recherche de conseils

J'ai besoin de la capacité de vérifier qu'un utilisateur a correctement dessiné une forme, en commençant par des formes simples comme un cercle, un triangle et des formes plus avancées comme la lettre A.

Je dois pouvoir calculer l'exactitude en temps réel, par exemple si l'utilisateur est supposé dessiner un cercle mais dessine un rectangle, j'espère pouvoir le détecter pendant le dessin.

Il existe différentes approches pour la reconnaissance des formes. Malheureusement, je n'ai ni l'expérience ni le temps pour toutes les essayer et voir ce qui fonctionne.

Quelle approche recommanderiez-vous pour cette tâche spécifique?

Votre aide est appréciée. 

14
aviran

Nous pouvons définir la "reconnaissance" comme étant la capacité de détecter des caractéristiques/caractéristiques dans des éléments et de les comparer aux caractéristiques des éléments connus observés dans notre expérience. Les objets ayant des caractéristiques similaires sont probablement des objets similaires. Plus la quantité et la complexité des fonctionnalités sont élevées, plus nous avons le pouvoir de distinguer des objets similaires. 

Dans le cas de formes, nous pouvons utiliser leurs propriétés géométriques telles que le nombre d'angles, les valeurs des angles, le nombre de côtés, la taille des côtés, etc. Par conséquent, afin d'accomplir votre tâche, vous devez utiliser des algorithmes de traitement d'images pour extraire ces caractéristiques des dessins.

Ci-dessous, je présente une approche très simple qui montre ce concept dans la pratique. Nous allons reconnaître différentes formes en utilisant le nombre de coins. Comme je l'ai dit: "Plus le nombre et la complexité des fonctionnalités sont élevés, plus nous avons le pouvoir de distinguer des objets similaires". Comme nous n’utilisons qu’une caractéristique, le nombre de coins, nous pouvons différencier quelques types de formes. Les formes ayant le même nombre de coins ne seront pas discriminées. Par conséquent, afin d'améliorer l'approche, vous pouvez ajouter de nouvelles fonctionnalités.


METTRE À JOUR:

Afin d'accomplir cette tâche en temps réel, vous pouvez extraire les fonctionnalités en temps réel. Si l'objet à dessiner est un triangle et que l'utilisateur dessine le quatrième côté d'une autre figure, vous savez qu'il ou elle ne dessine pas de triangle. À propos du niveau de correction, vous pouvez calculer la distance entre le vecteur de fonctions de l’objet souhaité et celui dessiné.


Contribution:

enter image description here

L'algorithme

  1. Réduisez l'image d'entrée car les fonctions souhaitées peuvent être détectées avec une résolution inférieure.
  2. Segmentez chaque objet à traiter indépendamment.
  3. Pour chaque objet, extrayez ses caractéristiques, dans ce cas, seulement le nombre de coins.
  4. A l'aide des fonctionnalités, classifiez la forme de l'objet.

Les logiciels:

Le logiciel présenté ci-dessous a été développé en Java sous Marvin Image Processing Framework . Cependant, vous pouvez utiliser n'importe quel langage et outils de programmation.

import static marvin.MarvinPluginCollection.floodfillSegmentation;
import static marvin.MarvinPluginCollection.moravec;
import static marvin.MarvinPluginCollection.scale;

public class ShapesExample {

    public ShapesExample(){
        // Scale down the image since the desired features can be extracted
        // in a lower resolution.
        MarvinImage image = MarvinImageIO.loadImage("./res/shapes.png");
        scale(image.clone(), image, 269);

        // segment each object
        MarvinSegment[] objs = floodfillSegmentation(image);
        MarvinSegment seg;

        // For each object...
        // Skip position 0 which is just the background
        for(int i=1; i<objs.length; i++){
            seg = objs[i];
            MarvinImage imgSeg = image.subimage(seg.x1-5, seg.y1-5, seg.width+10, seg.height+10);
            MarvinAttributes output = new MarvinAttributes();
            output = moravec(imgSeg, null, 18, 1000000);
            System.out.println("figure "+(i-1)+":" + getShapeName(getNumberOfCorners(output)));
        }
    }

    public String getShapeName(int corners){
        switch(corners){
            case 3: return "Triangle";
            case 4: return "Rectangle";
            case 5: return "Pentagon";
        }
        return null;
    }

    private static int getNumberOfCorners(MarvinAttributes attr){
        int[][] cornernessMap = (int[][]) attr.get("cornernessMap");
        int corners=0;
        List<Point> points = new ArrayList<Point>();
        for(int x=0; x<cornernessMap.length; x++){
            for(int y=0; y<cornernessMap[0].length; y++){
                // Is it a corner?
                if(cornernessMap[x][y] > 0){
                    // This part of the algorithm avoid inexistent corners
                    // detected almost in the same position due to noise.
                    Point newPoint = new Point(x,y);
                    if(points.size() == 0){
                        points.add(newPoint); corners++;
                    }else {
                        boolean valid=true;
                        for(Point p:points){
                            if(newPoint.distance(p) < 10){
                                valid=false;
                            }
                        }
                        if(valid){
                            points.add(newPoint); corners++;
                        }
                    }
                }
            }
        }
        return corners;
    }

    public static void main(String[] args) {
        new ShapesExample();
    }
}

La sortie du logiciel:

figure 0:Rectangle
figure 1:Triangle
figure 2:Pentagon

L’autre méthode consiste à utiliser les mathématiques avec ce problème en calculant la moyenne de chaque point le plus éloigné de celui auquel vous le comparez, Tout d’abord, vous devez redimensionner la forme avec celles de votre bibliothèque de formes, puis:

      function shortestDistanceSum( subject, test_subject ) {

         var sum = 0;

         operate( subject, function( shape ){

            var smallest_distance = 9999;

            operate( test_subject, function( test_shape ){
                var distance = dist( shape.x, shape.y, test_shape.x, test_shape.y );

                smallest_distance = Math.min( smallest_distance, distance );
            });

            sum += smallest_distance;

        });

            var average = sum/subject.length;

            return average;
       }

       function operate( array, callback ) {
          $.each(array, function(){
              callback( this );
          });
       }

       function dist( x, y, x1, y1 ) {
            return Math.sqrt( Math.pow( x1 - x, 2) + Math.pow( y1 - y, 2) );
        }

        var square_shape = Array; // collection of vertices in a square shape
        var triangle_shape = Array; // collection of vertices in a triangle
        var unknown_shape = Array; // collection of vertices in the shape your'e comparing from

        square_sum = shortestDistanceSum( square_shape, unknown_shape );
        triangle_sum = shortestDistanceSum( triangle_shape, unknown_shape );

Où la somme la plus basse est la forme la plus proche. 

0
PauAI

Vous avez deux entrées - l'image initiale et l'entrée utilisateur - et vous recherchez un résultat booléen.

Idéalement, vous convertiriez toutes vos données d'entrée dans un format comparable. Au lieu de cela, vous pouvez également paramétrer les deux types d’entrée et utiliser un algorithme supervised machine learning (le plus proche voisin vient à l’esprit pour les formes fermées).

L'astuce consiste à trouver les bons paramètres. Si votre entrée est un fichier image plat, il peut s’agir d’une conversion binaire. Si la saisie de l'utilisateur est un mouvement de balayage ou un trait de stylo, je suis sûr qu'il existe des moyens de la capturer et de la mapper en binaire, mais l'algorithme serait probablement plus robuste s'il utilisait des données proches de l'entrée d'origine.

0
freekvd