我计划检测从 C# 中的字符 (OCR) 生成的行的端点。我想要这样的东西:
我所说的“端点”的意思是我想得到字符中任何行的结尾......例如,“C”有两个端点(一个在顶部,一个在底部),如上图所示作为一个红色像素。我可以从“较胖”的现有扫描字符中提取单行,我可以进行边缘检测和 Flood-fill 分析,但我似乎无法复制上述内容!任何指向文章或现有代码的指针将不胜感激!任何代码示例都可以,因为我可以轻松地将 C++ 或任何 .NET 语言转换为 C#。
谢谢,乔什
由于您还没有“端点”的定义,我建议:
找到每个相邻黑点的角度应该不会太难。对这些角度进行排序并找到范围也并不困难,尽管您需要注意不连续性(角度突然变化 360 度)。在不实际计算角度的情况下按斜率排序可能会稍微快一些。使用提前退出逻辑可以获得额外的加速。
我就是这样做的。对于每个不为 0 的像素,计算该像素周围 3 x 3 网格中不为 0 的像素数。如果数字为 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 返回所有找到的端点的数组。
PS此功能适用于黑色(0)背景和白色(1-255)als线条。