既没有找到最大的矩形,也没有通过霍夫变换检测角点

时间:2014-05-23 11:31:27

标签: java android opencv contour hough-transform

我一直在尝试检测点击图片上的最大矩形/正方形。我尝试了轮廓Android OpenCV Find Largest Square or Rectangle和霍夫变换http://opencv-code.com/tutorials/automatic-perspective-correction-for-quadrilateral-objects/

两者都像从画廊中选择的图像上的魅力。但是当我整合从相机拍摄的图像时,它大部分时间都会失败。

谁能告诉我背后的原因是什么?我在这里错过了什么?

据我所知,有可能像camscanner这样的扫描应用程序非常精美,准确度超过90%。

请建议。我已经尝试了很多。

供参考:

public static String houghTransform(Mat original_image ,String outFile) {
        Mat imgSource = original_image;
        Mat untouched = original_image.clone();

        //convert the image to black and white
        Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY);


        //apply gaussian blur to smoothen lines of dots
        Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 0); 

        //adaptive threshold thresholds the image taking an optimum value for a local neighbourhood. 
        //Imgproc.adaptiveThreshold(imgSource, imgSource, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, 3, 1);

        //convert the image to black and white does (8 bit)
        Imgproc.Canny(imgSource, imgSource, 80, 100);
        Mat lines = new Mat();
        int threshold = 70;
        int minLineSize = 20;
        int lineGap = 20;

        Imgproc.HoughLinesP(imgSource, lines, 1, Math.PI/180, threshold, minLineSize, lineGap);

        ArrayList<Point> corners = new ArrayList<Point>();
        for (int i = 0; i < lines.cols(); i++)
        {
            for (int j = i+1; j < lines.cols(); j++)
            {
                Point pt = computeIntersect(lines.get(0,i), lines.get(0,j));
                if (pt.x >= 0 && pt.y >= 0)
                    corners.add(pt);
            }
        }
        L.v("Points corner size: ", ""+corners.size());
        if(corners.size()<4){
            return "";
        }

        Point center = new Point(0,0);
        // Get mass center
        for (int i = 0; i < corners.size(); i++){
            center.x += corners.get(i).x;
            center.y+= corners.get(i).y;
        }
        center.x = (center.x / corners.size());
        center.y = (center.y / corners.size());

        Core.circle(untouched, center, 20, new Scalar(255, 0, 0), 5); //p1 is colored red

        Core.circle(untouched, corners.get(0), 20, new Scalar(255, 0, 0), 5); 
        Core.circle(untouched, corners.get(1), 20, new Scalar(255, 0, 0), 5); 
        Core.circle(untouched, corners.get(2), 20, new Scalar(255, 0, 0), 5); 
        Core.circle(untouched, corners.get(3), 20, new Scalar(255, 0, 0), 5);

        Highgui.imwrite(outFile, untouched);
         return outFile;

 } 

这是用于检测作为角落的四个点的computerIntersect模块。

  private static Point computeIntersect(double[] a, double[] b) {
    double x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3], x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3];
    double denom = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
    Point pt = new Point();
    if (denom!=0)
    {

            pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom;
            pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom;
            return pt;
    }
    else
            return new Point(-1, -1);
}

当我将它应用于从相机拍摄的图像时,它会返回四个以上的点。

我尝试的另一种方法是:

  public static String findLargestRectangle(Mat original_image ,String outFile) {
        Mat imgSource = original_image;
        Mat untouched = original_image.clone();

        //convert the image to black and white
        Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY);


        //apply gaussian blur to smoothen lines of dots
        Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 0); 

        //convert the image to black and white does (8 bit)
        Imgproc.Canny(imgSource, imgSource, 80, 100);

            //find the contours
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Imgproc.findContours(imgSource, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);

        double maxArea = -1;
        int maxAreaIdx = -1;

        MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point
        MatOfPoint2f approxCurve = new MatOfPoint2f();
        MatOfPoint2f maxCurve = new MatOfPoint2f();
        List<MatOfPoint> largest_contours = new ArrayList<MatOfPoint>();
        for (int idx = 0; idx < contours.size(); idx++) {
            temp_contour = contours.get(idx);
            double contourarea = Imgproc.contourArea(temp_contour);
            //compare this contour to the previous largest contour found
            if (contourarea > maxArea) {
                // Imgproc.drawContours(untouched, contours, maxAreaIdx, new Scalar(0, 255, 0), 1); 
                //check if this contour is a square
                MatOfPoint2f new_mat = new MatOfPoint2f( temp_contour.toArray() );
                int contourSize = (int)temp_contour.total();
                Imgproc.approxPolyDP(new_mat, approxCurve, contourSize*0.05, true);
                if (approxCurve.total() == 4) {
                    maxCurve = approxCurve;
                    maxArea = contourarea;
                    maxAreaIdx = idx;
                    largest_contours.add(temp_contour);
                }
            }
        }
  Imgproc.drawContours(imgSource, contours, maxAreaIdx, new Scalar(0, 255, 0), 5); //will draw the largest square/rectangle
 }

感谢。

enter image description here enter image description here

