https://blog.csdn.net/huobanjishijian/article/details/63685503

前面我们已经学了一些OpenCV中基本的图片处理的知识,可以拿来做一些小应用。比如怎样从一张图片中,把文字圈出来。这一步骤对OCR(Optical Character Recognition)非常有用,因为一般的OCR引擎只是拿来识别文字,并没有对图片做预处理,因此精度可能会收到图片质量影响。

当然,我们这里只是粗略的查找文字区域,并没有进一步地处理图片。而且对背景复杂,或者文字旋转角度过于倾斜的情况也无法自适应,因此只能给大家做参考。若要实用到项目中,还有很多工作要做。


效果图

比如我们有下面的一篇文章的截图,想把其中的文字区域全部找出来。


当然这里的截图只有文字和白花花的背景,效果会非常好。绿色的的矩形框的是我们根据检测到的文字区域,手动画出来的。


原理

那么我们是怎么做到检测到区域的呢?

首先,我们会注意到,文字区域和其他的图片背景很不一样。我们用膨胀处理图片,让文字变成一块块大区域,然后识别整块的轮廓,用矩形去框住这个轮廓。

这个程序分三个子函数,detect(检测),preprocess(图片预处理),findTextRegion(查找和筛选文字区域)。即main函数调用detect函数去实际完成文字区域检测。detect函数又分成preprocess和findTextRegion两个步骤来做。

见下面的序列图,可能会清晰点。

mainmaindetectdetectpreprocesspreprocessfindTextRegionfindTextRegion检测文本区域返回检测到的文本矩形Sobel,二值化,膨胀和腐蚀Morphology方法预处理图片返回预处理后的图片轮廓检测,去掉面积小的,过长的查找和筛选文字区域返回区域box的坐标

1. Detect

先来看main函数和Detect函数

def detect(img):
# 1. 转化成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 2. 形态学变换的预处理,得到可以查找矩形的图片
dilation = preprocess(gray) # 3. 查找和筛选文字区域
region = findTextRegion(dilation) # 4. 用绿线画出这些找到的轮廓
for box in region:
cv2.drawContours(img, [box], 0, (0, 255, 0), 2) cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.imshow("img", img) # 带轮廓的图片
cv2.imwrite("contours.png", img) cv2.waitKey(0)
cv2.destroyAllWindows() if __name__ == '__main__':
# 读取文件
imagePath = sys.argv[1]
img = cv2.imread(imagePath)
detect(img)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2. Preprocess

利用数学形态学(Morphology)进行预处理。

这个过程很重要,是文字区域检测效果好坏的核心代码,尤其是一下几个参数:

  • 膨胀的核函数大小,这里用了 30 x 9,可以调节
  • 腐蚀的核函数大小,这里用了 24 x 6,可以调节
def preprocess(gray):
# 1. Sobel算子,x方向求梯度
sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize = 3)
# 2. 二值化
ret, binary = cv2.threshold(sobel, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY) # 3. 膨胀和腐蚀操作的核函数
element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 9))
element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (24, 6)) # 4. 膨胀一次,让轮廓突出
dilation = cv2.dilate(binary, element2, iterations = 1) # 5. 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
erosion = cv2.erode(dilation, element1, iterations = 1) # 6. 再次膨胀,让轮廓明显一些
dilation2 = cv2.dilate(erosion, element2, iterations = 3) # 7. 存储中间图片
cv2.imwrite("binary.png", binary)
cv2.imwrite("dilation.png", dilation)
cv2.imwrite("erosion.png", erosion)
cv2.imwrite("dilation2.png", dilation2) return dilation2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

3. findTextRegion

def findTextRegion(img):
region = [] # 1. 查找轮廓
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 2. 筛选那些面积小的
for i in range(len(contours)):
cnt = contours[i]
# 计算该轮廓的面积
area = cv2.contourArea(cnt) # 面积小的都筛选掉
if(area < 1000):
continue # 轮廓近似,作用很小
epsilon = 0.001 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True) # 找到最小的矩形,该矩形可能有方向
rect = cv2.minAreaRect(cnt)
print "rect is: "
print rect # box是四个点的坐标
box = cv2.cv.BoxPoints(rect)
box = np.int0(box) # 计算高和宽
height = abs(box[0][1] - box[2][1])
width = abs(box[0][0] - box[2][0]) # 筛选那些太细的矩形,留下扁的
if(height > width * 1.2):
continue region.append(box) return region
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

