tesseractOCR 特征提取篇----MF特征提取

时间:2022-04-20 23:37:27

  一直在做ocr识别的相关工作。由于兴趣及工作需要,研究优化了下tesseract识别引擎的各个模块。发现关于tesseract引擎国内的资料,对于代码及原理的介绍相对较少,大部分都是应用类的文章,我将看过的代码结合自己的理解介绍识别的各个模块,与大家一起交流学习。

 先看下训练时我这边提取到的数字1的MF特征(该特征我是理解为笔画直线中点的坐标,该直线长度及角度等,字提取轮廓后其实就是一条条直线了)

tesseractOCR  特征提取篇----MF特征提取

mf 5

 0.022858083 0.32230198 0.37753356 0 0 0              

 -0.16590869 0.11053124 0.42354149 0.25 0 0

 -0.25303182 -0.20042329 0.26402926 0.13528861 0 0

 -0.064265043 -0.29960707 0.55177981 0.5 0 0

 0.21162486 0.011347458 0.62190902 0.75 0 0

  X      y        len     dir  . . .


下面来看MF特征是如何得到的:

  

首先定义一些方向的sign

 Left 0 down 32 right 64 up 96  

 leftdown 16  downright 48  rightup 80  upleft  112 类似对应45度  刚好8个方向

 1:二值化提取出轮廓     

      tesseractOCR  特征提取篇----MF特征提取              

    轮廓点集  <x,y,dir>由46个点组成

       tesseractOCR  特征提取篇----MF特征提取tesseractOCR  特征提取篇----MF特征提取 


2:去掉同一条直线上的点,以及将直线变平滑(如90度角处理成45度)得到点集                      

   tesseractOCR  特征提取篇----MF特征提取

 点集连成的直线   tesseractOCR  特征提取篇----MF特征提取  图像和1中的差不多,但点少了很多

去掉冗余点的程序过程大概如下:

  pos = c_outline->start_pos (); //start of loop c_outline轮廓点集

  length = c_outline->pathlength ();//个数

  stepindex = 0;

  epindex = 0;//提取的个数

  prevdir = c_outline->step_dir (0);

  do {

    dir = c_outline->step_dir (stepindex);

        if (stepindex < length - 1 && c_outline->step_dir (stepindex + 1) - dir == -32) {  

                        //方向为 DownLeft 16  Rightdown 48 upright 80 rightup 112一个                   

      dir += 128 - 16; //一个字节  不为零 +128不变0128意义一样

          stepinc = 2;  //出现拐点则为2

    }

    else

      stepinc = 1;

    if (count == 0) {

      prevdir = dir;

    }

    if (prevdir.get_dir () != dir.get_dir ()) {//两个点角度不一样

      edgepts[epindex].pos.x = pos.x ();

      edgepts[epindex].pos.y = pos.y ();//提取该点

      prevdir = dir;

      pos = edgepts[epindex].pos;

          }

    stepindex += stepinc;

  }

  while (stepindex < length);

 

0:index = 13 prevdir 32 dir16  push(<5,28>)

1:index = 15 prevdir 16 dir 32  push(<5,15>)

2:index = 20 prevdir 32 dir 48  push(<4,14>)

3:index = 22 prevdir 48 dir 64  push(<4,9>)

4:index = 23 prevdir 64 dir 16  push(<5,8>)

5:index = 25 prevdir 16 dir 96  push(<6,8>)

6:index = 44 prevdir 96 dir 0   push(<7,9>)

7:   加入最后pos

ps:  这边的dir可以理解为这7个点中,该点后两个点连成直线的走势角度

     5,15)(3,14) 刚好为leftdown 16


3:再次去冗余。大概去掉距离比较近的点,这部分没怎么看,

   tesseractOCR  特征提取篇----MF特征提取  只剩五个点了。

   

 点集连成直线  tesseractOCR  特征提取篇----MF特征提取

Ps:最后得到的点类似于笔画拐点,点的个数也是mf特征的个数(两点一条直线一个特征,n个点闭合有n条直线,即有n个特征,最后提取的特征为直线的属性)


4:MF特征计算


先看下一行字中每个位置sign

tesseractOCR  特征提取篇----MF特征提取

以我测试的一张图片为例

tesseractOCR  特征提取篇----MF特征提取

所有矩形框文字点范围 rect x(4,229) y(0,38)  mid_x  116.5

X_height 求得21  调为128则对应比率scale  6.095238

数字 1的矩形框x(1,15)y(8,27)

Origion_y  8.02  猜测类似矩形框中点y的起点base_line((4+7)/2)

 

mid_x为坐标中点且mid_x映射到0x_height高度大小放大到128:

 X1,x2    文字点范围   Rectmid_x设     将x_height高度设

                                            0,对应坐标     为128,乘以scale                                                                

<1,15>      <4,7>     -116.5=<-113,-110>                        *6.095238 = <-689,-670>     

X_height高度大小放大到128,以64为中心点

Y1,y2     文字点范围   -origion_y           x_height高度设      +final_y_offset

 

                                                                         128,乘以scale

<8,27>    <9,28>                -8.02=<1,20>         *6.095238<6,122>                       +64=<70,186>

 

对于提取到的拐点按上面步骤运算,得到下列5个原始点。再做映射


tesseractOCR  特征提取篇----MF特征提取

<1>其中映射到0-255 做了宽高比的归一化

X_mid  -677.15    y_mid 126.6    x_mid,y_mid的计算非那五个点,而是点连成的直线所有点

X_scale 7.4345096    

Y_scale 1.3724890   个人理解,因为文字有可能被压缩变形,默认类似正方形,因为数字1宽度较小,高度长,而为了归一化为正方形,X_scale便会比较大

计算结果 (xi-x_mid)*scale_x+128

      如(-683 + 677.15* 7.4345096 + 128 = 83.21  结果有误差,因为有些小数点损失

 

<2>映射到-0.5 - 0.5   除以128范围是(-1,1) 所以要除以256

 

(Xi-127.5) /  128 / 2    

 

(84.5-127.5)/256 = -0.167  

 

通过拐点提取特征点,取两个拐点的直线的中点坐标,直线长度,直线角度,最终提取到的特征

 tesseractOCR  特征提取篇----MF特征提取

五个拐点五条直线五个特征