Ask Your Question

Closing contours with approxPolyDP or convexHull

asked 2017-01-17 06:32:39 -0600

Brk gravatar image

updated 2017-01-17 06:53:23 -0600

Hello OpenCV Community,

I'm currently trying to close the contours on the right of this picture: Sample . The reason for the opened contour lies in kabeja, a library to convert DXF files to images. It seems that on some images it doesn't convert the last pixel column (or row) and thats why the Sample picture is open.

I had the idea to use Core.copyMakeBorder() in Opencv, to add some space to the picture. After that I tried to use Imgproc.approxPolyDP() to close the contour, but this doesn't work. I tried this with different Epsilon values: Eps3 Eps50 Eps125

The reason for that is maybe that the contour surrounds the line. It never closes the contour where i want it to do.

I tried another method using Imgproc.convexHull(), which delivers this one: ConvexHull. This could be useful for me, but i have no idea how to take out the part of the convex hull i need and merge it together with the contour to close it.

I hope that someone has an idea.

Here is my method for Imgproc.approxPolyDP()

public static ArrayList<MatOfPoint> makeComplete(Mat mat) {
    System.out.println("makeComplete: START");
    Mat dst = new Mat();
    Core.copyMakeBorder(mat, dst, 10, 10, 10, 10, Core.BORDER_CONSTANT);

    ArrayList<MatOfPoint> cnts = Tools.getContours(dst);
    ArrayList<MatOfPoint2f> opened = new ArrayList<>();

    //convert to MatOfPoint2f to use approxPolyDP
    for (MatOfPoint m : cnts) {
        MatOfPoint2f temp = new MatOfPoint2f(m.toArray());
        System.out.println("First loop runs");

    ArrayList<MatOfPoint> closed = new ArrayList<>();
    for (MatOfPoint2f conts : opened) {
        MatOfPoint2f temp = new MatOfPoint2f();
        Imgproc.approxPolyDP(conts, temp, 3, true);
        MatOfPoint closedTemp = new MatOfPoint(temp.toArray());
        System.out.println("Second loop runs");

    System.out.println("makeComplete: END");
    return closed;

And here the code for Imgproc.convexHull()

 public static ArrayList<MatOfPoint> getConvexHull(Mat mat) {
    Mat dst = new Mat();
    Core.copyMakeBorder(mat, dst, 10, 10, 10, 10, Core.BORDER_CONSTANT);

    ArrayList<MatOfPoint> cnts = Tools.getContours(dst);
    ArrayList<MatOfPoint> out = new ArrayList<MatOfPoint>();
    MatOfPoint mopIn = cnts.get(0);
    MatOfInt hull = new MatOfInt();
    Imgproc.convexHull(mopIn, hull, false);

    MatOfPoint mopOut = new MatOfPoint();
    mopOut.create((int) hull.size().height, 1, CvType.CV_32SC2);

    for (int i = 0; i < hull.size().height; i++) {
        int index = (int) hull.get(i, 0)[0];
        double[] point = new double[]{
                mopIn.get(index, 0)[0], mopIn.get(index, 0)[1]
        mopOut.put(i, 0, point);

    return out;

Best regards, Brk

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2017-01-17 09:01:49 -0600

updated 2017-01-17 09:03:43 -0600

Maybe I do not fully understand the problem, but using contours in this case seems like ovekill to me. If that's always the last column, and there is always only one segment missing, then maybe:

  • rotate the image 90deg counterclockwise (in order to get the pointer to the last two columns and add the column faster) cv::transpose()
  • add the missing column cv::Mat::push_back() (append your image to the single-row image)
  • go along the (n-1)th column (which after rotation becomes the second row) and
    • starting from the first non-white pixel in (n-1)th column
      • set all n-th column pixels to red
    • until you reach next non-white pixel in the (n-1)th column.

For more information on how to iterate over the image see:

If there are more than one segments missing, this will be still doable.

edit flag offensive delete link more

Question Tools

1 follower


Asked: 2017-01-17 06:32:39 -0600

Seen: 2,547 times

Last updated: Jan 17 '17