在Talmud页面上识别文本区域

8
我有一张像这样的塔木德页面: enter image description here enter image description here 我想用opencv找到文本区域,得到如下结果,每个文本都像这样单独出现:

enter image description here

在附加的图像中,每个区域用不同的颜色标记,并给文本编号,重要的是识别属于每个文本的区域,并将其与属于另一个文本的区域区分开来,数字顺序并不重要。
用眼睛做这件事真的很容易,根据穿过文本之间的白条纹,但我试图用opencv来做,但失败了。
在下面的代码中,我尝试捕获所有的字母并将它们变成黑色矩形, 然后放大每个矩形以与相邻的矩形相遇, 这样整个文本区域将变成黑色,文本之间将有明显的白条纹。
我不知道该怎么做,也不知道这是否是一个好的方法。
public List<Rectangle> getRects(Mat grayImg)
{
    BlobCounter blobCounter = new BlobCounter();
    blobCounter.ObjectsOrder = ObjectsOrder.None;
    blobCounter.ProcessImage(grayImg);
    IEnumerable<Blob> blobs = blobCounter.GetObjectsInformation();

    var blackBlobs = grayImg.Clone;
    foreach (var b in blobs)
        blackBlobs.Rectangle(b.Rectangle.ToCvRect, Scalar.Black, -1);

    var widths = blobs.Select(X => X.Rectangle.Width).ToList;
    widths.Sort();
    var median = widths(widths.Count / (double)2);

    Mat erodet = new Mat();
    Cv2.Erode(grayImg, erodet, null, iterations: median);

    using (Window win = new Window())
    {
        win.ShowImage(erodet);
        win.WaitKey();
    }
}

提前感谢,任何帮助都将不胜感激。

额外说明:

正如您在上一张图片中看到的那样,文本区域不是矩形的, 但可以将这些区域描述为不同大小的矩形集合,排列成一堆,一个接一个地放置。

请注意,当两个矩形属于同一文本时,不要将一个矩形排列在另一个矩形旁边,而只需将其一个接一个地放置在上面。

我想要实现的是这些矩形的集合,并知道每个矩形属于哪个文本。

答案可以使用任何编程语言,尤其是C++ PythonC#


我不会在第一次尝试中寻找矩形,而是会寻找白色线条。查询如何进行光学滤波,并查找识别文本块为灰色、但能够捕捉到白色空间的一维滤波器。沿着每个方向(比如频率为每个字符高度的3或4个扫描)扫描页面,并建立由白色空间分隔的灰色斑块模型。这需要一些试错才能做到。如果页面未对齐(如您所示),那么它将更加困难。如果是这样,您可能首先要做一些事情来确定对齐,然后再进行预旋转。 - Flydog57
你可以尝试形态学操作——腐蚀。 kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(19,8)) out = cv2.morphologyEx(thresh, cv2.MORPH_ERODE, kernel) - Alex Alex
2个回答

12

我相信这个任务可以大部分使用形态学操作来完成。
中更容易展示该概念,但也有等效的操作。

我们首先粗略估计页面不同部分之间间隙的大小。通过查看您的示例,间隙大约为页面高度的1%。

img = im2single(rgb2gray(imread('https://istack.dev59.com/LoV5x.webp')));  % read the image into 1ch gray scale image in range [0, 1]
gap = ceil(size(img,1) * 0.01);  % gap estimation

首先,我们想要使用图像膨胀运算来创建一个掩膜,使同一部分中的所有单词相互连接:

d1 = imdilate(img < 0.5, ones(gap));

最终结果为:
输入图像描述

(如果不是打印机在每个部分底部添加的烦人字词,我们早就完成了...)

有一些扩张没有填充的大空白区域,我们可以使用floodfill来完成它们:

f = imfill(d1, 'holes');

现在我们对文本区域使用完整的面罩:
enter image description here

利用腐蚀处理来分隔不同部分之间的空白:

e = imerode(f, ones(1, 5*gap));  % erosion only horizontally

虽然过于稀疏,但分割结果是正确的:
enter image description here

扩张回去

d2 = imdilate(e, ones(1, 5*gap));

给出这个二进制掩码:
enter image description here

现在,您只需查看此二进制掩码的连通组件
enter image description here

我希望这对我来说算是一个“Daf Yomi”...


更新:
下一步 - 从分段转换为矩形多边形需要进行一些几何运算,我将在此处概述方法,并留下实现细节交给您。
最终,我们希望每个段都有一个包围多边形,基本多边形是该段的矩形边界框。 您将不得不实现这个“多边形”类。 这个类的关键方法是“多边形减法” - 即poly_result = poly_a - poly_b创建一个新的多边形poly_result,它是poly_a减去poly_bpoly_a之间的交集。

以下是算法:

  1. 对于每个段,计算其边界框、边界框面积和段中实际像素数。
    将每个段的多边形初始化为其边界框。
  2. 根据像素数量与边界框面积之比以递减顺序对段进行排序。
  3. 对于每个递减顺序的段:
    从此段的所有先前多边形中减去。

您应该会得到类似于这样的结果:

enter image description
第二张图片:
enter image description


谢谢,您如何将非矩形区域转换为覆盖该区域的多个矩形,就像我在问题中所解释的那样? - google dev
3
@googledev 的意思是 stackoverflow 不是用来“为我写代码”的,而是“帮助我自己写代码”。这个回答逐步概述了一个算法,并包含了实现每个步骤所需的 opencv 函数的参考。从这里开始,你应该能够继续下去。我给了你塔木德+拉什,现在你需要自己完成托斯福特(Tosfot)。 - Shai
1
如回答中所解释的那样,该算法基于使用形态学操作来为每个文本区域形成“实心”掩码。为此,我们估计文本“块”内行和单词之间的间隙大小。标题行显然不共享相同的“统计数据”-它具有较少的单词,间距较大且字体较大。因此,标题行不遵循页面其余部分的规则,需要单独处理。如果页面上还有其他行为明显不同的部分-那么您是正确的。 - Shai
@Shai,你的代码中d1 = imdilate(img < 0.5, ones(gap));这一行中的(img <0.5 )部分是什么意思?我正在使用Python OpenCV,猜测它是用来调整图像大小的。 - Shashiwadana
@Shashiwadana 这不是调整大小,而是阈值化。 - Shai
显示剩余4条评论

0

从我看到的情况来看,您首先尝试执行布局分析以提取感兴趣的区域。这是一个研究领域,不是很出名,但对于该问题有一些良好的结果。如果您不确定要使用opencv解决此问题,我建议您研究光学布局识别(OLR)。LAREX开源工具是一个很好的起点。


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