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

67640f67f50d746ca4b3acbf4cf132cb0bd.jpg

文字检测是文字识别过程中的一个非常重要的环节,文字检测的主要目标是将图片中的文字区域位置检测出来,以便于进行后面的文字识别,只有找到了文本所在区域,才能对其内容进行识别。

文字检测的场景主要分为两种,一种是简单场景,另一种是复杂场景。其中,简单场景的文字检测较为简单,例如像书本扫描、屏幕截图、或者清晰度高、规整的照片等;而复杂场景,主要是指自然场景,情况比较复杂,例如像街边的广告牌、产品包装盒、设备上的说明、商标等等,存在着背景复杂、光线忽明忽暗、角度倾斜、扭曲变形、清晰度不足等各种情况,文字检测的难度更大。如下图:

23f855c482ae1bc2dcf1422db388ca6c90d.jpg

本文将介绍简单场景、复杂场景中常用的文字检测方法,包括形态学操作、MSER+NMS、CTPN、SegLink、EAST等方法,并主要以ICDAR场景文字图片数据集介绍如何使用这些方法,如下图:

07aa9880a855058c9cafb648a78b5930a37.jpg

1、简单场景:形态学操作法

通过利用计算机视觉中的图像形态学操作,包括膨胀、腐蚀基本操作,即可实现简单场景的文字检测,例如检测屏幕截图中的文字区域位置,如下图:

e85932d7bd8013d4a57e69c8a7ff8df49d2.jpg

其中,“膨胀”就是对图像中的高亮部分进行扩张,让白色区域变多;“腐蚀”就是图像中的高亮部分被蚕食,让黑色区域变多。通过膨胀、腐蚀的一系列操作,可将文字区域的轮廓突出,并消除掉一些边框线条,再通过查找轮廓的方法计算出文字区域的位置出来。主要的步骤如下:

  • 读取图片,并转为灰度图
  • 图片二值化,或先降噪后再二值化,以便简化处理
  • 膨胀、腐蚀操作,突出轮廓、消除边框线条
  • 查找轮廓,去除不符合文字特点的边框
  • 返回文字检测的边框结果

通过OpenCV,便能轻松实现以上过程,核心代码如下:

# -*- coding: utf-8 -*-

import cv2
import numpy as np

# 读取图片
imagePath = '/data/download/test1.jpg'
img = cv2.imread(imagePath)

# 转化成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 利用Sobel边缘检测生成二值图
sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize=3)
# 二值化
ret, binary = cv2.threshold(sobel, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)

# 膨胀、腐蚀
element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 9))
element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (24, 6))

# 膨胀一次,让轮廓突出
dilation = cv2.dilate(binary, element2, iterations=1)

# 腐蚀一次,去掉细节
erosion = cv2.erode(dilation, element1, iterations=1)

# 再次膨胀,让轮廓明显一些
dilation2 = cv2.dilate(erosion, element2, iterations=2)

#  查找轮廓和筛选文字区域
region = []
contours, hierarchy = cv2.findContours(dilation2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
    cnt = contours[i]

    # 计算轮廓面积,并筛选掉面积小的
    area = cv2.contourArea(cnt)
    if (area < 1000):
        continue

    # 找到最小的矩形
    rect = cv2.minAreaRect(cnt)
    print ("rect is: ")
    print (rect)

    # box是四个点的坐标
    box = cv2.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.3):
        continue

    region.append(box)

# 绘制轮廓
for box in region:
    cv2.drawContours(img, [box], 0, (0, 255, 0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

该图像处理过程如下图所示:

edc5719933aeb5a58c17ecbac12ed7c461b.jpg

可以看到最终成功将图像中的文字区域检测出来了。

这种方法的特点是计算简单、处理起来非常快,但在文字检测中的应用场景非常有限,例如如果图片是拍照的,光线有明有暗或者角度有倾斜、纸张变形等,则该方法需要不断重新调整才能检测,而且效果也不会很好,如下图。例如上面介绍的代码是针对白底黑字的检测,如果是深色底白色字则需要重新调整代码,如果有需要,可再私信我交流

00559dd34d760be212c5eaffe69f6d61dca.jpg

1ddae807a8a05ae719d93aaeca50a7c4ff3.jpg

 

2、简单场景:MSER+NMS检测法

MSER(Maximally Stable Extremal Regions,最大稳定极值区域)是一个较为流行的文字检测传统方法(相对于基于深度学习的AI文字检测而言),在传统OCR中应用较广,在某些场景下,又快又准。

MSER算法是在2002提出来的,主要是基于分水岭的思想进行检测。分水岭算法思想来源于地形学,将图像当作自然地貌,图像中每一个像素的灰度值表示该点的海拔高度,每一个局部极小值及区域称为集水盆地,两个集水盆地之间的边界则为分水岭,如下图:

e3c42f868d8fe8a99d5639dce79f1ce8481.jpg

MSER的处理过程是这样的,对一幅灰度图像取不同的阈值进行二值化处理,阈值从0至255递增,这个递增的过程就好比是一片土地上的水面不断上升,随着水位的不断上升,一些较低的区域就会逐渐被淹没,从天空鸟瞰,大地变为陆地、水域两部分,并且水域部分在不断扩大。在这个“漫水”的过程中,图像中的某些连通区域变化很小,甚至没有变化,则该区域就被称为最大稳定极值区域。在一幅有文字的图像上,文字区域由于颜色(灰度值)是一致的,因此在水平面(阈值)持续增长的过程中,一开始不会被“淹没”,直到阈值增加到文字本身的灰度值时才会被“淹没”。该算法可以用来粗略地定位出图像中的文字区域位置。

听起来这个处理过程似乎非常复杂,好在OpenCV中已内置了MSER的算法,可以直接调用,大大简化了处理过程。

检测效果如下图:

33d6043eb346b1f2661097b02e4fdd6af2d.jpg

检测后的结果是存在各种不规则的检测框形状,通过对这些框的坐标作重新处理,变成一个个的矩形框。如下图:

736e438147ef0d45234d94ac1974d46472d.jpg

核心代码如下:

# 读取图片
imagePath = '/data/download/test2.jpg'
img = cv2.imread(imagePath)

# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()
orig = img.copy()

# 调用 MSER 算法
mser = cv2.MSER_create()
regions, _ = mser.detectRegions(gray)  # 获取文本区域
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]  # 绘制文本区域
cv2.polylines(img, hulls, 1, (0, 255, 0))
cv2.imshow('img', img)

# 将不规则检测框处理成矩形框
keep = []
for c in hulls:
    x, y
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值