天天看点

计算机视觉 文本检测与文本识别 (一)

文本检测

  • ​​传统文本检测​​
  • ​​形态学:​​
  • ​​MSER+NMS​​
  • ​​深度学习文本检测分类​​
  • ​​基于候选框的文本检测​​
  • ​​基于分割的文本检测​​
  • ​​基于混合的文本检测​​

传统文本检测

当前应用中面对文本检测会遇到很多难点:

  • 文本图像的背景多样化,很多背景可能像素情况与文本结构相似
  • 文本的形状和方向多样化,可能图像中文本的摆放方向是倾斜的,横向的
  • 文本的颜色,字体多样化
  • 图像中受光照等环境因素影响

    由于这些检测上的难点,传统基于opencv通过形态学、MSER+NMS的方法无法实现实际场景的文本检测。因此对于复杂场景下文本检测大多基于深度学习算法实现。

形态学:

计算机视觉 文本检测与文本识别 (一)
import cv2
import numpy as np
 
# 读取图片
imagePath = 'data.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()      

MSER+NMS

MSER全称叫做最大稳定极值区域(MSER-Maximally Stable Extremal Regions),是一种检测图像中文本区域的传统图像算法,主要是基于分水岭的思想来对图像进行斑点(blob)区域检测。

MSER对灰度图像取阈值进行二值化处理,阈值从0到255依次进行递增,阈值的递增类似于分水岭算法中的水平面的上升,随着水平面的上升,有一些山谷和较矮的丘陵会被淹没,如果从天空往下看,则整个区域被分为陆地和水域两个部分,这类似于二值图像。图像中灰度值的不同就对应地势高低的不同,每个阈值都都会生成一个二值图。

NMS的基本思想是将所有框按得分进行排序,然后无条件保留其中得分最高的框,然后遍历其余框找到和当前最高分的框的重叠面积(IOU)大于一定阈值的框,并删除。然后继续这个过程,找另一个得分高的框,再删除和其IOU大于阈值的框,一直循环直到所有的框都被处理。

NMS流程:

  1. 根据候选框的类别分类概率(得分),按最高到最低将BBox排序,例如:A>B>C>D>E>F
  2. 先标记最大概率矩形框A是要保留下来的,即A的分数最高,则无条件保留
  3. 将B~E分别与A求重叠率IoU(两框的交并比),假设B、D与A的IoU大于设定的阈值,那么B和D可以认为是重复标记被剔除
  4. 继续从剩下的矩形框C、E、F中选择概率最大的C,标记为要无条件保留下来的框,然后分别计算C与E、F的重叠度,扔掉重叠度超过设定阈值的矩形框
  5. 就这样一直重复下去,直到剩下的矩形框没有了,得到所有要保留下来的矩形框
    计算机视觉 文本检测与文本识别 (一)
    MSER实现:
# 读取图片
imagePath = 'data.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)      

NMS实现:

# NMS 方法(Non Maximum Suppression,非极大值抑制)
def nms(boxes, overlapThresh):
    if len(boxes) == 0:
        return []
 
    if boxes.dtype.kind == "i":
        boxes = boxes.astype("float")
 
    pick = []
 
    # 取四个坐标数组
    x1 = boxes[:, 0]
    y1 = boxes[:, 1]
    x2 = boxes[:, 2]
    y2 = boxes[:, 3]
 
    # 计算面积数组
    area = (x2 - x1 + 1) * (y2 - y1 + 1)
 
    # 按得分排序(如没有置信度得分,可按坐标从小到大排序,如右下角坐标)
    idxs = np.argsort(y2)
 
    # 开始遍历,并删除重复的框
    while len(idxs) > 0:
        # 将最右下方的框放入pick数组
        last = len(idxs) - 1
        i = idxs[last]
        pick.append(i)
 
        # 找剩下的其余框中最大坐标和最小坐标
        xx1 = np.maximum(x1[i], x1[idxs[:last]])
        yy1 = np.maximum(y1[i], y1[idxs[:last]])
        xx2 = np.minimum(x2[i], x2[idxs[:last]])
        yy2 = np.minimum(y2[i], y2[idxs[:last]])
 
        # 计算重叠面积占对应框的比例,即 IoU
        w = np.maximum(0, xx2 - xx1 + 1)
        h = np.maximum(0, yy2 - yy1 + 1)
        overlap = (w * h) / area[idxs[:last]]
 
        # 如果 IoU 大于指定阈值,则删除
        idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlapThresh)[0])))
 
    return boxes[pick].astype("int")      

深度学习文本检测分类

目前基于在深度学习的文本检测方法主要包括如下:

  • 基于候选框的文本检测
  • 基于分割的文本检测
  • 基于两者方法混合文本检测

基于候选框的文本检测

思路:基于候选框文本检测,是利用像素特征提取,用若干个先验框产生一些对应的候选文本框。再经过非最大抑制(NMS)得到最终的预测结果

计算机视觉 文本检测与文本识别 (一)

基于分割的文本检测

基于混合的文本检测

继续阅读