Search code examples
c#image-processingbresenhamdouglas-peucker

Find corners/edges on a shape (minimum vertices that can define that shape)


I'm trying to get the corners of the following shape:

enter image description here

By corners I mean this (red dots):

enter image description here

The minimum quantity of points that can define this shape.

And I have implemented the following:

    public Shape Optimize()
    {
        // If the vertices are null or empty this can't be executed
        if (vertices.IsNullOrEmpty())
            return this; // In this case, return the same instance.

        if (!edges.IsNullOrEmpty())
            edges = null; //Reset edges, because a recalculation was requested

        // The corners available on each iteration
        var corners = new Point[] { Point.upperLeft, Point.upperRight, Point.downLeft, Point.downRight };

        //The idea is to know if any of the following or previous vertice is inside of the the array from upside, if it is true then we can add it.

        Point[] vs = vertices.ToArray();

        for (int i = 0; i < vertices.Count - 1; ++i)
        {
            Point backPos = i > 0 ? vs[i - 1] : vs[vertices.Count - 1],
                  curPos = vs[i], //Punto actual
                  nextPos = i < vertices.Count - 1 ? vs[i + 1] : vs[0];

            // We get the difference point between the actual point and the back & next point
            Point backDiff = backPos - curPos,
                  nextDiff = nextPos - curPos,
                  totalDiff = nextPos - backPos;

            if (corners.Contains(backDiff) || corners.Contains(nextDiff) || corners.Contains(totalDiff))
                AddEdge(curPos, center); // If any of the two points are defined in the corners of the point of before or after it means that the actual vertice is a edge/corner
        }

        return this;
    }

This works rectangled shapes, but rotated shapes are very sharp, so, this code doesn't work well:

enter image description here

  • Blue pixels (in this photo and the following) are the vertices variable processed on Optimize method.
  • Green pixels are the detected corners/edges (on both photos).

But sharpness in a shape only defines the side inclination, so what can I do to improve this?

Also, I have tested Accord.NET BaseCornersDetector inherited classes, but the best result is obtained with HarrisCornersDetector, but:

enter image description here

Many edges/corners are innecesary, and they aren't in the needed place (see first photo).


Solution

  • Well, after hours of research I found a library called Simplify.NET that internally runs the Ramer–Douglas–Peucker algorithm.

    Also, you maybe interested on the Bresenham algorithm, with this algorithm you can draw a line using two Points.

    With this algorithm, you can check if your tolerance is too high, comparing the actual points and the points that this algorithm outputs and making some kind of percentage calculator of similarity.

    Finally, is interesting to mention Concave Hull and Convex Hull algorithms.

    All this is related to Unity3D.

    My outputs:

    enter image description here

    enter image description here

    And my implementation.

    It's very important to say, that points needs to be sorted forcing them to be connected. If the shape is concave as you can see on the second photo maybe you need to iterate walls of the shape.

    You can see an example of implementation here. Thanks to @Bunny83.