前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DIY自动分类“错题集”:一种基于视觉词汇的文本分类法

DIY自动分类“错题集”:一种基于视觉词汇的文本分类法

作者头像
量子位
发布2018-03-26 17:44:29
1.9K1
发布2018-03-26 17:44:29
举报
文章被收录于专栏:量子位
作者:曹阳敏 万达网络科技 | 资深研发经理 量子位 已获授权编辑发布 转载请联系原作者

一年多以前我脑子一热,想做一款移动应用:一款给学生朋友用的“错题集”应用,可以将错题拍照,记录图像的同时,还能自动分类。比如拍个题目,应用会把它自动分类为”物理/力学/曲线运动”。

当然,这个项目其实不靠谱,市场上已经有太多“搜题”类应用了。但过程很有趣,导致我过了一年多,清理磁盘垃圾时,还舍不得删掉这个项目的“成果”,所以干脆回收利用一下,写篇文章圈圈粉。

源码地址:

https://github.com/caoym/odr

这个项目,核心要解决的问题就是文本分类。所以最初想到的方案是先 OCR 图片转文本,然后分词,再计算 tf-idf,最后用 SVM 分类。但这个方案的问题是:开源 OCR 普遍需要自己训练,且需要做大量的优化、调校和训练,才能在中文识别上有不错的效果,加上图像上还会有公式、几何图形,这些特征也会决定分类,这又提高了对 OCR 的要求。

所以我最终选择的方案是,不使用 OCR,而是直接从图像中寻找有区分性的、鲁棒的特征,作为视觉词汇。之后再通过传统文本分类的方法,训练分类器。

下面将展示整个训练过程,训练的样本来自《2016 B版 5年高考3年模拟:高考理数》,并手工标注了14个分类,每个分类下约50个样本,每个样本为一个题目, 图像为手机拍摄。

样本数据下载地址:

https://github.com/caoym/odr

本文中大部分算法库来自numpy、scipy、opencv、skimage、sklearn。

1. 预处理

为了获取到稳定的特征,我们需要对图像进行预处理,包括调整图像大小,将图像缩放到合适尺寸;旋转图像,或者说调整成水平;二值化,去除色彩信息,产生黑白图像。

1.1. 调整图像大小

调整的目的是为了让图像中文字的尺寸保持大致相同的像素尺寸。这里做了一个简单假设,即:图像基本是一段完整的文本,比如一个段落,或者一页文档,那么不同的图像中,每行文本的字数相差不会很大。

这样我就可以从我所了解的、少得可怜的图像工具库里找到一个工具了:直线拟合。即通过拟合的直线(线段)长度与图像宽度的比例,调整图像的大小。下图为两张不同尺寸图像,经过多次拟合+调整大小后的结果,其中红色算法检查到的直线(线段)。

下面是使用 opencv 直线拟合的代码:

1.2. 图像二值化

二值算法选用skimage.filters.threshold_adaptive(局部自适应阀值的二值化), 试下来针对这种场景,这个算法效果最好,其他算法可以去scikit-image文档了解。下图为全局阀值和局部自适应阀值的效果对比:

文档地址:

http://scikit-image.org/docs/dev/api/skimage.filters.html?highlight=threshold_adaptive#skimage.filters.threshold_adaptive

相关代码如下:

1.3. 旋转图像

从第一步获取到的直线,可以计算出图像的倾斜角度,针对只是轻微倾斜的图像,可以反向旋转进行调整。由于可能存在干扰线条,所以这里取所有直线倾斜角度的中值比平均值更合适。下图展示了图像旋转跳转前后的效果:

相关代码如下:

2. 提取特征

这里的思路是,首先通过形态学处理,可以分割出文本行(的图像),再从文本行中分割出词汇(的图像),然后从”词汇”中提取特征。但这里的需要克服的困难是:

  • 很多汉字分左右部,容易被错分,比如你好, 可能被分割成以4块图像:亻、尔、女、子。
  • 独立的“字”并不适合于文本分类,还需能学习出词汇。

针对以上问题的解决方案是:

  • 将小的图像块进行组合,组合后的新图像块和原来的小块图像一起作为原始图像的特征,如你好将得到10个特征:亻、你、你女,你好,尔、尔女、尔好、女、好、子。
  • 得益于上面的方案,词汇信息也被保留了下来,所以第二个问题也就解决了,同时增加了算法的鲁棒性。

下面将介绍具体实现。

2.1. 提取文本行

