2013-10-30 54 views
18

我想製作一個像凸輪掃描儀一樣的應用程序來裁剪文檔。如何對文檔執行自動裁剪使用相機識別圖像?

但我需要一個像我的兩個圖像相同的功能..

顯示有照相機捕獲的圖像首先打開圖片..

enter image description here

2圖像識別拍攝圖像的一部分這樣的..

enter image description here

我越來越多的研究,但沒有得到任何出來,我問這裏如果,任何一個做到了這一點告訴我..

感謝

+0

檢查出來[這一個](http://answers.opencv.org/question/17607/searching-for-a-good-object-detection-tutorial-on/)希望它有幫助。 –

回答

11

我認爲你的問題是檢測對象進行掃描。

像模式匹配或功能檢測的對象檢測機制不會爲您尋找的結果,因爲你不知道你正在掃描的對象究竟是什麼。

基本上你在圖片中搜索一個矩形對象。

這一基本方法可能是如下:

  • 運行圖像上的canny edge detector。在做這件事之前,它可能有助於模糊圖像。物體的邊緣應清晰可見。

  • 現在你想要做一個Hough transform找到圖片中的行。

  • 搜索彼此之間的角度大約90度的線。問題是要找到合適的。也許只要使用與圖片框架最接近的線條就足夠了。

  • 找到相交點來定義對象的邊緣。

至少這應該給你一個提示,進一步研究。

作爲這樣的應用程序中的進一步步驟,你將不得不計算點的投影,並做對象的仿射變換。

我希望這會有所幫助。

寫完所有這些後我發現this post.它應該會幫助你很多。

由於我的答案是針對OpenCV,所以您必須使用OpenCV庫。 爲了做到這一點,您需要安裝Android Native Development Kit (NDK)。 關於如何在Android的OpenCV for Android頁面上使用OpenCV有一些很好的教程。

有一點要記住,幾乎Java包裝器的每個函數都調用一個本地方法。這花費很多時間。因此,在將結果返回給Java部分之前,您希望儘可能在本機代碼中執行操作。

+0

如何在android原生代碼中實現此代碼.. – Roadies

+0

之後我看到這被標記爲OpenCV,所以我添加了一部分關於OpenCV和本地工具。有一些很好的教程。 – Grey

+0

有關如何修改此過程的任何想法,我的意思是使它與文檔幾乎相同的背景下工作? –

5

我知道我爲時已晚,但可能對某人有所幫助。

請嘗試下面的代碼。

@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

我創建了一個混帳回購協議的代碼爲本地支持,這是正確的方式裁剪圖像,請找到它:link

如果您想出更好的解決方案,請隨意編輯代碼。

0

通過你的形象墊在這個方法:

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

        } 
       } 
      } 
     } 
    } 
} 

在這種方法中,你得到四點的文件,那麼你可以用下面的方法削減這一形象:

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