识别 Talmud 页面上的文本区域

goo*_*dev 6 ocr opencv image-processing computer-vision image-segmentation

我有一个像这样的 Talmud 页面: 在此处输入图片说明 在此处输入图片说明 我想找到文本区域opencv以获得这样的结果,每个文本都将像这样自己:

在此处输入图片说明

在附图中,每个区域用不同的颜色标记,并且文本有一个数字,重要的是识别属于每个文本的区域,并将其与属于另一个文本的区域区分开来,数字顺序无关紧要.

根据文本之间的白色条纹,用眼睛做这件事真的很容易,但我试图用眼睛做,但我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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

补充说明:

正如您在上图中所看到的,文本区域不是矩形,但这些区域可以描述为一堆不同大小的矩形的集合,一个叠一个。

请注意,当两个矩形属于同一个文本时,不要将一个矩形与另一个矩形相邻排列,而只能将一个矩形放在另一个矩形之上。

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

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

Sha*_*hai 9

我相信这项任务可以主要使用形态学操作来完成。
更容易展示这个概念,但有等效的操作。

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

img = im2single(rgb2gray(imread('https://i.stack.imgur.com/LoV5x.jpg')));  % read the image into 1ch gray scale image in range [0, 1]
gap = ceil(size(img,1) * 0.01);  % gap estimation
Run Code Online (Sandbox Code Playgroud)

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

d1 = imdilate(img < 0.5, ones(gap));
Run Code Online (Sandbox Code Playgroud)

结果是:
在此处输入图片说明

(如果不是因为打印机在每个部分的底部添加了下一页的烦人的话,我们就已经完成了......)

有一些大的空白没有被扩张填补,我们可以用floodfill它们来完成:

f = imfill(d1, 'holes');
Run Code Online (Sandbox Code Playgroud)

现在我们有文本区域的完整掩码:
在此处输入图片说明

使用腐蚀在不同部分之间进行切割:

e = imerode(f, ones(1, 5*gap));  % erosion only horizontally
Run Code Online (Sandbox Code Playgroud)

产生正确的分区,虽然太细了:
在此处输入图片说明

向后扩张

d2 = imdilate(e, ones(1, 5*gap));
Run Code Online (Sandbox Code Playgroud)

给出这个二进制掩码:
在此处输入图片说明

您现在可以简单地查看此二进制掩码的连接组件
在此处输入图片说明

我希望这对我来说算作“Daf Yomi”...


更新:
下一步 - 从线段到矩形多边形需要一些几何运算,我将在此处概述该方法并将实现细节留给您。
最终,我们需要每个线段的边界多边形,基本多边形是线段的矩形边界框。你必须实现这个“多边形”类。这个类的一个重要方法是“多边形减法” -即poly_result = poly_a - poly_b创建一个新的多边形poly_resultpoly_a零下之间的交叉poly_apoly_b

这是算法:

  1. 对于每个段,计算它的边界框、边界框的面积和段中的实际像素数。
    将每个线段的多边形初始化为其边界框。
  2. 根据像素数与边界框区域之间的比率按降序对段进行排序。
  3. 对于按降序排列的每个线段:
    从该线段中减去所有先前的多边形。

你应该得到这样的东西:

输入图片说明
对于第二张图片:
输入图片说明

  • @googledev stackoverflow 不是“为我编写代码”,而是“帮助我编写自己的代码”。该答案逐步概述了一个算法,并且还包含对实现每个步骤输出操作的 opencv 函数的引用。你应该可以从这里拿走它。我给了你《塔木德》+《拉希》,你需要自己做《Tosfot》。 (2认同)