文本检测 传统文本检测 形态学: MSER+NMS 深度学习文本检测分类 基于候选框的文本检测 基于分割的文本检测 基于混合的文本
文本检测
- 传统文本检测
- 形态学:
- MSER+NMS
- 深度学习文本检测分类
- 基于候选框的文本检测
- 基于分割的文本检测
- 基于混合的文本检测
传统文本检测
当前应用中面对文本检测会遇到很多难点:
- 文本图像的背景多样化,很多背景可能像素情况与文本结构相似
- 文本的形状和方向多样化,可能图像中文本的摆放方向是倾斜的,横向的
- 文本的颜色,字体多样化
- 图像中受光照等环境因素影响
由于这些检测上的难点,传统基于opencv通过形态学、MSER+NMS的方法无法实现实际场景的文本检测。因此对于复杂场景下文本检测大多基于深度学习算法实现。
形态学:
import cv2import 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流程:
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)得到最终的预测结果
基于分割的文本检测
基于分割的文本检测,其基本思路是通过分割网络结构进行像素级别的语义分割,再基于分割的结果构建文本行
基于混合的文本检测