由于预处理过程中已经将样本的图像尺寸基本调整一致,所以可以比较容易的利用形态学的处理方法,分割出文本行。过程如下:

下图展示了每一步的变化:

接下来可以利用scipy库中的measurements.label方法,标记出不同的的区域,下图展示了标注后的效果,不同区域以不同的灰度表示。

相关代码如下:

接下来根据标记的区域,可从图像中裁剪出每行的数据,如下图:

相关代码如下:

2.2. 提取特征(视觉词汇)

裁剪出单行文本图像后,我们可以将图像中各列的像素的值各自累加,得到一个一纬数组,此数组中的每个局部最小值所在的位置,即为文字间的空隙。如下图所示,其中蓝色线为像素值的累加值,绿色线为其通过高斯滤波平滑后的效果,红色线为最终检测到的分割点。

详细过程见下面代码:

将单行的图像按上述方法获取的分割点进行裁剪,裁剪出单个字符,然后再把相邻的单个字符进行组合,得到最终的特征数据。组合相邻字符是为了使特征中保留词汇信息,同时增加鲁棒性。下图为最终获得的特征信息:

本文中使用的所有样本,最终能提取出约30万个特征。

2.3. 选择特征描述子

选择合适的特征描述子通常需要直觉+运气+不停的尝试(好吧我承认这里没有什么经验可分享),经过几次尝试,最终选中了HOG(方向梯度直方图)描述子。HOG 最让人熟悉的应用领域应该是行人检测了,它很适合描述钢性物体的边缘特征(方向),而印刷字体首先是刚性的,其次其关键信息都包含在边缘的方向上,所以理论上也适合用 HOG 描述。下图为文字图像及其 HOG 描述子的可视化:

更多关于HOG的介绍请点击:

http://scikit-image.org/docs/dev/auto_examples/features_detection/plot_hog.html#sphx-glr-auto-examples-features-detection-plot-hog-py

代码如下:

3. 训练词汇分类器

对词汇进行人工标注工作量太大,所以最好能做到自动分类。我的做法是先聚类,再基于聚类的结果训练分类器。

但有个问题,主流的聚类算法中,除了 K-Means 外,其他都不适合处理大量样本(目前有30万+样本),但 K-Means 在这个场景上聚类效果不佳,高频但不相关的词汇容易被聚成一类,而 DBSCAN 效果很好,但样本数一多,所需时间几何级增长(在我的机器上,超过两万个样本就需要耗费数个小时)。

下图来自sklearn 文档,对各聚类算法做了比较:

为解决这一问题,我的做法是:

1. 先对每类样本下的词汇用 DBSCAN 聚类(约1万个词汇样本),得到一级分类。

2. 聚类后,计算每个一级分类的中心,然后以所有中心为样本再用DBSCAN聚类,得到二级分类。完成后,原一级分类中心的新分类,即代表其原一级分类下所有元素的分类。

聚类的过程为,使用前面提取的HOG特征,先 PCA 降纬,再 DBSCAN 聚类。这里注意,计算二级分类时,PCA应使用全局样本计算。

分类器使用SGDClassifier,原因是其支持分批计算,不至于导致内存不足。

本文中使用的样本,最终得到3000+词汇类型。下图为分类效果,其中每一行为一个分类:

4. 训练文本分类器

有了词汇分类器,我们终于可以识别出每个文本样本上所包含的词汇了(事实上前面步骤的中间过程也能得到每个样本的词汇信息),于是我们可以给每个样本计算一个词袋模型(即用每个词出现的次数表示一篇文本),再通过池袋模型计算TF-IDF模型(即用每个词的 TF*IDF 值表示一篇文本),并最终训练 SVM 分类器。

下面展示了此过程的主要代码:

执行结果如下:

测试集上正确率81%,召回率 78%。个别分类正确率较低,可能是因为样本数太少,另外训练过程大多使用默认参数,若进行细致调校,应该还有提高空间。

5. 结束

此项目完整代码及样本数据均可下载,地址为:

https://github.com/caoym/odr

任何想在实际项目中使用此方法的朋友请注意,以上方法目前只在一个样本库中测试过,在其他样本库中表现如何还不知道,但愿没把你带坑里。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 量子位 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 预处理
    • 1.1. 调整图像大小
      • 1.2. 图像二值化
        • 1.3. 旋转图像
        • 2. 提取特征
          • 2.1. 提取文本行
            • 2.2. 提取特征(视觉词汇)
              • 2.3. 选择特征描述子
              • 3. 训练词汇分类器
              • 4. 训练文本分类器
              • 5. 结束
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档