线端点检测

6
我打算在C#中检测从字符(OCR)生成的线条的端点。我想要像这样的东西:
![Image](https://istack.dev59.com/SBf4D.webp)
我所说的“端点”是指获取字符中任何线条的末端……例如,'C'有两个端点(一个在顶部,一个在底部),如上图所示,用红色像素表示。我可以从“更胖”的现有扫描字符中提取单个线条,可以进行边缘检测和Flood-fill分析,但我似乎无法复制上面的内容!如果有文章或现有代码的指针,将不胜感激!任何代码示例都可以,因为我可以轻松地将C++或任何.NET语言转换为C#。
谢谢,Josh
2个回答

1

由于您还没有“端点”的定义,我建议:

  • 当且仅当所有邻居点(即具有曼哈顿距离<= 3的黑色点)位于小于45度的扇形区域内时,黑色点为端点。

找到每个相邻黑点的角度应该不太困难。排序这些角度并找到范围也不难,尽管您需要注意不连续性(即角度突然变化360度的地方)。按斜率排序而不实际计算角度可能略快。可以通过提前退出逻辑来获得额外的加速。


好的,我会用一个定义来更新问题。基本上,我想要得到的是任何线条的端点...例如,'C'有两个端点(一个在顶部,一个在底部),如上图所示,表示为红色像素。我还考虑扫描整个线条(因为我已经有了黑色像素,因为我使用了洪水填充算法从PNG中选择字符,然后使用了线条细化算法将其减少到单个线条),并搜索被仅由一个其他黑色像素包围(在所有方向上包括对角线)的黑色像素。 - jduncanator
@jduncanator:这个定义不够技术化,无法实际使用。此外,一个端点可能很容易有两个黑色邻居,都在同一侧。 - Ben Voigt

0

这是我做的方法。 对于每个像素不为0的点,在其周围3 x 3的网格中计算非零像素的数量。如果数量为2,则表示该点是一条线段的端点。

// count the number of points in the neighborhood of our pixel
inline int countNeighborhood(cv::Mat &img, int xc, int yc)
{
    if (img.empty()) return 0;
    if (img.type() != CV_8UC1) return 0;
    xc++;
    yc++;
    int iCnt = 0;
    for (int y = yc - 2; y <= yc; y++)
    {
        if ((y < 0) || (y >= img.rows)) continue;
        uint8_t *buf = img.ptr(y);
        for (int x = xc - 2; x <= xc; x++)
            if ((x > 0) && (x < img.cols) && (buf[x])) iCnt++;
    }
    return iCnt;
}

/*  get endpoints of a image with lines in it
*/
std::vector<cv::Point> getEndPoints(cv::Mat &img)
{
    std::vector<cv::Point> res;
    for (int y = 0; y < img.rows; y++)
    {
        uint8_t *buf = img.ptr(y);
        for (int x = 0; x < img.cols; x++)
        {
            if (buf[x] == 0) continue;
            int iCnt = countNeighborhood(img, x, y);
            if (iCnt == 2) res.push_back(cv::Point(x, y));
        }
    }
    return res;
}

如果您喜欢,可以使用内核来完成countNeighborhood。

函数getEndPoints返回所有找到的端点数组。

附言:此函数适用于黑色(0)背景和白色(1-255)线条。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接