转自:https://www.cnblogs.com/skyfsm/p/8029668.html

要做文字识别,第一步要考虑的就是怎么将每一个字符从图片中切割下来,然后才可以送入我们设计好的模型进行字符识别。现在就以下面这张图片为例,说一说最一般的字符切割的步骤是哪些。

当然,我们实际上要识别的图片很可能没上面那张图片如此整洁,很可能是倾斜的,或者是带噪声的,又或者这张图片是用手机拍下来下来的,变得歪歪扭扭,所以需要进行图片预处理,把文本位置矫正,把噪声去除,然后才可以进行进一步的字符分割和文字识别。这些预处理的方法在我的前面几篇博客都有提到了,大家可以参考参考:
透视矫正
水平矫正

在预处理工作做好之后,我们就可以开始切割字符了。最普通的切割算法可以总结为以下几个步骤:

  1. 对图片进行水平投影,找到每一行的上界限和下界限,进行行切割
  2. 对切割出来的每一行,进行垂直投影,找到每一个字符的左右边界,进行单个字符的切割

一看只有两个步骤,好像不太难,马上编程实现看看效果。

首先是行切割。这里提到了水平投影的概念,估计有的读者没听过这个名词,我来解释一下吧。水平投影,就是对一张图片的每一行元素进行统计(就是往水平方向统计),然后我们根据这个统计结果画出统计结果图,进而确定每一行的起始点和结束点。下面提到的垂直投影也是类似的,只是它的投影方向是往下的,即统计每一列的元素个数。

根据上面的解释,我们可以写出一个用于水平投影和垂直投影的函数。

