OpenCV finding corners of contours

╄→гoц情女王★ 提交于 2020-01-06 08:14:20

问题


I am completely new to OpenCV. For practice I decided to do a "Sudoku Solver". So far I was able to do this :

public Mat processImage(final Mat originalImage, final CvCameraViewFrame frame) {
    image = originalImage.clone();
    image = frame.gray();

    /*
      We load the image in grayscale mode. We don't want to bother with the colour information,
      so just skip it. Next, we create a blank image of the same size. This image will hold
      the actual outer box of puzzle.
     */
    Mat outerBox = new Mat(image.size(), CV_8UC1);


    /*
      Blur the image a little. This smooths out the noise a bit and makes extracting the grid
      lines easier.
     */
    GaussianBlur(image, image, new Size(11, 11), 0);

    /*
      With the noise smoothed out, we can now threshold the image. The image can have varying
      illumination levels, so a good choice for a thresholding algorithm would be an adaptive
      threshold. It calculates a threshold level several small windows in the image.
      This threshold level is calculated using the mean level in the window. So it keeps things
      illumination independent.

      It calculates a mean over a 5x5 window and subtracts 2 from the mean.
      This is the threshold level for every pixel.
     */
    adaptiveThreshold(image, outerBox, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 5, 2);

    /*
      Since we're interested in the borders, and they are black, we invert the image outerBox.
      Then, the borders of the puzzles are white (along with other noise).
     */
    bitwise_not(outerBox, outerBox);

    /*
      This thresholding operation can disconnect certain connected parts (like lines).
      So dilating the image once will fill up any small "cracks" that might have crept in.
     */
    Mat kernel = new Mat(3,3, outerBox.type()) {
        {
            put(0,0,0);
            put(0,1,1);
            put(0,2,0);

            put(1,0,1);
            put(1,1,1);
            put(1,2,1);

            put(2,0,0);
            put(2,1,1);
            put(2,2,0);
        }
    };
    dilate(outerBox, outerBox, kernel);

    final List<MatOfPoint> contours = new ArrayList<>();
    findContours(outerBox, contours, new Mat(outerBox.size(), outerBox.type()), CV_SHAPE_RECT, CHAIN_APPROX_SIMPLE);

    final Integer biggestPolygonIndex = getBiggestPolygonIndex(contours);

    if (biggestPolygonIndex != null) {
        setGreenFrame(contours, biggestPolygonIndex, originalImage);
        return originalImage;
    }

     return outerBox;
}

It ends up looking like this

So everything inside green area would be my puzzle. My question is how to extract it and do some digit recognition on it.

So in my mind first logical step would be to cut this area. But I have no idea how can I get it. So how can I get the corners of green contours ?

Any help/hint is welcome.


回答1:


After some tries I was able to solve it

    final List<MatOfPoint> contours = new ArrayList<>();
    findContours(outerBox, contours, new Mat(outerBox.size(), outerBox.type()), CV_SHAPE_RECT, CHAIN_APPROX_SIMPLE);

    final Integer biggestPolygonIndex = getBiggestPolygonIndex(contours);
    if (biggestPolygonIndex != null) {
        final MatOfPoint biggest = contours.get(biggestPolygonIndex);
        List<Point> corners = getCornersFromPoints(biggest.toList());
        System.out.println("corner size " + corners.size());
        for (Point corner : corners) {
            drawMarker(originalImage, corner, new Scalar(0,191,255), 0, 20, 3);
        }

        setGreenFrame(contours, biggestPolygonIndex, originalImage);
    }

private List<Point> getCornersFromPoints(final List<Point> points) {
    double minX = 0;
    double minY = 0;
    double maxX = 0;
    double maxY = 0;


    for (Point point : points) {
        double x = point.x;
        double y = point.y;

        if (minX == 0 || x < minX) {
            minX = x;
        }
        if (minY == 0 || y < minY) {
            minY = y;
        }
        if (maxX == 0 || x > maxX) {
            maxX = x;
        }
        if (maxY == 0 || y > maxY) {
            maxY = y;
        }
    }

    List<Point> corners = new ArrayList<>(4);
    corners.add(new Point(minX, minY));
    corners.add(new Point(minX, maxY));
    corners.add(new Point(maxX, minY));
    corners.add(new Point(maxX, maxY));

    return corners;
}

private Integer getBiggestPolygonIndex(final List<MatOfPoint> contours) {
    double maxVal = 0;
    Integer maxValIdx = null;
    for (int contourIdx = 0; contourIdx < contours.size(); contourIdx++) {
        double contourArea = contourArea(contours.get(contourIdx));
        if (maxVal < contourArea) {
            maxVal = contourArea;
            maxValIdx = contourIdx;
        }
    }

    return maxValIdx;
}

private void setGreenFrame(final List<MatOfPoint> contours,
                           final int biggestPolygonIndex,
                           Mat originalImage) {
    drawContours(originalImage, contours, biggestPolygonIndex, new Scalar(124,252,0), 3);
}


来源:https://stackoverflow.com/questions/55311775/opencv-finding-corners-of-contours

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!