web-dev-qa-db-fra.com

Comment effectuer un recadrage automatique d'un document? Reconnaître une image à l'aide d'un appareil photo?

Je veux faire une application comme un scanner à cames pour rogner un document.

Mais j'ai besoin des mêmes fonctionnalités que mes deux images.

Première image affichée image capturée par la caméra ..

enter image description here

La deuxième image reconnaît une partie d’image capturée comme celle-ci.

enter image description here

Je recherche de plus en plus, mais je ne mets rien à sa place, je demande ici si quelqu'un me l'a fait ..

Merci

22
Roadies

Voici une démos identique à celle que vous souhaitez réaliser

https://github.com/Aniruddha-Tapas/Document-Scanner (A la fonction de détection automatique)

https://github.com/jhansireddy/AndroidScannerDemo

16
Hardik

Je suppose que votre problème est de détecter l'objet à analyser.

Les mécanismes de détection d'objet tels que la correspondance de modèle ou la détection de fonctionnalité ne vous apporteront pas les résultats que vous recherchez, car vous ne savez pas exactement quel est l'objet que vous numérisez.

Fondamentalement, vous recherchez un objet rectangulaire dans l'image.

Une approche de base à cela pourrait être la suivante:

  • Exécutez un détecteur de bords sophistiqué sur l’image. Cela pourrait aider à rendre l’image floue un peu avant de le faire. Les bords de l'objet doivent être clairement visibles.

  • Maintenant, vous voulez faire une transformation Hough pour trouver des lignes dans l’image.

  • Recherchez des lignes avec un angle d'environ 90 degrés les unes par rapport aux autres. Le problème serait de trouver les bons. Peut-être suffit-il d’utiliser les lignes les plus proches du cadre de l’image qui leur sont raisonnablement parallèles.

  • Trouvez les points d'intersection pour définir les arêtes de votre objet.

Au moins, cela devrait vous indiquer où approfondir vos recherches.

Comme étapes ultérieures dans une telle application, vous devrez calculer la projection des points et effectuer une transformation affine de l'objet.

J'espère que ça aide.

Après avoir écrit tout cela, j'ai trouvé ce post. Cela devrait vous aider beaucoup.

Comme ma réponse vise OpenCV, vous devez utiliser la bibliothèque OpenCV . Pour ce faire, vous devez installer le Kit de développement Android (NDK) . Il existe quelques bons tutoriels sur la utilisez OpenCV sur Android sur la page OpenCV pour Android .

Une chose à garder à l'esprit est que presque chaque fonction de l'encapsuleur Java appelle une méthode native. Cela coûte beaucoup de temps. Vous souhaitez donc utiliser le plus possible votre code natif avant de renvoyer vos résultats dans la partie Java.

14
Grey

Je sais que je suis trop tard pour répondre, mais cela pourrait être utile à quelqu'un.

Essayez le code suivant.

@Override
protected void onDraw(Canvas canvas) {

  super.onDraw(canvas);
  path = new Path();

  path.moveTo(x1, y1);        // this should set the start point right

  //path.lineTo(x1, y1);    <-- this line should be drawn at the end of     course,sorry
  path.lineTo(x2, y2);
  path.lineTo(x3, y3);
  path.lineTo(x4, y4);
  path.lineTo(x1, y1); 
  canvas.drawPath(path, currentPaint);

}
5