完整代码

加上头文件,把几个函数合并以后,贴在这里。注意开头要写明用utf8编码,不然中文注释可能不会被系统识别。而且Python没有花括号来控制流程,所以对看不见的Tab缩进很敏感,写代码的时候要规范。

直接在终端里敲下面的命令,既可以运行

python textDetection.py ./pic/1.png

代码:textDetection.py

# coding:utf8

import sys

import cv2
import numpy as np def preprocess(gray):
# 1. Sobel算子,x方向求梯度
sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize = 3)
# 2. 二值化
ret, binary = cv2.threshold(sobel, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY) # 3. 膨胀和腐蚀操作的核函数
element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 9))
element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (24, 6)) # 4. 膨胀一次,让轮廓突出
dilation = cv2.dilate(binary, element2, iterations = 1) # 5. 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
erosion = cv2.erode(dilation, element1, iterations = 1) # 6. 再次膨胀,让轮廓明显一些
dilation2 = cv2.dilate(erosion, element2, iterations = 3) # 7. 存储中间图片
cv2.imwrite("binary.png", binary)
cv2.imwrite("dilation.png", dilation)
cv2.imwrite("erosion.png", erosion)
cv2.imwrite("dilation2.png", dilation2) return dilation2 def findTextRegion(img):
region = [] # 1. 查找轮廓
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 2. 筛选那些面积小的
for i in range(len(contours)):
cnt = contours[i]
# 计算该轮廓的面积
area = cv2.contourArea(cnt) # 面积小的都筛选掉
if(area < 1000):
continue # 轮廓近似,作用很小
epsilon = 0.001 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True) # 找到最小的矩形,该矩形可能有方向
rect = cv2.minAreaRect(cnt)
print "rect is: "
print rect # box是四个点的坐标
box = cv2.cv.BoxPoints(rect)
box = np.int0(box) # 计算高和宽
height = abs(box[0][1] - box[2][1])
width = abs(box[0][0] - box[2][0]) # 筛选那些太细的矩形,留下扁的
if(height > width * 1.2):
continue region.append(box) return region def detect(img):
# 1. 转化成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 2. 形态学变换的预处理,得到可以查找矩形的图片
dilation = preprocess(gray) # 3. 查找和筛选文字区域
region = findTextRegion(dilation) # 4. 用绿线画出这些找到的轮廓
for box in region:
cv2.drawContours(img, [box], 0, (0, 255, 0), 2) cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.imshow("img", img) # 带轮廓的图片
cv2.imwrite("contours.png", img) cv2.waitKey(0)
cv2.destroyAllWindows() if __name__ == '__main__':
# 读取文件
imagePath = sys.argv[1]
img = cv2.imread(imagePath)
detect(img)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 10

