• 字符识别中的图像归一化算法


    源地址:http://blog.csdn.net/rushkid02/article/details/9242415

    本文介绍3种基本的字符形状归一化算法(Character Shape Normalization)。字符归一化是光学字符识别中的一个子步骤,给定一个字符区域,我们要做的就是将该区域内的字符归一化到一个标准模板大小,然后才能提取特征,并送给分类器做具体的识别。好的归一化算法可以尽量提高后续特征提取在同一类内的一致性。

    先来看一个例子,假如上帝拥有一个完美的字符归一化算法,那么他将可以做到如下所示的效果:

    图1,完美的归一化:左边为原始字符区域,右边为归一化后的结果。

    如果说我们能做到上述结果,那么也就无需再做特征提取,也无需再做训练,而只需简单的模板匹配即可得到100%准确的分类结果。可以看到,上述算法的能力在于:

    1. 归一化到标准模板大小

    2. 倾斜校正

    3. 笔画宽度归一化

    4. 字形归一化

    可惜的是,今天介绍的几种常见算法仅能保证第1点的实现,而2,3则只能实现部分。至于4,就让后续的特征提取去弥补吧。言归正传,3个算法分别是:线性归一化算法,基于图像矩的归一化以及非线性归一化算法。

    按惯例,3个算法的标准c实现可在:

    https://github.com/UnilVision/visionbase/tree/master/ocr/baseline/normalization找到。希望对大家有所帮助。

    线性归一化:线性归一化算法就是一个标准的线性采样过程,采用线性插值获得最终的图像结果。在我们的实现中,使用反向计算的方式:

    其中为长和宽的比值。

    对应代码中的函数为:

    1. void backward_linear(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    2.                      CHARECT_t* region,  
    3.                      unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,  
    4.                      int ratio_preserve_func);  
    [cpp] view plain copy
     
     print?
    1. void backward_linear(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    2.                      CHARECT_t* region,  
    3.                      unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,  
    4.                      int ratio_preserve_func);  

    图像矩归一化: 我们可以通过图像矩来预先校正字符的倾斜度,并通过矩来获得字体的实际大小[w1, h1]及中心位置[xc, yc]。归一化的原始区域被修改为

    [xc-w1/2, xc+w1/2, yc-h1/2, yc+h1/2]。其计算方法为:

    是一个经验值,一般取4。

    其中图像矩的计算方法:



    在找到新的区域[xc-w1/2, xc+w1/2, yc-h1/2, yc+h1/2]后,后续即调用线性归一化算法即可。对应代码中的实现为:

    1. void backward_moment(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    2.                      CHARECT_t* region,  
    3.                      unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,  
    4.                      int ratio_preserve_func);  
    [cpp] view plain copy
     
     print?
    1. void backward_moment(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    2.                      CHARECT_t* region,  
    3.                      unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,  
    4.                      int ratio_preserve_func);  

     

    图像矩倾斜校正:利用图像矩,我们可以找到字符的倾斜角

    采样计算方式为:

    注意这里我们仅调整x的位置以保证图像的中心仍然处于原始的xc,yc。其实现对于:

    1. // slant correction   
    2. // Note>> (dst_wid, dst_hei) must equal to (region.width, region.height)   
    3. void backward_moment_slantcorrection(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    4.                      CHARECT_t* region,  
    5.                      unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep);  
    [cpp] view plain copy
     
     print?
    1. // slant correction  
    2. // Note>> (dst_wid, dst_hei) must equal to (region.width, region.height)  
    3. void backward_moment_slantcorrection(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    4.                      CHARECT_t* region,  
    5.                      unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep);  


    通常倾斜校正会放在归一化之前,已获得更好的效果。

    非线性归一化:这里实现的是Jun Tsukumo在1988年提出的一个经典算法(原论文名称为Classification of Handprinted Chinese Characters Using Non-linear Normalization and Correlation Methods)。作者的思路是希望每一行,每一列的背景区域都可以平均分布。

    为此,他首先为每个像素在x,y方向分别定义了个概率密度函数:以及。这两个函数的计算方法是:

    如果(x,y)是一个属于字符区域的像素,那么都取一个极小值(在我们的实现中,这个值是0.001f,调整这个参数可以引起归一化后笔画的粗细变化)。

    如果(x,y)是背景区域像素,那么:

    其中分别是当前像素所处x方向背景像素的run-length和y方向的run-length。有了这两个密度函数,定义:

    这里px和py就是归一化后的投影直方图了,为了在归一化后的图像中让px和py平均分布,引入两个函数hx,hy:

    通过前向映射采样即可实现归一化操作:

    注意这里与前两个算法的不同之处,前向映射是将当前图像的某个像素映射到归一化的图像中。而反向映射则是将归一化的图像中的某个像素位置映射到原图像中。

    非线性归一化的实现对应:

    1. void forward_nonlinear_1d(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    2.                           CHARECT_t* region,  
    3.                           unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,  
    4.                           int ratio_preserve_func);  
    [cpp] view plain copy
     
     print?
    1. void forward_nonlinear_1d(unsigned char* src, int src_wid, int src_hei, int src_widstep,  
    2.                           CHARECT_t* region,  
    3.                           unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,  
    4.                           int ratio_preserve_func);  

    参考结果

    最后看下各个算法的结果:


    图2,参考结果。从左到右依次:1. 原始扣取的图像通过OpenCV的resize函数缩放。2. 线性归一化。3.基于矩的归一化。4.先倾斜校正再基于矩的归一化。5.非线性归一化。

    [原创文章,转载请注明出处:http://blog.csdn.net/unilvision/article/details/8624606]

  • 相关阅读:
    Javascript 公共代码(可重用)
    ExtJs之Ext.data.Store
    delete exists
    c++ builder adoquery sql语句的动态增加
    C++ XML解析之TinyXML篇
    oracle数据类型varchar2和varchar的区别
    adoquery查询结果如何赋给一个变量(delphi和c++ builder)
    没有安装 BCB 的机器上运行会提示 找不到 库之类
    select union 查询出来的结果,如何按指定顺序输出
    oracle 已有 表 增加 列
  • 原文地址:https://www.cnblogs.com/lanye/p/5363529.html
Copyright © 2020-2023  润新知