Passez votre image mat dans cette méthode:

       void findSquares(Mat image, List<MatOfPoint> squares) {
    int N = 10;

    squares.clear();

    Mat smallerImg = new Mat(new Size(image.width() / 2, image.height() / 2), image.type());

    Mat gray = new Mat(image.size(), image.type());

    Mat gray0 = new Mat(image.size(), CvType.CV_8U);

    // down-scale and upscale the image to filter out the noise
    Imgproc.pyrDown(image, smallerImg, smallerImg.size());
    Imgproc.pyrUp(smallerImg, image, image.size());
    // find squares in every color plane of the image
    Outer:
    for (int c = 0; c < 3; c++) {

        extractChannel(image, gray, c);

        // try several threshold levels
        Inner:
        for (int l = 1; l < N; l++) {

            Imgproc.threshold(gray, gray0, (l + 1) * 255 / N, 255, Imgproc.THRESH_BINARY);


            List<MatOfPoint> contours = new ArrayList<MatOfPoint>();

            // find contours and store them all as a list
            Imgproc.findContours(gray0, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

            MatOfPoint approx = new MatOfPoint();

            // test each contour
            for (int i = 0; i < contours.size(); i++) {

                approx = approxPolyDP(contours.get(i), Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true) * 0.02, true);

                // square contours should have 4 vertices after approximation
                // relatively large area (to filter out noisy contours)
                // and be convex.
                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                double area = Imgproc.contourArea(approx);

                if (area > 5000) {

                    if (approx.toArray().length == 4 &&
                            Math.abs(Imgproc.contourArea(approx)) > 1000 &&
                            Imgproc.isContourConvex(approx)) {

                        double maxCosine = 0;
                        Rect bitmap_rect = null;
                        for (int j = 2; j < 5; j++) {
                            // find the maximum cosine of the angle between joint edges
                            double cosine = Math.abs(angle(approx.toArray()[j % 4], approx.toArray()[j - 2], approx.toArray()[j - 1]));
                            maxCosine = Math.max(maxCosine, cosine);
                            bitmap_rect = new Rect(approx.toArray()[j % 4], approx.toArray()[j - 2]);

                        }

                        // if cosines of all angles are small
                        // (all angles are ~90 degree) then write quandrange
                        // vertices to resultant sequence
                        if (maxCosine < 0.3)
                            squares.add(approx);

                    }
                }
            }
        }
    }
}

Dans cette méthode, vous obtenez quatre points de document, puis vous pouvez couper cette image en utilisant la méthode suivante:

      public Bitmap warpDisplayImage(Mat inputMat) {
    List<Point> newClockVisePoints = new ArrayList<>();

    int resultWidth = inputMat.width();
    int resultHeight = inputMat.height();

    Mat startM = Converters.vector_Point2f_to_Mat(orderRectCorners(Previes method four poit list(like : List<Point> points)));

    Point ocvPOut4 = new Point(0, 0);
    Point ocvPOut1 = new Point(0, resultHeight);
    Point ocvPOut2 = new Point(resultWidth, resultHeight);
    Point ocvPOut3 = new Point(resultWidth, 0);



        ocvPOut3 = new Point(0, 0);
        ocvPOut4 = new Point(0, resultHeight);
        ocvPOut1 = new Point(resultWidth, resultHeight);
        ocvPOut2 = new Point(resultWidth, 0);
    }

    Mat outputMat = new Mat(resultWidth, resultHeight, CvType.CV_8UC4);

    List<Point> dest = new ArrayList<Point>();
    dest.add(ocvPOut3);
    dest.add(ocvPOut2);
    dest.add(ocvPOut1);
    dest.add(ocvPOut4);


    Mat endM = Converters.vector_Point2f_to_Mat(dest);

    Mat perspectiveTransform = Imgproc.getPerspectiveTransform(startM, endM);

    Imgproc.warpPerspective(inputMat, outputMat, perspectiveTransform, new Size(resultWidth, resultHeight), Imgproc.INTER_CUBIC);


    Bitmap descBitmap = Bitmap.createBitmap(outputMat.cols(), outputMat.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(outputMat, descBitmap);



    return descBitmap;
}
0
user7176550

J'ai créé un repo git avec un code pour le support natif, c'est-à-dire que vous rognez l'image correctement, retrouvez-la sur: link .

N'hésitez pas à éditer le code si vous trouvez une meilleure solution.

0
Vulovic Vukasin