2016-04-15 253 views
0

我使用openCV和tesseract读取卡片。我目前停留在“我发现在从相机所有的长方形和正方形后,如何剪裁最大矩形。下面是代码,请看看。使用OpenCV裁剪最大的矩形

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {  
     if (Math.random()>0.80) {  
      findSquares(inputFrame.rgba().clone(),squares);  
     } 

     Mat image = inputFrame.rgba();  
     Imgproc.drawContours(image, squares, -1, new Scalar(0,0,255));  
     return image; 
    } 

    int thresh = 50, N = 11; 

    // helper function: 
    // finds a cosine of angle between vectors 
    // from pt0->pt1 and from pt0->pt2 
    double angle(Point pt1, Point pt2, Point pt0) { 
     double dx1 = pt1.x - pt0.x; 
     double dy1 = pt1.y - pt0.y; 
     double dx2 = pt2.x - pt0.x; 
     double dy2 = pt2.y - pt0.y; 
     return (dx1*dx2 + dy1*dy2)/Math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); 
    } 

    // returns sequence of squares detected on the image. 
    // the sequence is stored in the specified memory storage 
    void findSquares(Mat image, List<MatOfPoint> squares) 
    {  
     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 
     for(int c = 0; c < 3; c++) 
     {  
      extractChannel(image, gray, c);  
      // try several threshold levels 
      for(int l = 1; l < N; l++) 
      { 
       //Cany removed... Didn't work so well   
       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++) 
       {  
        // approximate contour with accuracy proportional 
        // to the contour perimeter 
        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  
        if(approx.toArray().length == 4 && 
          Math.abs(Imgproc.contourArea(approx)) > 1000 && 
          Imgproc.isContourConvex(approx)) 
        { 
         double maxCosine = 0; 

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

    void extractChannel(Mat source, Mat out, int channelNum) { 
     List<Mat> sourceChannels=new ArrayList<Mat>(); 
     List<Mat> outChannel=new ArrayList<Mat>();  
     Core.split(source, sourceChannels);  
     outChannel.add(new Mat(sourceChannels.get(0).size(),sourceChannels.get(0).type()));  
     Core.mixChannels(sourceChannels, outChannel, new MatOfInt(channelNum,0));  
     Core.merge(outChannel, out); 
    } 

    MatOfPoint approxPolyDP(MatOfPoint curve, double epsilon, boolean closed) { 
     MatOfPoint2f tempMat=new MatOfPoint2f();  
     Imgproc.approxPolyDP(new MatOfPoint2f(curve.toArray()), tempMat, epsilon, closed);  
     return new MatOfPoint(tempMat.toArray()); 
    } 
} 
+2

示例输入和想要的结果图像请 – Micka

回答

0

所以,你要在这做什么点是排序区域的正方形列表

如果您不担心算法的效率或复杂性(尽管您可能应该),您可以简单地添加一行,然后将aprox添加到计算轮廓区域为当前的大约那么,有一个循环检查一个索引的轮廓区域,以正方形为单位,直到它到达正方形的末端或正方形中当前轮廓的区域大于区域i的元素n该索引处的轮廓。这称为选择排序,尽管它很简单,但速度很慢,但确实有效。

如果您有兴趣进一步学习,在计算机科学中排序是一个非常有趣的概念。要更有效地排列方阵,请阅读heapsort,mergesort和quicksort。您可以了解排序的基本知识here

祝您好运!

+0

你好@bstadt,这不是我正在寻找的,我正在寻找一个代码,实际上会裁剪或调整我的图像只有我检测到的平方。而且我不需要这种排序,因为我的图像只包含一个方块。 –