如何删除重叠的轮廓

时间:2017-08-12 22:04:17

标签: java opencv opencv-contour

我正在制作一个程序,我试图从拼图中提取彩色方块。我从视频捕捉中取出一帧然后找到所有轮廓。然后我删除不是正方形形状的轮廓(这可以正常工作,但寻找更好的方法)。我面临的主要问题是轮廓重叠。我使用RETR_TREE来获取所有轮廓,但在使用RETR_EXTERNAL时,轮廓变得更难以检测。有没有办法可以改善方块的检测?或者我可以删除图像中重叠轮廓的方法。

以下是轮廓重叠的图像: 在这张图片中找到了11个轮廓,但我只想要9个。(我绘制了rects以便更容易看到重叠) Overlapping image

。如何去除内轮廓? 这是我的代码:

public Mat captureFrame(Mat capturedFrame){

    Mat newFrame = new Mat();
    capturedFrame.copyTo(newFrame); 

    //Gray
    Mat gray = new Mat();
    Imgproc.cvtColor(capturedFrame, gray, Imgproc.COLOR_RGB2GRAY);

    //Blur
    Mat blur = new Mat();
    Imgproc.blur(gray, blur, new Size(3,3));
    //Canny image
    Mat canny = new Mat();
    Imgproc.Canny(blur, canny, 20, 40, 3, true);

    //Dilate image to increase size of lines
    Mat kernel = Imgproc.getStructuringElement(1, new Size(3,3));
    Mat dilated = new Mat();
    Imgproc.dilate(canny,dilated, kernel);


    List<MatOfPoint> contours = new ArrayList<>();
    List<MatOfPoint> squareContours = new ArrayList<>();

    //find contours
    Imgproc.findContours(dilated, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_NONE);


    //Remove contours that aren't close to a square shape.
    //Wondering if there is a way I can improve this?
    for(int i = 0; i < contours.size(); i++){

        double area = Imgproc.contourArea( contours.get(i)); 
        MatOfPoint2f contour2f = new MatOfPoint2f(contours.get(i).toArray());

        double perimeter = Imgproc.arcLength(contour2f, true);
        //Found squareness equation on wiki... 
        //https://en.wikipedia.org/wiki/Shape_factor_(image_analysis_and_microscopy)
        double squareness = 4 * Math.PI * area / Math.pow(perimeter, 2);

        //add contour to new List if it has a square shape.
        if(squareness >= 0.7 && squareness <= 0.9 && area >= 3000){
           squareContours.add(contours.get(i));
        }
    }

    MatOfPoint2f approxCurve = new MatOfPoint2f();
    for(int n = 0; n < squareContours.size(); n++){

        //Convert contours(n) from MatOfPoint to MatOfPoint2f
        MatOfPoint2f contour2f = new MatOfPoint2f( squareContours.get(n).toArray());
        //Processing on mMOP2f1 which is in type MatOfPoint2f
        double approxDistance = Imgproc.arcLength(contour2f, true)*0.02;
        Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);

        //Convert back to MatOfPoint
        MatOfPoint points = new MatOfPoint( approxCurve.toArray());

        // Get bounding rect of contour
        Rect rect = Imgproc.boundingRect(points);
        //length and width should be about the same
        if(rect.height - rect.width < Math.abs(10)){
            System.out.printf("%s , %s \n", rect.height, rect.width);
        }

         // draw enclosing rectangle (all same color, but you could use variable i to make them unique)
        Imgproc.rectangle(newFrame, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height),new Scalar (255, 0, 0, 255), 3); 

        }  

    return newFrame;
}

1 个答案:

答案 0 :(得分:2)

幸运的是,cv :: findContours还为我们提供了层次结构矩阵,您在代码片段中忽略了该层次结构,该层次结构对于RETR_EXTERNAL以外的所有模式非常有用,您可以找到层次结构矩阵的详细文档{ {3}}。

层次结构矩阵包含每个轮廓的格式 [Next,Previous,First_Child,Parent] 的数据。现在您可以过滤轮廓,例如select only those contours where parent == -1这样的逻辑,这将消除父轮廓内的子轮廓。

要使用层次结构矩阵,您需要将cv :: findContours称为:

cv::Mat hierarchy;
Imgproc.findContours(dilated, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_NONE);