1 个答案:

答案 0 :(得分:0)

非常感谢这么棒的帖子。这对我帮助很大。 希望这些代码可以帮到你。

 public static String houghTransform(Mat original_image, String outFile) {
            Mat imgSource = original_image;
            Mat untouched = original_image.clone();
Imgproc.cvtColor(imgSource, imageGray, Imgproc.COLOR_RGB2GRAY);




            Imgproc.GaussianBlur(imgSource, imgSource, new Size(11,11), 0);

            // 2) AdaptiveThreshold -> classify as either black or white
            Imgproc.adaptiveThreshold(imgSource, imgSource, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 5, 2);

            // 3) Invert the image -> so most of the image is black
            Core.bitwise_not(imgSource, imgSource);

            // 4) Dilate -> fill the image using the MORPH_DILATE
            Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(3,3), new Point(1,1));
            Imgproc.dilate(imgSource, imgSource, kernel);


    //      Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 0);
    //
    //      // adaptive threshold thresholds the image taking an optimum value for a
    //      // local neighbourhood.
    //      // Imgproc.adaptiveThreshold(imgSource, imgSource, 255,
    //      // Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, 3, 1);
    //
    //      // convert the image to black and white does (8 bit)
    //      Imgproc.Canny(imgSource, imgSource, 20, 60);

            Mat lines = new Mat();
            int threshold = 80;
            int minLineSize = 40;
            int lineGap = 20;

            Imgproc.HoughLinesP(imgSource, lines, 1, Math.PI / 2, threshold,
                    minLineSize, lineGap);

            ArrayList<Point> corners = new ArrayList<Point>();
            for (int i = 0; i < lines.cols(); i++) {
                for (int j = i + 1; j < lines.cols(); j++) {
                    Point pt = computeIntersect(lines.get(0, i), lines.get(0, j));
                    if (pt.x >= 0 && pt.y >= 0)
                        corners.add(pt);
                }
            }

            if (corners.size() < 4) {
                return "";
            }

            Point center = new Point(0, 0);
            // Get mass center
            for (int i = 0; i < corners.size(); i++) {
                center.x += corners.get(i).x;
                center.y += corners.get(i).y;
            }
            center.x = (center.x / corners.size());
            center.y = (center.y / corners.size());

            ArrayList<Point> top = new ArrayList<Point>();
            ArrayList<Point> bottom = new ArrayList<Point>();

            for (int i = 0; i < corners.size(); i++) {
                if (center.y > corners.get(i).y) {

                    top.add(corners.get(i));

                } else {
                    bottom.add(corners.get(i));

                }

            }
            if (top.size() > 0 && bottom.size() > 0) {
                double largest_top_x = top.get(0).x;
                double smallest_top_x = top.get(0).x;
                double largest_top_y = top.get(0).y;
                double smallest_top_y = top.get(0).y;

                int min_top, max_top, min_bottom, max_bottom;

                double largest_bottom_x = bottom.get(0).x;
                double smallest_bottom_x = bottom.get(0).x;
                double largest_bottom_y = bottom.get(0).y;
                double smallest_bottom_y = bottom.get(0).y;

                for (int i = 0; i < top.size(); i++) {
                    if (top.get(i).x > largest_top_x) {
                        largest_top_x = top.get(i).x;
                        min_top = i;
                    } else if (top.get(i).x < smallest_top_x) {
                        smallest_top_x = top.get(i).x;
                        max_top = i;
                    }

                    if (top.get(i).y > largest_top_y) {
                        largest_top_y = top.get(i).y;
                        min_top = i;
                    } else if (top.get(i).y < smallest_top_y) {
                        smallest_top_y = top.get(i).y;
                        max_top = i;
                    }

                }

                for (int i = 0; i < bottom.size(); i++) {
                    if (bottom.get(i).x > largest_bottom_x) {
                        largest_bottom_x = bottom.get(i).x;
                        min_top = i;
                    } else if (bottom.get(i).x < smallest_bottom_x) {
                        smallest_bottom_x = bottom.get(i).x;
                        max_top = i;
                    }

                    if (bottom.get(i).y > largest_bottom_y) {
                        largest_bottom_y = bottom.get(i).y;
                        min_top = i;
                    } else if (bottom.get(i).y < smallest_bottom_y) {
                        smallest_bottom_y = bottom.get(i).y;
                        max_top = i;
                    }

                }

                Core.circle(untouched, center, 20, new Scalar(255, 0, 0), 5); // p1

                Core.circle(untouched, new Point(smallest_top_x, smallest_top_y),
                        20, new Scalar(255, 0, 0), 5);
                Core.circle(untouched, new Point(largest_top_x, smallest_top_y),
                        20, new Scalar(255, 0, 0), 5);
                Core.circle(untouched, new Point(smallest_bottom_x,
                        largest_bottom_y), 20, new Scalar(255, 0, 0), 5);
                Core.circle(untouched,
                        new Point(largest_bottom_x, largest_bottom_y), 20,
                        new Scalar(255, 0, 0), 5);

                Highgui.imwrite(outFile, untouched);

            }
            return outFile;
        }