【问题标题】:How to trace line segments in a binary skeletonized image?如何在二进制骨架化图像中跟踪线段?
【发布时间】:2015-10-14 04:17:05
【问题描述】:

我有一个二值化和骨架化的图像。我使用 Zhang-Suen 算法进行骨架化。现在我需要以 2 点格式(线段的起点和终点)从图像中获取线段。 到目前为止,我一直在使用 OpenCV 函数 findContours,带有 CV_CHAIN_APPROX_SIMPLE 和 CV_RETR_LIST 选项。但是,出现了三个问题:

  1. 此方法返回重复的线段(方向相反)
  2. 由于“层次结构特征”,连接的结构有时会断开连接
  3. 线条交叉点附近的结果很混乱。

还有其他方法可以从图像中追踪线段吗?

我需要追踪的图像的放大部分:

【问题讨论】:

  • 你需要每条8连线的起点和终点吗?具有多条路径的轮廓(例如最低的一条)呢?
  • 是的,他们呢?我只需要所有直线和对角线段的坐标。
  • 因此,例如考虑顶部的行。对你来说,它是由一行组成的,还是由两行组成的?即直接你的意思是具有相同的 y 值?
  • 最上面的第一行? 3段。两条水平线和一条对角线(长度只有两个像素)。
  • 好的,明白了。如果您发布您的原始图片,我会试一试

标签: opencv image-processing computer-vision


【解决方案1】:

应该可以。它对图像进行 4 次扫描(您可能可以减少扫描次数,但逻辑会更复杂)。

在每次扫描中,它会跟踪水平线、垂直线、对角线向下线和对角线向上线。

行存储在vector<Vec4i> 中,其中每个Vec4i 是带有Xstart, Ystart, Xend, Yend 的行;

让我知道这是否适合你。

#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;
}

从这张图片开始:

用随机颜色绘制每条检测到的线(从开始到结束)给出:

放大:

【讨论】:

    猜你喜欢
    • 2017-08-19
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多