使用OpenCV

时间:2016-04-15 07:26:07

标签: android opencv

我正在使用openCV和tesseract来读取卡片。我目前陷入“如何在从相机中检测到所有矩形和正方形后裁剪最大的矩形。下面是代码,请看一下。

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

1 个答案:

答案 0 :(得分:0)

所以你想要做的就是对区域的方块列表进行排序。

如果您不担心算法的效率或复杂性(尽管您可能应该这样做),您可以在将aprox添加到方块之前添加一条线,以计算当前大约的轮廓区域。然后,有一个循环,用于检查正方形中索引的轮廓区域,直到它到达正方形的末端或正方形中的元素,其中当前轮廓的面积大于该索引处轮廓的面积。这称为选择排序,虽然它简单而缓慢,但确实有效。

如果您对进一步的收入感兴趣,排序是计算机科学中一个非常有趣的概念。有关对square数组进行排序的更有效方法,请在heapsort,mergesort和quicksort上进行一些阅读。您可以学习排序here

的基础知识

祝你好运!