背景

本文,主要介绍我之前在学校时候,研究的一些跟手写数字识别相关的技术心得,主要涉及:数字图像处理、特征提取、神经网络等等相关的一些技术。。

虽然很多用到的还是网上现有的比较成熟的算法,但是在这些基础上,我还是有做了不少算法上的改进的。。

并且为了写这个项目,我当时还特地写了一整套神经网络库,从图像处理开始到最后的识别过程,没有使用任何第三方库,都是从0还是写起
也没有用到opencv啊什么的。

上层ui当时用的qt,虽然当时也算是为了跨平台,但那个时候毕竟还是学生,代码经验欠缺,因此我的基础库对跨平台处理的并不是很好。。

那个基础库,我稍微简单说下,那是我的第一个开发库,是一个类似boost的c++模板库,里面用到了很多c++的模板元编程的特性,但是现在已经对c++无爱了,所以早已废弃不用了。

不过也就是这个库的开发,很大程度上影响了我之后的编码风格,也是至此之后,我重点转向了对c的开发上。。

这套识别系统,仅仅是我当时为了学习神经网络,拿来练手用的,没法跟那些成熟的相比,识别率不是很高哈,只能给大家用来参考学习了。

简介

本文在基本BP算法和数字图像与处理的基础上,通过改进网络、图像处理算法,并结合实践来探索如何实现具有高鲁棒的、高精度的、高效率的脱机数字识别。

在这我主要研究脱机单体数字识别,其主要步骤为:

overview_1

数字样本的采集

主要采用5行10列的数字样本规格。采集方式是通过扫描样本卡片来获取图像,也尽量避免样本了的失真,如图:

overview_2

图像二值化

主要采用全局阈值分割法和自适应的局部阈值分割法,来实现在不同亮度背景下的自适应分割,并对结果进行比对。

数字提取

目前主要考虑聚类法、矩阵式分割法、连通区域标记法,并比较其优劣,选取效果最好的一种算法。

图像归一化

主要采用双线性内插和最邻近内插来实现放大,为了减少图像在收缩时带来的失真,目前打算采用求平均法来实现。

特征提取

主要采用逐像素提取法,PCA主成分提取两种方法来实现。

样本学习

主要采用基于BP算法(反向传播学习算法)的神经网络进行识别,并对BP进行一定的改进和优化,来改进训练效果并且适当的提高训练速率。

目前,针对BP的改进算法,主要采添加动量项和自适应步长法。

而对于BP算法,其主要步骤为:

    前向计算=〉反向计算=〉权值修正=〉循环迭代

为了进一步改进网络,实现高精度、高效率的识别,打算考虑采用多网络集成法,来进行优化。
主要针对不同权值、隐层数的基本BP网络进行集成。通过每个网络分类的结果进行加权输出,来达到有效的分类。

阈值分割

阈值分割法是一种基于区域的图像分割技术,其基本原理是:通过设定不同的特征阈值,把图像像素点分为若干类。

在本文中,我们主要处理针对两类的分割,令阈值为T,图像像素对应的灰度级为f(x, y),那么经阈值分割后的图像g(x, y)定义为:

split_1

因此,标记为1的像素对应于对象,也就是前景,而标记为0的对象对应于背景,也就是我们通常所说的图像二值化。

利用阈值分割进行图像二值化的主要难题就是阈值的选取,事实证明,阈值的选择的恰当与否对分割的效果起着决定性的作用。

常用的阈值分割方法有以下三种:

整体阈值法

利用整幅图像的信息对图像求出最优阈值, 在二值化分割过程中只使用这一个固定阈值,因此计算量小,但对于亮度条件不好的图像的分割效果较差。

局部阈值法

它是把原始图像分为几个小的子图像,再对每个子图像求出最佳阈值。因此效果较好,但开销较大,且局部大小不太好确定,太小容易失真,太大效果不显著。

动态阈值法

它的阈值求取方法不仅取决于该像素的灰度值及其领域内像素灰度值, 而且还与像素的坐标位置有关, 这种方法灵活性大, 但是复杂度高, 计算量和时间开销都比较大。