#define V_PROJECT 1  //垂直投影(vertical)
#define H_PROJECT 2  //水平投影(horizational)typedef struct
{int begin;int end;}char_range_t;//获取文本的投影以用于分割字符(垂直,水平),默认图片是白底黑色
int GetTextProjection(Mat &src, vector<int>& pos, int mode)
{if (mode == V_PROJECT){for (int i = 0; i < src.rows; i++){uchar* p = src.ptr<uchar>(i);for (int j = 0; j < src.cols; j++){if (p[j] == 0)  //是黑色像素{pos[j]++;}}}}else if (mode == H_PROJECT){for (int i = 0; i < src.cols; i++){for (int j = 0; j < src.rows; j++){if (src.at<uchar>(j, i) == 0){pos[j]++;}}}}return 0;
}

上面代码提到的vector pos就是用于存储垂直投影和水平投影的位置的,我们可以根据它来确定行的位置。我们先把水平投影画出来。

下面是画出水平(垂直)投影图的代码实现。

void draw_projection(vector<int>& pos, int mode)
{vector<int>::iterator max = std::max_element(std::begin(pos), std::end(pos)); //求最大值if (mode == H_PROJECT){int height = pos.size();int width = *max;Mat project = Mat::zeros(height, width, CV_8UC1);for (int i = 0; i < project.rows; i++){for (int j = 0; j < pos[i]; j++){project.at<uchar>(i, j) = 255;}}imshow("horizational projection", project);}else if (mode == V_PROJECT){int height = *max;int width = pos.size();Mat project = Mat::zeros(height, width, CV_8UC1);for (int i = 0; i < project.cols; i++){for (int j = project.rows - 1; j >= project.rows - pos[i]; j--){//std::cout << "j:" << j << "i:" << i << std::endl;project.at<uchar>(j, i) = 255;}}imshow("vertical projection", project);}waitKey();
}

水平投影图:

通过上面的水平投影图,我们很容易就能确定每一行文字的位置,确定的思路如下:我们可以以每个小山峰的起始结束点作为我们文本行的起始结束点,当然我们要对这些山峰做些约束,比如这些山峰的跨度不能太小。这样子我们就得到每一个文本行的位置,接着我们就根据这些位置将每个文本行切割下来用于接下来的单个字符的切割。

//获取每个分割字符的范围,min_thresh:波峰的最小幅度,min_range:两个波峰的最小间隔
int GetPeekRange(vector<int> &vertical_pos, vector<char_range_t> &peek_range, int min_thresh = 2, int min_range = 10)
{int begin = 0;int end = 0;for (int i = 0; i < vertical_pos.size(); i++){if (vertical_pos[i] > min_thresh && begin == 0){begin = i;}else if (vertical_pos[i] > min_thresh && begin != 0){continue;}else if (vertical_pos[i] < min_thresh && begin != 0){end = i;if (end - begin >= min_range){char_range_t tmp;tmp.begin = begin;tmp.end = end;peek_range.push_back(tmp);begin = 0;end = 0;}}else if (vertical_pos[i] < min_thresh || begin == 0){continue;}else{//printf("raise error!\n");}}return 0;
}

切割每一行,然后我们得到了一行文本,我们继续对这行文本进行垂直投影。

紧接着我们根据垂直投影求出来每个字符的边界值进行单个字符切割。方法与垂直投影的方法一样,只不过,因为字符排列得比较紧密,仅通过投影确定字符得到的结果往往不够准确的。不过先不管了,先切下来看看。

从上图看出,切割效果不太好,那多切割几行再看看。

效果确实不咋滴,那换成英文文档来测试这个切割算法。

比如切割这个英语文本图片

切割效果还是很不错的:

那为什么英语的切割效果很好,但中文效果一般呢?

分析其原因,这其实跟中文的字体复杂度有关的,中文的字符的笔画和形态都比英文的多,更重要的是英文字母都是绝大部分都是联通体,切割起来很简单,但是汉字多存在左右结构和上下结构,很容易造成过度切割,即把一个左右偏旁的汉字切成了两份,比如上面的“则”字。

针对行字符分割,左右偏旁的字难以分割的情况,我觉得可以做以下处理:

  1. 先用通用的分割方法切割字符,得到一堆候选的切割字符集合。
  2. 统计字符集合的大多数字符的尺寸,作为标准尺寸。
  3. 根据标准尺寸选出标准的字符,切割保存。并对切割保存好的字符原位置涂成白色
  4. 对剩下下来的图片进行腐蚀,让字体粘连。
  5. 用1中算法再次分割,得到完整字体集合。

因为以上的思路可能只适应于纯汉字文本,所以就不贴代码了。

最后贴几张分割字符的图吧,感觉分割效果不太让人满意,主要是汉字的分割确实很有难度,左右偏旁的字经常分割错误。

英文的切割还是比较简单的,毕竟英文字母基本都是联通体,而且没有像汉字那样的左右结构。

对于字体间隔比较宽的汉字文档,总的看来分割任务基本完成,但是左右结构的汉字依然难以正确分割。

最后看一下一些字体较小,字体间隔较窄的情况。这类情况确实分割效果大打折扣,因为每个字体粘连过于接近,字体的波谷很难确定下来,进而造成切割字符失败。

总结

汉字字符切割,看似简单,做起来其实很难做得很好,我也对此查阅了很多论文,发现其实很多论文也谈到了,汉字确实很那做到一个高正确率的分割,直至现在还没有一统江湖的解决方案。汉字切割的失败,就会直接导致了后面OCR识别的失败,这也是当前很多一些很厉害的OCR公司都没法把汉字做到100%识别的一个原因吧。所以这个问题就必须得到很好的解决。现在解决汉字切割失败(过切割,一个字被拆成两个)的较好方法是,在OCR识别中再把它修正。比如“刺”字被分为两部分了,那么我们就直接将这两个“字”送去识别,结果当然是得到一个置信度很低的一个反馈,那么我们就将这两个部分往他们身边最近的、而且没被成功识别的部分进行合并,再将这个合并后的字送进OCR识别,这样子我们就可以通过识别反馈来完成汉字的正确分割和识别了。既然一些基于图像处理的方法基本很难把汉字分割的效果做得很好,那深度学习呢?我先去试试,效果好的话再分享给大家。

文字识别(三)--文字定位与切割相关推荐

  1. python常用的OCR文字识别与图片定位方式

    python常用的OCR文字识别与图片定位方式 前言 统一版本 更换pip源 1. Python调用百度文字识别ocr的实现方式 1.1 使用PyCharm安装依赖 baidu-aip chardet ...

  2. c#批量文字识别,百度文字识别源码

    文章目录 批量文字识别演示 下载地址 重要源码 一.一键识别按钮 二.后台工作 三.报告进度,完成任务 四.鼠标截图 五.文字识别 总结 批量文字识别演示 下载地址 https://download. ...

  3. 【AI实战】手把手教你深度学习文字识别(文字检测篇:基于MSER, CTPN, SegLink, EAST等方法)

    附Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读书籍书单大全: 书单导航页(点击右侧 极客侠栈 即可打开个人博客):极客侠栈 ①[Java]学习之路吐血整理技术书 ...

  4. java怎么实现华为云文字识别,OCR文字识别服务快速入门教程

    [入门介绍]OCR服务快速入门汇总 1.[快速入门 01] 申请华为文字识别服务 现阶段,华为文字识别服务处于公测阶段,需要先申请公测,再申请开通服务,具体操作步骤如下: 步骤1       申请华为 ...

  5. python屏幕文字识别_Python文字截图识别OCR工具实例解析

    一.简介 你一定用过那种"OCR神器",可以把图片中的文字提取出来,极大的提高工作效率. 今天,我们就来做一款实时截图识别的小工具.顾名思义,运行程序时,可以实时把你截出来的图片中 ...

  6. 中的图片文字识别_文字识别 图片转文字【小程序】

    文字识别小程序在文章的底部 直接拉到文章底部就可使用 ↓↓↓↓↓↓ 大家在平时办公或者学习中经常会处理到图片转文字的问题,对于一些打字比较快的朋友来说并没有太大的问题,但是对于一些打字慢的人来说确实一 ...

  7. 文字识别_文字识别的应用

    是否有过这样的经历,在网上发现一篇好文,却没办法复制,怎么办?手动抄录吗,我想如果没有OCR,大部分人会这么做. OCR是一种图像处理技术,又叫文字识别,能够将图像中不可复制的文字转换成可编辑的文字形 ...

  8. OCR文字识别 少数民族文字识别 国外文字识别

    文字识别软件将图象制作成点阵信息保存于字库 ,可以识别扫描图片上的文字和 pdf文档上面的文字并且把这些文字转换为可编辑的文字. 维文OCR文字识别,维吾尔族有着独特的历史和悠久的文化,单就其文字来说 ...

  9. 【AI实战】手把手教你深度学习文字识别(文字检测篇:基于MSER, CTPN, SegLink, EAST等方法)...

    2019独角兽企业重金招聘Python工程师标准>>> 文字检测是文字识别过程中的一个非常重要的环节,文字检测的主要目标是将图片中的文字区域位置检测出来,以便于进行后面的文字识别,只 ...

  10. python 文字识别 tesseract_Python_文字识别引擎试用:tesseract-ocr

    tesseract-ocr是一 个OCR引擎,在1985年到1995年由HP实验室开发,后来由google开发并且开源,支持多平台,支持多达40种语言,其中包括中文,支持训练,tesseract-oc ...

最新文章

  1. vue-router 去掉#
  2. 数据结构之单链表尾插法创建-RearCreate
  3. Mybatis的增删改查操作(包含动态代理,动态SQL标签,缓存,#与$的使用传入多参数,获取自增id等基本操作)
  4. 关于私有变量,静态私有变量
  5. ON DUPLICATE KEY UPDATE 附带更新条件
  6. 第三次学JAVA再学不好就吃翔(part69)--System类
  7. 中科大开源镜像使用帮助列表
  8. NeHe OpenGL第四十六课:全屏反走样
  9. Java中多实现接口的一个好处
  10. mysql数据库原理
  11. 怎么用命令来查询自己的IP地址?
  12. IDL代码实现湖泊水体范围遥感提取
  13. 高并发实战之幂等处理
  14. 【openJDK系列3】java OOM 分析(mat工具的使用)
  15. Excel零基础入门(真对2021版Excel)
  16. DNA甲基化经CTCF和黏连蛋白复合体调节RNA可变剪切
  17. 智能药盒的设计与实现
  18. OTN / SONET / SDH
  19. It was possible to detect the usage of the deprecated TLSv1.0 and/or TLSv1.1 protocol on this system
  20. 百度地图行政区优化卡顿问题

热门文章

  1. InputService
  2. android 恢复出厂设置代码流程(Good!)
  3. Redis之允许远程访问
  4. 深度学习自学(三十六):ABCNet实时自适应贝塞尔曲线场景文字检测识别网络
  5. linux-清除登录系统成功记录的命令
  6. ES6中的React生命周期详解
  7. JAVA提示定义常量_如何在Java中定义常量(Constant)
  8. win10连接mysql服务器频繁断线_MySQL连接数过多导致服务无法正常运行
  9. 每日三道前端面试题--vue 第五弹
  10. 3h精通OpenCV(五)-透视变换