安卓OpenCV如何找到最大的正方形或矩形

10
这个问题可能已经有答案了,但我迫切需要一个答案。我想在Android上使用OpenCV找到图像中最大的正方形或矩形。我找到的所有解决方案都是C ++的,我尝试转换它,但它不起作用,我不知道哪里出错了。
private Mat findLargestRectangle(Mat original_image) {
    Mat imgSource = original_image;

    Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY);
    Imgproc.Canny(imgSource, imgSource, 100, 100);

    //I don't know what to do in here

    return imgSource;
}

我在这里想要实现的是创建一个基于原始图像中最大正方形的新图像(返回值Mat image)。
这就是我想要发生的事情: 1 http://img14.imageshack.us/img14/7855/s7zr.jpg 只获取最大正方形的四个点也可以,然后我认为我可以从那里开始。但是如果我可以返回裁剪后的图像,那会更好。

1
如果你有 C++ 的源代码,并且它可以工作,也许你可以展示完整的源代码(我的意思是你展示那些代替了你的 //我不知道在这里该怎么做 的部分)。我们可以尝试一起转换所有的代码。 - McBodik
2
如果你已经找到了解决方案,能否发布一下呢? - TharakaNirmana
3个回答

13

3
在进行Canny算子之前,最好先对图像进行模糊处理。 - baci
谢谢Baci,我现在可以检测图像中最大的正方形了:https://dev59.com/n3TYa4cB1Zd3GeqPuGE2 但是我的问题是,我无法使用透视变换,因为我不知道最大检测到的正方形/矩形区域的四个点。你能帮我吗? - James Arnold
我想指出高斯滤波Canny输出非常有效。在一些嘈杂的图像中,我有些难以找到矩形。因此,我运行了双边滤波、Canny边缘检测,然后对Canny输出进行了高斯滤波。高斯滤波处理了Canny输出中所有残留的噪声。如果我在Canny操作之前尝试过于激进地进行滤波,那么就会扭曲我的矩形边缘。 - MeetTitan

13

花了我一些时间将C++代码转换为Java,但现在完成了 :-)

警告!这是原始代码,完全没有优化。

对于任何伤害或致命事故,本人不承担任何责任。

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

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接