Android OpenCV Find Largest Square or Rectangle

后端 未结 3 875
盖世英雄少女心
盖世英雄少女心 2020-12-02 16:14

This might have been answered but I desperately need an answer for this. I want to find the largest square or rectangle in an image using OpenCV in Android. All of the solut

相关标签:
3条回答
  • 2020-12-02 16:40

    There are some related questions here in SO. Check them out:

    • OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection

    • How do I recognize squares in this image?

    There is also an example shipped with OpenCV:

    • https://code.ros.org/trac/opencv/browser/trunk/opencv/samples/cpp/squares.cpp?rev=4079

    Once you have the rectangle, you can align the picture by computing the homography with the rectangle corners and applying a perspective transform.

    0 讨论(0)
  • 2020-12-02 16:43

    After canny

    1- you need to reduce noises with gaussian blur and find all the contours

    2- find and list all the contours' areas.

    3- the largest contour will be nothing but the painting.

    4- now use perpective transformation to transform your shape to a rectangle.

    check sudoku solver examples to see the similar processing problem. (largest contour + perspective)

    0 讨论(0)
  • 2020-12-02 16:49

    Took me a while to convert the C++ code to Java, but here it is :-)

    Warning ! Raw code, totally not optimized and all.

    I decline any liability in cases of injury or lethal accident

        List<MatOfPoint> squares = new ArrayList<MatOfPoint>();
    
        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());
     }
    
    0 讨论(0)
提交回复
热议问题