How to track line segments in a binary skeletonized image?

I have a binarized and skeletonized image. I used Zhang-Suen's algorithm for skeletonization. Now I need to get line segments from an image in 2-point format (start and end points of line segment). So far I have used the OpenCV findContours function with the CV_CHAIN_APPROX_SIMPLE and CV_RETR_LIST parameters. However, three problems arise:

  • This method returns repeating line segments (in the opposite direction)
  • Linked structures are sometimes disabled due to the "hierarchy function"
  • Unhelpful results in the vicinity of line intersections.

Is there another way to keep track of image line segments?

Enlarged section of the image that I need to trace: Zoomed section of the image that I need to track

+3


source to share


1 answer


This should work. It does 4 scans of the image (you can probably reduce the number of scans, but the logic will be more complicated).

In each scan, it tracks horizontal lines, vertical lines, downward diagonal lines, and upward diagonal lines.

Lines are stored in vector<Vec4i>

, where each Vec4i

is a string with Xstart, Ystart, Xend, Yend

;

Let me know if this works for you.

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);

    Mat1b w;
    // Add bg border
    copyMakeBorder(img, w, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(0));

    vector<Vec4i> lines;
    Vec4i line;

    // Scan horizontal lines 
    for (int y = 1; y < w.rows - 1; ++y)
    {
        for (int x = 1; x < w.cols - 1; ++x)
        {
            if (w(y, x) == 255)
            {
                int yy = y;
                int xx = x;

                //Save first point
                line[0] = xx - 1;
                line[1] = yy - 1;

                while (true)
                {
                    if (w(yy, xx + 1))
                    {
                        // Mark as detected
                        w(yy, xx) = 1;
                        ++xx;
                    }
                    else
                    {
                        // End of the line
                        line[2] = xx - 1;
                        line[3] = yy - 1;

                        if (line[2] - line[0] > 0)
                        {
                            lines.push_back(line);
                        }
                        break;
                    }
                }
            }
        }
    }

    // Scan vertical lines 
    for (int y = 1; y < w.rows - 1; ++y)
    {
        for (int x = 1; x < w.cols - 1; ++x)
        {
            if (w(y, x) == 255)
            {
                int yy = y;
                int xx = x;

                //Save first point
                line[0] = xx - 1;
                line[1] = yy - 1;

                while (true)
                {
                    if (w(yy + 1, xx))
                    {
                        // Mark as detected
                        w(yy, xx) = 1;
                        ++yy;
                    }
                    else
                    {
                        // End of the line
                        line[2] = xx - 1;
                        line[3] = yy - 1;

                        if (line[3] - line[1] > 0)
                        {
                            lines.push_back(line);
                        }
                        break;
                    }
                }
            }
        }
    }

    // Scan for diagonal low lines 
    for (int y = 1; y < w.rows - 1; ++y)
    {
        for (int x = 1; x < w.cols - 1; ++x)
        {
            if (w(y, x) == 255)
            {
                int yy = y;
                int xx = x;

                //Save first point
                line[0] = xx - 1;
                line[1] = yy - 1;

                while (true)
                {
                    if (w(yy + 1, xx + 1))
                    {
                        // Mark as detected
                        w(yy, xx) = 1;
                        ++xx;
                        ++yy;
                    }
                    else
                    {
                        // End of the line
                        line[2] = xx - 1;
                        line[3] = yy - 1;
                        if (line[2] - line[0] > 0)
                        {
                            lines.push_back(line);
                        }
                        break;
                    }
                }
            }
        }
    }

    // Scan for diagonal high lines 
    for (int y = 1; y < w.rows - 1; ++y)
    {
        for (int x = 1; x < w.cols - 1; ++x)
        {
            if (w(y, x) == 255)
            {
                int yy = y;
                int xx = x;

                //Save first point
                line[0] = xx - 1;
                line[1] = yy - 1;

                while (true)
                {
                    if (w(yy - 1, xx + 1))
                    {
                        // Mark as detected
                        w(yy, xx) = 1;
                        ++xx;
                        --yy;
                    }
                    else
                    {
                        // End of the line
                        line[2] = xx - 1;
                        line[3] = yy - 1;
                        if (line[2] - line[0] > 0)
                        {
                            lines.push_back(line);
                        }
                        break;
                    }
                }
            }
        }
    }

    RNG rng(12345);
    Mat3b res;
    cvtColor(img, res, COLOR_GRAY2BGR);

    for (int i = 0; i < lines.size(); ++i)
    {
        const Vec4i& lin = lines[i];
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        cv::line(res, Point(lin[0], lin[1]), Point(lin[2], lin[3]), color);
    }

    imshow("res", res);
    waitKey();

    return 0;
}

      

Starting with this image:



enter image description here

Drawing each line found (from start to finish) with random colors gives:

enter image description here

Increased:

enter image description here

+1


source







All Articles