而冈萨雷斯写的那本书数字图像处理里面,给出了一种最小误差阈值,通过利用共轭梯度法对灰度直方图进行双峰的高斯密度曲线进行拟合,求取最佳阈值,效果相当好,但是计算太大,而且对于双峰不显著的图像比较难处理,还需进行附加的单峰检测,并进行插值处理,由于过于复杂且实现也相当困难。

split_2

而本文采用具有自适应性的OTSU局部阈值法来分割图像,并对OTSU和局部阈值法进行了改进,不仅提高了性能而且改善了分割效果,对于亮度不均匀的图像也能实现较好的分割。

最大类间方差法(OTSU)

由Otsu于1978年提出的最大类间方差法以其计算简单、稳定有效,一直广为使用。其主要思想就是选取阈值使其类内方差最小化或类间方差最大化。Otsu算法不仅计算简单,而且能够应用于多阈值确定,因此可以说是一种相当好的阈值选取方法。
我们通常采用最大化类间方差,来实现阈值分割,其类间方差定义为:

otsu_1

其中

|| u || 图像中总的灰度均值 ||
|| u1 || 图像中小于阈值T的像素灰度均值 ||
|| u2 || 图像中大于阈值T的像素灰度均值 ||
|| n1 || 图像中小于阈值T的像素数 ||
|| n2 || 图像中大于阈值T的像素数 ||

因此,只需通过遍历256个灰度级,寻找使其类间方差最大的那个灰度值就是最佳阈值T。

OTSU的实现与改进

然而如果每次遍历都需要重新计算阈值两边的均值与像素数的话计算量是相当大的,如果能够在下次遍历时利用上次计算的结果,那么计算量可以大大减少。
假设灰度直方图为,图像总均值为,图像总像素数为,那么其递推方式如下:

otsu_2

为了进一步简化计算,我们可以通过用otsu_3来替换,得到

otsu_4

由于n在递归中不变可以省略,因此可以改为

otsu_5

由于本文是针对字符图像的分割,由于字符的笔画通常较细,通常只占图像的1/4都不到,因此可以适当的调整阈值,以实现较好的分割效果,改进后的阈值为

otsu_6

局部阈值的实现与改进

然而在实际图像中, 由于噪声或其他干扰等因素的影响,OTSU阈值分割并不能使图像分割得到满意的结果, 往往会产生严重的分割错误。这是因为图像的灰度直方图分布不一定
出现明显的峰和谷, 像素灰度值仅仅反映了像素灰度级的幅值大小, 并没有反映出像素与邻域的空间相关信息。

通过具体的实验发现:

当图像亮度分布不均匀时,往往无法得到好的分割效果,通常会出现大块的黑块,或者过渡分割而丢失信息的情况。

因此,可以通过对图像进行分块,针对每一小块进行OTSU分割,可以减少这些情况的发生,但是这又会出现不希望的“棋盘”效果,为了避免这种情况的发生,可以采用如下改进的局部阈值算法:

遍历图像中每一像素,在该像素的邻域内进行灰度统计,计算OTSU阈值,并仅对该点进行阈值分割。

这样就能在较好的分割效果下实现像素平滑过渡,避免了“棋盘”效应,由于在当像素移动时,只有一行或一列改变,所以可以在每步移动中,以新数据更新前一个位置得到的直方图,从而避免了每次重新计算整个直方图,大大减少了计算量,使其在一个可接受的范围内。

为了防止部分区域受到噪声干扰而产生的黑块现象,可以在进行局部阈值处理前,进行三阶的平滑处理,效果相当显著。

结果

原图

split_3

经全局阈值处理后的图象

split_4

经改进的局部阈值处理后的图像

split_5

总结

由上图可见,经改进的局部阈值处理后的图像的效果还是相当明显的,可是还是有些不足之处。。

就是处理后的图像笔画较粗,容易填掉数字中的空洞,尤其是4,6,8,9这些含有小孔的数字,这些都有待进一步改进。

后续,我还会总结下:倾斜矫正、数字提取、特征提取、神经网络相关的一些心得和改进算法。。

最后,再贴两张hnr项目,界面截图哈。。

before
after


TBOOX项目主页
原文出处:http://tboox.org/cn/2016/07/28/hnr-split-image/


waruqi
195 声望15 粉丝

专注于c跨平台开发解决方案