2013-10-30 12 views
18

Voglio creare un'applicazione come un cam scanner per ritagliare un documento.Come eseguire il ritaglio automatico per il documento Riconoscere l'immagine usando la fotocamera?

Ma ho bisogno stessa funzionalità come i miei due immagini ..

Prime immagini mostrate immagine catturata dalla telecamera ..

enter image description here

seconda immagine riconoscere una parte dell'immagine catturata come questo ..

enter image description here

Io ricerca sempre di più ma non ne esco messo così, Chiedo qui se, uno fatto in questo mi dica ..

Grazie

+0

Check it out [questo ] (http://answers.opencv.org/question/17607/searching-for-a-good-object-detection-tutorial-on/) spero che sia d'aiuto. –

risposta

11

Presumo il tuo problema è quello di individuare l'oggetto da esaminare.

I meccanismi di rilevamento degli oggetti, come la corrispondenza dei modelli o il rilevamento delle funzioni, non forniscono i risultati desiderati poiché non si conosce esattamente l'oggetto che si sta scansionando.

Fondamentalmente si cerca un oggetto rettangolare nell'immagine.

Un approccio di base per questo potrebbe essere il seguente:

  • Eseguire un canny edge detector sull'immagine. Potrebbe aiutare a sfocare l'immagine un po 'prima di farlo. I bordi dell'oggetto dovrebbero essere chiaramente visibili.

  • Ora si vuole fare un Hough transform per trovare le linee nella foto.

  • Ricerca di linee con un angolo di circa 90 gradi l'una rispetto all'altra. Il problema sarebbe trovare quelli giusti. Forse è sufficiente usare le linee più vicine al fotogramma dell'immagine che sono ragionevolmente parallele a loro.

  • Trova i punti di intersezione per definire i bordi del tuo oggetto.

Almeno questo dovrebbe darvi un suggerimento su dove effettuare ulteriori ricerche.

Come ulteriori passaggi in tale app, dovrai calcolare la proiezione dei punti e fare una trasformazione affine dell'oggetto.

Spero che questo aiuti.

Dopo aver scritto tutto questo ho trovato this post. Dovrebbe aiutarti molto.

Poiché la mia risposta è rivolta a OpenCV, è necessario utilizzare la libreria OpenCV. Per eseguire questa operazione, è necessario installare Android Native Development Kit (NDK). Ci sono alcuni buoni tutorial su come usare OpenCV su Android nella pagina OpenCV for Android.

Una cosa da tenere a mente è che quasi ogni funzione del wrapper Java chiama un metodo nativo. Questo costa molto tempo.Quindi vuoi fare il più possibile nel tuo codice nativo prima di restituire i risultati alla parte Java.

+0

come implementare in Android questo codice .. – Roadies

+0

Ho visto questo è stato taggato in seguito OpenCV quindi ho aggiunto una parte su OpenCV e gli strumenti nativi. Ci sono alcuni buoni tutorial su questo. – Grey

+0

Qualche idea su come modificare questa procedura, voglio dire farlo funzionare con lo stesso sfondo del documento? –

5

So che sono in ritardo per rispondere ma potrebbe essere utile a qualcuno.

Provare il seguente codice.

@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); 

} 
0

ho creato un repo git con codice nativo supporto, che sta ritagliando l'immagine nel modo giusto, si prega di trovarlo su: link.

Sentiti libero di modificare il codice se trovi una soluzione migliore.

0

Far passare il tuo lettuccio immagine in questo metodo:

 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); 

        } 
       } 
      } 
     } 
    } 
} 

In questo metodo si ottiene quattro punti di documento, quindi è possibile tagliare questa immagine usando sotto metodo:

 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; 
}