当前位置: 代码迷 >> 综合 >> 【AI实战】手把手教你深度学习文字识别(文字检测篇:基于MSER, CTPN, SegLink, EAST等方法)
  详细解决方案

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

热度:41   发布时间:2023-12-16 18:36:57.0

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

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

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

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

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

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

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

通过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):continueregion.append(box)# 绘制轮廓
for box in region:cv2.drawContours(img, [box], 0, (0, 255, 0), 2)cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

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

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

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

 

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

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

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

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

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

检测效果如下图:

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

核心代码如下:

# 读取图片
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, w, h = cv2.boundingRect(c)keep.append([x, y, x + w, y + h])cv2.rectangle(vis, (x, y), (x + w, y + h), (255, 255, 0), 1)
cv2.imshow("hulls", vis)

从上图可以看出,检测框有很多是重叠的,大框里面有小框,框与框之间有交叉?