OpenCV入门笔记(七) 文字区域的提取的更多相关文章

  1. 【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

    今天我们来看一下如何访问图像的像素,以及如何改变图像的亮度与对比度. 在之前我们先来看一下图像矩阵数据的排列方式.我们以一个简单的矩阵来说明: 对单通道图像排列如下: 对于双通道图像排列如下: 那么对 ...

  2. OpenCV入门:(七:OpenCV取随机数以及显示文字)

    1.随机颜色 OpenCV中自带了取随机数的方法,使用步骤: RNG rng( 0xFFFFFFFF ); 随机数 = rng.uniform( 下限,上限 ); 2.显示文字 , , bool bo ...

  3. opencv入门笔记

    一.图片基本操作 1.1 显示图片 #include <opencv2/opencv.hpp> //头文件 using namespace cv; //包含cv命名空间 void main ...

  4. OpenCV入门笔记(二) 图片的文件操作

    以下介绍一下重要的几个,设计基本 图片处理 的函数,依次来了解OpenCV的入门知识.具体的具体使用方法还是以官方的API[Official Tutorials][Python-OpenCV]为准. ...

  5. OpenCV入门笔记(三) 图片处理

    OpenCV中提供了非常多处理图片的强大函数,能够对非常多格式的图片 加特效.有点实现Photoshop里的工具的感觉. 以下先介绍一些简单和常见的特效. 二值化(Image Threshold) 參 ...

  6. OpenCV入门笔记(一) Linux下的安装

    关于OpenCV,有中文的官方站点.里面翻译了官网的教程和API等.中文官方Tutorials见这里:[Tutorials] 一.Ubuntu下的安装 能够选择直接从库里安装,或者手动编译安装,请參考 ...

  7. opencv学习笔记(七)---图像金字塔

    图像金字塔指的是同一图像不同分辨率的子图的集合,有向下取样金字塔,向上取样金字塔,拉普拉斯金字塔....它是图像多尺度表达的一种,最主要的是用于图像的分割 向下取样金字塔指高分辨率图像向低分辨率图像的 ...

  8. OpenCV学习笔记七:opencv_nonfree模块

    一,简介: 顾名思义,这个模块不是free的.主要包含: 1,SIFT implementation. The class implements SIFT algorithm by D. Lowe. ...

  9. OpenCV入门学习笔记

    OpenCV入门学习笔记 参照OpenCV中文论坛相关文档(http://www.opencv.org.cn/) 一.简介 OpenCV(Open Source Computer Vision),开源 ...

随机推荐

  1. 虚拟主机是设置在httpd-vhosts.conf还是vhosts.conf还是httpd.conf

    https://blog.csdn.net/weisubao/article/details/43536723 解决方案:虚拟主机是设置在httpd-vhosts.conf还是vhosts.conf还 ...

  2. (转)spring计划任务,springMvc计划任务,Spring@Scheduled,spring定时任务

    一.计划任务实现类 1.用@Component注解标识计划任务类,这样spring可以自动扫描 2.在方法中使用注解标识要执行的方法:@Scheduled(cron="*/30 * * * ...

  3. Py中axis理解【转载】

    转载:https://blog.csdn.net/yaoqi_isee/article/details/77714570 1.理解 numpy当中axis的值表示的是这个多维数组维度的下标,比如有一个 ...

  4. JS快速入门

    字符串 模板字符串 需要特别注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果: var s = 'Test'; s[0] = 'X'; alert(s); ...

  5. github pages搭建网站(三)

    一.个人站点 访问 https://用户名.github.io 搭建步骤 (1)创建个人站点 ->新建仓库(注:仓库名必须是[用户名.github.io]) (2)在仓库下新建index.htm ...

  6. Kotlin 型变 + 星号投影(扯蛋)

    Kotlin中的型变: 1. in,顾名思义,就是只能作为传入参数的参数类型 2.out, ..............,就是只能作为返回类型参数的参数类型 星号投影: 我们引用官网的吧-- For ...

  7. cocos2d JS 错误异常抛出捕获和崩溃拦截

    Error对象 一旦代码解析或运行时发生错误,JavaScript引擎就会自动产生并抛出一个Error对象的实例,然后整个程序就中断在发生错误的地方. Error对象的实例有三个最基本的属性: nam ...

  8. (3)Python3笔记之变量与运算符

    一.变量 1). 命名规则: 1.  变量名不能使用系统关键字或保留关键字 2. 变量区分大小写 3. 变量命名由字母,数字,下划线组成但不能以数字开头 4. 不需要声明变量类型  是 a = 1  ...

  9. LeetCode12.整数转罗马数字

    给定一个整数,将其转为罗马数字.输入确保在 1 到 3999 的范围内. 示例 1: 输入: 3 输出: "III" 示例 2: 输入: 4 输出: "IV" ...

  10. Uva297 Quadtrees【递归建四分树】【例题6-11】

    白书 例题6-11 用四分树来表示一个黑白图像:最大的图为根,然后按照图中的方式编号,从左到右对应4个子结点.如果某子结点对应的区域全黑或者全白,则直接用一个黑结点或者白结点表示:如果既有黑又有白,则 ...